Hi,

attached are tests for authentication indicators. Please note:

1. newly created service tracker is not exactly complete, list of unimplemented methods is in doc. These methods can be filled in when existing declarative tests are refactored.

2. patch 0015 depends on 0014, so it should not be pushed without it.


Lenka

From 2dfcc81b979a345dbed2449a5c30ba19fd2025ee Mon Sep 17 00:00:00 2001
From: Lenka Doudova <ldoud...@redhat.com>
Date: Wed, 15 Jun 2016 13:40:00 +0200
Subject: [PATCH] Tests: Tracker class for services

Provides basic service tracker, so far for purposes of [1].
Tracker is not complete, some methods will need to be added in case of service test refactoring.

[1] https://fedorahosted.org/freeipa/ticket/433
---
 ipatests/test_xmlrpc/tracker/service_plugin.py | 173 +++++++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/tracker/service_plugin.py

diff --git a/ipatests/test_xmlrpc/tracker/service_plugin.py b/ipatests/test_xmlrpc/tracker/service_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fdf17ddf9cd7fee7b5af71347b32c41f61cd355
--- /dev/null
+++ b/ipatests/test_xmlrpc/tracker/service_plugin.py
@@ -0,0 +1,173 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+
+import six
+
+from ipalib import api
+from ipatests.test_xmlrpc.tracker.base import Tracker
+from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_uuid
+from ipatests.test_xmlrpc import objectclasses
+from ipatests.util import assert_deepequal
+from ipapython.dn import DN
+
+if six.PY3:
+    unicode = str
+
+
+class ServiceTracker(Tracker):
+    """
+    Tracker class for service plugin
+
+    So far does not include methods for these commands:
+        service-add-host
+        service-remove-host
+        service-allow-retrieve-keytab
+        service-disallow-retrieve-keytab
+        service-allow-create-keytab
+        service-disallow-create-keytab
+        service-disable
+        service-add-cert
+        service-remove-cert
+    """
+
+    retrieve_keys = {
+        u'dn', u'krbprincipalname', u'usercertificate', u'has_keytab',
+        u'ipakrbauthzdata', u'ipaallowedtoperform', u'subject',
+        u'managedby', u'serial_number', u'serial_number_hex', u'issuer',
+        u'valid_not_before', u'valid_not_after', u'md5_fingerprint',
+        u'sha1_fingerprint', u'krbprincipalauthind', u'managedby_host'}
+    retrieve_all_keys = retrieve_keys | {
+        u'ipaKrbPrincipalAlias', u'ipaUniqueID', u'krbExtraData',
+        u'krbLastPwdChange', u'krbLoginFailedCount', u'memberof',
+        u'objectClass', u'ipakrbrequirespreauth',
+        u'ipakrbokasdelegate'}
+
+    create_keys = (retrieve_keys | {u'objectclass', u'ipauniqueid'}) - {
+        u'usercertificate', u'has_keytab'}
+    update_keys = retrieve_keys - {u'dn'}
+
+    def __init__(self, name, host_fqdn, options):
+        super(ServiceTracker, self).__init__(default_version=None)
+        self._name = "{0}/{1}@{2}".format(name, host_fqdn, api.env.realm)
+        self.dn = DN(
+            ('krbprincipalname', self.name), api.env.container_service,
+            api.env.basedn)
+        self.host_fqdn = host_fqdn
+        self.options = options
+
+    @property
+    def name(self):
+        return self._name
+
+    def make_create_command(self, force=True):
+        """ Make function that creates a service """
+        return self.make_command('service_add', self.name,
+                                 force=force, **self.options)
+
+    def make_delete_command(self):
+        """ Make function that deletes a service """
+        return self.make_command('service_del', self.name)
+
+    def make_retrieve_command(self, all=False, raw=False):
+        """ Make function that retrieves a service """
+        return self.make_command('service_show', self.name, all=all)
+
+    def make_find_command(self, *args, **kwargs):
+        """ Make function that searches for a service"""
+        return self.make_command('service_find', *args, **kwargs)
+
+    def make_update_command(self, updates):
+        """ Make function that updates a service """
+
+        return self.make_command('service_mod', self.name, **updates)
+
+    def track_create(self, **options):
+        """ Update expected state for service creation """
+        self.attrs = {
+            u'dn': self.dn,
+            u'krbprincipalname': [u'{0}'.format(self.name)],
+            u'objectclass': objectclasses.service,
+            u'ipauniqueid': [fuzzy_uuid],
+            u'managedby_host': [self.host_fqdn],
+        }
+
+        for key in self.options:
+            self.attrs[key] = [self.options[key]]
+
+    def check_create(self, result):
+        """ Check service-add command result """
+        assert_deepequal({
+            u'value': u'{0}'.format(self.name),
+            u'summary': u'Added service "{0}"'.format(self.name),
+            u'result': self.filter_attrs(self.create_keys)
+            }, result)
+
+    def check_delete(self, result):
+        """ Check service-del command result """
+        assert_deepequal({
+            u'value': [u'{0}'.format(self.name)],
+            u'summary': u'Deleted service "{0}"'.format(self.name),
+            u'result': {u'failed': []}
+            }, result)
+
+    def check_retrieve(self, result, all=False, raw=False):
+        """ Check service-show command result """
+        if all:
+            expected = self.filter_attrs(self.retrieve_all_keys)
+        else:
+            expected = self.filter_attrs(self.retrieve_keys)
+
+        assert_deepequal({
+            u'value': u'{0}'.format(self.name),
+            u'summary': None,
+            u'result': expected,
+        }, result)
+
+    def check_find(self, result, all=False, raw=False):
+        """ Check service-find command result """
+        if all:
+            expected = self.filter_attrs(self.retrieve_all_keys)
+        else:
+            expected = self.filter_attrs(self.retrieve_keys)
+
+        assert_deepequal({
+            u'count': 1,
+            u'truncated': False,
+            u'summary': u'1 service matched',
+            u'result': [expected]
+            }, result)
+
+    def check_update(self, result, extra_keys=()):
+        """ Check service-mod command result """
+        assert_deepequal({
+            u'value': u'{0}'.format(self.name),
+            u'summary': u'Modified service "{0}"'.format(self.name),
+            u'result': self.filter_attrs(self.update_keys | set(extra_keys))
+            }, result)
+
+    def update(self, updates, expected_updates=None):
+        """Helper function to update service and check the result
+
+        The ``updates`` are used as options to the *_mod command,
+        and the self.attrs is updated with this dict. In case ``updates``
+        contain ``addattr``, self.attrs is not updated with the dict.
+
+        Additionally, self.attrs is updated with ``expected_updates``.
+        """
+        if expected_updates is None:
+            expected_updates = {}
+
+        self.create()
+        command = self.make_update_command(updates)
+        result = command()
+        if u'addattr' not in updates:
+            self.attrs.update(updates)
+        self.attrs.update(expected_updates)
+        for key, value in self.attrs.items():
+            if value is None:
+                del self.attrs[key]
+
+        self.check_update(result, extra_keys=set(updates.keys()) |
+                          set(expected_updates.keys()))
-- 
2.7.4

From fee1c0072ed26bb7428d042968f769acc435bd9c Mon Sep 17 00:00:00 2001
From: Lenka Doudova <ldoud...@redhat.com>
Date: Wed, 15 Jun 2016 13:44:16 +0200
Subject: [PATCH] Tests: Authentication indicators xmlrpc tests

https://fedorahosted.org/freeipa/ticket/433
---
 ipatests/test_xmlrpc/test_service_plugin.py | 43 ++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/ipatests/test_xmlrpc/test_service_plugin.py b/ipatests/test_xmlrpc/test_service_plugin.py
index 0a38e3d653ed0b3083301b1ca9a5f252f9bbaa4b..f936d2b128024c9f7ef639911f34387246302377 100644
--- a/ipatests/test_xmlrpc/test_service_plugin.py
+++ b/ipatests/test_xmlrpc/test_service_plugin.py
@@ -24,10 +24,14 @@ Test the `ipaserver/plugins/service.py` module.
 from ipalib import api, errors, x509
 from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid, fuzzy_hash
 from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_digits, fuzzy_date, fuzzy_issuer
-from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_hex
+from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_hex, XMLRPC_test
 from ipatests.test_xmlrpc import objectclasses
 from ipatests.test_xmlrpc.testcert import get_testcert
 from ipatests.test_xmlrpc.test_user_plugin import get_user_result, get_group_dn
+
+from ipatests.test_xmlrpc.tracker.service_plugin import ServiceTracker
+from ipatests.test_xmlrpc.tracker.host_plugin import HostTracker
+
 import base64
 from ipapython.dn import DN
 import pytest
