diff options
author | Ricardo Marques <rimarques@suse.com> | 2018-06-11 11:29:08 +0200 |
---|---|---|
committer | Ricardo Marques <rimarques@suse.com> | 2018-11-08 16:27:37 +0100 |
commit | 04f4d5053e2181ba70731ce2d253af208dadc7f1 (patch) | |
tree | 8b7f1f0aa3d1633450a401e752b46f3267d8abae /src/pybind/mgr/dashboard/controllers/saml2.py | |
parent | Merge pull request #24817 from tone-zhang/wip-64-assert (diff) | |
download | ceph-04f4d5053e2181ba70731ce2d253af208dadc7f1.tar.xz ceph-04f4d5053e2181ba70731ce2d253af208dadc7f1.zip |
mgr/dashboard: SAML 2.0 support
Fixes: https://tracker.ceph.com/issues/24268
Signed-off-by: Ricardo Dias <rdias@suse.com>
Signed-off-by: Ricardo Marques <rimarques@suse.com>
Diffstat (limited to 'src/pybind/mgr/dashboard/controllers/saml2.py')
-rw-r--r-- | src/pybind/mgr/dashboard/controllers/saml2.py | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/controllers/saml2.py b/src/pybind/mgr/dashboard/controllers/saml2.py new file mode 100644 index 00000000000..0cc55367539 --- /dev/null +++ b/src/pybind/mgr/dashboard/controllers/saml2.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +import sys +import cherrypy + +try: + from onelogin.saml2.auth import OneLogin_Saml2_Auth + from onelogin.saml2.errors import OneLogin_Saml2_Error + from onelogin.saml2.settings import OneLogin_Saml2_Settings + + python_saml_imported = True +except ImportError: + python_saml_imported = False + +from .. import mgr, logger +from ..exceptions import UserDoesNotExist +from ..services.auth import JwtManager +from ..services.access_control import ACCESS_CTRL_DB +from ..services.sso import SSO_DB +from ..tools import prepare_url_prefix +from . import Controller, Endpoint, BaseController + + +@Controller('/auth/saml2', secure=False) +class Saml2(BaseController): + + @staticmethod + def _build_req(request, post_data): + return { + 'https': 'on' if request.scheme == 'https' else 'off', + 'http_host': request.host, + 'script_name': request.path_info, + 'server_port': str(request.port), + 'get_data': {}, + 'post_data': post_data + } + + @staticmethod + def _check_python_saml(): + if not python_saml_imported: + python_saml_name = 'python3-saml' if sys.version_info >= (3, 0) else 'python-saml' + raise cherrypy.HTTPError(400, + 'Required library not found: `{}`'.format(python_saml_name)) + try: + OneLogin_Saml2_Settings(SSO_DB.saml2.onelogin_settings) + except OneLogin_Saml2_Error: + raise cherrypy.HTTPError(400, 'Single Sign-On is not configured.') + + @Endpoint('POST', path="") + def auth_response(self, **kwargs): + Saml2._check_python_saml() + req = Saml2._build_req(self._request, kwargs) + auth = OneLogin_Saml2_Auth(req, SSO_DB.saml2.onelogin_settings) + auth.process_response() + errors = auth.get_errors() + + if auth.is_authenticated(): + JwtManager.reset_user() + username_attribute = auth.get_attribute(SSO_DB.saml2.get_username_attribute()) + if username_attribute is None: + raise cherrypy.HTTPError(400, + 'SSO error - `{}` not found in auth attributes. ' + 'Received attributes: {}' + .format( + SSO_DB.saml2.get_username_attribute(), + auth.get_attributes())) + username = username_attribute[0] + try: + ACCESS_CTRL_DB.get_user(username) + except UserDoesNotExist: + raise cherrypy.HTTPError(400, + 'SSO error - Username `{}` does not exist.' + .format(username)) + + token = JwtManager.gen_token(username) + JwtManager.set_user(JwtManager.decode_token(token)) + token = token.decode('utf-8') + logger.debug("JWT Token: %s", token) + url_prefix = prepare_url_prefix(mgr.get_config('url_prefix', default='')) + raise cherrypy.HTTPRedirect("{}/#/login?access_token={}".format(url_prefix, token)) + else: + return { + 'is_authenticated': auth.is_authenticated(), + 'errors': errors, + 'reason': auth.get_last_error_reason() + } + + @Endpoint(xml=True) + def metadata(self): + Saml2._check_python_saml() + saml_settings = OneLogin_Saml2_Settings(SSO_DB.saml2.onelogin_settings) + return saml_settings.get_sp_metadata() + + @Endpoint(json_response=False) + def login(self): + Saml2._check_python_saml() + req = Saml2._build_req(self._request, {}) + auth = OneLogin_Saml2_Auth(req, SSO_DB.saml2.onelogin_settings) + raise cherrypy.HTTPRedirect(auth.login()) + + @Endpoint(json_response=False) + def slo(self): + Saml2._check_python_saml() + req = Saml2._build_req(self._request, {}) + auth = OneLogin_Saml2_Auth(req, SSO_DB.saml2.onelogin_settings) + raise cherrypy.HTTPRedirect(auth.logout()) + + @Endpoint(json_response=False) + def logout(self, **kwargs): + # pylint: disable=unused-argument + Saml2._check_python_saml() + JwtManager.reset_user() + url_prefix = prepare_url_prefix(mgr.get_config('url_prefix', default='')) + raise cherrypy.HTTPRedirect("{}/#/login".format(url_prefix)) |