3 # Copyright (C) 2014 Simo Sorce <simo@redhat.com>
5 # see file 'COPYING' for use and warranty information
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.
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.
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/>.
20 from ipsilon.providers.common import ProviderBase, ProviderPageBase
21 from ipsilon.providers.saml2.auth import AuthenticateRequest
22 from ipsilon.util.user import UserSession
28 class Redirect(AuthenticateRequest):
30 def GET(self, *args, **kwargs):
32 query = cherrypy.request.query_string
34 login = self.saml2login(query)
35 return self.auth(login)
38 class POSTAuth(AuthenticateRequest):
40 def POST(self, *args, **kwargs):
42 request = kwargs.get(lasso.SAML2_FIELD_REQUEST)
43 relaystate = kwargs.get(lasso.SAML2_FIELD_RELAYSTATE)
45 login = self.saml2login(request)
46 login.set_msgRelayState(relaystate)
47 return self.auth(login)
50 class Continue(AuthenticateRequest):
52 def GET(self, *args, **kwargs):
54 session = UserSession()
55 user = session.get_user()
56 session.nuke_data('login', 'Return')
57 self.stage = session.get_data('saml2', 'stage')
60 self._debug("User is marked anonymous?!")
61 # TODO: Return to SP with auth failed error
62 raise cherrypy.HTTPError(401)
64 self._debug('Continue auth for %s' % user.name)
66 dump = session.get_data('saml2', 'Request')
68 self._debug("Couldn't find Request dump?!")
69 # TODO: Return to SP with auth failed error
70 raise cherrypy.HTTPError(400)
73 login = lasso.Login.newFromDump(self.cfg.idp, dump)
74 except Exception, e: # pylint: disable=broad-except
75 self._debug('Failed to load status from dump: %r' % e)
78 self._debug("Empty Request dump?!")
79 # TODO: Return to SP with auth failed error
80 raise cherrypy.HTTPError(400)
82 return self.auth(login)
85 class SSO(ProviderPageBase):
87 def __init__(self, *args, **kwargs):
88 super(SSO, self).__init__(*args, **kwargs)
89 self.Redirect = Redirect(*args, **kwargs)
90 self.POST = POSTAuth(*args, **kwargs)
91 self.Continue = Continue(*args, **kwargs)
94 class SAML2(ProviderPageBase):
96 def __init__(self, *args, **kwargs):
97 super(SAML2, self).__init__(*args, **kwargs)
101 self.cfg.idp = lasso.Server(self.cfg.idp_metadata_file,
102 self.cfg.idp_key_file,
104 self.cfg.idp_certificate_file)
105 self.cfg.idp.role = lasso.PROVIDER_ROLE_IDP
106 except Exception, e: # pylint: disable=broad-except
107 self._debug('Failed to enable SAML2 provider: %r' % e)
110 # Import all known applications
111 data = self.cfg.get_data()
113 if 'type' not in data[idval] or data[idval]['type'] != 'SP':
115 path = os.path.join(self.cfg.idp_storage_path, str(idval))
122 meta = os.path.join(path, 'metadata.xml')
123 cert = os.path.join(path, 'certificate.pem')
124 self.cfg.idp.addProvider(lasso.PROVIDER_ROLE_SP, meta, cert)
125 self._debug('Added SP %s' % name)
126 except Exception, e: # pylint: disable=broad-except
127 self._debug('Failed to add SP %s: %r' % (name, e))
129 self.SSO = SSO(*args, **kwargs)
132 class IdpProvider(ProviderBase):
135 super(IdpProvider, self).__init__('saml2', 'saml2')
137 self.description = """
138 Provides SAML 2.0 authentication infrastructure. """
141 'idp storage path': [
142 """ Path to data storage accessible by the IdP """,
144 '/var/lib/ipsilon/saml2'
146 'idp metadata file': [
147 """ The IdP Metadata file genearated at install time. """,
151 'idp certificate file': [
152 """ The IdP PEM Certificate genearated at install time. """,
157 """ The IdP Certificate Key genearated at install time. """,
161 'allow self registration': [
162 """ Allow authenticated users to register applications. """,
166 'default allowed nameids': [
167 """Default Allowed NameIDs for Service Providers. """,
169 ['persistent', 'transient', 'email', 'kerberos', 'x509']
172 """Default NameID used by Service Providers. """,
176 'default email domain': [
177 """Default email domain, for users missing email property.""",
184 def allow_self_registration(self):
185 return self.get_config_value('allow self registration')
188 def idp_storage_path(self):
189 return self.get_config_value('idp storage path')
192 def idp_metadata_file(self):
193 return os.path.join(self.idp_storage_path,
194 self.get_config_value('idp metadata file'))
197 def idp_certificate_file(self):
198 return os.path.join(self.idp_storage_path,
199 self.get_config_value('idp certificate file'))
202 def idp_key_file(self):
203 return os.path.join(self.idp_storage_path,
204 self.get_config_value('idp key file'))
207 def default_allowed_nameids(self):
208 return self.get_config_value('default allowed nameids')
211 def default_nameid(self):
212 return self.get_config_value('default nameid')
215 def default_email_domain(self):
216 return self.get_config_value('default email domain')
218 def get_tree(self, site):
219 self.page = SAML2(site, self)