Skip to content

Commit d2cba17

Browse files
committed
Adds an optional authorization function for the OIDC authentication.
* custom oidc auth module allows an optional parameter OIDC_AUTHORIZATION_FUNCTION * askbot/deps/django_authopenid/protocols/__init__.py: - get_protocol: passes the oidc_authorization_function to the OIDC protocol * askbot/deps/django_authopenid/protocols/oidc/protocol.py: - __init__method gets the authorization function and stores it on self - adds method is_user_authorized to check if the user is authorized to access the resource * askbot/deps/django_authopenid/util.py: - LoginMethod: reads the OIDC_AUTHORIZATION_FUNCTION or sets a dummy lambda function returning True the function takes the decoded token as an argument and returns a boolean * askbot/deps/django_authopenid/protocols/oidc/views.py: - complete_oidc_signin: checks if the user is authorized to access the resource by calling the oidc protocols is_user_authorized method allows to continue or return a Bad Request response
1 parent 0af5323 commit d2cba17

File tree

4 files changed

+20
-1
lines changed

4 files changed

+20
-1
lines changed

askbot/deps/django_authopenid/protocols/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def get_protocol(provider_name):
1212
client_id=params['oidc_client_id'],
1313
client_secret=params['oidc_client_secret'],
1414
provider_url=params['oidc_provider_url'],
15+
authorization_function=params['oidc_authorization_function'],
1516
trust_email=params['trust_email'])
1617

1718
raise NotImplementedError(f'Not implemented for protocol {protocol_type}')

askbot/deps/django_authopenid/protocols/oidc/protocol.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""OpenId Connect protocol"""
22
import asyncio
3+
import logging
34
import requests
45
from django.core.cache import cache
56
from askbot.deps.django_authopenid.protocols.oidc.jwt_verifier import JwtVerifier
@@ -22,12 +23,14 @@ def __init__(self, # pylint: disable=too-many-arguments
2223
client_secret=None,
2324
provider_url=None,
2425
trust_email=False,
26+
authorization_function=None,
2527
audience=None):
2628
self.protocol_type = 'oidc'
2729
self.audience = audience
2830
self.client_id = client_id
2931
self.client_secret = client_secret
3032
self.provider_url = provider_url
33+
self.authorization_function = authorization_function
3134
self.trust_email = trust_email
3235
discovery = self.load_discovery_data()
3336
self.authenticate_url = discovery['authorization_endpoint']
@@ -84,6 +87,14 @@ def get_email(self, id_token):
8487
payload = get_jwt_payload(id_token)
8588
return payload['email']
8689

90+
def is_user_authorized(self, id_token):
91+
payload = get_jwt_payload(id_token)
92+
try:
93+
return self.authorization_function(payload)
94+
except Exception as error:
95+
logging.critical('Error in authorization function: %s', error)
96+
return False
97+
8798
def is_access_token_valid(self, access_token):
8899
"""Validates the OIDC access token"""
89100
jwt_verifier = JwtVerifier(issuer=self.provider_url,

askbot/deps/django_authopenid/protocols/oidc/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ def complete_oidc_signin(request): #pylint: disable=too-many-return-statements
5050
if not oidc.is_id_token_valid(id_token, auth_csrf_token):
5151
return HttpResponseBadRequest("ID token is invalid")
5252

53+
if not oidc.is_user_authorized(id_token):
54+
return HttpResponseBadRequest("You do not have access to this resource")
55+
5356
user_id = oidc.get_user_id(id_token)
5457

5558
email = oidc.get_email(id_token)

askbot/deps/django_authopenid/util.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ def read_params(self):
332332
self.oidc_client_id = self.get_required_attr('OIDC_CLIENT_ID', for_what)
333333
self.oidc_client_secret = self.get_required_attr('OIDC_CLIENT_SECRET', for_what)
334334
self.oidc_audience = self.get_required_attr('OIDC_AUDIENCE', for_what)
335+
if hasattr(self.mod, 'OIDC_AUTHORIZATION_FUNCTION'):
336+
self.oidc_authorization_function = self.mod.OIDC_AUTHORIZATION_FUNCTION
337+
else:
338+
self.oidc_authorization_function = lambda parsed_token: True
335339

336340
if self.login_type.startswith('openid'):
337341
self.openid_endpoint = self.get_required_attr('OPENID_ENDPOINT', 'custom OpenID login')
@@ -357,7 +361,7 @@ def as_dict(self):
357361
'check_password', 'auth_endpoint', 'token_endpoint',
358362
'resource_endpoint', 'response_parser', 'token_transport',
359363
'trust_email', 'oidc_provider_url', 'oidc_client_id',
360-
'oidc_client_secret', 'oidc_audience'
364+
'oidc_client_secret', 'oidc_audience', 'oidc_authorization_function'
361365
)
362366
#some parameters in the class have different names from those
363367
#in the dictionary

0 commit comments

Comments
 (0)