Beispiel #1
0
def create_authorization_server(app, lazy=False):
    query_client = create_query_client_func(db.session, Client)
    save_token = create_save_token_func(db.session, Token)

    if lazy:
        server = AuthorizationServer()
        server.init_app(app, query_client, save_token)
    else:
        server = AuthorizationServer(app, query_client, save_token)

    @app.route('/oauth/authorize', methods=['GET', 'POST'])
    def authorize():
        if request.method == 'GET':
            user_id = request.args.get('user_id')
            if user_id:
                end_user = User.query.get(int(user_id))
            else:
                end_user = None
            try:
                grant = server.get_consent_grant(end_user=end_user)
                return grant.prompt or 'ok'
            except OAuth2Error as error:
                return url_encode(error.get_body())
        user_id = request.form.get('user_id')
        if user_id:
            grant_user = User.query.get(int(user_id))
        else:
            grant_user = None
        return server.create_authorization_response(grant_user=grant_user)

    @app.route('/oauth/token', methods=['GET', 'POST'])
    def issue_token():
        return server.create_token_response()
    return server
Beispiel #2
0
def config_oauth(app):
    query_client = create_query_client_func(db.session, OAuth2Client)
    save_token = create_save_token_func(db.session, OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)

    # support all openid grants
    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(require_nonce=True),
    ])
    #authorization.register_grant(ImplicitGrant)
    #authorization.register_grant(OpenIDImplicitGrant)
    #authorization.register_grant(HybridGrant)
    #authorization.register_grant(grants.ClientCredentialsGrant)
    #authorization.register_grant(RefreshTokenGrant)
    #authorization.register_grant(PasswordGrant)

    # protect resource
    bearer_cls = create_bearer_token_validator(db.session, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())

    # support revocation
    revocation_cls = create_revocation_endpoint(db.session, OAuth2Token)
    authorization.register_endpoint(revocation_cls)
Beispiel #3
0
def init_app(app, db):
    query_client = create_query_client_func(db.session, Client)
    save_token = create_save_token_func(db.session, Token)
    server.init_app(app, query_client=query_client, save_token=save_token)

    import logging
    import sys
    log = logging.getLogger('authlib')
    log.addHandler(logging.StreamHandler(sys.stdout))
    log.setLevel(logging.DEBUG)

    # Register grants
    server.register_grant(grants.ImplicitGrant)
    server.register_grant(PasswordGrant)
    server.register_grant(AuthorizationCodeGrant)
Beispiel #4
0
def config_oauth(app):
    query_client = create_query_client_func(db.session, OAuth2Client)
    save_token = create_save_token_func(db.session, OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)

    # support all openid grants
    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(require_nonce=True),
    ])
    authorization.register_grant(ImplicitGrant)
    authorization.register_grant(HybridGrant)

    # protect resource
    bearer_cls = create_bearer_token_validator(db.session, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())
Beispiel #5
0
 def __init__(self, app=None):
     super().__init__(app,
                      query_client=create_query_client_func(db.session, Client),
                      save_token=create_save_token_func(db.session, Token))
     # register it to grant endpoint
     self.register_grant(AuthorizationCodeGrant, [
         OpenIDCode(require_nonce=True),
         CodeChallenge(required=True)
     ])
     # register it to grant endpoint
     self.register_grant(grants.ImplicitGrant)
     # register it to grant endpoint
     self.register_grant(PasswordGrant)
     # register it to grant endpoint
     self.register_grant(ClientCredentialsGrant)
     # register it to grant endpoint
     self.register_grant(RefreshTokenGrant)
Beispiel #6
0
def config_oauth(app):
    '''Setup the application configuration'''
    query_client = create_query_client_func(db, OAuth2Client)
    save_token = create_save_token_func(db, OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)

    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(require_nonce=True),
    ])
    authorization.register_grant(RefreshTokenGrant)
    authorization.register_endpoint(IntrospectionEndpoint)

    revocation_cls = create_revocation_endpoint(db, OAuth2Token)
    authorization.register_endpoint(revocation_cls)

    bearer_cls = create_bearer_token_validator(db, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())
