Esempio n. 1
0
    def __init__(self,
                 client_id=None,
                 client_secret=None,
                 request_token_url=None,
                 request_token_params=None,
                 access_token_url=None,
                 access_token_params=None,
                 refresh_token_url=None,
                 refresh_token_params=None,
                 authorize_url=None,
                 api_base_url=None,
                 client_kwargs=None,
                 compliance_fix=None,
                 **kwargs):
        if not client_id and 'client_key' in kwargs:
            client_id = kwargs.get('client_key')
            deprecate('"client_key" has been renamed to "client_id".', '0.6')
        self.client_id = client_id
        self.client_secret = client_secret
        self.request_token_url = request_token_url
        self.request_token_params = request_token_params
        self.access_token_url = access_token_url
        self.access_token_params = access_token_params
        self.refresh_token_url = refresh_token_url
        self.refresh_token_params = refresh_token_params
        self.authorize_url = authorize_url
        self.api_base_url = api_base_url
        self.client_kwargs = client_kwargs or {}
        self.compliance_fix = compliance_fix

        self._kwargs = kwargs
        self._sess = None
 def validate_authorization_request(self):  # pragma: no cover
     deprecate(
         'use `server.validate_consent_request(end_user=current_user)` instead',
         '0.8', link_uid='vAAUK', link_file='VAR')
     grant = self.get_authorization_grant(_create_oauth2_request())
     grant.validate_authorization_request()
     return grant
Esempio n. 3
0
    def create_token_response(self):
        """If valid and authorized, the authorization server issues an access
        token as described in Section 5.1.  If the request failed
        verification or is invalid, the authorization server returns an error
        response as described in Section 5.2.
        """
        scope = self.request.scope
        credential = self.request.credential
        if not scope:
            scope = credential.get_scope()

        client = self.request.client
        expires_in = credential.get_expires_in()
        token = self.generate_token(
            client,
            self.GRANT_TYPE,
            expires_in=expires_in,
            scope=scope,
        )
        log.debug('Issue token {!r} to {!r}'.format(token, client))
        if self.server.save_token:
            user = self.authenticate_user(credential)
            if not user:
                raise InvalidRequestError('There is no "user" for this token.')
            self.request.user = user
            self.server.save_token(token, self.request)
            token = self.process_token(token, self.request)
        else:
            deprecate('"create_access_token" deprecated', '0.8', 'vAAUK', 'gt')
            self.create_access_token(token, client,
                                     credential)  # pragma: no cover
        return 200, token, self.TOKEN_RESPONSE_HEADER
    def create_authorization_response(self, request=None, grant_user=None):
        """Create the HTTP response for authorization. If resource owner
        granted the authorization, pass the resource owner as the user
        parameter, otherwise None::

            @app.route('/authorize', methods=['POST'])
            def confirm_authorize():
                if request.form['confirm'] == 'ok':
                    grant_user = current_user
                else:
                    grant_user = None
                return server.create_authorization_response(grant_user=grant_user)
        """
        if request and not grant_user:  # pragma: no cover
            grant_user = request
            # prepare for next upgrade
            deprecate(
                'Use "create_authorization_response(grant_user=grant_user)" instead',
                '0.8', 'vAAUK', 'car'
            )
        status, body, headers = self.create_valid_authorization_response(
            _create_oauth2_request(),
            grant_user=grant_user
        )
        if isinstance(body, dict):
            body = json.dumps(body)
        return Response(body, status=status, headers=headers)
Esempio n. 5
0
 def expires_in(client, grant_type):
     conf_key = 'OAUTH2_EXPIRES_{}'.format(grant_type.upper())
     expires = app.config.get(conf_key)
     if expires:
         deprecate('Deprecate "{}".'.format(conf_key), '0.10', 'vpCH5', 'as')
         return expires
     return expires_conf.get(grant_type, BearerToken.DEFAULT_EXPIRES_IN)
