コード例 #1
0
    def validate_access_token_request(self):
        """
        Override the parent method from authlib to not fail immediately for
        public clients.
        """
        client = self.authenticate_token_endpoint_client()
        if not client.check_grant_type(self.GRANT_TYPE):
            raise UnauthorizedClientError(uri=self.uri)
        self._authenticated_client = client

        refresh_token = self.params.get("refresh_token")
        if refresh_token is None:
            raise InvalidRequestError(
                'Missing "refresh_token" in request.', uri=self.uri
            )

        refresh_claims = self.authenticate_refresh_token(refresh_token)
        if not refresh_claims:
            raise InvalidRequestError(
                'Invalid "refresh_token" in request.', uri=self.uri
            )

        scope = self.params.get("scope")
        if scope:
            original_scope = refresh_claims["scope"]
            if not original_scope:
                raise InvalidScopeError(uri=self.uri)
            original_scope = set(scope_to_list(original_scope))
            if not original_scope.issuperset(set(scope_to_list(scope))):
                raise InvalidScopeError(uri=self.uri)

        self._authenticated_token = refresh_claims
コード例 #2
0
    def _validate_token_scope(self, token):
        """
        OVERRIDES method from authlib.

        Why? Becuase our "token" is not a class with `get_scope` method.
        So we just need to treat it like a dictionary.
        """
        scope = self.request.scope
        if not scope:
            return

        # token is dict so just get the scope, don't use get_scope()
        original_scope = token.get("scope")

        ##### begin refresh token patch block #####
        # TODO: In the next release, remove this if block
        # Old refresh tokens are not compatible with new validation, so to smooth
        # the transition, allow old style refresh tokens with this patch;
        # remove patch in next tag. Refresh tokens have default TTL of 30 days.
        if not original_scope:
            original_scope = token.get("aud")
        ##### end refresh token patch block #####

        if not original_scope:
            raise InvalidScopeError(
                "No scope claim found in original refresh token.")

        original_scope = set(scope_to_list(original_scope))
        if not original_scope.issuperset(set(scope_to_list(scope))):
            raise InvalidScopeError(
                "Cannot request scopes that were not in original refresh token."
            )
コード例 #3
0
ファイル: tokens.py プロジェクト: chewcw/flask-azure-oauth
    def scope_insufficient(self, token: AzureToken, scope: str, operator: Union[str, Callable] = 'AND') -> bool:
        """
        Determines whether a token has sufficient scopes to interact with a resource

        I.e. whether the token bearer has suitable permissions to perform their intended action.

        This method overloads the default method in the 'BearerTokenValidator' class to make it compatible with our
        AzureToken class.

        :type token: AzureToken
        :param token: JSON Web Token as an Azure Token object
        :type scope: str
        :param scope: space concatenated list of scopes required to interact with the current resource
        :type operator: str or Callable
        :param operator: Strategy of validating whether token scopes meet resource scopes (i.e. all represent, at
        least one present)

        :rtype bool
        :return: True if the token has insufficient scopes, False if ok
        """
        if not scope:
            return False

        token_scopes = token.scopes
        resource_scopes = set(scope_to_list(scope))

        if operator == 'AND':
            return not token_scopes.issuperset(resource_scopes)
        if operator == 'OR':
            for resource_scope in resource_scopes:
                if resource_scope in token_scopes:
                    return False
        if callable(operator):
            return not operator(token_scopes, resource_scopes)
        raise ValueError(f"Invalid operator value [{ operator }], valid options are 'AND', 'OR' or <callable>")
コード例 #4
0
def generate_id_token(key,
                      token,
                      request,
                      alg,
                      iss,
                      exp,
                      nonce=None,
                      auth_time=None,
                      code=None):
    scopes = scope_to_list(token['scope'])

    # TODO: merge scopes and claims
    user_info = _generate_user_info(request.user, scopes)
    client = request.client

    payload = _generate_id_token_payload(
        alg,
        iss,
        [client.get_client_id()],
        exp=exp,
        nonce=nonce,
        auth_time=auth_time,
        code=code,
        access_token=token.get('access_token'),
    )
    payload.update(user_info)
    return _jwt_encode(alg, payload, key)