Beispiel #7
0
def config_oauth(app):
    require_oauth = ResourceProtector()
    authorization = AuthorizationServer()
    query_client = create_query_client_func(db.session, OAuth2Client)
    save_token = create_save_token_func(db.session, OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)
    # support all openid grants
    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(require_nonce=True, **app.config['OAUTH_JWT_CONFIG']),
    ])
    authorization.register_grant(HybridGrant)

    # protect resource
    bearer_cls = create_bearer_token_validator(db.session, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())

    register_as_extension(app, 'authorization', authorization)
    register_as_extension(app, 'require_oauth', require_oauth)
Beispiel #8
0
def config_oauth(app):
    """
    configure all grants we have (namely open id and oauth2) in authlib
    """
    query_client = create_query_client_func(database.session, OAuth2Client)
    save_token = create_save_token_func(database.session, OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)

    # support all openid grants
    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(),
    ])
    authorization.register_grant(ImplicitGrant)
    authorization.register_grant(HybridGrant)

    # protect resource
    bearer_cls = create_bearer_token_validator(database.session, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())
Beispiel #9
0
def config_oauth(app):
    """Initialize authorization server, and register suportted authorization grant types

    For more information, please refer to https://docs.authlib.org/en/latest/flask/2/authorization-server.html#server
    """

    query_client = create_query_client_func(auth_db.session, OAuth2Client)
    save_token = save_token = create_save_token_func(auth_db.session,
                                                     OAuth2Token)
    authorization.init_app(app,
                           query_client=query_client,
                           save_token=save_token)

    # Register Authorization code grant types
    authorization.register_grant(AuthorizationCodeGrant, [
        OpenIDCode(require_nonce=False),
    ])

    # protect resource
    bearer_cls = create_bearer_token_validator(auth_db.session, OAuth2Token)
    require_oauth.register_token_validator(bearer_cls())
Beispiel #10
0
        token = OAuth2Token.query.filter_by(refresh_token=refresh_token).first()
        if token and not token.revoked and not token.is_refresh_token_expired():
            return token

    def authenticate_user(self, credential):
        current_app.logger.debug("auth user grant user")

        return User.query.get(credential.user_id)


class ClientCredentialsGrant(grants.ClientCredentialsGrant):
    TOKEN_ENDPOINT_AUTH_METHODS = ["client_secret_basic", "client_secret_post"]


query_client = create_query_client_func(db.session, OAuth2Client)
save_token = create_save_token_func(db.session, OAuth2Token)
authorization = AuthorizationServer(query_client=query_client, save_token=save_token)
require_oauth = ResourceProtector()


def config_oauth(app):
    print(" * OAuth init")
    authorization.init_app(app)

    # support all grants
    authorization.register_grant(grants.ImplicitGrant)
    authorization.register_grant(ClientCredentialsGrant)
    authorization.register_grant(AuthorizationCodeGrant)
    authorization.register_grant(PasswordGrant)
    authorization.register_grant(RefreshTokenGrant)
Beispiel #11
0
app = Flask(__name__)

# Load configuration--default, then custom. Path to latter set in Dockerfile.
app.config.from_object('default_settings')
app.config.from_envvar('PATH_TO_APP_CONFIG')

# Configure app to work with SQLAlchemy
db.init_app(app)
# Create tables.
# SQLAlchemy object not bound to app, so pass in app as arg.
# Alternatively could push an app context.
db.create_all(app=app)

query_client = create_query_client_func(db.session, Client)
save_token = create_save_token_func(db.session, Token)

server = AuthorizationServer(app,
                             query_client=query_client,
                             save_token=save_token)

# register AuthorizationCodeGrant to grant endpoint
server.register_grant(AuthorizationCodeGrant,
                      [OpenIDCode(require_nonce=False)])


def get_or_create_shib_user():
    if request.remote_user:
        user = User.query.filter(
            User.shib_id == request.remote_user).one_or_none()
        if not user:
Beispiel #12
0
def _init_oauth():
    """
    Initialize Afterglow OAuth2 server

    :return: None
    """
    from authlib.oauth2.rfc6749 import ClientMixin
    from authlib.oauth2.rfc6749 import grants
    from authlib.oauth2.rfc7636 import CodeChallenge
    from authlib.integrations.sqla_oauth2 import (OAuth2AuthorizationCodeMixin,
                                                  OAuth2TokenMixin,
                                                  create_save_token_func)
    from authlib.integrations.flask_oauth2 import AuthorizationServer
    from .resources.users import DbUser, db

    global Token, oauth_server

    class OAuth2Client(ClientMixin):
        """
        OAuth2 client definition class
        """
        name = None
        description = None
        client_id = None
        client_secret = None
        redirect_uris = None
        default_scopes = ('email', )
        token_endpoint_auth_method = 'client_secret_basic'
        allowed_grant_types = (
            'authorization_code',
            'refresh_token',
        )

        def __init__(self, **kwargs):
            """
            Initialize OAuth2 client from a dictionary of attributes

            :param kwargs: client attributes; the following are required::
                    - name: client name
                    - client_id: a random string
                    - client_secret: a random string
                    - redirect_uris: a list of redirect uris; the first one
                        is used by default
                    - consent_uri: redirect URI of the user consent page

                Optional attributes::
                    - description: client description
                    - default_scopes: list of default scopes of the client
                    - token_endpoint_auth_method: RFC7591 token endpoint
                        authentication method: "none" (public client),
                        "client_secret_post" (client uses the HTTP POST
                        parameters), or "client_secret_basic" (client uses
                        basic HTTP auth)
                    - allowed_grant_types: list of allowed grant types,
                        including "authorization_code", "implicit",
                        "client_credentials", and "password"
            """
            for name, val in kwargs.items():
                setattr(self, name, val)

            if self.name is None:
                raise ValueError('Missing OAuth client name')
            if self.client_id is None:
                raise ValueError('Missing OAuth client ID')

            if not self.redirect_uris:
                raise ValueError('Missing OAuth redirect URIs')

            if self.token_endpoint_auth_method not in ('none',
                                                       'client_secret_post',
                                                       'client_secret_basic'):
                raise ValueError('Invalid token endpoint auth method')

            if self.token_endpoint_auth_method != 'none' and \
                    self.client_secret is None:
                raise ValueError('Missing OAuth client secret')

            if self.description is None:
                self.description = self.name

        def get_client_id(self) -> str:
            """Return ID of the client"""
            return self.client_id

        def get_default_redirect_uri(self) -> str:
            """Return client default redirect_uri"""
            return self.redirect_uris[0]

        def get_allowed_scope(self, scope: str) -> str:
            """
            Return requested scopes which are supported by this client

            :param scope: requested scope(s), multiple scopes are separated
                by spaces
            """
            if scope is None:
                scope = ''
            return ' '.join(
                {s
                 for s in scope.split() if s in self.default_scopes})

        def check_redirect_uri(self, redirect_uri: str) -> bool:
            """Validate redirect_uri parameter in authorization endpoints

            :param redirect_uri: URL string for redirecting.

            :return: True if valid redirect URI
            """
            return redirect_uri in self.redirect_uris

        def has_client_secret(self) -> bool:
            """Does the client has a secret?"""
            return bool(self.client_secret)

        def check_client_secret(self, client_secret: str) -> bool:
            """Validate client_secret

            :param client_secret: client secret

            :return: True if client secret matches the stored value
            """
            return client_secret == self.client_secret

        def check_token_endpoint_auth_method(self, method: str) -> bool:
            """Validate token endpoint auth method

            :param method: token endpoint auth method

            :return: True if the given token endpoint auth method matches
                the one for the server
            """
            return method == self.token_endpoint_auth_method

        def check_response_type(self, response_type: str) -> bool:
            """Check that the client can handle the given response_type

            :param response_type: requested response_type

            :return: True if a valid response type
            """
            return response_type in ('code', 'token')

        def check_grant_type(self, grant_type: str) -> bool:
            """Check that the client can handle the given grant_type

            :param grant_type: requested grant type

            :return: True if grant type is supported by client
            """
            return grant_type in self.allowed_grant_types

    class OAuth2AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin):
        __tablename__ = 'oauth_codes'
        __table_args__ = dict(sqlite_autoincrement=True)

        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer,
                            db.ForeignKey('users.id', ondelete='CASCADE'),
                            nullable=False)

        user = db.relationship('DbUser', uselist=False, backref='oauth_codes')

    class _Token(db.Model, OAuth2TokenMixin):
        """
        Token object; stored in the memory database
        """
        __tablename__ = 'oauth_tokens'
        __table_args__ = dict(sqlite_autoincrement=True)

        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer,
                            db.ForeignKey('users.id', ondelete='CASCADE'),
                            nullable=False)
        # override Mixin to set default=oauth2
        token_type = db.Column(db.String(40), default='oauth2')
        note = db.Column(db.Text, default='')

        user = db.relationship('DbUser', uselist=False, backref='oauth_tokens')

        @property
        def active(self) -> bool:
            if self.revoked:
                return False
            if not self.expires_in:
                return True
            return self.issued_at + self.expires_in >= time.time()

        def is_refresh_token_active(self):
            if self.revoked:
                return False
            expires_at = self.issued_at + \
                app.config.get('REFRESH_TOKEN_EXPIRES')
            return expires_at >= time.time()

    Token = _Token

    class AuthorizationCodeGrant(grants.AuthorizationCodeGrant):
        def save_authorization_code(self, code, req) -> None:
            """Save authorization_code for later use"""
            try:
                # noinspection PyArgumentList
                code_challenge = request.data.get('code_challenge')
                code_challenge_method = request.data.get(
                    'code_challenge_method')

                # noinspection PyArgumentList
                db.session.add(
                    OAuth2AuthorizationCode(
                        code=code,
                        client_id=req.client.client_id,
                        redirect_uri=req.redirect_uri,
                        scope=req.scope,
                        user_id=req.user.id,
                        code_challenge=code_challenge,
                        code_challenge_method=code_challenge_method,
                    ))
                db.session.commit()
            except Exception:
                db.session.rollback()
                raise

        def query_authorization_code(self, code, client) \
                -> OAuth2AuthorizationCode:
            item = OAuth2AuthorizationCode.query.filter_by(
                code=code, client_id=client.client_id).first()
            if item and not item.is_expired():
                return item

        def delete_authorization_code(self, authorization_code) -> None:
            try:
                db.session.delete(authorization_code)
                db.session.commit()
            except Exception:
                db.session.rollback()
                raise

        def authenticate_user(self, authorization_code) -> DbUser:
            return DbUser.query.get(authorization_code.user_id)

    class RefreshTokenGrant(grants.RefreshTokenGrant):
        def authenticate_refresh_token(self, refresh_token) -> Token:
            token = Token.query \
                .filter_by(refresh_token=refresh_token) \
                .first()
            if token and token.is_refresh_token_active():
                return token

        def authenticate_user(self, credential) -> DbUser:
            return credential.user

        def revoke_old_credential(self, credential) -> None:
            credential.revoked = True
            try:
                db.session.add(credential)
                db.session.commit()
            except Exception:
                db.session.rollback()
                raise

    for client_def in app.config.get('OAUTH_CLIENTS', []):
        oauth_clients[client_def.get('client_id')] = OAuth2Client(**client_def)

    def access_token_generator(*_):
        return secrets.token_hex(20)

    # Configure Afterglow OAuth2 tokens
    app.config['OAUTH2_ACCESS_TOKEN_GENERATOR'] = \
        app.config['OAUTH2_REFRESH_TOKEN_GENERATOR'] = \
        access_token_generator

    oauth_server = AuthorizationServer(
        app,
        query_client=lambda client_id: oauth_clients.get(client_id),
        save_token=create_save_token_func(db.session, Token),
    )
    oauth_server.register_grant(grants.ImplicitGrant)
    oauth_server.register_grant(grants.ClientCredentialsGrant)
    oauth_server.register_grant(AuthorizationCodeGrant,
                                [CodeChallenge(required=True)])
    oauth_server.register_grant(RefreshTokenGrant)

    app.logger.info('Initialized Afterglow OAuth2 Service')