Esempio n. 6
0
def verify_id_token(response,
                    key,
                    response_type='code',
                    issuers=None,
                    client_id=None,
                    nonce=None,
                    max_age=None,
                    now=None):
    deprecate('"verify_id_token" is deprecated, use JWT instead.', 0.8)
    if 'id_token' not in response:
        raise ValueError('Invalid OpenID response')

    claims_cls = get_claim_cls_by_response_type(response_type)
    claims_request = {
        'access_token': response.get('access_token'),
        'client_id': client_id,
        'nonce': nonce,
        'max_age': max_age
    }
    claims_options = {
        'iss': {
            'values': issuers,
        }
    }
    claims = jwt.decode(
        response['id_token'],
        key,
        claims_cls,
        claims_options=claims_options,
        claims_params=claims_request,
    )
    claims.validate(now=now)
    return claims
    def create_authorization_response(self, redirect_uri, grant_user):
        """If the resource owner grants the access request, the authorization
        server issues an authorization code and delivers it to the client by
        adding the following parameters to the query component of the
        redirection URI using the "application/x-www-form-urlencoded" format.
        Per `Section 4.1.2`_.

        code
            REQUIRED.  The authorization code generated by the
            authorization server. The authorization code MUST expire
            shortly after it is issued to mitigate the risk of leaks. A
            maximum authorization code lifetime of 10 minutes is
            RECOMMENDED. The client MUST NOT use the authorization code
            more than once. If an authorization code is used more than
            once, the authorization server MUST deny the request and SHOULD
            revoke (when possible) all tokens previously issued based on
            that authorization code.  The authorization code is bound to
            the client identifier and redirection URI.
        state
            REQUIRED if the "state" parameter was present in the client
            authorization request.  The exact value received from the
            client.

        For example, the authorization server redirects the user-agent by
        sending the following HTTP response.

        .. code-block:: http

            HTTP/1.1 302 Found
            Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
                   &state=xyz

        .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc6749#section-4.1.2

        :param redirect_uri: Redirect to the given URI for the authorization
        :param grant_user: if resource owner granted the request, pass this
            resource owner, otherwise pass None.
        :returns: (status_code, body, headers)
        """
        state = self.request.state
        if grant_user:
            self.request.user = grant_user

            if hasattr(self, 'create_authorization_code'):
                deprecate('Use "generate_authorization_code" instead', '1.0')
                code = self.create_authorization_code(self.request.client,
                                                      grant_user, self.request)
            else:
                code = self.generate_authorization_code()
                self.save_authorization_code(code, self.request)

            params = [('code', code)]
            if state:
                params.append(('state', state))
            uri = add_params_to_uri(redirect_uri, params)
            headers = [('Location', uri)]
            return 302, '', headers

        else:
            raise AccessDeniedError(state=state, redirect_uri=redirect_uri)
Esempio n. 8
0
    def create_token_expires_in_generator(self, app):
        """Create a generator function for generating ``expires_in`` value.
        Developers can re-implement this method with a subclass if other means
        required. The default expires_in value is defined by ``grant_type``,
        different ``grant_type`` has different value. It can be configured
        with::

            OAUTH2_TOKEN_EXPIRES_IN = {
                'authorization_code': 864000,
                'urn:ietf:params:oauth:grant-type:jwt-bearer': 3600,
            }
        """
        expires_conf = {}
        expires_conf.update(GRANT_TYPES_EXPIRES)

        _old_expires = app.config.get('OAUTH2_EXPIRES_IN')
        if _old_expires:  # pragma: no cover
            deprecate('Deprecate "OAUTH2_EXPIRES_IN".', '0.11', 'vhL75', 'ae')
            expires_conf.update(_old_expires)
        expires_conf.update(app.config.get('OAUTH2_TOKEN_EXPIRES_IN', {}))

        def expires_in(client, grant_type):
            return expires_conf.get(grant_type, BearerToken.DEFAULT_EXPIRES_IN)

        return expires_in
