add scope
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
from http import HTTPStatus, client
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
import jwt
|
||||
from authlib.oauth2.rfc6749 import errors
|
||||
from authlib.oauth2.rfc6749.util import scope_to_list
|
||||
from aws_lambda_powertools import Logger
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
from aws_lambda_powertools.event_handler.exceptions import BadRequestError
|
||||
from aws_lambda_powertools.event_handler.exceptions import BadRequestError, ServiceError
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
@@ -26,15 +28,24 @@ def authorize():
|
||||
raise BadRequestError('Missing session_id')
|
||||
|
||||
try:
|
||||
user_id = verify_session(session_id)
|
||||
sub, session_scope = verify_session(session_id)
|
||||
grant = server.get_consent_grant(
|
||||
request=router.current_event,
|
||||
end_user={'id': user_id},
|
||||
end_user=sub,
|
||||
)
|
||||
req_scopes = set(scope_to_list(grant.request.payload.scope))
|
||||
user_scopes = set(scope_to_list(session_scope)) if session_scope else set()
|
||||
client_scopes = set(scope_to_list(grant.client.scope))
|
||||
|
||||
if not req_scopes.issubset(
|
||||
client_scopes
|
||||
& (user_scopes | {'openid', 'email', 'profile', 'offline_access'})
|
||||
):
|
||||
raise errors.InvalidScopeError(status_code=HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
return server.create_authorization_response(
|
||||
request=router.current_event,
|
||||
grant_user={'id': user_id},
|
||||
grant_user=sub,
|
||||
grant=grant,
|
||||
)
|
||||
except jwt.exceptions.InvalidTokenError as err:
|
||||
@@ -42,10 +53,13 @@ def authorize():
|
||||
raise BadRequestError(str(err))
|
||||
except errors.OAuth2Error as err:
|
||||
logger.exception(err)
|
||||
return dict(err.get_body())
|
||||
raise ServiceError(
|
||||
status_code=err.status_code,
|
||||
msg=dict(err.get_body()), # type: ignore
|
||||
)
|
||||
|
||||
|
||||
def verify_session(session_id: str) -> str:
|
||||
def verify_session(session_id: str) -> tuple[str, str | None]:
|
||||
payload = jwt.decode(
|
||||
session_id,
|
||||
JWT_SECRET,
|
||||
@@ -65,7 +79,7 @@ def verify_session(session_id: str) -> str:
|
||||
exc_cls=SessionRevokedError,
|
||||
)
|
||||
|
||||
return payload['sub']
|
||||
return payload['sub'], payload.get('scope')
|
||||
|
||||
|
||||
def _parse_cookies(cookies: list[str] | None) -> dict[str, str]:
|
||||
|
||||
@@ -26,7 +26,11 @@ def session(
|
||||
username: Annotated[str, Body()],
|
||||
password: Annotated[str, Body()],
|
||||
):
|
||||
user_id, password_hash = _get_user(username)
|
||||
(
|
||||
user_id,
|
||||
password_hash,
|
||||
scope,
|
||||
) = _get_user(username)
|
||||
|
||||
if not pbkdf2_sha256.verify(password, password_hash):
|
||||
raise ForbiddenError('Invalid credentials')
|
||||
@@ -36,7 +40,7 @@ def session(
|
||||
cookies=[
|
||||
Cookie(
|
||||
name='session_id',
|
||||
value=new_session(user_id),
|
||||
value=new_session(user_id, scope),
|
||||
http_only=True,
|
||||
secure=True,
|
||||
same_site=None,
|
||||
@@ -46,7 +50,7 @@ def session(
|
||||
)
|
||||
|
||||
|
||||
def _get_user(username: str) -> tuple[str, str]:
|
||||
def _get_user(username: str) -> tuple[str, str, str | None]:
|
||||
sk = SortKey(username, path_spec='user_id')
|
||||
user = oauth2_layer.collection.get_items(
|
||||
KeyPair(pk='email', sk=sk, rename_key=sk.path_spec)
|
||||
@@ -57,15 +61,33 @@ def _get_user(username: str) -> tuple[str, str]:
|
||||
if not user:
|
||||
raise UserNotFoundError()
|
||||
|
||||
password = oauth2_layer.collection.get_item(
|
||||
KeyPair(user['user_id'], 'PASSWORD'),
|
||||
exc_cls=UserNotFoundError,
|
||||
userdata = oauth2_layer.collection.get_items(
|
||||
KeyPair(
|
||||
pk=user['user_id'],
|
||||
sk=SortKey(
|
||||
sk='PASSWORD',
|
||||
path_spec='hash',
|
||||
rename_key='password',
|
||||
),
|
||||
)
|
||||
+ KeyPair(
|
||||
pk=user['user_id'],
|
||||
sk=SortKey(
|
||||
sk='SCOPE',
|
||||
path_spec='scope',
|
||||
rename_key='scope',
|
||||
),
|
||||
),
|
||||
flatten_top=False,
|
||||
)
|
||||
|
||||
return user['user_id'], password['hash']
|
||||
if not userdata:
|
||||
raise UserNotFoundError()
|
||||
|
||||
return user['user_id'], userdata['password'], userdata.get('scope')
|
||||
|
||||
|
||||
def new_session(sub: str) -> str:
|
||||
def new_session(sub: str, scope: str | None) -> str:
|
||||
now_ = now()
|
||||
sid = str(uuid4())
|
||||
exp = ttl(start_dt=now_, seconds=JWT_EXP_SECONDS)
|
||||
@@ -76,6 +98,7 @@ def new_session(sub: str) -> str:
|
||||
'iss': ISSUER,
|
||||
'iat': int(now_.timestamp()),
|
||||
'exp': exp,
|
||||
'scope': scope,
|
||||
},
|
||||
JWT_SECRET,
|
||||
algorithm=JWT_ALGORITHM,
|
||||
|
||||
Reference in New Issue
Block a user