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