Esempio n. 9
0
    def create_granted_params(self, grant_user):
        self.request.user = grant_user
        client = self.request.client

        if hasattr(self, 'create_authorization_code'):  # pragma: no cover
            deprecate('Use "generate_authorization_code" instead', '1.0')
            code = self.create_authorization_code(client, grant_user,
                                                  self.request)
        else:
            code = self.generate_authorization_code()
            self.save_authorization_code(code, self.request)

        params = [('code', code)]
        token = self.generate_token(grant_type='implicit',
                                    user=grant_user,
                                    scope=self.request.scope,
                                    include_refresh_token=False)

        response_types = self.request.response_type.split()
        if 'token' in response_types:
            log.debug('Grant token %r to %r', token, client)
            self.server.save_token(token, self.request)
            if 'id_token' in response_types:
                token = self.process_implicit_token(token, code)
        else:
            # response_type is "code id_token"
            token = {
                'expires_in': token['expires_in'],
                'scope': token['scope']
            }
            token = self.process_implicit_token(token, code)

        params.extend([(k, token[k]) for k in token])
        return params
Esempio n. 10
0
def _compatible_query_client(query_client):
    if query_client and hasattr(query_client, 'get_by_client_id'):
        message = (
            'client_model is deprecated.\n\n'
            'Please read: <https://github.com/lepture/authlib/issues/27>')
        deprecate(message, '0.7')
        query_client = query_client.get_by_client_id
    return query_client
Esempio n. 11
0
 def __init__(self, *args, **kwargs):
     super(AuthorizationCodeGrant, self).__init__(*args, **kwargs)
     deprecate('Use CodeChallenge as an extension instead.', '0.12',
               'fAmW1', 'CC')
     challenge = CodeChallenge(required=True)
     challenge.get_authorization_code_challenge = self.get_authorization_code_challenge
     challenge.get_authorization_code_challenge_method = self.get_authorization_code_challenge_method
     self.challenge = challenge
Esempio n. 12
0
 def create_authorization_response(self, request=None, grant_user=None):
     if request and not grant_user:  # pragma: no cover
         deprecate(
             'Use "create_authorization_response(grant_user=user)" instead',
             '0.11')
         grant_user = request
         request = None
     return super(AuthorizationServer, self)\
         .create_authorization_response(request, grant_user)
Esempio n. 13
0
 def get_jwt_config(self):  # pragma: no cover
     # TODO: developers MUST re-implement this method
     deprecate('Missing "OpenIDImplicitGrant.get_jwt_config"', '1.0',
               'fjPsV', 'oi')
     config = self.server.config
     key = config['jwt_key']
     alg = config['jwt_alg']
     iss = config['jwt_iss']
     exp = config['jwt_exp']
     return dict(key=key, alg=alg, iss=iss, exp=exp)
Esempio n. 14
0
    def __init__(self, algorithms, private_headers=None):
        self._algorithms = {}
        self._private_headers = private_headers

        if isinstance(algorithms, dict):  # pragma: no cover
            deprecate('Pass list of algorithms to JWS instead', '0.10')
            self._algorithms = algorithms
        elif isinstance(algorithms, list):
            for algorithm in algorithms:
                self.register_algorithm(algorithm)
Esempio n. 15
0
    def __init__(self, require_nonce=False, **kwargs):
        self.require_nonce = require_nonce
        if 'required_nonce' in kwargs:
            deprecate('Use "require_nonce" instead', '1.0')
            if kwargs['required_nonce']:
                self.require_nonce = True

        self.key = kwargs.get('key')
        self.alg = kwargs.get('alg')
        self.iss = kwargs.get('iss')
        self.exp = kwargs.get('exp')
        self._exists_nonce = kwargs.get('exists_nonce')
Esempio n. 16
0
def register_error_uri(error, error_uri):
    """Register ``error_uri`` for each error code. When raise an OAuth2Error
    without ``error_uri``, it will use the URI in this registry::

        register_error_uri('invalid_client', 'https://example.com/errors#invalid-client')

    :param error: OAuth 2 error code.
    :param error_uri: A human-readable web page with information about the error.
    """
    global _error_uris
    _error_uris[error] = error_uri
    deprecate('This function is deprecated.', version='0.10')
