cdf4f0b4f75dd58a0f0b629e869a657dd2cb1c54
[cascardo/ipsilon.git] / tests / testlogout.py
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2015  Rob Crittenden <rcritten@redhat.com>
4 #
5 # see file 'COPYING' for use and warranty information
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21 from helpers.common import IpsilonTestBase  # pylint: disable=relative-import
22 from helpers.http import HttpSessions  # pylint: disable=relative-import
23 import os
24 import pwd
25 import sys
26 from string import Template
27
28
29 idp_g = {'TEMPLATES': '${TESTDIR}/templates/install',
30          'CONFDIR': '${TESTDIR}/etc',
31          'DATADIR': '${TESTDIR}/lib',
32          'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
33          'STATICDIR': '${ROOTDIR}',
34          'BINDIR': '${ROOTDIR}/ipsilon',
35          'WSGI_SOCKET_PREFIX': '${TESTDIR}/${NAME}/logs/wsgi'}
36
37
38 idp_a = {'hostname': '${ADDRESS}:${PORT}',
39          'admin_user': '${TEST_USER}',
40          'system_user': '${TEST_USER}',
41          'instance': '${NAME}',
42          'secure': 'no',
43          'testauth': 'yes',
44          'pam': 'no',
45          'gssapi': 'no',
46          'ipa': 'no',
47          'server_debugging': 'True'}
48
49
50 sp_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
51         'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
52         'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
53         'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
54
55
56 sp_a = {'hostname': '${ADDRESS}:${PORT}',
57         'saml_idp_metadata': 'http://127.0.0.10:45080/idp1/saml2/metadata',
58         'saml_secure_setup': 'False',
59         'saml_auth': '/sp',
60         'httpd_user': '${TEST_USER}'}
61
62
63 sp2_g = {'HTTPDCONFD': '${TESTDIR}/${NAME}/conf.d',
64          'SAML2_TEMPLATE': '${TESTDIR}/templates/install/saml2/sp.conf',
65          'SAML2_CONFFILE': '${TESTDIR}/${NAME}/conf.d/ipsilon-saml.conf',
66          'SAML2_HTTPDIR': '${TESTDIR}/${NAME}/saml2'}
67
68
69 sp2_a = {'hostname': '${ADDRESS}:${PORT}',
70          'saml_idp_metadata': 'http://127.0.0.10:45080/idp1/saml2/metadata',
71          'saml_secure_setup': 'False',
72          'saml_auth': '/sp',
73          'httpd_user': '${TEST_USER}'}
74
75
76 def fixup_sp_httpd(httpdir):
77     location = """
78
79 Alias /sp ${HTTPDIR}/sp
80
81 <Directory ${HTTPDIR}/sp>
82     Require all granted
83 </Directory>
84
85 Alias /open ${HTTPDIR}/open
86
87 <Directory ${HTTPDIR}/open>
88 </Directory>
89 """
90     index = """WORKS!"""
91     logged_out = """Logged out"""
92
93     t = Template(location)
94     text = t.substitute({'HTTPDIR': httpdir})
95     with open(httpdir + '/conf.d/ipsilon-saml.conf', 'a') as f:
96         f.write(text)
97
98     os.mkdir(httpdir + '/sp')
99     with open(httpdir + '/sp/index.html', 'w') as f:
100         f.write(index)
101     os.mkdir(httpdir + '/open')
102     with open(httpdir + '/open/logged_out.html', 'w') as f:
103         f.write(logged_out)
104
105
106 def ensure_logout(session, idp_name, spurl):
107     """
108     Fetch the secure page without following redirects. If we get
109     a 303 then we should be redirected to the IDP for authentication
110     which means we aren't logged in.
111
112     Returns nothing or raises exception on error
113     """
114     try:
115         logout_page = session.fetch_page(idp_name, spurl,
116                                          follow_redirect=False)
117         if logout_page.result.status_code != 303:
118             raise ValueError('Still logged into url')
119     except ValueError:
120         raise
121
122     return True
123
124
125 class IpsilonTest(IpsilonTestBase):
126
127     def __init__(self):
128         super(IpsilonTest, self).__init__('testlogout', __file__)
129
130     def setup_servers(self, env=None):
131         print "Installing IDP server"
132         name = 'idp1'
133         addr = '127.0.0.10'
134         port = '45080'
135         idp = self.generate_profile(idp_g, idp_a, name, addr, port)
136         conf = self.setup_idp_server(idp, name, addr, port, env)
137
138         print "Starting IDP's httpd server"
139         self.start_http_server(conf, env)
140
141         print "Installing SP server"
142         name = 'sp1'
143         addr = '127.0.0.11'
144         port = '45081'
145         sp = self.generate_profile(sp_g, sp_a, name, addr, port)
146         conf = self.setup_sp_server(sp, name, addr, port, env)
147         fixup_sp_httpd(os.path.dirname(conf))
148
149         print "Starting SP's httpd server"
150         self.start_http_server(conf, env)
151
152         print "Installing second SP server"
153         name = 'sp2'
154         addr = '127.0.0.10'
155         port = '45082'
156         sp2 = self.generate_profile(sp2_g, sp2_a, name, addr, port)
157         conf = self.setup_sp_server(sp2, name, addr, 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     spname = 'sp1'
168     sp2name = 'sp2'
169     user = pwd.getpwuid(os.getuid())[0]
170
171     sess = HttpSessions()
172     sess.add_server(idpname, 'http://127.0.0.10:45080', user, 'ipsilon')
173     sess.add_server(spname, 'http://127.0.0.11:45081')
174     sess.add_server(sp2name, 'http://127.0.0.10:45082')
175
176     print "testlogout: 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 "testlogout: Add SP Metadata to IDP ...",
185     try:
186         sess.add_sp_metadata(idpname, spname)
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     print "testlogout: Add second SP Metadata to IDP ...",
193     try:
194         sess.add_sp_metadata(idpname, sp2name)
195     except Exception, e:  # pylint: disable=broad-except
196         print >> sys.stderr, " ERROR: %s" % repr(e)
197         sys.exit(1)
198     print " SUCCESS"
199
200     print "testlogout: Logout without logging into SP ...",
201     try:
202         page = sess.fetch_page(idpname, '%s/%s?%s' % (
203             'http://127.0.0.11:45081', 'saml2/logout',
204             'ReturnTo=http://127.0.0.11:45081/open/logged_out.html'))
205         page.expected_value('text()', 'Logged out')
206     except ValueError, e:
207         print >> sys.stderr, " ERROR: %s" % repr(e)
208         sys.exit(1)
209     print " SUCCESS"
210
211     print "testlogout: Access SP Protected Area ...",
212     try:
213         page = sess.fetch_page(idpname, 'http://127.0.0.11:45081/sp/')
214         page.expected_value('text()', 'WORKS!')
215     except ValueError, e:
216         print >> sys.stderr, " ERROR: %s" % repr(e)
217         sys.exit(1)
218     print " SUCCESS"
219
220     print "testlogout: Logout from SP ...",
221     try:
222         page = sess.fetch_page(idpname, '%s/%s?%s' % (
223             'http://127.0.0.11:45081', 'saml2/logout',
224             'ReturnTo=http://127.0.0.11:45081/open/logged_out.html'))
225         page.expected_value('text()', 'Logged out')
226     except ValueError, e:
227         print >> sys.stderr, " ERROR: %s" % repr(e)
228         sys.exit(1)
229     print " SUCCESS"
230
231     print "testlogout: Try logout again ...",
232     try:
233         page = sess.fetch_page(idpname, '%s/%s?%s' % (
234             'http://127.0.0.11:45081', 'saml2/logout',
235             'ReturnTo=http://127.0.0.11:45081/open/logged_out.html'))
236         page.expected_value('text()', 'Logged out')
237     except ValueError, e:
238         print >> sys.stderr, " ERROR: %s" % repr(e)
239         sys.exit(1)
240     print " SUCCESS"
241
242     print "testlogout: Ensure logout ...",
243     try:
244         ensure_logout(sess, idpname, 'http://127.0.0.11:45081/sp/')
245     except ValueError, e:
246         print >> sys.stderr, " ERROR: %s" % repr(e)
247         sys.exit(1)
248     print " SUCCESS"
249
250     print "testlogout: Access SP Protected Area of SP1...",
251     try:
252         page = sess.fetch_page(idpname, 'http://127.0.0.11:45081/sp/')
253         page.expected_value('text()', 'WORKS!')
254     except ValueError, e:
255         print >> sys.stderr, " ERROR: %s" % repr(e)
256         sys.exit(1)
257     print " SUCCESS"
258
259     print "testlogout: Access SP Protected Area of SP2...",
260     try:
261         page = sess.fetch_page(idpname, 'http://127.0.0.10:45082/sp/')
262         page.expected_value('text()', 'WORKS!')
263     except ValueError, e:
264         print >> sys.stderr, " ERROR: %s" % repr(e)
265         sys.exit(1)
266     print " SUCCESS"
267
268     print "testlogout: Logout from both ...",
269     try:
270         page = sess.fetch_page(idpname, '%s/%s?%s' % (
271             'http://127.0.0.11:45081', 'saml2/logout',
272             'ReturnTo=http://127.0.0.11:45081/open/logged_out.html'))
273         page.expected_value('text()', 'Logged out')
274     except ValueError, e:
275         print >> sys.stderr, " ERROR: %s" % repr(e)
276         sys.exit(1)
277     print " SUCCESS"
278
279     print "testlogout: Ensure logout of SP1 ...",
280     try:
281         ensure_logout(sess, idpname, 'http://127.0.0.11:45081/sp/')
282     except ValueError, e:
283         print >> sys.stderr, " ERROR: %s" % repr(e)
284         sys.exit(1)
285     print " SUCCESS"
286
287     print "testlogout: Ensure logout of SP2 ...",
288     try:
289         ensure_logout(sess, idpname, 'http://127.0.0.10:45082/sp/')
290     except ValueError, e:
291         print >> sys.stderr, " ERROR: %s" % repr(e)
292         sys.exit(1)
293     print " SUCCESS"
294
295     # Test IdP-initiated logout
296     print "testlogout: Access SP Protected Area of SP1...",
297     try:
298         page = sess.fetch_page(idpname, 'http://127.0.0.11:45081/sp/')
299         page.expected_value('text()', 'WORKS!')
300     except ValueError, e:
301         print >> sys.stderr, " ERROR: %s" % repr(e)
302         sys.exit(1)
303     print " SUCCESS"
304
305     print "testlogout: Access SP Protected Area of SP2...",
306     try:
307         page = sess.fetch_page(idpname, 'http://127.0.0.10:45082/sp/')
308         page.expected_value('text()', 'WORKS!')
309     except ValueError, e:
310         print >> sys.stderr, " ERROR: %s" % repr(e)
311         sys.exit(1)
312     print " SUCCESS"
313
314     print "testlogout: Access the IdP...",
315     try:
316         page = sess.fetch_page(idpname, 'http://127.0.0.10:45080/%s' % idpname)
317         page.expected_value('//div[@id="welcome"]/p/text()',
318                             'Welcome %s!' % user)
319     except ValueError, e:
320         print >> sys.stderr, " ERROR: %s" % repr(e)
321         sys.exit(1)
322     print " SUCCESS"
323
324     print "testlogout: IdP-initiated logout ...",
325     try:
326         page = sess.fetch_page(idpname,
327                                'http://127.0.0.10:45080/%s/logout' % idpname)
328         page.expected_value('//div[@id="content"]/p/a/text()', 'Log In')
329     except ValueError, e:
330         print >> sys.stderr, " ERROR: %s" % repr(e)
331         sys.exit(1)
332     print " SUCCESS"
333
334     print "testlogout: Ensure logout of SP1 ...",
335     try:
336         ensure_logout(sess, idpname, 'http://127.0.0.11:45081/sp/')
337     except ValueError, e:
338         print >> sys.stderr, " ERROR: %s" % repr(e)
339         sys.exit(1)
340     print " SUCCESS"
341
342     print "testlogout: Ensure logout of SP2 ...",
343     try:
344         ensure_logout(sess, idpname, 'http://127.0.0.10:45082/sp/')
345     except ValueError, e:
346         print >> sys.stderr, " ERROR: %s" % repr(e)
347         sys.exit(1)
348     print " SUCCESS"
349
350     print "testlogout: Access the IdP...",
351     try:
352         page = sess.fetch_page(idpname,
353                                'http://127.0.0.10:45080/%s/login' % idpname)
354         page.expected_value('//div[@id="welcome"]/p/text()',
355                             'Welcome %s!' % user)
356     except ValueError, e:
357         print >> sys.stderr, " ERROR: %s" % repr(e)
358         sys.exit(1)
359     print " SUCCESS"
360
361     print "testlogout: IdP-initiated logout with no SP sessions...",
362     try:
363         page = sess.fetch_page(idpname,
364                                'http://127.0.0.10:45080/%s/logout' % idpname)
365         page.expected_value('//div[@id="logout"]/p//text()',
366                             'Successfully logged out.')
367     except ValueError, e:
368         print >> sys.stderr, " ERROR: %s" % repr(e)
369         sys.exit(1)
370     print " SUCCESS"