]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | # -*- coding: utf-8 -*- |
11fdf7f2 | 2 | |
11fdf7f2 TL |
3 | import cherrypy |
4 | ||
5 | try: | |
6 | from onelogin.saml2.auth import OneLogin_Saml2_Auth | |
7 | from onelogin.saml2.errors import OneLogin_Saml2_Error | |
8 | from onelogin.saml2.settings import OneLogin_Saml2_Settings | |
9 | ||
10 | python_saml_imported = True | |
11 | except ImportError: | |
12 | python_saml_imported = False | |
13 | ||
eafe8130 | 14 | from .. import mgr |
11fdf7f2 TL |
15 | from ..exceptions import UserDoesNotExist |
16 | from ..services.auth import JwtManager | |
17 | from ..tools import prepare_url_prefix | |
a4b75251 | 18 | from . import BaseController, ControllerAuthMixin, Endpoint, Router, allow_empty_body |
11fdf7f2 TL |
19 | |
20 | ||
a4b75251 | 21 | @Router('/auth/saml2', secure=False) |
f67539c2 | 22 | class Saml2(BaseController, ControllerAuthMixin): |
11fdf7f2 TL |
23 | |
24 | @staticmethod | |
25 | def _build_req(request, post_data): | |
26 | return { | |
27 | 'https': 'on' if request.scheme == 'https' else 'off', | |
28 | 'http_host': request.host, | |
29 | 'script_name': request.path_info, | |
30 | 'server_port': str(request.port), | |
31 | 'get_data': {}, | |
32 | 'post_data': post_data | |
33 | } | |
34 | ||
35 | @staticmethod | |
36 | def _check_python_saml(): | |
37 | if not python_saml_imported: | |
9f95a23c | 38 | raise cherrypy.HTTPError(400, 'Required library not found: `python3-saml`') |
11fdf7f2 TL |
39 | try: |
40 | OneLogin_Saml2_Settings(mgr.SSO_DB.saml2.onelogin_settings) | |
41 | except OneLogin_Saml2_Error: | |
42 | raise cherrypy.HTTPError(400, 'Single Sign-On is not configured.') | |
43 | ||
f67539c2 | 44 | @Endpoint('POST', path="", version=None) |
adb31ebb | 45 | @allow_empty_body |
11fdf7f2 TL |
46 | def auth_response(self, **kwargs): |
47 | Saml2._check_python_saml() | |
48 | req = Saml2._build_req(self._request, kwargs) | |
49 | auth = OneLogin_Saml2_Auth(req, mgr.SSO_DB.saml2.onelogin_settings) | |
50 | auth.process_response() | |
51 | errors = auth.get_errors() | |
52 | ||
53 | if auth.is_authenticated(): | |
54 | JwtManager.reset_user() | |
55 | username_attribute = auth.get_attribute(mgr.SSO_DB.saml2.get_username_attribute()) | |
56 | if username_attribute is None: | |
57 | raise cherrypy.HTTPError(400, | |
58 | 'SSO error - `{}` not found in auth attributes. ' | |
59 | 'Received attributes: {}' | |
60 | .format( | |
61 | mgr.SSO_DB.saml2.get_username_attribute(), | |
62 | auth.get_attributes())) | |
63 | username = username_attribute[0] | |
64 | url_prefix = prepare_url_prefix(mgr.get_module_option('url_prefix', default='')) | |
65 | try: | |
66 | mgr.ACCESS_CTRL_DB.get_user(username) | |
67 | except UserDoesNotExist: | |
68 | raise cherrypy.HTTPRedirect("{}/#/sso/404".format(url_prefix)) | |
69 | ||
70 | token = JwtManager.gen_token(username) | |
71 | JwtManager.set_user(JwtManager.decode_token(token)) | |
1e59de90 TL |
72 | |
73 | # For backward-compatibility: PyJWT versions < 2.0.0 return bytes. | |
74 | token = token.decode('utf-8') if isinstance(token, bytes) else token | |
75 | ||
f67539c2 | 76 | self._set_token_cookie(url_prefix, token) |
11fdf7f2 | 77 | raise cherrypy.HTTPRedirect("{}/#/login?access_token={}".format(url_prefix, token)) |
9f95a23c TL |
78 | |
79 | return { | |
80 | 'is_authenticated': auth.is_authenticated(), | |
81 | 'errors': errors, | |
82 | 'reason': auth.get_last_error_reason() | |
83 | } | |
11fdf7f2 | 84 | |
f67539c2 | 85 | @Endpoint(xml=True, version=None) |
11fdf7f2 TL |
86 | def metadata(self): |
87 | Saml2._check_python_saml() | |
88 | saml_settings = OneLogin_Saml2_Settings(mgr.SSO_DB.saml2.onelogin_settings) | |
89 | return saml_settings.get_sp_metadata() | |
90 | ||
f67539c2 | 91 | @Endpoint(json_response=False, version=None) |
11fdf7f2 TL |
92 | def login(self): |
93 | Saml2._check_python_saml() | |
94 | req = Saml2._build_req(self._request, {}) | |
95 | auth = OneLogin_Saml2_Auth(req, mgr.SSO_DB.saml2.onelogin_settings) | |
96 | raise cherrypy.HTTPRedirect(auth.login()) | |
97 | ||
f67539c2 | 98 | @Endpoint(json_response=False, version=None) |
11fdf7f2 TL |
99 | def slo(self): |
100 | Saml2._check_python_saml() | |
101 | req = Saml2._build_req(self._request, {}) | |
102 | auth = OneLogin_Saml2_Auth(req, mgr.SSO_DB.saml2.onelogin_settings) | |
103 | raise cherrypy.HTTPRedirect(auth.logout()) | |
104 | ||
f67539c2 | 105 | @Endpoint(json_response=False, version=None) |
11fdf7f2 TL |
106 | def logout(self, **kwargs): |
107 | # pylint: disable=unused-argument | |
108 | Saml2._check_python_saml() | |
109 | JwtManager.reset_user() | |
f67539c2 TL |
110 | token = JwtManager.get_token_from_header() |
111 | self._delete_token_cookie(token) | |
11fdf7f2 TL |
112 | url_prefix = prepare_url_prefix(mgr.get_module_option('url_prefix', default='')) |
113 | raise cherrypy.HTTPRedirect("{}/#/login".format(url_prefix)) |