Esempio n. 17
0
    def create_token_response(self):
        """If the access token request is valid and authorized, the
        authorization server issues an access token and optional refresh
        token as described in Section 5.1.  If the request client
        authentication failed or is invalid, the authorization server returns
        an error response as described in Section 5.2. Per `Section 4.1.4`_.

        An example successful response:

        .. code-block:: http

            HTTP/1.1 200 OK
            Content-Type: application/json
            Cache-Control: no-store
            Pragma: no-cache

            {
                "access_token":"2YotnFZFEjr1zCsicMWpAA",
                "token_type":"example",
                "expires_in":3600,
                "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
                "example_parameter":"example_value"
            }

        :returns: (status_code, body, headers)

        .. _`Section 4.1.4`: https://tools.ietf.org/html/rfc6749#section-4.1.4
        """
        client = self.request.client
        authorization_code = self.request.credential

        scope = authorization_code.get_scope()
        token = self.generate_token(
            client,
            self.GRANT_TYPE,
            scope=scope,
            include_refresh_token=client.has_client_secret(),
        )
        log.debug('Issue token {!r} to {!r}'.format(token, client))

        if self.server.save_token:
            user = self.authenticate_user(authorization_code)
            if not user:
                raise InvalidRequestError('There is no "user" for this code.')
            self.request.user = user
            self.server.save_token(token, self.request)
            token = self.process_token(token, self.request)
        else:
            deprecate('"create_access_token" deprecated', '0.8', 'vAAUK', 'gt')
            self.create_access_token(token, client,
                                     authorization_code)  # pragma: no cover
        self.delete_authorization_code(authorization_code)
        return 200, token, self.TOKEN_RESPONSE_HEADER
Esempio n. 18
0
    def create_client(self, name):
        if not self.app:
            raise RuntimeError('OAuth is not init with Flask app.')

        if name in self._clients:
            return self._clients[name]

        keys = (
            'client_id',
            'client_secret',
            'request_token_url',
            'request_token_params',
            'access_token_url',
            'access_token_params',
            'refresh_token_url',
            'refresh_token_params',
            'authorize_url',
            'api_base_url',
            'client_kwargs',
        )

        kwargs = self._registry[name]
        compliance_fix = kwargs.pop('compliance_fix', None)
        for k in keys:
            if k not in kwargs:
                conf_key = '{}_{}'.format(name, k).upper()
                v = self.app.config.get(conf_key, None)
                kwargs[k] = v

        if not kwargs['client_id']:
            conf_key = '{}_client_key'.format(name).upper()
            kwargs['client_id'] = self.app.config.get(conf_key, None)
            deprecate(
                'Use "{}" instead of "{}".'.format(
                    conf_key.replace('CLIENT_KEY', 'CLIENT_ID'), conf_key),
                '0.6')

        fetch_token = kwargs.pop('fetch_token', None)
        if fetch_token is None and self.fetch_token:
            fetch_token = functools.partial(self.fetch_token, name=name)

        update_token = kwargs.pop('update_token', None)
        if update_token is None and self.update_token:
            update_token = functools.partial(self.update_token, name=name)

        client = RemoteApp(name, self.cache, fetch_token, update_token,
                           **kwargs)
        if compliance_fix:
            client.compliance_fix = compliance_fix

        self._clients[name] = client
        return client
Esempio n. 19
0
    def __init__(self, *args, **kwargs):
        deprecate('Deprecate "OpenIDCodeGrant".', '1.0', 'fjPsV', 'oi')

        super(OpenIDCodeGrant, self).__init__(*args, **kwargs)
        config = self.server.config
        extension = OpenIDCode(
            key=config['jwt_key'],
            alg=config['jwt_alg'],
            iss=config['jwt_iss'],
            exp=config['jwt_exp'],
            exists_nonce=self.exists_nonce,
        )
        extension(self)
