Example #1
0
    def authenticate(self, req):
        token = req.headers.get('X-Auth-Token')

        if not token:
            raise exc.UnauthorizedException('Auth token is not provided.')

        data = {'token': token}
        headers = {'St2-Api-Key': cfg.CONF.st2.api_key}
        url = cfg.CONF.st2.auth_url + '/tokens/validate'
        resp = http.post(url, data, headers=headers)

        if (resp.status_code != http_client.OK or
                not resp.json().get('valid', False)):
            LOG.error('Unable to verify auth token. %s' % str(resp.content))
            raise exc.UnauthorizedException('Unable to verify auth token.')
Example #2
0
def obtain_service_catalog(ctx):
    token = ctx.auth_token

    if ctx.is_trust_scoped and is_token_trust_scoped(token):
        if ctx.trust_id is None:
            raise Exception(
                "'trust_id' must be provided in the admin context.")

        # trust_client = client_for_trusts(ctx.trust_id)
        # Using trust client, it can't validate token
        # when cron trigger running because keystone policy
        # don't allow do this. So we need use admin client to
        # get token data
        token_data = _admin_client().tokens.get_token_data(
            token, include_catalog=True)
        response = token_data['token']
    else:
        response = ctx.service_catalog

        # Target service catalog may not be passed via API.
        # If we don't have the catalog yet, it should be requested.
        if not response:
            response = client().tokens.get_token_data(
                token, include_catalog=True)['token']

    if not response:
        raise exceptions.UnauthorizedException()

    service_catalog = ks_service_catalog.ServiceCatalog.factory(response)

    return service_catalog
Example #3
0
def obtain_service_catalog(ctx):
    token = ctx.auth_token

    if ctx.is_trust_scoped and is_token_trust_scoped(token):
        if ctx.trust_id is None:
            raise Exception(
                "'trust_id' must be provided in the admin context."
            )

        trust_client = client_for_trusts(ctx.trust_id)
        token_data = trust_client.tokens.get_token_data(
            token,
            include_catalog=True
        )
        response = token_data['token']
    else:
        response = ctx.service_catalog

        # Target service catalog may not be passed via API.
        # If we don't have the catalog yet, it should be requested.
        if not response:
            response = client().tokens.get_token_data(
                token,
                include_catalog=True
            )['token']

    if not response:
        raise exceptions.UnauthorizedException()

    service_catalog = ks_service_catalog.ServiceCatalog.factory(response)

    return service_catalog
Example #4
0
    def authenticate(self, req):
        # Note(nmakhotkin): Since we have deferred authentication,
        # need to check for auth manually (check for corresponding
        # headers according to keystonemiddleware docs.
        identity_status = req.headers.get('X-Identity-Status')
        service_identity_status = req.headers.get('X-Service-Identity-Status')

        if (identity_status == 'Confirmed'
                or service_identity_status == 'Confirmed'):
            return

        if req.headers.get('X-Auth-Token'):
            msg = 'Auth token is invalid: %s' % req.headers['X-Auth-Token']
        else:
            msg = 'Authentication required'

        raise exc.UnauthorizedException(msg)
Example #5
0
    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
Example #6
0
    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
Example #7
0
 def authenticate(self, req):
     raise exc.UnauthorizedException()