3 # Copyright (C) 2015 Ipsilon project Contributors, for license see COPYING
5 from helpers.common import IpsilonTestBase # pylint: disable=relative-import
6 from helpers.common import WRAP_HOSTNAME # pylint: disable=relative-import
7 from helpers.common import TESTREALM # pylint: disable=relative-import
8 from helpers.http import HttpSessions # pylint: disable=relative-import
9 from ipsilon.tools.saml2metadata import SAML2_NAMEID_MAP
14 from string import Template
17 idp_g = {'TEMPLATES': '${TESTDIR}/templates/install',
18 'CONFDIR': '${TESTDIR}/etc',
19 'DATADIR': '${TESTDIR}/lib',
20 'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
21 'STATICDIR': '${ROOTDIR}',
22 'BINDIR': '${ROOTDIR}/ipsilon',
23 'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
26 idp_a = {'hostname': '${ADDRESS}:${PORT}',
27 'admin_user': '${TEST_USER}',
28 'system_user': '${TEST_USER}',
29 'instance': '${NAME}',
34 'gssapi_httpd_keytab': '${TESTDIR}/${HTTP_KTNAME}',
36 'server_debugging': 'True'}
39 sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
40 'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
41 'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
42 'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
45 sp_a = {'hostname': '${ADDRESS}:${PORT}',
46 'saml_idp_metadata': 'http://%s:45080/idp1/saml2/metadata' %
48 'saml_secure_setup': 'False',
50 'saml_nameid': '${NAMEID}',
51 'httpd_user': '${TEST_USER}'}
54 def generate_sp_list():
58 for nameid in SAML2_NAMEID_MAP.keys():
60 spdata = {'nameid': nameid, 'addr': '127.0.0.11', 'port': str(spport)}
67 def get_sp_by_nameid(splist, nameid):
69 if server['nameid'] == nameid:
75 def convert_to_dict(envlist):
77 for pair in envlist.split('\n'):
78 if pair.find('=') > 0:
79 (key, value) = pair.split('=', 1)
84 def fixup_sp_httpd(httpdir):
87 AddOutputFilter INCLUDES .html
89 Alias /sp ${HTTPDIR}/sp
91 <Directory ${HTTPDIR}/sp>
96 index = """<!--#echo var="REMOTE_USER" -->"""
98 t = Template(location)
99 text = t.substitute({'HTTPDIR': httpdir})
100 with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f:
103 os.mkdir(httpdir + '/sp')
104 with open(httpdir + '/sp/index.html', 'w') as f:
108 class IpsilonTest(IpsilonTestBase):
111 super(IpsilonTest, self).__init__('testnameid', __file__)
113 def setup_servers(self, env=None):
114 os.mkdir("%s/ccaches" % self.testdir)
116 print "Installing KDC server"
117 kdcenv = self.setup_kdc(env)
119 print "Creating principals and keytabs"
120 self.setup_keys(kdcenv)
122 print "Getting a TGT"
123 self.kinit_keytab(kdcenv)
125 print "Installing IDP server"
129 idp = self.generate_profile(idp_g, idp_a, name, addr, port)
130 conf = self.setup_idp_server(idp, name, addr, port, env)
132 print "Starting IDP's httpd server"
134 self.start_http_server(conf, env)
136 for spdata in generate_sp_list():
137 nameid = spdata['nameid']
138 addr = spdata['addr']
139 port = spdata['port']
140 print "Installing SP server %s" % nameid
141 sp_prof = self.generate_profile(
142 sp_g, sp_a, nameid, addr, str(port), nameid
144 conf = self.setup_sp_server(sp_prof, nameid, addr, str(port), env)
145 fixup_sp_httpd(os.path.dirname(conf))
147 print "Starting SP's httpd server"
148 self.start_http_server(conf, env)
151 if __name__ == '__main__':
154 user = pwd.getpwuid(os.getuid())[0]
157 'x509': False, # not supported
160 'windows': False, # not supported
161 'encrypted': False, # not supported
165 'entity': False, # not supported
169 'x509': 'Unauthorized', # not supported
170 'transient': '_[0-9a-f]{32}',
171 'persistent': '_[0-9a-f]{128}',
172 'windows': 'Unauthorized', # not supported
173 'encrypted': 'Unauthorized', # not supported
174 'kerberos': '%s@%s' % (user, TESTREALM),
175 'email': '%s@.*' % user,
177 'entity': 'Unauthorized', # not supported
180 testdir = os.environ['TESTDIR']
182 krb5conf = os.path.join(testdir, 'krb5.conf')
183 kenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
184 'KRB5_CONFIG': krb5conf,
185 'KRB5CCNAME': 'FILE:' + os.path.join(testdir, 'ccaches/user')}
188 os.environ[kkey] = kenv[kkey]
190 sp_list = generate_sp_list()
193 spname = sp['nameid']
194 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
195 sess = HttpSessions()
196 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME, user,
198 sess.add_server(spname, spurl)
201 print "testnameid: Testing NameID format %s ..." % spname
203 if spname == 'kerberos':
206 print "testnameid: Authenticate to IDP ...",
208 sess.auth_to_idp(idpname, krb=krb)
209 except Exception, e: # pylint: disable=broad-except
210 print >> sys.stderr, " ERROR: %s" % repr(e)
214 print "testnameid: Add SP Metadata to IDP ...",
216 sess.add_sp_metadata(idpname, spname)
217 except Exception, e: # pylint: disable=broad-except
218 print >> sys.stderr, " ERROR: %s" % repr(e)
222 print "testnameid: Set supported Name ID formats ...",
224 sess.set_sp_default_nameids(idpname, spname, [spname])
225 except Exception, e: # pylint: disable=broad-except
226 print >> sys.stderr, " ERROR: %s" % repr(e)
230 print "testnameid: Access SP Protected Area ...",
232 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
233 if not re.match(expected_re[spname], page.text):
235 'page did not contain expression %s' %
238 except ValueError, e:
240 print >> sys.stderr, " ERROR: %s" % repr(e)
242 print " OK, EXPECTED TO FAIL"
246 print "testnameid: Try authentication failure ...",
247 newsess = HttpSessions()
248 newsess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
251 newsess.auth_to_idp(idpname)
252 print >> sys.stderr, " ERROR: Authentication should have failed"
254 except Exception, e: # pylint: disable=broad-except
257 # Ensure that transient names change with each authentication
258 sp = get_sp_by_nameid(sp_list, 'transient')
259 spname = sp['nameid']
260 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
263 print "testnameid: Testing NameID format %s ..." % spname
267 sess = HttpSessions()
268 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
270 sess.add_server(spname, spurl)
271 print "testnameid: Authenticate to IDP ...",
273 sess.auth_to_idp(idpname)
274 except Exception, e: # pylint: disable=broad-except
275 print >> sys.stderr, " ERROR: %s" % repr(e)
280 print "testnameid: Access SP ...",
282 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
284 except ValueError, e:
285 print >> sys.stderr, " ERROR: %s" % repr(e)
290 print "testnameid: Access SP again ...",
292 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
294 except ValueError, e:
295 print >> sys.stderr, " ERROR: %s" % repr(e)
300 print "testnameid: Ensure ID is consistent between requests ...",
302 print >> sys.stderr, " ERROR: New ID between reqeusts"
308 print "testnameid: Ensure uniqueness across sessions ...",
309 if len(ids) != len(set(ids)):
310 print >> sys.stderr, " ERROR: IDs are not unique between sessions"
315 # Ensure that persistent names remain the same with each authentication
316 sp = get_sp_by_nameid(sp_list, 'persistent')
317 spname = sp['nameid']
318 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
321 print "testnameid: Testing NameID format %s ..." % spname
325 sess = HttpSessions()
326 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
328 sess.add_server(spname, spurl)
329 print "testnameid: Authenticate to IDP ...",
331 sess.auth_to_idp(idpname)
332 except Exception, e: # pylint: disable=broad-except
333 print >> sys.stderr, " ERROR: %s" % repr(e)
338 print "testnameid: Access SP ...",
340 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
342 except ValueError, e:
343 print >> sys.stderr, " ERROR: %s" % repr(e)
348 print "testnameid: Access SP again ...",
350 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
352 except ValueError, e:
353 print >> sys.stderr, " ERROR: %s" % repr(e)
358 print "testnameid: Ensure ID is consistent between requests ...",
360 print >> sys.stderr, " ERROR: New ID between reqeusts"
366 print "testnameid: Ensure same ID across sessions ...",
367 if len(set(ids)) != 1:
368 print >> sys.stderr, " ERROR: IDs are not the same between sessions"