wip
This commit is contained in:
0
id.saladeaula.digital/app/routes/___init__.py
Normal file
0
id.saladeaula.digital/app/routes/___init__.py
Normal file
33
id.saladeaula.digital/app/routes/authorize.py
Normal file
33
id.saladeaula.digital/app/routes/authorize.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from uuid import uuid4
|
||||
|
||||
from authlib.oauth2 import OAuth2Error
|
||||
from authlib.oauth2.rfc6749 import errors
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
|
||||
from oauth2 import authorization
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get('/authorize')
|
||||
def authorize():
|
||||
user = {
|
||||
'id': str(uuid4()),
|
||||
'sub': 'sergio@somosbeta.com.br',
|
||||
}
|
||||
try:
|
||||
grant = authorization.get_consent_grant(
|
||||
request=router.current_event,
|
||||
end_user=user,
|
||||
)
|
||||
except OAuth2Error as err:
|
||||
return dict(err.get_body())
|
||||
|
||||
try:
|
||||
return authorization.create_authorization_response(
|
||||
request=router.current_event,
|
||||
grant_user=user,
|
||||
grant=grant,
|
||||
)
|
||||
except errors.OAuth2Error:
|
||||
return {}
|
||||
8
id.saladeaula.digital/app/routes/jwks.py
Normal file
8
id.saladeaula.digital/app/routes/jwks.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get('/jwks.json')
|
||||
def jwks():
|
||||
return {}
|
||||
46
id.saladeaula.digital/app/routes/login.html
Normal file
46
id.saladeaula.digital/app/routes/login.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
</head>
|
||||
<body
|
||||
class="bg-black text-white flex items-center justify-center min-h-screen"
|
||||
>
|
||||
<form
|
||||
method="POST"
|
||||
action="/login"
|
||||
class="bg-gray-900 p-8 rounded-lg shadow-lg w-full max-w-sm space-y-4"
|
||||
>
|
||||
<div>
|
||||
<label for="username" class="block mb-1">Email ou CPF</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
class="w-full p-2 rounded bg-gray-800 text-white border border-gray-700"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block mb-1">Senha</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
class="w-full p-2 rounded bg-gray-800 text-white border border-gray-700"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full bg-blue-600 hover:bg-blue-700 transition-colors p-2 rounded font-semibold"
|
||||
>
|
||||
Entrar
|
||||
</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
82
id.saladeaula.digital/app/routes/login.py
Normal file
82
id.saladeaula.digital/app/routes/login.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from http import HTTPStatus
|
||||
from pathlib import Path
|
||||
from typing import Annotated
|
||||
|
||||
from aws_lambda_powertools.event_handler import (
|
||||
Response,
|
||||
)
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
from aws_lambda_powertools.event_handler.exceptions import ForbiddenError, NotFoundError
|
||||
from aws_lambda_powertools.event_handler.openapi.params import Form
|
||||
from aws_lambda_powertools.shared.cookies import Cookie
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||
from passlib.hash import pbkdf2_sha256
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import OAUTH2_TABLE
|
||||
from jose_ import generate_jwt
|
||||
|
||||
router = Router()
|
||||
oauth2_layer = DynamoDBPersistenceLayer(OAUTH2_TABLE, dynamodb_client)
|
||||
|
||||
|
||||
@router.get('/login')
|
||||
def login_form():
|
||||
html = Path(__file__).with_name('login.html').read_text(encoding='utf-8')
|
||||
|
||||
return Response(
|
||||
body=html,
|
||||
status_code=HTTPStatus.OK.value,
|
||||
content_type='text/html',
|
||||
)
|
||||
|
||||
|
||||
@router.post('/login')
|
||||
def login(
|
||||
username: Annotated[str, Form()],
|
||||
password: Annotated[str, Form()],
|
||||
):
|
||||
user_id, password_hash = _get_user(username)
|
||||
|
||||
if not pbkdf2_sha256.verify(password, password_hash):
|
||||
raise ForbiddenError('Invalid credentials')
|
||||
|
||||
jwt_token = generate_jwt(user_id, username)
|
||||
|
||||
return Response(
|
||||
status_code=HTTPStatus.OK,
|
||||
cookies=[
|
||||
Cookie(
|
||||
name='id_token',
|
||||
value=jwt_token,
|
||||
http_only=True,
|
||||
same_site=None,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _get_user(username: str) -> tuple[str, str]:
|
||||
r = oauth2_layer.collection.get_item(
|
||||
# Post-migration: uncomment the following line
|
||||
# KeyPair('EMAIL', username),
|
||||
KeyPair('email', username),
|
||||
exc_cls=EmailNotFoundError,
|
||||
)
|
||||
|
||||
password = oauth2_layer.collection.get_item(
|
||||
KeyPair(r['user_id'], 'PASSWORD'),
|
||||
exc_cls=UserNotFoundError,
|
||||
)
|
||||
|
||||
return r['user_id'], password['hash']
|
||||
|
||||
|
||||
class EmailNotFoundError(NotFoundError):
|
||||
def __init__(self, *_):
|
||||
super().__init__('Email not found')
|
||||
|
||||
|
||||
class UserNotFoundError(NotFoundError):
|
||||
def __init__(self, *_):
|
||||
super().__init__('User not found')
|
||||
25
id.saladeaula.digital/app/routes/openid_configuration.py
Normal file
25
id.saladeaula.digital/app/routes/openid_configuration.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
|
||||
from config import ISSUER, JWT_ALGORITHM
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get('/.well-known/openid-configuration')
|
||||
def openid_configuration():
|
||||
return {
|
||||
'issuer': ISSUER,
|
||||
'authorization_endpoint': f'{ISSUER}/authorize',
|
||||
'token_endpoint': f'{ISSUER}/token',
|
||||
'userinfo_endpoint': f'{ISSUER}/userinfo',
|
||||
'jwks_uri': f'{ISSUER}/jwks.json',
|
||||
'scopes_supported': ['openid', 'profile', 'email'],
|
||||
'response_types_supported': ['code'],
|
||||
'grant_types_supported': ['authorization_code', 'refresh_token'],
|
||||
'subject_types_supported': ['public'],
|
||||
'id_token_signing_alg_values_supported': [JWT_ALGORITHM],
|
||||
'token_endpoint_auth_methods_supported': [
|
||||
'client_secret_basic',
|
||||
'client_secret_post',
|
||||
],
|
||||
}
|
||||
8
id.saladeaula.digital/app/routes/token.py
Normal file
8
id.saladeaula.digital/app/routes/token.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get('/token')
|
||||
def token():
|
||||
return {}
|
||||
8
id.saladeaula.digital/app/routes/userinfo.py
Normal file
8
id.saladeaula.digital/app/routes/userinfo.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.get('/userinfo')
|
||||
def userinfo():
|
||||
return {}
|
||||
Reference in New Issue
Block a user