summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2015-03-19 15:20:28 -0400
committerSimo Sorce <simo@redhat.com>2015-03-24 09:42:24 -0400
commit0f56ef9942ee631a9306806bea8f3bb8e7b81076 (patch)
tree8cf07962da831a3238ebdee7f7c94eb08e9daae5
parent424a03e5bd141bfa80220816d6e9bd6be9aa256f (diff)
downloadipsilon-0f56ef9942ee631a9306806bea8f3bb8e7b81076.tar.gz
ipsilon-0f56ef9942ee631a9306806bea8f3bb8e7b81076.tar.xz
ipsilon-0f56ef9942ee631a9306806bea8f3bb8e7b81076.zip
Add tests for Name ID functionality
Some Name ID formats are not implemented so are expected to fail. Kerberos is implemented but the test is done using form authentication so no Kerberos principal is available so authentication is denied. https://fedorahosted.org/ipsilon/ticket/27 Signed-off-by: Rob Crittenden <rcritten@redhat.com> Reviewed-by: Simo Sorce <simo@redhat.com>
-rw-r--r--Makefile1
-rwxr-xr-xtests/helpers/common.py4
-rwxr-xr-xtests/helpers/http.py16
-rwxr-xr-xtests/testnameid.py336
4 files changed, 356 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 6068024..bfe3121 100644
--- a/Makefile
+++ b/Makefile
@@ -60,6 +60,7 @@ wrappers:
tests: wrappers
PYTHONPATH=./ ./tests/tests.py --test=test1
PYTHONPATH=./ ./tests/tests.py --test=testlogout
+ PYTHONPATH=./ ./tests/tests.py --test=testnameid
PYTHONPATH=./ ./tests/tests.py --test=testrest
PYTHONPATH=./ ./tests/tests.py --test=attrs
PYTHONPATH=./ ./tests/tests.py --test=trans
diff --git a/tests/helpers/common.py b/tests/helpers/common.py
index 07a41fe..f3799c4 100755
--- a/tests/helpers/common.py
+++ b/tests/helpers/common.py
@@ -55,7 +55,8 @@ class IpsilonTestBase(object):
os.mkdir(os.path.join(self.testdir, 'lib', test.name))
os.mkdir(os.path.join(self.testdir, 'log'))
- def generate_profile(self, global_opts, args_opts, name, addr, port):
+ def generate_profile(self, global_opts, args_opts, name, addr, port,
+ nameid='unspecified'):
newconf = ConfigParser.ConfigParser()
newconf.add_section('globals')
for k in global_opts.keys():
@@ -71,6 +72,7 @@ class IpsilonTestBase(object):
text = t.substitute({'NAME': name, 'ADDRESS': addr, 'PORT': port,
'TESTDIR': self.testdir,
'ROOTDIR': self.rootdir,
+ 'NAMEID': nameid,
'TEST_USER': self.testuser})
filename = os.path.join(self.testdir, '%s_profile.cfg' % name)
diff --git a/tests/helpers/http.py b/tests/helpers/http.py
index cf59853..d8c56b3 100755
--- a/tests/helpers/http.py
+++ b/tests/helpers/http.py
@@ -266,6 +266,22 @@ class HttpSessions(object):
page.expected_value('//div[@class="alert alert-success"]/p/text()',
'SP Successfully added')
+ def set_sp_default_nameids(self, idp, sp, nameids):
+ """
+ nameids is a list of Name ID formats to enable
+ """
+ idpsrv = self.servers[idp]
+ idpuri = idpsrv['baseuri']
+ url = '%s/%s/admin/providers/saml2/admin/sp/%s' % (idpuri, idp, sp)
+ headers = {'referer': url}
+ headers['content-type'] = 'application/x-www-form-urlencoded'
+ payload = {'submit': 'Submit',
+ 'allowed_nameids': ', '.join(nameids)}
+ r = idpsrv['session'].post(url, headers=headers,
+ data=payload)
+ if r.status_code != 200:
+ raise ValueError('Failed to post SP data [%s]' % repr(r))
+
def fetch_rest_page(self, idpname, uri):
"""
idpname - the name of the IDP to fetch the page from
diff --git a/tests/testnameid.py b/tests/testnameid.py
new file mode 100755
index 0000000..a47e44b
--- /dev/null
+++ b/tests/testnameid.py
@@ -0,0 +1,336 @@
+#!/usr/bin/python
+# Copyright (C) 2015 Ipsilon Project Contributors
+
+from helpers.common import IpsilonTestBase # pylint: disable=relative-import
+from helpers.http import HttpSessions # pylint: disable=relative-import
+from ipsilon.tools.saml2metadata import SAML2_NAMEID_MAP
+import os
+import pwd
+import sys
+import re
+from string import Template
+
+
+idp_g = {'TEMPLATES': '${TESTDIR}/templates/install',
+ 'CONFDIR': '${TESTDIR}/etc',
+ 'DATADIR': '${TESTDIR}/lib',
+ 'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
+ 'STATICDIR': '${ROOTDIR}',
+ 'BINDIR': '${ROOTDIR}/ipsilon',
+ 'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
+
+
+idp_a = {'hostname': '${ADDRESS}:${PORT}',
+ 'admin_user': '${TEST_USER}',
+ 'system_user': '${TEST_USER}',
+ 'instance': '${NAME}',
+ 'secure': 'no',
+ 'testauth': 'yes',
+ 'pam': 'no',
+ 'krb': 'no',
+ 'ipa': 'no',
+ 'server_debugging': 'True'}
+
+
+sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
+ 'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
+ 'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
+ 'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
+
+
+sp_a = {'hostname': '${ADDRESS}:${PORT}',
+ 'saml_idp_metadata': 'http://127.0.0.10:45080/idp1/saml2/metadata',
+ 'saml_secure_setup': 'False',
+ 'saml_auth': '/sp',
+ 'saml_nameid': '${NAMEID}',
+ 'httpd_user': '${TEST_USER}'}
+
+
+def generate_sp_list():
+ splist = []
+ spport = 45081
+
+ for nameid in SAML2_NAMEID_MAP.keys():
+ nameid = nameid
+ spdata = {'nameid': nameid, 'addr': '127.0.0.11', 'port': str(spport)}
+ splist.append(spdata)
+ spport += 1
+
+ return splist
+
+
+def get_sp_by_nameid(splist, nameid):
+ for server in splist:
+ if server['nameid'] == nameid:
+ return server
+
+ return None
+
+
+def convert_to_dict(envlist):
+ values = {}
+ for pair in envlist.split('\n'):
+ if pair.find('=') > 0:
+ (key, value) = pair.split('=', 1)
+ values[key] = value
+ return values
+
+
+def fixup_sp_httpd(httpdir):
+ location = """
+
+AddOutputFilter INCLUDES .html
+
+Alias /sp ${HTTPDIR}/sp
+
+<Directory ${HTTPDIR}/sp>
+ Require all granted
+ Options +Includes
+</Directory>
+"""
+ index = """<!--#echo var="REMOTE_USER" -->"""
+
+ t = Template(location)
+ text = t.substitute({'HTTPDIR': httpdir})
+ with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f:
+ f.write(text)
+
+ os.mkdir(httpdir + '/sp')
+ with open(httpdir + '/sp/index.html', 'w') as f:
+ f.write(index)
+
+
+class IpsilonTest(IpsilonTestBase):
+
+ def __init__(self):
+ super(IpsilonTest, self).__init__('testnameid', __file__)
+
+ def setup_servers(self, env=None):
+ print "Installing IDP server"
+ name = 'idp1'
+ addr = '127.0.0.10'
+ port = '45080'
+ idp = self.generate_profile(idp_g, idp_a, name, addr, port)
+ conf = self.setup_idp_server(idp, name, addr, port, env)
+
+ print "Starting IDP's httpd server"
+ self.start_http_server(conf, env)
+
+ for spdata in generate_sp_list():
+ nameid = spdata['nameid']
+ addr = spdata['addr']
+ port = spdata['port']
+ print "Installing SP server %s" % nameid
+ sp_prof = self.generate_profile(
+ sp_g, sp_a, nameid, addr, str(port), nameid
+ )
+ conf = self.setup_sp_server(sp_prof, nameid, addr, str(port), env)
+ fixup_sp_httpd(os.path.dirname(conf))
+
+ print "Starting SP's httpd server"
+ self.start_http_server(conf, env)
+
+
+if __name__ == '__main__':
+
+ idpname = 'idp1'
+ user = pwd.getpwuid(os.getuid())[0]
+
+ expected = {
+ 'x509': False, # not supported
+ 'transient': True,
+ 'persistent': True,
+ 'windows': False, # not supported
+ 'encrypted': False, # not supported
+ 'kerberos': False, # no auth with kerberos, no princ
+ 'email': True,
+ 'unspecified': True,
+ 'entity': False, # not supported
+ }
+
+ expected_re = {
+ 'x509': None, # not supported
+ 'transient': '_[0-9a-f]{32}',
+ 'persistent': '_[0-9a-f]{128}',
+ 'windows': None, # not supported
+ 'encrypted': None, # not supported
+ 'kerberos': False, # no auth with kerberos, no princ
+ 'email': '%s@.*' % user,
+ 'unspecified': user,
+ 'entity': False, # not supported
+ }
+
+ sp_list = generate_sp_list()
+ for sp in sp_list:
+ spname = sp['nameid']
+ spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
+ sess = HttpSessions()
+ sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'ipsilon')
+ sess.add_server(spname, spurl)
+
+ print ""
+ print "testnameid: Testing NameID format %s ..." % spname
+
+ print "testnameid: Authenticate to IDP ...",
+ try:
+ sess.auth_to_idp(idpname)
+ except Exception, e: # pylint: disable=broad-except
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ print " SUCCESS"
+
+ print "testnameid: Add SP Metadata to IDP ...",
+ try:
+ sess.add_sp_metadata(idpname, spname)
+ except Exception, e: # pylint: disable=broad-except
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ print " SUCCESS"
+
+ print "testnameid: Set supported Name ID formats ...",
+ try:
+ sess.set_sp_default_nameids(idpname, spname, [spname])
+ except Exception, e: # pylint: disable=broad-except
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ print " SUCCESS"
+
+ print "testnameid: Access SP Protected Area ...",
+ try:
+ page = sess.fetch_page(idpname, '%s/sp/' % spurl)
+ if not re.match(expected_re[spname], page.text):
+ raise ValueError(
+ 'id %s did not match expression %s' %
+ (id, expected_re[spname])
+ )
+ except ValueError, e:
+ if expected[spname]:
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ print " OK, EXPECTED TO FAIL"
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Try authentication failure ...",
+ newsess = HttpSessions()
+ newsess.add_server(idpname, 'http://127.0.0.10:45080', user, 'wrong')
+ try:
+ newsess.auth_to_idp(idpname)
+ print >> sys.stderr, " ERROR: Authentication should have failed"
+ sys.exit(1)
+ except Exception, e: # pylint: disable=broad-except
+ print " SUCCESS"
+
+ # Ensure that transient names change with each authentication
+ sp = get_sp_by_nameid(sp_list, 'transient')
+ spname = sp['nameid']
+ spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
+
+ print ""
+ print "testnameid: Testing NameID format %s ..." % spname
+
+ ids = []
+ for i in xrange(4):
+ sess = HttpSessions()
+ sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'ipsilon')
+ sess.add_server(spname, spurl)
+ print "testnameid: Authenticate to IDP ...",
+ try:
+ sess.auth_to_idp(idpname)
+ except Exception, e: # pylint: disable=broad-except
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Access SP ...",
+ try:
+ page = sess.fetch_page(idpname, '%s/sp/' % spurl)
+ t1 = page.text
+ except ValueError, e:
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Access SP again ...",
+ try:
+ page = sess.fetch_page(idpname, '%s/sp/' % spurl)
+ t2 = page.text
+ except ValueError, e:
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Ensure ID is consistent between requests ...",
+ if t1 != t2:
+ print >> sys.stderr, " ERROR: New ID between reqeusts"
+ else:
+ print " SUCCESS"
+
+ ids.append(t1)
+
+ print "testnameid: Ensure uniqueness across sessions ...",
+ if len(ids) != len(set(ids)):
+ print >> sys.stderr, " ERROR: IDs are not unique between sessions"
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ # Ensure that persistent names remain the same with each authentication
+ sp = get_sp_by_nameid(sp_list, 'persistent')
+ spname = sp['nameid']
+ spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
+
+ print ""
+ print "testnameid: Testing NameID format %s ..." % spname
+
+ ids = []
+ for i in xrange(4):
+ sess = HttpSessions()
+ sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'ipsilon')
+ sess.add_server(spname, spurl)
+ print "testnameid: Authenticate to IDP ...",
+ try:
+ sess.auth_to_idp(idpname)
+ except Exception, e: # pylint: disable=broad-except
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Access SP ...",
+ try:
+ page = sess.fetch_page(idpname, '%s/sp/' % spurl)
+ t1 = page.text
+ except ValueError, e:
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Access SP again ...",
+ try:
+ page = sess.fetch_page(idpname, '%s/sp/' % spurl)
+ t2 = page.text
+ except ValueError, e:
+ print >> sys.stderr, " ERROR: %s" % repr(e)
+ sys.exit(1)
+ else:
+ print " SUCCESS"
+
+ print "testnameid: Ensure ID is consistent between requests ...",
+ if t1 != t2:
+ print >> sys.stderr, " ERROR: New ID between reqeusts"
+ else:
+ print " SUCCESS"
+
+ ids.append(t1)
+
+ print "testnameid: Ensure same ID across sessions ...",
+ if len(set(ids)) != 1:
+ print >> sys.stderr, " ERROR: IDs are not the same between sessions"
+ sys.exit(1)
+ else:
+ print " SUCCESS"