Store raw access token within user; get resource
This commit is contained in:
parent
e1dac77738
commit
dc181bd3a8
7 changed files with 94 additions and 30 deletions
|
@ -25,8 +25,8 @@ oidc_providers_settings: dict[str, OIDCProvider] = dict(
|
|||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
def fetch_token(name, request):
|
||||
breakpoint()
|
||||
async def fetch_token(name, request):
|
||||
logger.warn("TODO: fetch_token")
|
||||
...
|
||||
# if name in oidc_providers:
|
||||
# model = OAuth2Token
|
||||
|
@ -37,8 +37,8 @@ def fetch_token(name, request):
|
|||
# return token.to_token()
|
||||
|
||||
|
||||
def update_token(*args, **kwargs):
|
||||
breakpoint()
|
||||
async def update_token(*args, **kwargs):
|
||||
logger.warn("TODO: update_token")
|
||||
...
|
||||
|
||||
|
||||
|
@ -211,7 +211,8 @@ async def get_user_from_token(
|
|||
)
|
||||
try:
|
||||
user = await db.get_user(user_id)
|
||||
user.access_token = payload
|
||||
if user.access_token != token:
|
||||
user.access_token = token
|
||||
except UserNotInDB:
|
||||
logger.info(
|
||||
f"User {user_id} not found in DB, creating it (real apps can behave differently"
|
||||
|
@ -221,6 +222,6 @@ async def get_user_from_token(
|
|||
user_info=payload,
|
||||
oidc_provider=getattr(authlib_oauth, auth_provider_id),
|
||||
user_info_from_endpoint={},
|
||||
access_token=payload,
|
||||
access_token=token,
|
||||
)
|
||||
return user
|
||||
|
|
|
@ -30,7 +30,7 @@ class Database:
|
|||
user_info: dict,
|
||||
oidc_provider: StarletteOAuth2App,
|
||||
user_info_from_endpoint: dict,
|
||||
access_token: dict,
|
||||
access_token: str,
|
||||
) -> User:
|
||||
user = User.from_auth(userinfo=user_info, oidc_provider=oidc_provider)
|
||||
user.access_token = access_token
|
||||
|
|
|
@ -200,7 +200,7 @@ async def auth(request: Request, oidc_provider_id: str) -> RedirectResponse:
|
|||
user_info=userinfo,
|
||||
oidc_provider=oidc_provider,
|
||||
user_info_from_endpoint=user_info_from_endpoint,
|
||||
access_token=access_token,
|
||||
access_token=token["access_token"],
|
||||
)
|
||||
# Add the id_token to the session
|
||||
request.session["token"] = token["id_token"]
|
||||
|
@ -229,7 +229,7 @@ async def account(
|
|||
raise HTTPException(
|
||||
status.HTTP_406_NOT_ACCEPTABLE, detail="No oidc provider settings"
|
||||
)
|
||||
return RedirectResponse(f"{oidc_provider_settings.account_url}")
|
||||
return RedirectResponse(f"{oidc_provider_settings.account_url_template}")
|
||||
|
||||
|
||||
@app.get("/logout")
|
||||
|
@ -243,7 +243,9 @@ async def logout(
|
|||
if (
|
||||
provider_logout_uri := oidc_provider.server_metadata.get("end_session_endpoint")
|
||||
) is None:
|
||||
logger.warn(f"Cannot find end_session_endpoint for provider {provider.name}")
|
||||
logger.warn(
|
||||
f"Cannot find end_session_endpoint for provider {oidc_provider.name}"
|
||||
)
|
||||
return RedirectResponse(request.url_for("non_compliant_logout"))
|
||||
post_logout_uri = request.url_for("home")
|
||||
if (token := await db.get_token(request.session.pop("token", None))) is None:
|
||||
|
|
|
@ -25,14 +25,14 @@ class UserBase(SQLModel, extra="ignore"):
|
|||
|
||||
|
||||
class User(UserBase):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True) # type:ignore
|
||||
|
||||
sub: str = Field(
|
||||
description="""subject id of the user given by the oidc provider,
|
||||
also the key for the database 'table'""",
|
||||
)
|
||||
userinfo: dict = {}
|
||||
access_token: dict = {}
|
||||
access_token: str | None = None
|
||||
oidc_provider: StarletteOAuth2App | None = None
|
||||
|
||||
@classmethod
|
||||
|
@ -54,5 +54,15 @@ class User(UserBase):
|
|||
def has_scope(self, scope: str) -> bool:
|
||||
"""Check if the scope is present in user info or access token"""
|
||||
info_scopes = self.userinfo.get("scope", "").split(" ")
|
||||
access_token_scopes = self.access_token.get("scope", "").split(" ")
|
||||
access_token_scopes = self.access_token_parsed().get("scope", "").split(" ")
|
||||
return scope in set(info_scopes + access_token_scopes)
|
||||
|
||||
def access_token_parsed(self):
|
||||
assert self.access_token is not None
|
||||
assert self.oidc_provider is not None
|
||||
assert self.oidc_provider.name is not None
|
||||
from .auth_utils import oidc_providers_settings
|
||||
|
||||
return oidc_providers_settings[self.oidc_provider.name].decode(
|
||||
self.access_token
|
||||
)
|
||||
|
|
|
@ -3,9 +3,9 @@ body {
|
|||
background-color: floralwhite;
|
||||
margin: 0;
|
||||
font-family: system-ui;
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
background-color: #f7c7867d;
|
||||
margin: 0 0 0.2em 0;
|
||||
box-shadow: 0px 0.2em 0.2em #f7c7867d;
|
||||
|
@ -21,9 +21,6 @@ hr {
|
|||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -55,7 +52,6 @@ hr {
|
|||
border: 2px solid darkkhaki;
|
||||
padding: 3px 6px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
.user-info a.logout:hover {
|
||||
|
@ -70,7 +66,6 @@ hr {
|
|||
margin: 0;
|
||||
}
|
||||
.debug-auth p {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
.debug-auth ul {
|
||||
|
@ -101,16 +96,24 @@ hr {
|
|||
.hasResponseStatus.status-503 {
|
||||
background-color: #ffA88050;
|
||||
}
|
||||
.role {
|
||||
|
||||
.role, .scope {
|
||||
padding: 3px 6px;
|
||||
background-color: #44228840;
|
||||
margin: 3px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.role {
|
||||
background-color: #44228840;
|
||||
}
|
||||
|
||||
.scope {
|
||||
background-color: #8888FF80;
|
||||
}
|
||||
|
||||
/* For home */
|
||||
|
||||
.login-box {
|
||||
text-align: center;
|
||||
background-color: antiquewhite;
|
||||
margin: 0.5em auto;
|
||||
width: fit-content;
|
||||
|
@ -137,7 +140,6 @@ hr {
|
|||
max-height: 2em;
|
||||
}
|
||||
.providers .provider .link div {
|
||||
text-align: center;
|
||||
background-color: #f7c7867d;
|
||||
border-radius: 8px;
|
||||
padding: 6px;
|
||||
|
@ -152,13 +154,11 @@ hr {
|
|||
}
|
||||
.providers .error {
|
||||
padding: 3px 6px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.content .links-to-check {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
gap: 0.5em;
|
||||
flex-flow: wrap;
|
||||
|
|
|
@ -17,3 +17,24 @@ function checkPerms(className) {
|
|||
Array.from(elem.children).forEach(elem => checkHref(elem))
|
||||
)
|
||||
}
|
||||
|
||||
async function get_resource(id, token, authProvider) {
|
||||
//if (!keycloak.keycloak) { return }
|
||||
const resp = await fetch("resource/" + id, {
|
||||
method: "GET",
|
||||
headers: new Headers({
|
||||
"Content-type": "application/json",
|
||||
"Authorization": `Bearer ${token}`,
|
||||
"auth_provider": authProvider,
|
||||
}),
|
||||
})
|
||||
/*
|
||||
resource.value = resp['data']
|
||||
msg.value = ""
|
||||
}
|
||||
).catch (
|
||||
err => msg.value = err
|
||||
)
|
||||
*/
|
||||
console.log(await resp.json())
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
<img src="{{ user.picture }}" class="picture"></img>
|
||||
{% endif %}
|
||||
<div>{{ user.email }}</div>
|
||||
<div>
|
||||
<span>Provider:</span>
|
||||
{{ oidc_provider_settings.name }}
|
||||
</div>
|
||||
{% if user.roles %}
|
||||
<div>
|
||||
<span>Roles:</span>
|
||||
|
@ -38,17 +42,43 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div>
|
||||
<span>Provider:</span>
|
||||
{{ oidc_provider_settings.name }}
|
||||
</div>
|
||||
{% if user.access_token.scope %}
|
||||
<div>
|
||||
<span>Scopes</span>:
|
||||
{% for scope in user.access_token.scope.split(' ') %}
|
||||
<span class="scope">{{ scope }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if oidc_provider_settings.account_url_template %}
|
||||
<button onclick="location.href='{{ oidc_provider_settings.get_account_url(request, user) }}'" class="account">Account management</button>
|
||||
<button
|
||||
onclick="location.href='{{ oidc_provider_settings.get_account_url(request, user) }}'"
|
||||
class="account">
|
||||
Account management
|
||||
</button>
|
||||
{% endif %}
|
||||
<button onclick="location.href='{{ request.url_for("logout") }}'" class="logout">Logout</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr>
|
||||
<p class="center">
|
||||
Fetch resources from the resource server with your authentication token:
|
||||
</p>
|
||||
<div class="actions">
|
||||
<button onclick="get_resource('time', '{{ user.access_token }}', '{{ oidc_provider_settings.id }}')">Time</button>
|
||||
<button onclick="get_resource('bs', '{{ user.access_token }}', '{{ oidc_provider_settings.id }}')">BS</button>
|
||||
</div>
|
||||
<div class="resources">
|
||||
<div v-if="Object.entries(resource).length > 0" class="resource">
|
||||
<div v-for="(value, key) in resource">
|
||||
<div class="key">{{ key }}</div>
|
||||
<div v-if="key == 'sorry' || key == 'error'" class="error">{{ value }}</div>
|
||||
<div v-else class="value">{{ value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="msg" class="msg resource">{{ msg }}</div>
|
||||
<hr>
|
||||
<div class="content">
|
||||
<p>
|
||||
These links should get different response codes depending on the authorization:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue