Add scope management to self-service portal
parent
54e1ba0608
commit
3daace694e
|
@ -53,3 +53,10 @@ class ClientForm(FlaskForm):
|
||||||
choices=[("client_secret_basic", "Basic"), ("client_secret_post", "POST")],
|
choices=[("client_secret_basic", "Basic"), ("client_secret_post", "POST")],
|
||||||
validators=[DataRequired()],
|
validators=[DataRequired()],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
scope = MultiCheckboxField(
|
||||||
|
"Allowed scopes",
|
||||||
|
choices=[("profile:read", "profile:read"), ("openid", "openid")],
|
||||||
|
validators=[DataRequired()],
|
||||||
|
default=["openid"],
|
||||||
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from authlib.integrations.sqla_oauth2 import (
|
||||||
OAuth2TokenMixin,
|
OAuth2TokenMixin,
|
||||||
OAuth2AuthorizationCodeMixin,
|
OAuth2AuthorizationCodeMixin,
|
||||||
)
|
)
|
||||||
|
from authlib.oauth2.rfc6749.util import scope_to_list, list_to_scope
|
||||||
from sso.extensions import db
|
from sso.extensions import db
|
||||||
from sso.directory import LDAPUserProxy
|
from sso.directory import LDAPUserProxy
|
||||||
|
|
||||||
|
@ -14,6 +15,20 @@ class Client(db.Model, OAuth2ClientMixin):
|
||||||
|
|
||||||
owner_id = db.Column(db.String(40), nullable=True)
|
owner_id = db.Column(db.String(40), nullable=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Client %s>" % (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):
|
class AuthorizationCode(db.Model, OAuth2AuthorizationCodeMixin):
|
||||||
__tablename__ = "oauth2_code"
|
__tablename__ = "oauth2_code"
|
||||||
|
|
|
@ -79,7 +79,7 @@ class OpenIDCode(_OpenIDCode):
|
||||||
return exists_nonce(nonce, request)
|
return exists_nonce(nonce, request)
|
||||||
|
|
||||||
def get_jwt_config(self, grant):
|
def get_jwt_config(self, grant):
|
||||||
return app.get('JWT_CONFIG')
|
return app.config.get("JWT_CONFIG")
|
||||||
|
|
||||||
def generate_user_info(self, user, scope):
|
def generate_user_info(self, user, scope):
|
||||||
return generate_user_info(user, scope)
|
return generate_user_info(user, scope)
|
||||||
|
@ -90,7 +90,7 @@ class ImplicitGrant(_OpenIDImplicitGrant):
|
||||||
return exists_nonce(nonce, request)
|
return exists_nonce(nonce, request)
|
||||||
|
|
||||||
def get_jwt_config(self, grant):
|
def get_jwt_config(self, grant):
|
||||||
return app.get('JWT_CONFIG')
|
return app.config.get("JWT_CONFIG")
|
||||||
|
|
||||||
def generate_user_info(self, user, scope):
|
def generate_user_info(self, user, scope):
|
||||||
return generate_user_info(user, scope)
|
return generate_user_info(user, scope)
|
||||||
|
@ -113,6 +113,7 @@ class HybridGrant(_OpenIDHybridGrant):
|
||||||
authorization = AuthorizationServer()
|
authorization = AuthorizationServer()
|
||||||
require_oauth = ResourceProtector()
|
require_oauth = ResourceProtector()
|
||||||
|
|
||||||
|
|
||||||
def save_token(token, request):
|
def save_token(token, request):
|
||||||
if request.user:
|
if request.user:
|
||||||
user_id = request.user.get_user_id()
|
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
|
# FIXME: is this the correct way of handling this? left for backward
|
||||||
# compatiblity
|
# compatiblity
|
||||||
toks = Token.query.filter_by(client_id=client.client_id,
|
toks = Token.query.filter_by(client_id=client.client_id, user_id=user_id)
|
||||||
user_id=user_id)
|
|
||||||
|
|
||||||
# make sure that every client has only one token connected to a user
|
# make sure that every client has only one token connected to a user
|
||||||
for t in toks:
|
for t in toks:
|
||||||
db.session.delete(t)
|
db.session.delete(t)
|
||||||
|
|
||||||
item = Token(
|
item = Token(client_id=client.client_id, user_id=user_id, **token)
|
||||||
client_id=client.client_id,
|
|
||||||
user_id=user_id,
|
|
||||||
**token
|
|
||||||
)
|
|
||||||
db.session.add(item)
|
db.session.add(item)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
def config_oauth(app):
|
def config_oauth(app):
|
||||||
query_client = create_query_client_func(db.session, Client)
|
query_client = create_query_client_func(db.session, Client)
|
||||||
authorization.init_app(app, query_client=query_client, save_token=save_token)
|
authorization.init_app(app, query_client=query_client, save_token=save_token)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
{{ render_field(form.token_endpoint_auth_method) }}
|
{{ render_field(form.token_endpoint_auth_method) }}
|
||||||
{{ render_field(form.grant_types) }}
|
{{ render_field(form.grant_types) }}
|
||||||
{{ render_field(form.response_types) }}
|
{{ render_field(form.response_types) }}
|
||||||
|
{{ render_field(form.scope) }}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-9 col-md-offset-3">
|
<div class="col-md-9 col-md-offset-3">
|
||||||
<button type="submit" class="btn btn-primary btn-block">Save</button>
|
<button type="submit" class="btn btn-primary btn-block">Save</button>
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for client in clients %}
|
{% for client in clients %}
|
||||||
<tr><td>{{ client.client_name }}</td><td><a href="{{ url_for('.client_edit', client_id=client.id) }}" class="btn btn-xs btn-warning">Edit</a></td></tr>
|
<tr><td>{{ client.client_name }}</td><td class="text-right"><a href="{{ url_for('.client_edit', client_id=client.id) }}" class="btn btn-xs btn-warning">Edit</a></td></tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr><td colspan=4 class="placeholder">No registered applications yet</td></tr>
|
<tr><td colspan=4 class="placeholder">No registered applications yet</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
Loading…
Reference in New Issue