コード例 #5
0
    def get_allowed_scope(self, scope):
        """Get allowed scope. Has been slightly modified to accommodate parametric scopes.

        :param str scope: requested scope

        :return: str -- scopes
        """
        if not isinstance(scope, six.string_types):
            scope = list_to_scope(scope)
        allowed = scope_to_list(super(Client, self).get_allowed_scope(scope))
        for s in scope_to_list(scope):
            for def_scope in scope_to_list(self.scope):
                if s.startswith(def_scope) and s not in allowed:
                    allowed.append(s)
        gLogger.debug('Try to allow "%s" scope:' % scope, allowed)
        return list_to_scope(list(set(allowed)))
コード例 #6
0
ファイル: OAuth2IdProvider.py プロジェクト: TaykYoku/DIRAC
    def getGroupScopes(self, group: str) -> list:
        """Get group scopes

        :param group: DIRAC group
        """
        idPScope = getGroupOption(group, "IdPRole")
        return scope_to_list(idPScope) if idPScope else []
コード例 #7
0
    def group(self):
        """Search DIRAC group in scopes

        :return: str
        """
        groups = [s.split(":")[1] for s in scope_to_list(self.scope or "") if s.startswith("g:") and s.split(":")[1]]
        return groups[0] if groups else None
コード例 #8
0
 async def async_generate_user_info(self, user: UserWithRoles, scope: str):
     scope_list = scope_to_list(scope)
     includes = set()
     for scope in scope_list:
         if scope not in ('openid', 'offline_access'):
             includes.update(config.oauth2.user.scopes[scope].properties)
     user_data = user.user.dict(include=includes,
                                by_alias=True,
                                exclude_none=True)
     user_data['sub'] = user.user.id
     user_data['roles'] = user.roles
     if 'picture' in user_data:
         user_data[
             'picture'] = f"{config.oauth2.base_url}/picture/{user_data['picture']}"
     if 'groups' in user_data:
         # Only include visible groups
         user_data['groups'] = [
             group['_id']
             async for group in async_user_group_collection.find(
                 {
                     '_id': {
                         '$in': user_data['groups']
                     },
                     'visible': True
                 },
                 projection={'_id': 1})
         ]
     return UserInfo(**user_data)
コード例 #9
0
ファイル: AuthServer.py プロジェクト: TaykYoku/DIRAC
 def validate_requested_scope(self, scope, state=None):
     """See :func:`authlib.oauth2.rfc6749.authorization_server.validate_requested_scope`"""
     # We also consider parametric scope containing ":" charter
     extended_scope = list_to_scope(
         [re.sub(r":.*$", ":", s) for s in scope_to_list((scope or "").replace("+", " "))]
     )
     super(AuthServer, self).validate_requested_scope(extended_scope, state)
コード例 #10
0
    def get_allowed_scope(self, scope: str) -> str:
        """Returns the allowed scope."""
        if not scope:
            return ''

        allowed = {scope.scope for scope in self.scopes}
        scopes = scope_to_list(scope)
        return list_to_scope([scope for scope in scopes if scope in allowed])
コード例 #11
0
    def _validate_token_scope(self, token):
        """
        OVERRIDES method from authlib.

        Why? Becuase our "token" is not a class with `get_scope` method.
        So we just need to treat it like a dictionary.
        """
        scope = self.request.scope
        if not scope:
            return

        # token is dict so just get the scope, don't use get_scope()
        original_scope = token.get("aud")
        if not original_scope:
            raise InvalidScopeError()

        original_scope = set(scope_to_list(original_scope))
        if not original_scope.issuperset(set(scope_to_list(scope))):
            raise InvalidScopeError()
コード例 #12
0
    def process_implicit_token(self, token, code=None):
        config = self.get_jwt_config()
        config['nonce'] = self.request.data.get('nonce')
        if code is not None:
            config['code'] = code

        scopes = scope_to_list(token['scope'])
        user_info = self.generate_user_info(self.request.user, scopes)

        id_token = generate_id_token(token, self.request, user_info, **config)
        token['id_token'] = id_token
        return token
コード例 #13
0
 def __call__(self,
              client,
              grant_type,
              user=None,
              scope=None,
              expires_in=None,
              include_refresh_token=True):
     if 'offline_access' not in scope_to_list(scope):
         include_refresh_token = False
     return super(BearerToken,
                  self).__call__(client, grant_type, user, scope,
                                 expires_in, include_refresh_token)
