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 'CACHEDIR': '${TESTDIR}/cache',
21 'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
22 'STATICDIR': '${ROOTDIR}',
23 'BINDIR': '${ROOTDIR}/ipsilon',
24 'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
27 idp_a = {'hostname': '${ADDRESS}:${PORT}',
28 'admin_user': '${TEST_USER}',
29 'system_user': '${TEST_USER}',
30 'instance': '${NAME}',
35 'gssapi_httpd_keytab': '${TESTDIR}/${HTTP_KTNAME}',
37 'server_debugging': 'True'}
40 sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
41 'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
42 'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
43 'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
46 sp_a = {'hostname': '${ADDRESS}:${PORT}',
47 'saml_idp_metadata': 'http://%s:45080/idp1/saml2/metadata' %
49 'saml_secure_setup': 'False',
51 'saml_nameid': '${NAMEID}',
52 'httpd_user': '${TEST_USER}'}
55 def generate_sp_list():
59 for nameid in SAML2_NAMEID_MAP:
61 spdata = {'nameid': nameid, 'addr': '127.0.0.11', 'port': str(spport)}
68 def get_sp_by_nameid(splist, nameid):
70 if server['nameid'] == nameid:
76 def convert_to_dict(envlist):
78 for pair in envlist.split('\n'):
79 if pair.find('=') > 0:
80 (key, value) = pair.split('=', 1)
85 def fixup_sp_httpd(httpdir):
88 AddOutputFilter INCLUDES .html
90 Alias /sp ${HTTPDIR}/sp
92 <Directory ${HTTPDIR}/sp>
97 index = """<!--#echo var="REMOTE_USER" -->"""
99 t = Template(location)
100 text = t.substitute({'HTTPDIR': httpdir})
101 with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f:
104 os.mkdir(httpdir + '/sp')
105 with open(httpdir + '/sp/index.html', 'w') as f:
109 class IpsilonTest(IpsilonTestBase):
112 super(IpsilonTest, self).__init__('testnameid', __file__)
114 def setup_servers(self, env=None):
115 os.mkdir("%s/ccaches" % self.testdir)
117 print "Installing KDC server"
118 kdcenv = self.setup_kdc(env)
120 print "Creating principals and keytabs"
121 self.setup_keys(kdcenv)
123 print "Getting a TGT"
124 self.kinit_keytab(kdcenv)
126 print "Installing IDP server"
130 idp = self.generate_profile(idp_g, idp_a, name, addr, port)
131 conf = self.setup_idp_server(idp, name, addr, port, env)
133 print "Starting IDP's httpd server"
135 self.start_http_server(conf, env)
137 for spdata in generate_sp_list():
138 nameid = spdata['nameid']
139 addr = spdata['addr']
140 port = spdata['port']
141 print "Installing SP server %s" % nameid
142 sp_prof = self.generate_profile(
143 sp_g, sp_a, nameid, addr, str(port), nameid
145 conf = self.setup_sp_server(sp_prof, nameid, addr, str(port), env)
146 fixup_sp_httpd(os.path.dirname(conf))
148 print "Starting SP's httpd server"
149 self.start_http_server(conf, env)
152 if __name__ == '__main__':
155 user = pwd.getpwuid(os.getuid())[0]
158 'x509': False, # not supported
161 'windows': False, # not supported
162 'encrypted': False, # not supported
166 'entity': False, # not supported
170 'x509': 'Unauthorized', # not supported
171 'transient': '_[0-9a-f]{32}',
172 'persistent': '_[0-9a-f]{128}',
173 'windows': 'Unauthorized', # not supported
174 'encrypted': 'Unauthorized', # not supported
175 'kerberos': '%s@%s' % (user, TESTREALM),
176 'email': '%s@.*' % user,
178 'entity': 'Unauthorized', # not supported
181 testdir = os.environ['TESTDIR']
183 krb5conf = os.path.join(testdir, 'krb5.conf')
184 kenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin',
185 'KRB5_CONFIG': krb5conf,
186 'KRB5CCNAME': 'FILE:' + os.path.join(testdir, 'ccaches/user')}
189 os.environ[kkey] = kenv[kkey]
191 sp_list = generate_sp_list()
194 spname = sp['nameid']
195 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
196 sess = HttpSessions()
197 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME, user,
199 sess.add_server(spname, spurl)
202 print "testnameid: Testing NameID format %s ..." % spname
204 if spname == 'kerberos':
207 print "testnameid: Authenticate to IDP ...",
209 sess.auth_to_idp(idpname, krb=krb)
210 except Exception, e: # pylint: disable=broad-except
211 print >> sys.stderr, " ERROR: %s" % repr(e)
215 print "testnameid: Add SP Metadata to IDP ...",
217 sess.add_sp_metadata(idpname, spname)
218 except Exception, e: # pylint: disable=broad-except
219 print >> sys.stderr, " ERROR: %s" % repr(e)
223 print "testnameid: Set supported Name ID formats ...",
225 sess.set_sp_default_nameids(idpname, spname, [spname])
226 except Exception, e: # pylint: disable=broad-except
227 print >> sys.stderr, " ERROR: %s" % repr(e)
231 print "testnameid: Access SP Protected Area ...",
233 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
234 if not re.match(expected_re[spname], page.text):
236 'page did not contain expression %s' %
239 except ValueError, e:
241 print >> sys.stderr, " ERROR: %s" % repr(e)
243 print " OK, EXPECTED TO FAIL"
247 print "testnameid: Try authentication failure ...",
248 newsess = HttpSessions()
249 newsess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
252 newsess.auth_to_idp(idpname)
253 print >> sys.stderr, " ERROR: Authentication should have failed"
255 except Exception, e: # pylint: disable=broad-except
258 # Ensure that transient names change with each authentication
259 sp = get_sp_by_nameid(sp_list, 'transient')
260 spname = sp['nameid']
261 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
264 print "testnameid: Testing NameID format %s ..." % spname
268 sess = HttpSessions()
269 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
271 sess.add_server(spname, spurl)
272 print "testnameid: Authenticate to IDP ...",
274 sess.auth_to_idp(idpname)
275 except Exception, e: # pylint: disable=broad-except
276 print >> sys.stderr, " ERROR: %s" % repr(e)
281 print "testnameid: Access SP ...",
283 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
285 except ValueError, e:
286 print >> sys.stderr, " ERROR: %s" % repr(e)
291 print "testnameid: Access SP again ...",
293 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
295 except ValueError, e:
296 print >> sys.stderr, " ERROR: %s" % repr(e)
301 print "testnameid: Ensure ID is consistent between requests ...",
303 print >> sys.stderr, " ERROR: New ID between reqeusts"
309 print "testnameid: Ensure uniqueness across sessions ...",
310 if len(ids) != len(set(ids)):
311 print >> sys.stderr, " ERROR: IDs are not unique between sessions"
316 # Ensure that persistent names remain the same with each authentication
317 sp = get_sp_by_nameid(sp_list, 'persistent')
318 spname = sp['nameid']
319 spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
322 print "testnameid: Testing NameID format %s ..." % spname
326 sess = HttpSessions()
327 sess.add_server(idpname, 'http://%s:45080' % WRAP_HOSTNAME,
329 sess.add_server(spname, spurl)
330 print "testnameid: Authenticate to IDP ...",
332 sess.auth_to_idp(idpname)
333 except Exception, e: # pylint: disable=broad-except
334 print >> sys.stderr, " ERROR: %s" % repr(e)
339 print "testnameid: Access SP ...",
341 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
343 except ValueError, e:
344 print >> sys.stderr, " ERROR: %s" % repr(e)
349 print "testnameid: Access SP again ...",
351 page = sess.fetch_page(idpname, '%s/sp/' % spurl)
353 except ValueError, e:
354 print >> sys.stderr, " ERROR: %s" % repr(e)
359 print "testnameid: Ensure ID is consistent between requests ...",
361 print >> sys.stderr, " ERROR: New ID between reqeusts"
367 print "testnameid: Ensure same ID across sessions ...",
368 if len(set(ids)) != 1:
369 print >> sys.stderr, " ERROR: IDs are not the same between sessions"