Esempio n. 20
0
    def verify(self, s, key):  # pragma: no cover
        deprecate('Method "verify" is deprecated. Use "deserialize" instead.',
                  '0.9')
        rv = self.deserialize_compact(s, None)

        header, payload = rv['header'], rv['payload']
        algorithm, key = self._prepare_algorithm_key(header, payload, key)
        key = algorithm.prepare_verify_key(key)

        signing_input, signature = rv['signing_input'], rv['signature']
        verified = algorithm.verify(signing_input, key, signature)

        # Note that the payload can be any content and need not
        # be a representation of a JSON object
        return header, payload, verified
    def query_authorization_code(self, code, client):
        """Get authorization_code from previously savings. Developers MUST
        implement it in subclass::

            def query_authorization_code(self, code, client):
                return Authorization.get(code=code, client_id=client.client_id)

        :param code: a string represent the code.
        :param client: client related to this code.
        :return: authorization_code object
        """
        if hasattr(self, 'parse_authorization_code'):
            deprecate('Use "query_authorization_code" instead', '1.0')
            return self.parse_authorization_code(code, client)
        raise NotImplementedError()
Esempio n. 22
0
def _gen_token(func, client, grant_type, user, scope):
    if hasattr(inspect, 'getfullargspec'):
        spec = inspect.getfullargspec(func)
        no_args = not spec.args and not spec.varkw
    else:
        spec = inspect.getargspec(func)
        no_args = not spec.args and not spec.keywords
    if no_args:
        deprecate('Token generator now accepts parameters', '0.11', 'vhL75', 'tg')
        return func()

    return func(
        client=client, grant_type=grant_type,
        user=user, scope=scope,
    )
Esempio n. 23
0
    def __init__(self, token_endpoint, issuer, subject, audience=None, grant_type=None,
                 claims=None, token_placement='header', scope=None, **kwargs):
        Session.__init__(self)

        token_url = kwargs.pop('token_url', None)
        if token_url:
            deprecate('Use "token_endpoint" instead of "token_url"', '1.0')
            token_endpoint = token_url

        AssertionClient.__init__(
            self, session=self,
            token_endpoint=token_endpoint, issuer=issuer, subject=subject,
            audience=audience, grant_type=grant_type, claims=claims,
            token_placement=token_placement, scope=scope, **kwargs
        )
Esempio n. 24
0
    def exists_nonce(self, nonce, request):  # pragma: no cover
        """Check if the given nonce is existing in your database. Developers
        MUST implement this method in subclass, e.g.::

            def exists_nonce(self, nonce, request):
                exists = AuthorizationCode.query.filter_by(
                    client_id=request.client_id, nonce=nonce
                ).first()
                return bool(exists)

        :param nonce: A string of "nonce" parameter in request
        :param request: OAuth2Request instance
        :return: Boolean
        """
        deprecate('Missing "OpenIDCode.exists_nonce"', '1.0', 'fjPsV', 'oi')
        return self._exists_nonce(nonce, request)
Esempio n. 25
0
    def get_jwt_config(self, grant):  # pragma: no cover
        """Get the JWT configuration for OpenIDCode extension. The JWT
        configuration will be used to generate ``id_token``. Developers
        MUST implement this method in subclass, e.g.::

            def get_jwt_config(self, grant):
                return {
                    'key': read_private_key_file(key_path),
                    'alg': 'RS512',
                    'iss': 'issuer-identity',
                    'exp': 3600
                }

        :param grant: AuthorizationCodeGrant instance
        :return: dict
        """
        deprecate('Missing "OpenIDCode.get_jwt_config"', '1.0', 'fjPsV', 'oi')
        return dict(key=self.key, alg=self.alg, iss=self.iss, exp=self.exp)
Esempio n. 26
0
def register_session_client_auth_method(session,
                                        token_url=None,
                                        **kwargs):  # pragma: no cover
    """Register "client_secret_jwt" or "private_key_jwt" token endpoint auth
    method to OAuth2Session.

    :param session: OAuth2Session instance.
    :param token_url: Optional token endpoint url.
    """
    deprecate('Use `ClientSecretJWT` and `PrivateKeyJWT` instead', '1.0',
              'Jeclj', 'ca')
    if session.token_endpoint_auth_method == 'client_secret_jwt':
        cls = ClientSecretJWT
    elif session.token_endpoint_auth_method == 'private_key_jwt':
        cls = PrivateKeyJWT
    else:
        raise ValueError('Invalid token_endpoint_auth_method')

    session.register_client_auth_method(cls(token_url))
