These links should get different response codes depending on the authorization:
From af49242192c29a38b58819ebd0f2e8ae55bd87b6 Mon Sep 17 00:00:00 2001
From: phil
From b96bfa870a2b3e81dc31c2f4c5c0bbc5ffd77f00 Mon Sep 17 00:00:00 2001
From: phil User info
Test the authentication and authorization,
with OpenID Connect and OAuth2 with different providers.
From 54345dcafd38413acead9c0eb6fcb34b6157c2b2 Mon Sep 17 00:00:00 2001
From: phil
These links should get different response codes depending on the authorization:
+ Resources for this provider:
+
- This is because {{ provider.name }} does not provide "end_session_endpoint" in its metadata
- (see: {{ provider._server_metadata_url }}).
+ This is because {{ oidc_provider.name }} does not provide "end_session_endpoint" in its metadata
+ (see: {{ oidc_provider._server_metadata_url }}).
You can just also go back to the application home page, but
- it recommended to go to the provider's site
+ it recommended to go to the OIDC provider's site
and log out explicitely from there.
From f14d8d3114134dc58e6198a64701066ad216d143 Mon Sep 17 00:00:00 2001
From: phil
Not protected
")
-# Some URIs for testing the permissions
-
-
@app.get("/protected")
async def get_protected(
user: Annotated[User, Depends(get_current_user)]
@@ -277,12 +305,12 @@ async def get_protected_by_foorole_or_barrole(request: Request) -> HTMLResponse:
@app.get("/introspect")
async def get_introspect(
request: Request,
- provider: Annotated[StarletteOAuth2App, Depends(get_provider)],
+ oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)],
) -> JSONResponse:
if (
- response := await provider.post(
- provider.server_metadata["introspection_endpoint"],
+ response := await oidc_provider.post(
+ oidc_provider.server_metadata["introspection_endpoint"],
token=token,
data={"token": token["access_token"]},
)
@@ -296,11 +324,11 @@ async def get_introspect(
async def get_forgejo_user_info(
request: Request,
user: Annotated[User, Depends(get_current_user)],
- provider: Annotated[StarletteOAuth2App, Depends(get_provider)],
+ oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)],
) -> HTMLResponse:
if (
- response := await provider.get(
+ response := await oidc_provider.get(
"/api/v1/user/repos",
# headers={"Authorization": f"token {token['access_token']}"},
token=token,
@@ -313,11 +341,9 @@ async def get_forgejo_user_info(
raise HTTPException(status_code=response.status_code, detail=response.text)
-# @app.get("/fast_api_depends")
-# def fast_api_depends(
-# token: Annotated[str, Depends(fastapi_providers["Keycloak"])]
-# ) -> HTMLResponse:
-# return HTMLResponse("You're Authenticated")
+# Snippet for running standalone
+# Mostly useful for the --version option,
+# as running with uvicorn is easy and provides flaxibility
def main():
diff --git a/src/oidc_test/settings.py b/src/oidc_test/settings.py
index 0f41a2e..bf823ba 100644
--- a/src/oidc_test/settings.py
+++ b/src/oidc_test/settings.py
@@ -13,7 +13,16 @@ from pydantic_settings import (
)
+class Resource(BaseModel):
+ """A resource with an URL that can be accessed with an OAuth2 access token"""
+
+ name: str
+ url: str
+
+
class OIDCProvider(BaseModel):
+ """OIDC provider, can also be a resource server"""
+
id: str
name: str
url: str
@@ -22,6 +31,7 @@ class OIDCProvider(BaseModel):
# For PKCE (not implemented yet)
code_challenge_method: str | None = None
hint: str = "No hint"
+ resources: list[Resource] = []
@computed_field
@property
diff --git a/src/oidc_test/static/styles.css b/src/oidc_test/static/styles.css
new file mode 100644
index 0000000..8c6961a
--- /dev/null
+++ b/src/oidc_test/static/styles.css
@@ -0,0 +1,168 @@
+body {
+ font-family: Arial, Helvetica, sans-serif;
+ background-color: floralwhite;
+ margin: 0;
+}
+h1 {
+ text-align: center;
+ background-color: #f7c7867d;
+ margin: 0 0 0.2em 0;
+}
+p {
+ margin: 0.2em;
+}
+hr {
+ margin: 0.2em;
+}
+.hidden {
+ display: none;
+}
+.center {
+ text-align: center;
+}
+.content {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+.user-info {
+ padding: 0.5em;
+ display: flex;
+ gap: 0.5em;
+ flex-direction: column;
+ width: fit-content;
+ align-items: center;
+ margin: 5px auto;
+ box-shadow: 0px 0px 10px lightgreen;
+ background-color: lightgreen;
+ border-radius: 8px;
+}
+.user-info * {
+ flex: 2 1 auto;
+ margin: 0;
+}
+.user-info .picture {
+ max-width: 3em;
+ max-height: 3em
+}
+.user-info a.logout {
+ border: 2px solid darkkhaki;
+ padding: 3px 6px;
+ text-decoration: none;
+ text-align: center;
+ color: black;
+}
+.user-info a.logout:hover {
+ background-color: orange;
+}
+debug-auth {
+ font-size: 90%;
+ background-color: #d8bebc75;
+ padding: 6px;
+}
+.debug-auth * {
+ margin: 0;
+}
+.debug-auth p {
+ text-align: center;
+ border-bottom: 1px solid black;
+}
+.debug-auth ul {
+ padding: 0;
+ list-style: none;
+}
+.debug-auth p, .debug-auth .key {
+ font-weight: bold;
+}
+.content {
+ text-align: left;
+}
+.hasResponseStatus {
+ background-color: #88888840;
+}
+.hasResponseStatus.status-200 {
+ background-color: #00ff0040;
+}
+.hasResponseStatus.status-401 {
+ background-color: #ff000040;
+}
+.hasResponseStatus.status-403 {
+ background-color: #ff990040;
+}
+.hasResponseStatus.status-404 {
+ background-color: #ffCC0040;
+}
+.hasResponseStatus.status-503 {
+ background-color: #ffA88050;
+}
+.role {
+ padding: 3px 6px;
+ background-color: #44228840;
+}
+
+/* For home */
+
+.login-box {
+ text-align: center;
+ background-color: antiquewhite;
+ margin: 0.5em auto;
+ width: fit-content;
+ box-shadow: 0 0 10px #49759b88;
+ border-radius: 8px;
+}
+.login-box .description {
+ font-style: italic;
+ font-weight: bold;
+ background-color: #f7c7867d;
+ padding: 6px;
+ margin: 0;
+ border-radius: 8px 8px 0 0;
+}
+.providers {
+ justify-content: center;
+ padding: 0.8em;
+}
+.providers .provider {
+ min-height: 2em;
+}
+.providers .provider a.link {
+ text-decoration: none;
+ max-height: 2em;
+}
+.providers .provider .link div {
+ text-align: center;
+ background-color: #f7c7867d;
+ border-radius: 8px;
+ padding: 6px;
+ text-align: center;
+ color: black;
+ font-weight: bold;
+ cursor: pointer;
+}
+.providers .provider .hint {
+ font-size: 80%;
+ max-width: 13em;
+}
+.providers .error {
+ color: darkred;
+ 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;
+}
+.content #links-to-check a {
+ color: black;
+ padding: 5px 10px;
+ text-decoration: none;
+ border-radius: 8px;
+}
+
diff --git a/src/oidc_test/static/utils.js b/src/oidc_test/static/utils.js
new file mode 100644
index 0000000..ec9bcfc
--- /dev/null
+++ b/src/oidc_test/static/utils.js
@@ -0,0 +1,17 @@
+function checkHref(elem) {
+ var xmlHttp = new XMLHttpRequest()
+ xmlHttp.onreadystatechange = function () {
+ if (xmlHttp.readyState == 4) {
+ elem.classList.add("hasResponseStatus")
+ elem.classList.add("status-" + xmlHttp.status)
+ elem.title = "Response code: " + xmlHttp.status + " - " + xmlHttp.statusText
+ }
+ }
+ xmlHttp.open("GET", elem.href, true) // true for asynchronous
+ xmlHttp.send(null)
+}
+
+function checkPerms(rootId) {
+ var rootElem = document.getElementById(rootId)
+ Array.from(rootElem.children).forEach(elem => checkHref(elem))
+}
diff --git a/src/oidc_test/templates/base.html b/src/oidc_test/templates/base.html
index 30f6194..d2aa44b 100644
--- a/src/oidc_test/templates/base.html
+++ b/src/oidc_test/templates/base.html
@@ -1,136 +1,8 @@
OIDC-test
diff --git a/src/oidc_test/templates/home.html b/src/oidc_test/templates/home.html
index 80e7133..d20f74c 100644
--- a/src/oidc_test/templates/home.html
+++ b/src/oidc_test/templates/home.html
@@ -1,55 +1,5 @@
{% extends "base.html" %}
{% block content %}
-
Only authenticated users can see this
")
@app.get("/protected-by-foorole")
@hasrole("foorole")
async def get_protected_by_foorole(request: Request) -> HTMLResponse:
+ assert request is not None
return HTMLResponse("Only users with foorole can see this
")
@app.get("/protected-by-barrole")
@hasrole("barrole")
async def get_protected_by_barrole(request: Request) -> HTMLResponse:
+ assert request is not None
return HTMLResponse("Protected by barrole
")
@@ -318,12 +331,14 @@ async def get_protected_by_barrole(request: Request) -> HTMLResponse:
@hasrole("barrole")
@hasrole("foorole")
async def get_protected_by_foorole_and_barrole(request: Request) -> HTMLResponse:
+ assert request is not None
return HTMLResponse("Only users with foorole and barrole can see this
")
@app.get("/protected-by-foorole-or-barrole")
@hasrole(["foorole", "barrole"])
async def get_protected_by_foorole_or_barrole(request: Request) -> HTMLResponse:
+ assert request is not None
return HTMLResponse("Only users with foorole or barrole can see this
")
@@ -333,6 +348,7 @@ async def get_introspect(
oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)],
) -> JSONResponse:
+ assert request is not None
if (
response := await oidc_provider.post(
oidc_provider.server_metadata["introspection_endpoint"],
@@ -352,6 +368,7 @@ async def get_forgejo_user_info(
oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)],
) -> HTMLResponse:
+ assert request is not None
if (
response := await oidc_provider.get(
"/api/v1/user/repos",
diff --git a/src/oidc_test/templates/home.html b/src/oidc_test/templates/home.html
index ab4dc77..ac732e4 100644
--- a/src/oidc_test/templates/home.html
+++ b/src/oidc_test/templates/home.html
@@ -58,8 +58,6 @@
Auth + barrole protected content
Auth + foorole and barrole protected content
Using FastAPI Depends
- Other
- OAuth2 test (forgejo user info)
Introspect token (401 expected)
Only authenticated users can see this
")
@app.get("/protected-by-foorole")
@hasrole("foorole")
async def get_protected_by_foorole(request: Request) -> HTMLResponse:
- assert request is not None
+ assert request is not None # Just to keep QA checks happy
return HTMLResponse("Only users with foorole can see this
")
@app.get("/protected-by-barrole")
@hasrole("barrole")
async def get_protected_by_barrole(request: Request) -> HTMLResponse:
- assert request is not None
+ assert request is not None # Just to keep QA checks happy
return HTMLResponse("Protected by barrole
")
@@ -331,14 +333,14 @@ async def get_protected_by_barrole(request: Request) -> HTMLResponse:
@hasrole("barrole")
@hasrole("foorole")
async def get_protected_by_foorole_and_barrole(request: Request) -> HTMLResponse:
- assert request is not None
+ assert request is not None # Just to keep QA checks happy
return HTMLResponse("Only users with foorole and barrole can see this
")
@app.get("/protected-by-foorole-or-barrole")
@hasrole(["foorole", "barrole"])
async def get_protected_by_foorole_or_barrole(request: Request) -> HTMLResponse:
- assert request is not None
+ assert request is not None # Just to keep QA checks happy
return HTMLResponse("Only users with foorole or barrole can see this
")
@@ -348,7 +350,7 @@ async def get_introspect(
oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
token: Annotated[OAuth2Token, Depends(get_token)],
) -> JSONResponse:
- assert request is not None
+ assert request is not None # Just to keep QA checks happy
if (
response := await oidc_provider.post(
oidc_provider.server_metadata["introspection_endpoint"],
@@ -361,31 +363,10 @@ async def get_introspect(
raise HTTPException(status_code=response.status_code, detail=response.text)
-@app.get("/oauth2-forgejo-test")
-async def get_forgejo_user_info(
- request: Request,
- user: Annotated[User, Depends(get_current_user)],
- oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
- token: Annotated[OAuth2Token, Depends(get_token)],
-) -> HTMLResponse:
- assert request is not None
- if (
- response := await oidc_provider.get(
- "/api/v1/user/repos",
- # headers={"Authorization": f"token {token['access_token']}"},
- token=token,
- )
- ).is_success:
- repos = response.json()
- names = [repo["name"] for repo in repos]
- return HTMLResponse(f"{user.name} has {len(repos)} repos: {', '.join(names)}")
- else:
- raise HTTPException(status_code=response.status_code, detail=response.text)
-
-
# Snippet for running standalone
# Mostly useful for the --version option,
-# as running with uvicorn is easy and provides flaxibility
+# as running with uvicorn is easy and provides better flexibility, eg.
+# uvicorn --host foo oidc_test.main:app --reload
def main():
From 572d2a7b0d0973ec7fa56efdbc68cb9838dad74e Mon Sep 17 00:00:00 2001
From: phil
@@ -66,7 +69,7 @@
+ Fetch resources from the resource server with your authentication token: +
+
These links should get different response codes depending on the authorization:
From af49242192c29a38b58819ebd0f2e8ae55bd87b6 Mon Sep 17 00:00:00 2001
From: phil
Fetch resources from the resource server with your authentication token:
@@ -68,17 +69,9 @@ -
These links should get different response codes depending on the authorization:
From fefe44acfef0a16c492070ac8bc9f43d4637aa2c Mon Sep 17 00:00:00 2001
From: phil
From 3eb6dc3dcf4be7350aa4cda6b3157183fe77d5d8 Mon Sep 17 00:00:00 2001
From: phil Not protected
")
+async def public() -> dict:
+ return {"msg": "Not protected"}
@resource_server.get("/protected")
-async def get_protected(user: Annotated[User, Depends(get_user_from_token)]) -> HTMLResponse:
+async def get_protected(user: Annotated[User, Depends(get_user_from_token)]):
assert user is not None # Just to keep QA checks happy
- return HTMLResponse("Only authenticated users can see this
")
+ return {"msg": "Only authenticated users can see this"}
@resource_server.get("/protected-by-foorole")
async def get_protected_by_foorole(
- user: Annotated[User, Depends(UserWithRole("foorole"))]
-) -> HTMLResponse:
- return HTMLResponse("Only users with foorole can see this
")
+ user: Annotated[User, Depends(UserWithRole("foorole"))],
+):
+ assert user is not None
+ return {"msg": "Only users with foorole can see this"}
@resource_server.get("/protected-by-barrole")
async def get_protected_by_barrole(
- user: Annotated[User, Depends(UserWithRole("barrole"))]
-) -> HTMLResponse:
- return HTMLResponse("Protected by barrole
")
+ user: Annotated[User, Depends(UserWithRole("barrole"))],
+):
+ assert user is not None
+ return {"msg": "Protected by barrole"}
@resource_server.get("/protected-by-foorole-and-barrole")
async def get_protected_by_foorole_and_barrole(
user: Annotated[User, Depends(UserWithRole("foorole")), Depends(UserWithRole("barrole"))],
-) -> HTMLResponse:
+):
assert user is not None # Just to keep QA checks happy
- return HTMLResponse("Only users with foorole and barrole can see this
")
+ return {"msg": "Only users with foorole and barrole can see this"}
@resource_server.get("/protected-by-foorole-or-barrole")
async def get_protected_by_foorole_or_barrole(
- user: Annotated[User, Depends(UserWithRole(["foorole", "barrole"]))]
-) -> HTMLResponse:
+ user: Annotated[User, Depends(UserWithRole(["foorole", "barrole"]))],
+):
assert user is not None # Just to keep QA checks happy
- return HTMLResponse("Only users with foorole or barrole can see this
")
+ return {"msg": "Only users with foorole or barrole can see this"}
# @resource_server.get("/introspect")
@@ -118,9 +119,9 @@ async def get_resource_(
# oidc_provider: Annotated[StarletteOAuth2App, Depends(get_oidc_provider)],
# token: Annotated[OAuth2Token, Depends(get_token)],
user: Annotated[User, Depends(get_user_from_token)],
-) -> JSONResponse:
+):
"""Generic path for testing a resource provided by a provider"""
- return JSONResponse(await get_resource(id, user))
+ return await get_resource(id, user)
async def get_resource(resource_id: str, user: User) -> dict:
diff --git a/src/oidc_test/settings.py b/src/oidc_test/settings.py
index 2544bd7..b601739 100644
--- a/src/oidc_test/settings.py
+++ b/src/oidc_test/settings.py
@@ -43,9 +43,7 @@ class OIDCProvider(BaseModel):
info_url: str | None = (
None # Used eg. for Keycloak's public key (see https://stackoverflow.com/questions/54318633/getting-keycloaks-public-key)
)
- info: dict[str, str | int] | None = (
- None # Info fetched from info_url, eg. public key
- )
+ info: dict[str, str | int] | None = None # Info fetched from info_url, eg. public key
public_key: str | None = None
signature_alg: str = "RS256"
resource_provider_scopes: list[str] = []
@@ -62,25 +60,17 @@ class OIDCProvider(BaseModel):
def get_account_url(self, request: Request, user: User) -> str | None:
if self.account_url_template:
- if not (
- self.url.endswith("/") or self.account_url_template.startswith("/")
- ):
+ if not (self.url.endswith("/") or self.account_url_template.startswith("/")):
sep = "/"
else:
sep = ""
- return (
- self.url
- + sep
- + self.account_url_template.format(request=request, user=user)
- )
+ return self.url + sep + self.account_url_template.format(request=request, user=user)
else:
return None
def get_public_key(self) -> str:
"""Return the public key formatted for decoding token"""
- public_key = self.public_key or (
- self.info is not None and self.info["public_key"]
- )
+ public_key = self.public_key or (self.info is not None and self.info["public_key"])
if public_key is None:
raise AttributeError(f"Cannot get public key for {self.name}")
return f"""
@@ -91,17 +81,18 @@ class OIDCProvider(BaseModel):
def decode(self, token: str, verify_signature: bool = True) -> dict[str, Any]:
"""Decode the token with signature check"""
- decoded = decode(
- token,
- self.get_public_key(),
- algorithms=[self.signature_alg],
- audience=["account", "oidc-test", "oidc-test-web"],
- options={
- "verify_signature": False,
- "verify_aud": False,
- }, # not settings.insecure.skip_verify_signature},
- )
- logger.debug(str(decoded))
+ if settings.debug_token:
+ decoded = decode(
+ token,
+ self.get_public_key(),
+ algorithms=[self.signature_alg],
+ audience=["account", "oidc-test", "oidc-test-web"],
+ options={
+ "verify_signature": False,
+ "verify_aud": False,
+ }, # not settings.insecure.skip_verify_signature},
+ )
+ logger.debug(str(decoded))
return decode(
token,
self.get_public_key(),
@@ -143,6 +134,7 @@ class Settings(BaseSettings):
log: bool = False
insecure: Insecure = Insecure()
cors_origins: list[str] = []
+ debug_token: bool = False
@classmethod
def settings_customise_sources(
@@ -161,9 +153,7 @@ class Settings(BaseSettings):
settings_cls,
Path(
Path(
- environ.get(
- "OIDC_TEST_SETTINGS_FILE", Path.cwd() / "settings.yaml"
- ),
+ environ.get("OIDC_TEST_SETTINGS_FILE", Path.cwd() / "settings.yaml"),
)
),
),
diff --git a/src/oidc_test/static/styles.css b/src/oidc_test/static/styles.css
index 7e1260b..6262d79 100644
--- a/src/oidc_test/static/styles.css
+++ b/src/oidc_test/static/styles.css
@@ -171,11 +171,13 @@ hr {
gap: 0.5em;
flex-flow: wrap;
}
-.content .links-to-check a {
+.content .links-to-check button {
color: black;
padding: 5px 10px;
text-decoration: none;
border-radius: 8px;
+ border: none;
+ cursor: pointer;
}
.token {
@@ -183,12 +185,6 @@ hr {
font-family: monospace;
}
-.actions {
- display: flex;
- justify-content: center;
- gap: 0.5em;
-}
-
.resourceResult {
padding: 0.5em;
gap: 0.5em;
diff --git a/src/oidc_test/static/utils.js b/src/oidc_test/static/utils.js
index e6c4bfc..6ea8da2 100644
--- a/src/oidc_test/static/utils.js
+++ b/src/oidc_test/static/utils.js
@@ -1,6 +1,7 @@
async function checkHref(elem, token, authProvider) {
const msg = document.getElementById("msg")
- const resp = await fetch(elem.href, {
+ const url = `resource/${elem.getAttribute("resource-id")}`
+ const resp = await fetch(url, {
headers: new Headers({
"Content-type": "application/json",
"Authorization": `Bearer ${token}`,
diff --git a/src/oidc_test/templates/home.html b/src/oidc_test/templates/home.html
index 09c313f..92b7068 100644
--- a/src/oidc_test/templates/home.html
+++ b/src/oidc_test/templates/home.html
@@ -61,33 +61,30 @@
- Fetch resources from the resource server with your authentication token: -
-- These links should get different response codes depending on the authorization: +
+ Resources validated by scope:
+ Resources validated by role: +
+
From ff72f0cae585858e400a9bc8f7d3fe1727035c44 Mon Sep 17 00:00:00 2001
From: phil
User info
-Resources validated by role:
Log in with:
{{ provider.name }}
@@ -32,7 +32,7 @@
{{ user.email }}
Provider:
- {{ oidc_provider_settings.name }}
+ {{ auth_provider.name }}
{% if user.roles %}
@@ -50,9 +50,9 @@
{% endfor %}
{% endif %}
- {% if oidc_provider_settings.account_url_template %}
+ {% if auth_provider.account_url_template %}
@@ -67,21 +67,21 @@
Resources validated by scope:
-
-
+
+
Resources validated by role:
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
From 496ce016e3d31fdb003146a3f84bc86726275e6d Mon Sep 17 00:00:00 2001
From: phil
- {% if settings.show_token and id_token_parsed %}
+ {% if show_token and id_token_parsed %}
-
- {% endif %}
- {% if user %}
+ Log in with: -
+
+ {% else %}
- Log in with: +
-
-
-
{% if resources %}
Resources for this provider:
{% for resource in resources %}
- {{ resource.name }}
+
{% endif %}
+
+
+
+
diff --git a/src/oidc_test/templates/non_compliant_logout.html b/src/oidc_test/templates/non_compliant_logout.html
index 24a96ae..56758de 100644
--- a/src/oidc_test/templates/non_compliant_logout.html
+++ b/src/oidc_test/templates/non_compliant_logout.html
@@ -6,12 +6,12 @@
authorisation to log in again without asking for credentials.
- This is because {{ oidc_provider.name }} does not provide "end_session_endpoint" in its metadata - (see: {{ oidc_provider._server_metadata_url }}). + This is because {{ auth_provider.name }} does not provide "end_session_endpoint" in its metadata + (see: {{ auth_provider.authlib_client._server_metadata_url }}). You can just also go back to the application home page, but - it recommended to go to the OIDC provider's site + it recommended to go to the OIDC provider's site and log out explicitely from there. {% endblock %} From e56be3c378e10e4ac972a3901021226ed26c7c1f Mon Sep 17 00:00:00 2001 From: phil
-
{% endif %}
From 381ce1ebc175d899cca49de14b8b7b6a6b263866 Mon Sep 17 00:00:00 2001
From: phil - Resources validated by scope: - -
-
-
-
Resources validated by role:
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ {% if resource_providers %}
+ + Resource providers (validated by scope): + +
+ {% for name, resource_provider in resource_providers.items() %}
+ {% if resource_provider.default_resource_id %}
+
{% endif %}
From 0464047f8a6d17590f06fc7c52c4b1d4e007b2ce Mon Sep 17 00:00:00 2001
From: phil
- |
{{ provider.name }}
+ {{ provider.hint }}
|
@@ -62,42 +66,17 @@
{% endif %}
- - Resources validated by role: - -
-
-
{% if resource_providers %}
- Resource providers (validated by scope): + Resource providers:
{% for name, resource_provider in resource_providers.items() %}
- {% if resource_provider.default_resource_id %}
-
{% endif %}
From 5bd4b8280427d4a070a724cee141ee52ed3664a4 Mon Sep 17 00:00:00 2001
From: phil
{% if resource_providers %}
- Resource providers: + {{ auth_provider.name }} provides these resources:
{% for name, resource_provider in resource_providers.items() %}
{% if resource_provider.default_resource_id %}
-
From c89ca4098b2165014890af89caebde7310b88db0 Mon Sep 17 00:00:00 2001
From: phil
- {% if resource_providers %}
+
+ {% if resources %}
{{ auth_provider.name }} provides these resources:
- {% for name, resource_provider in resource_providers.items() %}
- {% if resource_provider.default_resource_id %}
-
{% endif %}
+ {% if resource_providers %}
+ {{ auth_provider.name }} can request resources from third party resource providers: + {% for resource_provider in resource_providers %} +
+ {{ resource_provider.name }}
+ {% for resource in resource_provider.resources %}
+
+ {% endfor %}
+ {% endif %}
From e925f2176258d4f73b5b7e565123652da02d6b12 Mon Sep 17 00:00:00 2001
From: phil - {{ auth_provider.name }} provides these resources: + This application provides all these resources, eventually protected with roles:
{% for name, resource in resources.items() %}
@@ -92,7 +92,7 @@
{% endif %}
{% if resource_providers %}
- {{ auth_provider.name }} can request resources from third party resource providers: +{{ auth_provider.name }} allows this applicaiton to request resources from third party resource providers: {% for resource_provider in resource_providers %}
{{ resource_provider.name }}
From ecdd3702f85c04e62741fa15910e25f425d5c20d Mon Sep 17 00:00:00 2001
From: phil - This application provides all these resources, eventually protected with roles: + This application provides all these resources, eventually protected with scope or roles:
{% for name, resource in resources.items() %}
From 347c3953943a1e0b7d84d5555727fae2f1d104be Mon Sep 17 00:00:00 2001
From: phil
-
{% if resources %}
- - This application provides all these resources, eventually protected with scope or roles: - +This application provides all these resources, eventually protected with scope or roles:
{% for name, resource in resources.items() %}
{% if resource.default_resource_id %}
@@ -91,8 +87,29 @@
{% endfor %}
{% endif %}
+ {% if auth_provider.resources %}
+ {{ auth_provider.name }} is also defined as a provider for these resources: +
+ {% for resource in auth_provider.resources %}
+ {% if resource.default_resource_id %}
+
+ {% endif %}
{% if resource_providers %}
- {{ auth_provider.name }} allows this applicaiton to request resources from third party resource providers: +{{ auth_provider.name }} allows this application to request resources from third party resource providers: {% for resource_provider in resource_providers %}
{{ resource_provider.name }}
From 4c2b197850a1e4e16f7b4d690eeb0ecd123422c5 Mon Sep 17 00:00:00 2001
From: phil v. {{ __version__}}
OIDC-test - FastAPI client{% block content %} {% endblock %} From b4653947660be16fbfee161fc4c52e2f4747f0f9 Mon Sep 17 00:00:00 2001 From: phil |