64a31cd16613e7cdec9f3bd0f758687b64592106
[cascardo/ipsilon.git] / tests / testmapping.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2015 Ipsilon project Contributors, for license see COPYING
4
5 from helpers.common import IpsilonTestBase  # pylint: disable=relative-import
6 from helpers.http import HttpSessions  # pylint: disable=relative-import
7 import os
8 import sys
9 import pwd
10 from string import Template
11
12 # Test Attribute Mapping and Allowed Attributes and their per-SP
13 # overrides.
14
15
16 idp_g = {'TEMPLATES': '${TESTDIR}/templates/install',
17          'CONFDIR': '${TESTDIR}/etc',
18          'DATADIR': '${TESTDIR}/lib',
19          'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
20          'STATICDIR': '${ROOTDIR}',
21          'BINDIR': '${ROOTDIR}/ipsilon',
22          'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
23
24
25 idp_a = {'hostname': '${ADDRESS}:${PORT}',
26          'admin_user': '${TEST_USER}',
27          'system_user': '${TEST_USER}',
28          'instance': '${NAME}',
29          'secure': 'no',
30          'testauth': 'yes',
31          'pam': 'no',
32          'gssapi': 'no',
33          'ipa': 'no',
34          'server_debugging': 'True'}
35
36
37 sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
38         'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
39         'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
40         'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
41
42
43 sp_a = {'hostname': '${ADDRESS}:${PORT}',
44         'saml_idp_metadata': 'http://127.0.0.10:45080/idp1/saml2/metadata',
45         'saml_secure_setup': 'False',
46         'saml_auth': '/sp',
47         'saml_nameid': '${NAMEID}',
48         'httpd_user': '${TEST_USER}'}
49
50 sp_list = [
51     {'name': 'sp1', 'addr': '127.0.0.11', 'port': '45081'},
52 ]
53
54
55 def convert_to_dict(envlist):
56     values = {}
57     for pair in envlist.split('\n'):
58         if pair.find('=') > 0:
59             (key, value) = pair.split('=', 1)
60             if key.startswith('MELLON_') and not key.endswith('_0'):
61                 values[key] = value
62     return values
63
64
65 def check_info_plugin(s, idp_name, urlbase, expected):
66     """
67     Logout, login, fetch SP page to get the info variables and
68     compare the MELLON_ ones to what we expect.  IDP and NAMEID are
69     ignored.
70     """
71
72     # Log out
73     page = s.fetch_page(idp_name, '%s/%s?%s' % (
74         urlbase, 'saml2/logout',
75         'ReturnTo=%s/open/logged_out.html' % urlbase))
76     page.expected_value('text()', 'Logged out')
77
78     # Fetch the page (with implicit login)
79     page = s.fetch_page(idp_name, '%s/sp/' % spurl)
80
81     # Confirm that the expected values are in the output and that there
82     # are no unexpected MELLON_ vars, and drop the _0 version.
83     data = convert_to_dict(page.text)
84
85     data.pop('MELLON_IDP')
86     data.pop('MELLON_NAME_ID')
87
88     for key in expected:
89         item = data.pop('MELLON_' + key)
90         if item != expected[key]:
91             raise ValueError('Expected %s, got %s' % (expected[key], item))
92
93     if len(data) > 0:
94         raise ValueError('Unexpected values %s' % data)
95
96
97 def fixup_sp_httpd(httpdir):
98     location = """
99
100 AddOutputFilter INCLUDES .html
101
102 Alias /sp ${HTTPDIR}/sp
103
104 <Directory ${HTTPDIR}/sp>
105     Require all granted
106     Options +Includes
107 </Directory>
108
109 Alias /open ${HTTPDIR}/open
110
111 <Directory ${HTTPDIR}/open>
112 </Directory>
113
114 """
115     index = """
116 <!--#printenv  -->
117 """
118     logged_out = """Logged out"""
119
120     t = Template(location)
121     text = t.substitute({'HTTPDIR': httpdir})
122     with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f:
123         f.write(text)
124
125     os.mkdir(httpdir + '/sp')
126     with open(httpdir + '/sp/index.html', 'w') as f:
127         f.write(index)
128     os.mkdir(httpdir + '/open')
129     with open(httpdir + '/open/logged_out.html', 'w') as f:
130         f.write(logged_out)
131
132
133 class IpsilonTest(IpsilonTestBase):
134
135     def __init__(self):
136         super(IpsilonTest, self).__init__('testmapping', __file__)
137
138     def setup_servers(self, env=None):
139         print "Installing IDP server"
140         name = 'idp1'
141         addr = '127.0.0.10'
142         port = '45080'
143         idp = self.generate_profile(idp_g, idp_a, name, addr, port)
144         conf = self.setup_idp_server(idp, name, addr, port, env)
145
146         print "Starting IDP's httpd server"
147         self.start_http_server(conf, env)
148
149         for spdata in sp_list:
150             addr = spdata['addr']
151             port = spdata['port']
152             name = spdata['name']
153
154             print "Installing SP server %s" % name
155             sp_prof = self.generate_profile(sp_g, sp_a, name, addr, str(port))
156             conf = self.setup_sp_server(sp_prof, name, addr, str(port), env)
157             fixup_sp_httpd(os.path.dirname(conf))
158
159             print "Starting SP's httpd server"
160             self.start_http_server(conf, env)
161
162
163 if __name__ == '__main__':
164
165     idpname = 'idp1'
166     user = pwd.getpwuid(os.getuid())[0]
167     sp = sp_list[0]
168     spurl = 'http://%s:%s' % (sp['addr'], sp['port'])
169
170     # Set global mapping and allowed attributes, then test fetch from
171     # SP.
172     sess = HttpSessions()
173     sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'ipsilon')
174     sess.add_server(sp['name'], spurl)
175
176     print "testmapping: Authenticate to IDP ...",
177     try:
178         sess.auth_to_idp(idpname)
179     except Exception, e:  # pylint: disable=broad-except
180         print >> sys.stderr, " ERROR: %s" % repr(e)
181         sys.exit(1)
182     print " SUCCESS"
183
184     print "testmapping: Add SP Metadata to IDP ...",
185     try:
186         sess.add_sp_metadata(idpname, sp['name'])
187     except Exception, e:  # pylint: disable=broad-except
188         print >> sys.stderr, " ERROR: %s" % repr(e)
189         sys.exit(1)
190     print " SUCCESS"
191
192     try:
193         print "testmapping: Test default mapping and attrs ...",
194         expect = {
195             'fullname': 'Test User %s' % user,
196             'surname': user,
197             'givenname': 'Test User',
198             'email': '%s@example.com' % user,
199             'groups': user,
200         }
201         check_info_plugin(sess, idpname, spurl, expect)
202     except Exception, e:  # pylint: disable=broad-except
203         print >> sys.stderr, " ERROR: %s" % repr(e)
204         sys.exit(1)
205     print " SUCCESS"
206
207     print "testmapping: Set default global mapping ...",
208     try:
209         sess.set_attributes_and_mapping(idpname,
210                                         [['*', '*'],
211                                          ['fullname', 'namefull']])
212     except Exception, e:  # pylint: disable=broad-except
213         print >> sys.stderr, " ERROR: %s" % repr(e)
214         sys.exit(1)
215     else:
216         print " SUCCESS"
217
218     try:
219         print "testmapping: Test global mapping ...",
220         expect = {
221             'fullname': 'Test User %s' % user,
222             'namefull': 'Test User %s' % user,
223             'surname': user,
224             'givenname': 'Test User',
225             'email': '%s@example.com' % user,
226             'groups': user
227         }
228         check_info_plugin(sess, idpname, spurl, expect)
229     except Exception, e:  # pylint: disable=broad-except
230         print >> sys.stderr, " ERROR: %s" % repr(e)
231         sys.exit(1)
232     else:
233         print " SUCCESS"
234
235     print "testmapping: Set default allowed attributes ...",
236     try:
237         sess.set_attributes_and_mapping(idpname, [],
238                                         ['namefull', 'givenname', 'surname'])
239     except Exception, e:  # pylint: disable=broad-except
240         print >> sys.stderr, " ERROR: %s" % repr(e)
241         sys.exit(1)
242     else:
243         print " SUCCESS"
244
245     try:
246         print "testmapping: Test global allowed attributes ...",
247         expect = {
248             'namefull': 'Test User %s' % user,
249             'surname': user,
250             'givenname': 'Test User',
251         }
252         check_info_plugin(sess, idpname, spurl, expect)
253     except Exception, e:  # pylint: disable=broad-except
254         print >> sys.stderr, " ERROR: %s" % repr(e)
255         sys.exit(1)
256     else:
257         print " SUCCESS"
258
259     print "testmapping: Set SP allowed attributes ...",
260     try:
261         sess.set_attributes_and_mapping(idpname, [['*', '*']],
262                                         ['wholename', 'givenname', 'surname',
263                                         'email', 'fullname'], sp['name'])
264     except Exception, e:  # pylint: disable=broad-except
265         print >> sys.stderr, " ERROR: %s" % repr(e)
266         sys.exit(1)
267     else:
268         print " SUCCESS"
269
270     try:
271         print "testmapping: Test SP allowed atributes ...",
272         expect = {
273             'fullname': 'Test User %s' % user,
274             'surname': user,
275             'givenname': 'Test User',
276             'email': '%s@example.com' % user,
277         }
278         check_info_plugin(sess, idpname, spurl, expect)
279     except Exception, e:  # pylint: disable=broad-except
280         print >> sys.stderr, " ERROR: %s" % repr(e)
281         sys.exit(1)
282     else:
283         print " SUCCESS"
284
285     print "testmapping: Set SP attribute mapping ...",
286     try:
287         sess.set_attributes_and_mapping(idpname,
288                                         [['*', '*'],
289                                          ['fullname', 'wholename']],
290                                         ['wholename', 'givenname',
291                                          'surname',
292                                          'email', 'fullname'],
293                                         sp['name'])
294     except Exception, e:  # pylint: disable=broad-except
295         print >> sys.stderr, " ERROR: %s" % repr(e)
296         sys.exit(1)
297     else:
298         print " SUCCESS"
299
300     try:
301         print "testmapping: Test SP attribute mapping ...",
302         expect = {
303             'wholename': 'Test User %s' % user,
304             'fullname': 'Test User %s' % user,
305             'surname': user,
306             'givenname': 'Test User',
307             'email': '%s@example.com' % user,
308         }
309         check_info_plugin(sess, idpname, spurl, expect)
310     except Exception, e:  # pylint: disable=broad-except
311         print >> sys.stderr, " ERROR: %s" % repr(e)
312         sys.exit(1)
313     else:
314         print " SUCCESS"
315
316     print "testmapping: Drop SP attribute mapping ...",
317     try:
318         sess.set_attributes_and_mapping(idpname, [],
319                                         ['givenname', 'surname', 'email',
320                                          'fullname'], sp['name'])
321     except Exception, e:  # pylint: disable=broad-except
322         print >> sys.stderr, " ERROR: %s" % repr(e)
323         sys.exit(1)
324     else:
325         print " SUCCESS"
326
327     try:
328         print "testmapping: Test SP attr mapping with default allowed...",
329         expect = {
330             'fullname': 'Test User %s' % user,
331             'surname': user,
332             'givenname': 'Test User',
333             'email': '%s@example.com' % user,
334         }
335         check_info_plugin(sess, idpname, spurl, expect)
336     except Exception, e:  # pylint: disable=broad-except
337         print >> sys.stderr, " ERROR: %s" % repr(e)
338         sys.exit(1)
339     else:
340         print " SUCCESS"
341
342     print "testmapping: Drop SP allowed attributes ...",
343     try:
344         sess.set_attributes_and_mapping(idpname, [], [], sp['name'])
345     except Exception, e:  # pylint: disable=broad-except
346         print >> sys.stderr, " ERROR: %s" % repr(e)
347         sys.exit(1)
348     else:
349         print " SUCCESS"
350
351     try:
352         print "testmapping: Test mapping, should be back to global...",
353         expect = {
354             'namefull': 'Test User %s' % user,
355             'surname': user,
356             'givenname': 'Test User',
357         }
358         check_info_plugin(sess, idpname, spurl, expect)
359     except Exception, e:  # pylint: disable=broad-except
360         print >> sys.stderr, " ERROR: %s" % repr(e)
361         sys.exit(1)
362     else:
363         print " SUCCESS"