Skip to content

Auth improvements #228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .idea/.gitignore

This file was deleted.

13 changes: 7 additions & 6 deletions .idea/bootstrap-python-fastapi.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/dataSources.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 0 additions & 21 deletions .idea/inspectionProfiles/Project_Default.xml

This file was deleted.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 2 additions & 9 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/runConfigurations/Tests.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion auth_volumes/kratos/identity.schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Person",
"type": "object",
Expand Down
9 changes: 8 additions & 1 deletion auth_volumes/kratos/kratos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,18 @@ selfservice:
registration:
lifespan: 10m
ui_url: http://127.0.0.1:8080/registration

after:
password:
hooks:
- hook: web_hook
config:
url: http://dev:8000/user_registered/
method: "POST"
body: file:///etc/config/kratos/user_registered.jsonnet
can_interrupt: true
emit_analytics_event: true
- hook: session
# - hook: show_verification_ui

log:
level: info
Expand Down
4 changes: 4 additions & 0 deletions auth_volumes/kratos/user_registered.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
function(ctx) {
user_id: ctx.identity.id,
email: ctx.identity.traits.email,
}
5 changes: 3 additions & 2 deletions auth_volumes/oathkeeper/access-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@
config:
to: http://127.0.0.1:8080/login

# Dev container access to protected /hello endpoint
# Dev container access to protected /api/* endpoints, to the dev container
- id: "http_app:protected"
upstream:
preserve_host: true
url: "http://dev:8000"
strip_path: /api
match:
url: "http://127.0.0.1:8080/hello<{,/,/**}>"
url: "http://127.0.0.1:8080/<{api/,api/**,openapi.json}>"
methods:
- GET
authenticators:
Expand Down
3 changes: 3 additions & 0 deletions auth_volumes/oathkeeper/oathkeeper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,8 @@ mutators:
jwks_url: file:///etc/config/oathkeeper/id_token.jwks.json
claims: |
{
{{ if .MatchContext.Header.Get "x-impersonate" }}
"impersonate": {{ .MatchContext.Header.Get "x-impersonate" | toJson }},
{{ end }}
"session": {{ .Extra | toJson }}
}
2 changes: 1 addition & 1 deletion docs/zero_trust.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ subgraph dn["Internal Docker Network (intranet)"]
OO-->|"Proxies /auth/login, /auth/registration, /dashboard, ... to"|SA
SA-->|Talks to|OK
OO-->|Validates auth sessions using|OK
OO-->|"Proxies /hello to"|DEV
OO-->|"Proxies /api/* requests (authenticated only)"|DEV
OK[Ory Kratos]
OO["Reverse Proxy (Ory Oathkeeper)"]
SA["SecureApp (Ory Kratos SelfService UI Node Example)"]
Expand Down
3 changes: 2 additions & 1 deletion src/http_app/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from fastapi import FastAPI

from http_app.routes import api, events, graphql, hello, ping
from http_app.routes import api, events, graphql, hello, ping, user_registered_hook


def init_routes(app: FastAPI) -> None:
app.include_router(api.router)
app.include_router(ping.router)
app.include_router(hello.router)
app.include_router(events.router)
app.include_router(user_registered_hook.router)
app.include_router(graphql.router, prefix="/graphql")
64 changes: 64 additions & 0 deletions src/http_app/routes/user_registered_hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import logging

from fastapi import APIRouter, status
from fastapi.responses import JSONResponse, Response
from pydantic import BaseModel

router = APIRouter(prefix="/user_registered")


class UserRegisteredWebhook(BaseModel):
user_id: str
email: str


@router.post("/")
async def user_registered(user: UserRegisteredWebhook): # pragma: no cover
"""
Handles the user registration webhook.

This function is triggered when a user registration webhook is received.
It logs the event details, evaluates the email validity, and returns an
appropriate HTTP response based on the validation. If the user's email
is invalid, it returns an error response along with a structured error
message. Otherwise, it confirms successful processing with no additional
content.

Args:
user (UserRegisteredWebhook): The webhook payload received when a user
registers, containing user details such as email and traits.

Returns:
Response: An HTTP response with a 403 Forbidden status and structured
error message if the user email is invalid.
Otherwise, an HTTP 204 No Content response to confirm successful
processing.
"""
logging.info("User registered", extra={"user": user.model_dump()})

error_message = {
"messages": [
{
"instance_ptr": "#/traits/email",
"messages": [
{
"id": 123, # Error id to be evaluated in frontend
"text": "You are not allowed to register.",
"type": "error",
"context": { # Additional context we can send to the Frontend
"value": "short value",
"any": "additional information",
},
}
],
}
]
}

if user.email == "[email protected]":
return JSONResponse(
error_message,
status.HTTP_403_FORBIDDEN,
)
else:
return Response(status_code=status.HTTP_204_NO_CONTENT)
Loading