コード例 #14
0
ファイル: IAMIdProvider.py プロジェクト: TaykYoku/DIRAC
    def getGroupScopes(self, group):
        """Get group scopes

        :param str group: DIRAC group

        :return: list
        """
        idPScope = getGroupOption(group, "IdPRole")
        if not idPScope:
            idPScope = "wlcg.groups:/%s/%s" % (getVOForGroup(group),
                                               group.split("_")[1])
        return S_OK(scope_to_list(idPScope))
コード例 #15
0
ファイル: AuthServer.py プロジェクト: TaykYoku/DIRAC
    def _getScope(self, scope, param):
        """Get parameter scope

        :param str scope: scope
        :param str param: parameter scope

        :return: str or None
        """
        try:
            return [s.split(":")[1] for s in scope_to_list(scope) if s.startswith("%s:" % param) and s.split(":")[1]][0]
        except Exception:
            return None
コード例 #16
0
ファイル: OAuth2IdProvider.py プロジェクト: TaykYoku/DIRAC
    def exchangeToken(self, group=None, scope=None):
        """Get new tokens for group scope

        :param str group: requested group
        :param list scope: requested scope

        :return: dict -- token
        """
        scope = scope or scope_to_list(self.scope)
        if group:
            if not (groupScopes := self.getGroupScopes(group)):
                return S_ERROR(f"No scope found for {group}")
            scope = list(set(scope + groupScopes))
コード例 #17
0
ファイル: CheckInIdProvider.py プロジェクト: TaykYoku/DIRAC
    def getGroupScopes(self, group):
        """Get group scopes

        :param str group: DIRAC group

        :return: list
        """
        idPScope = getGroupOption(group, "IdPRole")
        if not idPScope:
            idPScope = "eduperson_entitlement?value=urn:mace:egi.eu:group:%s:role=%s#aai.egi.eu" % (
                getVOForGroup(group),
                group.split("_")[1],
            )
        return S_OK(scope_to_list(idPScope))
コード例 #18
0
    def __call__(self, client: Client, grant_type: str, user: UserWithRoles,
                 scope: str):
        jwt_config = self.get_jwt_config()
        jwt_config['aud'] = [client.get_client_id()]
        jwt_config['auth_time'] = int(time.time())

        user_info = {'sub': user.user.id, 'roles': user.roles}
        if 'groups' in scope_to_list(scope):
            user_info['groups'] = user.user.groups
        return generate_id_token({},
                                 user_info,
                                 code=generate_token(
                                     config.oauth2.access_token_length),
                                 **jwt_config)
コード例 #19
0
    def process_token(self, grant, token):
        scope = token.get('scope')
        if not scope or not is_openid_scope(scope):
            # standard authorization code flow
            return token

        request = grant.request
        credential = request.credential

        scopes = scope_to_list(token['scope'])
        user_info = self.generate_user_info(request.user, scopes)

        config = self.get_jwt_config(grant)
        config['nonce'] = credential.get_nonce()
        config['auth_time'] = credential.get_auth_time()
        id_token = generate_id_token(token, request, user_info, **config)
        token['id_token'] = id_token
        return token
コード例 #20
0
 async def create_response(self, request: TypedRequest,
                           user_id: str) -> Response:
     try:
         assert isinstance(request, OAuth2Request)
         request.token = await run_in_threadpool(
             resource_protector.validate_request, None, request)
         if request.token is None:
             raise HTTPException(403, "Invalid token")
         if 'users' not in scope_to_list(request.token.scope):
             raise InsufficientScopeError('Missing "users" scope',
                                          request.uri)
         user = await UserWithRoles.async_load(user_id,
                                               request.token.client_id)
         if user is None:
             raise HTTPException(404, "User not found")
         user_info = await self.async_generate_user_info(user, 'users')
         return JSONResponse(user_info)
     except OAuth2Error as error:
         return authorization.handle_error_response(request, error)
コード例 #21
0
ファイル: code.py プロジェクト: musabdullah0/sendit
    def generate_user_info(self, user, scope):  # pragma: no cover
        """Provide user information for the given scope. Developers
        MUST implement this method in subclass, e.g.::

            from authlib.oidc.core import UserInfo

            def generate_user_info(self, user, scope):
                user_info = UserInfo(sub=user.id, name=user.name)
                if 'email' in scope:
                    user_info['email'] = user.email
                return user_info

        :param user: user instance
        :param scope: scope of the token
        :return: ``authlib.oidc.core.UserInfo`` instance
        """
        deprecate('Missing "OpenIDCode.generate_user_info"', '1.0', 'fjPsV',
                  'oi')
        scopes = scope_to_list(scope)
        return _generate_user_info(user, scopes)