@@ -1222,3 +1226,40 @@ class test_service_allowed_to(Declarative):
             ),
         ),
     ]
+
+
+@pytest.fixture(scope='function')
+def host1(request):
+    tracker = HostTracker(name=u'testhost1', fqdn=fqdn1)
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='function')
+def service2(request):
+    tracker = ServiceTracker(
+        name=u'SRV1', host_fqdn=fqdn1, options={
+            u'krbprincipalauthind': u'otp'})
+    return tracker.make_fixture(request)
+
+
+@pytest.mark.tier1
+class TestAuthenticationIndicators(XMLRPC_test):
+    def test_create_service_with_otp_indicator(self, host1, service2):
+        """ Since range of authentication indicator values is not limited,
+        only 'otp' option is tested """
+        host1.create()
+        service2.create()
+
+    def test_adding_second_indicator(self, host1, service2):
+        host1.create()
+        service2.update(
+            updates={u'addattr': u'krbprincipalauthind=radius'},
+            expected_updates={u'krbprincipalauthind': [u'otp', u'radius']}
+        )
+
+    def test_update_indicator(self, host1, service2):
+        host1.create()
+        service2.update(
+            updates={u'krbprincipalauthind': u'radius'},
+            expected_updates={u'krbprincipalauthind': [u'radius']}
+        )
-- 
2.7.4

From 8de3d5dcba66569700f0572e35c2b622ea46228c Mon Sep 17 00:00:00 2001
From: Lenka Doudova <ldoud...@redhat.com>
Date: Wed, 15 Jun 2016 13:45:59 +0200
Subject: [PATCH] Tests: Authentication indicators integration tests

https://fedorahosted.org/freeipa/ticket/433
---
 .../test_integration/test_service_permissions.py   | 56 ++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/ipatests/test_integration/test_service_permissions.py b/ipatests/test_integration/test_service_permissions.py
index 3d4a50d324ae71006bab3fafb966c60ab1574e13..59f46971303d7cda39dcd320a729a96abbc07b30 100644
--- a/ipatests/test_integration/test_service_permissions.py
+++ b/ipatests/test_integration/test_service_permissions.py
@@ -80,3 +80,59 @@ class TestServicePermissions(IntegrationTest):
 
         self.master.run_command(['ipa', 'service-del', service_name])
         self.master.run_command(['ipa', 'user-del', 'tuser'])
+
+
+class TestServiceAuthenticationIndicators(IntegrationTest):
+    topology = 'star'
+
+    def test_service_access(self):
+        """ Test that user is granted access when authenticated using
+        credentials that are sufficient for a service, and denied access
+        when using insufficient credentials"""
+
+        service_name = 'testservice/%s@%s' % (self.master.hostname,
+                                              self.master.domain.realm)
+
+        keytab_file = os.path.join(self.master.config.test_dir,
+                                   'testservice_keytab')
+
+        # Prepare a service without authentication indicator
+        self.master.run_command(['ipa', 'service-add', service_name])
+
+        self.master.run_command(['ipa-getkeytab',
+                                 '-p', service_name,
+                                 '-k', keytab_file])
+
+        # Set authentication-type for admin user
+        self.master.run_command(['ipa', 'user-mod', 'admin',
+                                 '--user-auth-type=password',
+                                 '--user-auth-type=otp'])
+
+        # Authenticate
+        self.master.run_command(['kinit', '-k', service_name,
+                                 '-t', keytab_file])
+
+        # Verify access to service is granted
+        result = self.master.run_command(['kvno', service_name],
+                                         raiseonerr=False)
+        assert result.returncode == 0
+
+        # Obtain admin ticket to be able to update service
+        tasks.kinit_admin(self.master)
+
+        # Modify service to have authentication indicator
+        self.master.run_command(['ipa', 'service-mod', service_name,
+                                 '--auth-ind=otp'])
+
+        self.master.run_command(['ipa-getkeytab',
+                                 '-p', service_name,
+                                 '-k', keytab_file])
+
+        # Authenticate
+        self.master.run_command(['kinit', '-k', service_name,
+                                 '-t', keytab_file])
+
+        # Verify access to service is rejected
+        result = self.master.run_command(['kvno', service_name],
+                                         raiseonerr=False)
+        assert result.returncode > 0
-- 
2.7.4

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to