Token revocation endpoint

This commit is contained in:
Éloi Rivard 2020-08-24 15:56:30 +02:00
parent a364b7ef1b
commit c664259b52
5 changed files with 70 additions and 3 deletions

View file

@ -0,0 +1,26 @@
from . import client_credentials
def test_token_revocation(testclient, user, client, token, slapd_connection):
assert not token.revoked
res = testclient.post(
"/oauth/revoke",
params=dict(token=token.oauthAccessToken,),
headers={"Authorization": f"Basic {client_credentials(client)}"},
)
assert 200 == res.status_code
assert {} == res.json
token.reload(slapd_connection)
assert token.revoked
def test_token_invalid(testclient, client):
res = testclient.post(
"/oauth/revoke",
params=dict(token="invalid"),
headers={"Authorization": f"Basic {client_credentials(client)}"},
)
assert 200 == res.status_code
assert {} == res.json

View file

@ -113,6 +113,14 @@ class LDAPObjectHelper:
return cls._attribute_type_by_name
def reload(self, conn=None):
conn = conn or self.ldap()
result = conn.search_s(self.dn, ldap.SCOPE_SUBTREE)
self.changes = {}
self.attrs = {
k: [elt.decode("utf-8") for elt in v] for k, v in result[0][1].items()
}
def save(self, conn=None):
conn = conn or self.ldap()
try:

View file

@ -182,9 +182,9 @@ class Token(LDAPObjectHelper, TokenMixin):
@revoked.setter
def revoked(self, value):
if value:
self.oauthRevoked = "true"
self.oauthRevoked = "TRUE"
else:
self.oauthRevoked = "false"
self.oauthRevoked = "FALSE"
def get_client_id(self):
return self.oauthClientID

View file

@ -3,7 +3,7 @@ from flask import Blueprint, request, session, redirect
from flask import render_template, jsonify, flash
from flask_babel import gettext
from .models import User, Client
from .oauth2utils import authorization, IntrospectionEndpoint
from .oauth2utils import authorization, IntrospectionEndpoint, RevocationEndpoint
from .forms import LoginForm
from .flaskutils import current_user
@ -61,3 +61,8 @@ def issue_token():
@bp.route("/introspect", methods=["POST"])
def introspect_token():
return authorization.create_endpoint_response(IntrospectionEndpoint.ENDPOINT_NAME)
@bp.route("/revoke", methods=["POST"])
def revoke_token():
return authorization.create_endpoint_response(RevocationEndpoint.ENDPOINT_NAME)

View file

@ -8,6 +8,7 @@ from authlib.oauth2.rfc6749.grants import (
ClientCredentialsGrant,
)
from authlib.oauth2.rfc6750 import BearerTokenValidator as _BearerTokenValidator
from authlib.oauth2.rfc7009 import RevocationEndpoint as _RevocationEndpoint
from authlib.oauth2.rfc7636 import CodeChallenge
from authlib.oauth2.rfc7662 import IntrospectionEndpoint as _IntrospectionEndpoint
from authlib.oidc.core.grants import (
@ -198,6 +199,32 @@ class BearerTokenValidator(_BearerTokenValidator):
return token.revoked
class RevocationEndpoint(_RevocationEndpoint):
def query_token(self, token, token_type_hint, client):
if token_type_hint == "access_token":
return Token.filter(
oauthClientID=client.oauthClientID, oauthAccessToken=token
)
elif token_type_hint == "refresh_token":
return Token.filter(
oauthClientID=client.oauthClientID, oauthRefreshToken=token
)
item = Token.filter(oauthClientID=client.oauthClientID, oauthAccessToken=token)
if item:
return item[0]
item = Token.filter(oauthClientID=client.oauthClientID, oauthRefreshToken=token)
if item:
return item[0]
return None
def revoke_token(self, token):
token.revoked = True
token.save()
class IntrospectionEndpoint(_IntrospectionEndpoint):
def query_token(self, token, token_type_hint, client):
if token_type_hint == "access_token":
@ -252,3 +279,4 @@ def config_oauth(app):
require_oauth.register_token_validator(BearerTokenValidator())
authorization.register_endpoint(IntrospectionEndpoint)
authorization.register_endpoint(RevocationEndpoint)