Esempio n. 27
0
    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)
    def create_token_response(self):
        """If the access token request is valid and authorized, the
        authorization server issues an access token and optional refresh
        token as described in Section 5.1.  If the request failed client
        authentication or is invalid, the authorization server returns an
        error response as described in Section 5.2.

        An example successful response:

        .. code-block:: http

            HTTP/1.1 200 OK
            Content-Type: application/json
            Cache-Control: no-store
            Pragma: no-cache

            {
                "access_token":"2YotnFZFEjr1zCsicMWpAA",
                "token_type":"example",
                "expires_in":3600,
                "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
                "example_parameter":"example_value"
            }

        :returns: (status_code, body, headers)
        """
        client = self.request.client
        user = self.request.user
        token = self.generate_token(
            client,
            self.GRANT_TYPE,
            scope=self.request.scope,
        )
        log.debug('Issue token {!r} to {!r}'.format(token, client))
        if self.server.save_token:
            self.server.save_token(token, self.request)
            token = self.process_token(token, self.request)
        else:
            deprecate('"create_access_token" deprecated', '0.8', 'vAAUK', 'gt')
            self.create_access_token(token, client, user)  # pragma: no cover
        return 200, token, self.TOKEN_RESPONSE_HEADER
    def init_app(self, app, query_client=None, save_token=None):
        """Initialize later with Flask app instance."""
        if query_client is not None:
            self.query_client = query_client
        if save_token is not None:
            self.save_token = save_token

        self.generate_token = self.create_bearer_token_generator(app.config)

        metadata_file = app.config.get('OAUTH2_METADATA_FILE')
        if metadata_file:
            with open(metadata_file) as f:
                metadata = self.metadata_class(json.load(f))
                metadata.validate()
                self.metadata = metadata

        self.config.setdefault('error_uris',
                               app.config.get('OAUTH2_ERROR_URIS'))
        if app.config.get('OAUTH2_JWT_ENABLED'):
            deprecate('Define "get_jwt_config" in OpenID Connect grants',
                      '1.0')
            self.init_jwt_config(app.config)
Esempio n. 30
0
    def __init__(self, app, config_prefix='AUTHLIB', **kwargs):
        deprecate(DEPRECATE_MESSAGE, 0.7)

        self.config_prefix = config_prefix
        self.config = app.config

        cache_type = self._config('type')
        kwargs.update(
            dict(default_timeout=self._config('DEFAULT_TIMEOUT', 100)))

        if cache_type == 'null':
            self.cache = NullCache()
        elif cache_type == 'simple':
            kwargs.update(dict(threshold=self._config('threshold', 500)))
            self.cache = SimpleCache(**kwargs)
        elif cache_type == 'memcache':
            kwargs.update(
                dict(
                    servers=self._config('MEMCACHED_SERVERS'),
                    key_prefix=self._config('KEY_PREFIX', None),
                ))
            self.cache = MemcachedCache(**kwargs)
        elif cache_type == 'redis':
            kwargs.update(
                dict(
                    host=self._config('REDIS_HOST', 'localhost'),
                    port=self._config('REDIS_PORT', 6379),
                    password=self._config('REDIS_PASSWORD', None),
                    db=self._config('REDIS_DB', 0),
                    key_prefix=self._config('KEY_PREFIX', None),
                ))
            self.cache = RedisCache(**kwargs)
        elif cache_type == 'filesystem':
            kwargs.update(dict(threshold=self._config('threshold', 500), ))
            self.cache = FileSystemCache(self._config('DIR'), **kwargs)
        else:
            raise RuntimeError('`%s` is not a valid cache type!' % cache_type)
        app.extensions[config_prefix.lower() + '_cache'] = self.cache