From 3daace694ef73e947d148e4c079cd5e0cd5df368 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Mon, 25 May 2020 22:57:17 +0200 Subject: [PATCH] Add scope management to self-service portal --- sso/forms.py | 7 +++++++ sso/models.py | 15 +++++++++++++++ sso/oauth2.py | 15 ++++++--------- templates/client_edit.html | 1 + templates/profile.html | 2 +- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/sso/forms.py b/sso/forms.py index 6287d80..555b0e3 100644 --- a/sso/forms.py +++ b/sso/forms.py @@ -53,3 +53,10 @@ class ClientForm(FlaskForm): choices=[("client_secret_basic", "Basic"), ("client_secret_post", "POST")], validators=[DataRequired()], ) + + scope = MultiCheckboxField( + "Allowed scopes", + choices=[("profile:read", "profile:read"), ("openid", "openid")], + validators=[DataRequired()], + default=["openid"], + ) diff --git a/sso/models.py b/sso/models.py index 5e5f4a9..f2208ba 100644 --- a/sso/models.py +++ b/sso/models.py @@ -3,6 +3,7 @@ from authlib.integrations.sqla_oauth2 import ( OAuth2TokenMixin, OAuth2AuthorizationCodeMixin, ) +from authlib.oauth2.rfc6749.util import scope_to_list, list_to_scope from sso.extensions import db from sso.directory import LDAPUserProxy @@ -14,6 +15,20 @@ class Client(db.Model, OAuth2ClientMixin): owner_id = db.Column(db.String(40), nullable=True) + def __repr__(self): + return "" % (self.client_id,) + + @property + def scope(self): + return self.client_metadata.get("scope", []) + + def get_allowed_scope(self, scope): + if not scope: + return "" + allowed = set(self.scope) + scopes = scope_to_list(scope) + return list_to_scope([s for s in scopes if s in allowed]) + class AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin): __tablename__ = "oauth2_code" diff --git a/sso/oauth2.py b/sso/oauth2.py index b4e6a4a..8323213 100644 --- a/sso/oauth2.py +++ b/sso/oauth2.py @@ -79,7 +79,7 @@ class OpenIDCode(_OpenIDCode): return exists_nonce(nonce, request) def get_jwt_config(self, grant): - return app.get('JWT_CONFIG') + return app.config.get("JWT_CONFIG") def generate_user_info(self, user, scope): return generate_user_info(user, scope) @@ -90,7 +90,7 @@ class ImplicitGrant(_OpenIDImplicitGrant): return exists_nonce(nonce, request) def get_jwt_config(self, grant): - return app.get('JWT_CONFIG') + return app.config.get("JWT_CONFIG") def generate_user_info(self, user, scope): return generate_user_info(user, scope) @@ -113,6 +113,7 @@ class HybridGrant(_OpenIDHybridGrant): authorization = AuthorizationServer() require_oauth = ResourceProtector() + def save_token(token, request): if request.user: user_id = request.user.get_user_id() @@ -122,21 +123,17 @@ def save_token(token, request): # FIXME: is this the correct way of handling this? left for backward # compatiblity - toks = Token.query.filter_by(client_id=client.client_id, - user_id=user_id) + toks = Token.query.filter_by(client_id=client.client_id, user_id=user_id) # make sure that every client has only one token connected to a user for t in toks: db.session.delete(t) - item = Token( - client_id=client.client_id, - user_id=user_id, - **token - ) + item = Token(client_id=client.client_id, user_id=user_id, **token) db.session.add(item) db.session.commit() + def config_oauth(app): query_client = create_query_client_func(db.session, Client) authorization.init_app(app, query_client=query_client, save_token=save_token) diff --git a/templates/client_edit.html b/templates/client_edit.html index 83970c2..8490cf1 100644 --- a/templates/client_edit.html +++ b/templates/client_edit.html @@ -24,6 +24,7 @@ {{ render_field(form.token_endpoint_auth_method) }} {{ render_field(form.grant_types) }} {{ render_field(form.response_types) }} + {{ render_field(form.scope) }}
diff --git a/templates/profile.html b/templates/profile.html index 0e49c34..c9d787a 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -51,7 +51,7 @@ {% for client in clients %} - {{ client.client_name }}Edit + {{ client.client_name }}Edit {% else %} No registered applications yet {% endfor %}