def create_authorization_server(app):
    query_client = create_query_client_func(db, Client)
    save_token = create_save_token_func(db, Token)

    server = AuthorizationServer()
    server.init_app(app, query_client, save_token)

    @app.get("/oauth/authorize")
    def authorize_get(request: Request):
        user_id = request.query_params.get("user_id")
        request.body = {}
        if user_id:
            end_user = db.query(User).filter(User.id == int(user_id)).first()
        else:
            end_user = None
        try:
            grant = server.validate_consent_request(request=request,
                                                    end_user=end_user)
            return grant.prompt or "ok"
        except OAuth2Error as error:
            return url_encode(error.get_body())

    @app.post("/oauth/authorize")
    def authorize_post(
            request: Request,
            response_type: str = Form(None),
            client_id: str = Form(None),
            state: str = Form(None),
            scope: str = Form(None),
            nonce: str = Form(None),
            redirect_uri: str = Form(None),
            response_mode: str = Form(None),
            user_id: str = Form(None),
    ):
        if not user_id:
            user_id = request.query_params.get("user_id")

        request.body = {"user_id": user_id}

        if response_type:
            request.body.update({"response_type": response_type})

        if client_id:
            request.body.update({"client_id": client_id})

        if state:
            request.body.update({"state": state})

        if nonce:
            request.body.update({"nonce": nonce})

        if scope:
            request.body.update({"scope": scope})

        if redirect_uri:
            request.body.update({"redirect_uri": redirect_uri})

        if response_mode:
            request.body.update({"response_mode": response_mode})

        if user_id:
            grant_user = db.query(User).filter(User.id == int(user_id)).first()
        else:
            grant_user = None

        return server.create_authorization_response(request=request,
                                                    grant_user=grant_user)

    @app.api_route("/oauth/token", methods=["GET", "POST"])
    def issue_token(
            request: Request,
            grant_type: str = Form(None),
            scope: str = Form(None),
            code: str = Form(None),
            refresh_token: str = Form(None),
            code_verifier: str = Form(None),
            client_id: str = Form(None),
            client_secret: str = Form(None),
            device_code: str = Form(None),
            client_assertion_type: str = Form(None),
            client_assertion: str = Form(None),
            assertion: str = Form(None),
            username: str = Form(None),
            password: str = Form(None),
            redirect_uri: str = Form(None),
    ):
        request.body = {
            "grant_type": grant_type,
            "scope": scope,
        }

        if not grant_type:
            grant_type = request.query_params.get("grant_type")
            request.body.update({"grant_type": grant_type})

        if grant_type == "authorization_code":
            request.body.update({"code": code})
        elif grant_type == "refresh_token":
            request.body.update({"refresh_token": refresh_token})

        if code_verifier:
            request.body.update({"code_verifier": code_verifier})

        if client_id:
            request.body.update({"client_id": client_id})

        if client_secret:
            request.body.update({"client_secret": client_secret})

        if device_code:
            request.body.update({"device_code": device_code})

        if client_assertion_type:
            request.body.update(
                {"client_assertion_type": client_assertion_type})

        if client_assertion:
            request.body.update({"client_assertion": client_assertion})

        if assertion:
            request.body.update({"assertion": assertion})

        if redirect_uri:
            request.body.update({"redirect_uri": redirect_uri})

        if username:
            request.body.update({"username": username})

        if password:
            request.body.update({"password": password})

        return server.create_token_response(request=request)

    return server