def send_request_to_auth_server(self, url, access_token=None): certfile = CONF.keycloak_oidc.certfile keyfile = CONF.keycloak_oidc.keyfile cafile = CONF.keycloak_oidc.cafile or self.get_system_ca_file() insecure = CONF.keycloak_oidc.insecure verify = None if parse.urlparse(url).scheme == "https": verify = False if insecure else cafile cert = (certfile, keyfile) if certfile and keyfile else None headers = {} if access_token: headers["Authorization"] = "Bearer %s" % access_token try: resp = requests.get( url, headers=headers, verify=verify, cert=cert ) except requests.ConnectionError: msg = _( "Can't connect to the keycloak server with address '%s'." ) % url LOG.exception(msg) raise exc.MistralException(message=msg) if resp.status_code == 401: LOG.warning( "HTTP response from OIDC provider:" " [%s] with WWW-Authenticate: [%s]", pprint.pformat(resp.text), resp.headers.get("WWW-Authenticate") ) else: LOG.debug( "HTTP response from the OIDC provider: %s", pprint.pformat(resp.json()) ) resp.raise_for_status() return resp.json()
from oslo_config import cfg from oslo_log import log from oslo_middleware import cors from osprofiler import opts as profiler from mistral import version from mistral._i18n import _ from mistral.workflow import states # Options under default group. launch_opt = cfg.ListOpt( 'server', default=['all'], help=_('Specifies which mistral server to start by the launch script. ' 'Valid options are all or any combination of ' 'api, engine, and executor.')) wf_trace_log_name_opt = cfg.StrOpt( 'workflow_trace_log_name', default='workflow_trace', help=_('Logger name for pretty workflow trace output.')) use_debugger_opt = cfg.BoolOpt( 'use-debugger', default=False, help=_('Enables debugger. Note that using this option changes how the ' 'eventlet library is used to support async IO. This could result ' 'in failures that do not occur under normal operation. ' 'Use at your own risk.'))
from oslo_config import cfg from oslo_log import log from oslo_middleware import cors from osprofiler import opts as profiler from mistral import version from mistral._i18n import _ # Options under default group. launch_opt = cfg.ListOpt( 'server', default=['all'], help=_('Specifies which mistral server to start by the launch script. ' 'Valid options are all or any combination of ' 'api, engine, and executor.')) wf_trace_log_name_opt = cfg.StrOpt( 'workflow_trace_log_name', default='workflow_trace', help=_('Logger name for pretty workflow trace output.')) use_debugger_opt = cfg.BoolOpt( 'use-debugger', default=False, help=_('Enables debugger. Note that using this option changes how the ' 'eventlet library is used to support async IO. This could result ' 'in failures that do not occur under normal operation. ' 'Use at your own risk.'))
def authenticate(self, req): certfile = CONF.keycloak_oidc.certfile keyfile = CONF.keycloak_oidc.keyfile cafile = CONF.keycloak_oidc.cafile or self.get_system_ca_file() insecure = CONF.keycloak_oidc.insecure if 'X-Auth-Token' not in req.headers: msg = _("Auth token must be provided in 'X-Auth-Token' header.") LOG.error(msg) raise exc.UnauthorizedException(message=msg) access_token = req.headers.get('X-Auth-Token') try: decoded = jwt.decode(access_token, algorithms=['RS256'], verify=False) except Exception as e: msg = _("Token can't be decoded because of wrong format %s")\ % str(e) LOG.error(msg) raise exc.UnauthorizedException(message=msg) # Get user realm from parsed token # Format is "iss": "http://<host>:<port>/auth/realms/<realm_name>", __, __, realm_name = decoded['iss'].strip().rpartition('/realms/') # Get roles from from parsed token roles = ','.join(decoded['realm_access']['roles']) \ if 'realm_access' in decoded else '' # NOTE(rakhmerov): There's a special endpoint for introspecting # access tokens described in OpenID Connect specification but it's # available in KeyCloak starting only with version 1.8.Final so we have # to use user info endpoint which also takes exactly one parameter # (access token) and replies with error if token is invalid. user_info_endpoint = ("%s/realms/%s/protocol/openid-connect/userinfo" % (CONF.keycloak_oidc.auth_url, realm_name)) verify = None if urllib.parse.urlparse(user_info_endpoint).scheme == "https": verify = False if insecure else cafile cert = (certfile, keyfile) if certfile and keyfile else None try: resp = requests.get( user_info_endpoint, headers={"Authorization": "Bearer %s" % access_token}, verify=verify, cert=cert) except requests.ConnectionError: msg = _("Can't connect to keycloak server with address '%s'." ) % CONF.keycloak_oidc.auth_url LOG.error(msg) raise exc.MistralException(message=msg) if resp.status_code == 401: LOG.warning( "HTTP response from OIDC provider:" " [%s] with WWW-Authenticate: [%s]", pprint.pformat(resp.text), resp.headers.get("WWW-Authenticate")) else: LOG.debug("HTTP response from OIDC provider: %s", pprint.pformat(resp.text)) resp.raise_for_status() LOG.debug("HTTP response from OIDC provider: %s", pprint.pformat(resp.json())) req.headers["X-Identity-Status"] = "Confirmed" req.headers["X-Project-Id"] = realm_name req.headers["X-Roles"] = roles
def authenticate(self, req): if 'X-Auth-Token' not in req.headers: msg = _("Auth token must be provided in 'X-Auth-Token' header.") LOG.error(msg) raise exc.UnauthorizedException(message=msg) access_token = req.headers.get('X-Auth-Token') try: decoded = jwt.decode(access_token, algorithms=['RS256'], verify=False) except Exception as e: msg = _("Token can't be decoded because of wrong format %s")\ % str(e) LOG.error(msg) raise exc.UnauthorizedException(message=msg) # Get user realm from parsed token # Format is "iss": "http://<host>:<port>/auth/realms/<realm_name>", __, __, realm_name = decoded['iss'].strip().rpartition('/realms/') audience = decoded.get('aud') # Get roles from parsed token roles = ','.join(decoded['realm_access']['roles']) \ if 'realm_access' in decoded else '' # NOTE(rakhmerov): There's a special endpoint for introspecting # access tokens described in OpenID Connect specification but it's # available in KeyCloak starting only with version 1.8.Final so we have # to use user info endpoint which also takes exactly one parameter # (access token) and replies with error if token is invalid. user_info_endpoint_url = CONF.keycloak_oidc.user_info_endpoint_url if user_info_endpoint_url.startswith(('http://', 'https://')): self.send_request_to_auth_server(url=user_info_endpoint_url, access_token=access_token) else: public_key = self.get_public_key(realm_name) keycloak_iss = None try: if CONF.keycloak_oidc.keycloak_iss: keycloak_iss = CONF.keycloak_oidc.keycloak_iss % realm_name jwt.decode(access_token, public_key, audience=audience, issuer=keycloak_iss, algorithms=['RS256'], verify=True) except Exception: LOG.exception('The request access token is invalid.') raise exc.UnauthorizedException() req.headers["X-Identity-Status"] = "Confirmed" req.headers["X-Project-Id"] = realm_name req.headers["X-Roles"] = roles
def authenticate(self, req): certfile = CONF.keycloak_oidc.certfile keyfile = CONF.keycloak_oidc.keyfile cafile = CONF.keycloak_oidc.cafile or self.get_system_ca_file() insecure = CONF.keycloak_oidc.insecure if 'X-Auth-Token' not in req.headers: msg = _("Auth token must be provided in 'X-Auth-Token' header.") LOG.error(msg) raise exc.UnauthorizedException(message=msg) access_token = req.headers.get('X-Auth-Token') try: decoded = jwt.decode(access_token, algorithms=['RS256'], verify=False) except Exception as e: msg = _("Token can't be decoded because of wrong format %s")\ % str(e) LOG.error(msg) raise exc.UnauthorizedException(message=msg) # Get user realm from parsed token # Format is "iss": "http://<host>:<port>/auth/realms/<realm_name>", __, __, realm_name = decoded['iss'].strip().rpartition('/realms/') # Get roles from from parsed token roles = ','.join(decoded['realm_access']['roles']) \ if 'realm_access' in decoded else '' # NOTE(rakhmerov): There's a special endpoint for introspecting # access tokens described in OpenID Connect specification but it's # available in KeyCloak starting only with version 1.8.Final so we have # to use user info endpoint which also takes exactly one parameter # (access token) and replies with error if token is invalid. user_info_endpoint_url = CONF.keycloak_oidc.user_info_endpoint_url if user_info_endpoint_url.startswith(('http://', 'https://')): user_info_endpoint = user_info_endpoint_url else: user_info_endpoint = ( ("%s" + user_info_endpoint_url) % (CONF.keycloak_oidc.auth_url, realm_name)) verify = None if urllib.parse.urlparse(user_info_endpoint).scheme == "https": verify = False if insecure else cafile cert = (certfile, keyfile) if certfile and keyfile else None try: resp = requests.get( user_info_endpoint, headers={"Authorization": "Bearer %s" % access_token}, verify=verify, cert=cert ) except requests.ConnectionError: msg = _("Can't connect to keycloak server with address '%s'." ) % CONF.keycloak_oidc.auth_url LOG.error(msg) raise exc.MistralException(message=msg) if resp.status_code == 401: LOG.warning("HTTP response from OIDC provider:" " [%s] with WWW-Authenticate: [%s]", pprint.pformat(resp.text), resp.headers.get("WWW-Authenticate")) else: LOG.debug("HTTP response from OIDC provider: %s", pprint.pformat(resp.text)) resp.raise_for_status() LOG.debug( "HTTP response from OIDC provider: %s", pprint.pformat(resp.json()) ) req.headers["X-Identity-Status"] = "Confirmed" req.headers["X-Project-Id"] = realm_name req.headers["X-Roles"] = roles
from keystoneauth1 import loading from oslo_config import cfg from oslo_log import log from oslo_middleware import cors from osprofiler import opts as profiler from mistral import version from mistral._i18n import _ # Options under default group. launch_opt = cfg.ListOpt( 'server', default=['all'], help=_('Specifies which mistral server to start by the launch script. ' 'Valid options are all or any combination of ' 'api, engine, and executor.') ) wf_trace_log_name_opt = cfg.StrOpt( 'workflow_trace_log_name', default='workflow_trace', help=_('Logger name for pretty workflow trace output.') ) use_debugger_opt = cfg.BoolOpt( 'use-debugger', default=False, help=_('Enables debugger. Note that using this option changes how the ' 'eventlet library is used to support async IO. This could result ' 'in failures that do not occur under normal operation. '