コード例 #22
0
 async def create_response(self, request: TypedRequest) -> Response:
     try:
         assert isinstance(request, OAuth2Request)
         request.token = await run_in_threadpool(
             resource_protector.validate_request, None, request)
         if request.token is None:
             raise HTTPException(403, "Invalid token")
         if 'users' not in scope_to_list(request.token.scope):
             raise InsufficientScopeError('Missing "users" scope',
                                          request.uri)
         user_infos = []
         async for user in UserWithRoles.async_load_all(
                 request.token.client_id):
             user_info = await self.async_generate_user_info(
                 UserWithRoles(user=user,
                               roles=[],
                               last_modified=user.updated_at), 'users')
             del user_info['roles']
             user_infos.append(user_info)
         return JSONResponse(user_infos)
     except OAuth2Error as error:
         return authorization.handle_error_response(request, error)
コード例 #23
0
    def groups(self):
        """Search DIRAC groups in scopes

        :return: list
        """
        return [s.split(":")[1] for s in scope_to_list(self.scope or "") if s.startswith("g:") and s.split(":")[1]]
コード例 #24
0
def is_openid_scope(scope):
    scopes = scope_to_list(scope)
    return scopes and scopes[0] == 'openid'
コード例 #25
0
ファイル: test_rfc6749_misc.py プロジェクト: imfht/flaskapps
 def test_scope_to_list(self):
     self.assertEqual(util.scope_to_list('a b'), ['a', 'b'])
     self.assertEqual(util.scope_to_list(['a', 'b']), ['a', 'b'])
     self.assertIsNone(util.scope_to_list(None))
コード例 #26
0
 def get_allowed_scope(self, scope):
     if not scope:
         return ''
     allowed = set(self.scope.split())
     scopes = scope_to_list(scope)
     return list_to_scope([s for s in scopes if s in allowed])
コード例 #27
0
ファイル: util.py プロジェクト: pingiun/authlib
def is_openid_scope(scope):
    scopes = scope_to_list(scope)
    return scopes and 'openid' in scopes
コード例 #28
0
ファイル: OAuth2IdProvider.py プロジェクト: TaykYoku/DIRAC
        return S_OK((credDict, payload))

    def submitDeviceCodeAuthorizationFlow(self, group=None):
        """Submit authorization flow

        :return: S_OK(dict)/S_ERROR() -- dictionary with device code flow response
        """
        groupScopes = []
        if group:
            if not (groupScopes := self.getGroupScopes(group)):
                return S_ERROR(f"No scope found for {group}")

        try:
            r = requests.post(
                self.get_metadata("device_authorization_endpoint"),
                data=dict(client_id=self.client_id, scope=list_to_scope(scope_to_list(self.scope) + groupScopes)),
                verify=self.verify,
            )
            r.raise_for_status()
            deviceResponse = r.json()
            if "error" in deviceResponse:
                return S_ERROR("%s: %s" % (deviceResponse["error"], deviceResponse.get("description", "")))

            # Check if all main keys are present here
            for k in ["user_code", "device_code", "verification_uri"]:
                if not deviceResponse.get(k):
                    return S_ERROR("Mandatory %s key is absent in authentication response." % k)

            return S_OK(deviceResponse)
        except requests.exceptions.Timeout:
            return S_ERROR("Authentication server is not answer, timeout.")
コード例 #29
0
ファイル: OAuth2IdProvider.py プロジェクト: TaykYoku/DIRAC
 def getScopeGroups(self, scope: str) -> list:
     """Get DIRAC groups related to scope"""
     groups = []
     for group in getAllGroups():
         if (g_scope := self.getGroupScopes(group)) and set(g_scope).issubset(scope_to_list(scope)):
             groups.append(group)
コード例 #30
0
    def addScopes(self, scopes):
        """Add new scopes to query

        :param list scopes: scopes
        """
        self.setQueryArguments(scope=list(set(scope_to_list(self.scope or "") + scopes)))