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
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)
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)
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())
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)
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())
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)
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())
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())
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)
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:
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