gitshark

Clone repository

git clone https://gitshark.de/git/workaround/Gitshark.git
git clone git@gitshark.de:workaround/Gitshark.git

← Commits

๐Ÿ› (OIDC): Disable RP-Initiated Logout for kanidm, add local POST /logout

d3912ea8d201d3db56ca431b985397e79fb73ccf ยท Miggi ยท 2026-06-27T08:25:14Z

Changes

6 files changed, +79 -4

MODIFY README.md +1 -1
diff --git a/README.md b/README.md
index f128cbe..5888382 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
15 15 - Clone/fetch/push over `ssh://git@<host>:2222/<owner>/<repo>.git`
16 16 - public-key authentication only; keys managed per user in the UI
17 17 - Web UI: landing page with login CTA for visitors (`/`), repository list for authenticated users (`/`), public repository browse at `/explore`, file/tree browser, commit log (paginated), branches & tags
18 -- OIDC login (authorization code flow) via `GET /login`; users provisioned on first login
18 +- OIDC login (authorization code flow) via `GET /login`; users provisioned on first login. Logout is local-session only via `POST /logout` (the kanidm provider advertises no `end_session_endpoint`, so RP-Initiated Logout is disabled)
19 19 - Single access policy on all paths: owner read/write, public world-readable, private owner-only
20 20 - **Federation (ForgeFed / ActivityPub)** โ€” *opt-in, off by default.* Public repositories are
21 21 exposed as ForgeFed `Repository` actors that remote instances can follow and receive `Push`
ADD src/main/java/de/workaround/account/LogoutResource.java +31 -0
diff --git a/src/main/java/de/workaround/account/LogoutResource.java b/src/main/java/de/workaround/account/LogoutResource.java
new file mode 100644
index 0000000..29872f7
--- /dev/null
+++ b/src/main/java/de/workaround/account/LogoutResource.java
@@ -0,0 +1,31 @@
1 +package de.workaround.account;
2 +
3 +import java.net.URI;
4 +
5 +import io.quarkus.oidc.OidcSession;
6 +import io.smallrye.mutiny.Uni;
7 +import jakarta.inject.Inject;
8 +import jakarta.ws.rs.Consumes;
9 +import jakarta.ws.rs.POST;
10 +import jakarta.ws.rs.Path;
11 +import jakarta.ws.rs.core.MediaType;
12 +import jakarta.ws.rs.core.Response;
13 +
14 +/**
15 + * Local logout. kanidm advertises no end_session_endpoint, so Quarkus RP-Initiated Logout is disabled
16 + * (no quarkus.oidc.logout.path). This endpoint clears the local OIDC session cookie and redirects home,
17 + * which is the most logout the provider allows.
18 + */
19 +@Path("/logout")
20 +public class LogoutResource
21 +{
22 + @Inject
23 + OidcSession oidcSession;
24 +
25 + @POST
26 + @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
27 + public Uni<Response> logout()
28 + {
29 + return oidcSession.logout().replaceWith(Response.seeOther(URI.create("/")).build());
30 + }
31 +}
MODIFY src/main/resources/application.properties +3 -2
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 663b387..02df5eb 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -20,8 +20,9 @@
20 20 %dev,test.quarkus.oidc.client-id=quarkus-app
21 21 %dev,test.quarkus.oidc.credentials.secret=secret
22 22 quarkus.oidc.application-type=web-app
23 -quarkus.oidc.logout.path=/logout
24 -quarkus.oidc.logout.post-logout-path=/
23 +# No RP-Initiated Logout: kanidm does not advertise an end_session_endpoint, and setting
24 +# quarkus.oidc.logout.path makes Quarkus validate that endpoint at startup and abort boot when
25 +# it is missing. Logout is therefore local session only (handled by the app).
25 26
26 27 # PKCE: kanidm enforces PKCE for the authorization code flow. The code_verifier rides through the
27 28 # redirect inside the state cookie, which must be encrypted with a stable, explicitly-set secret so
MODIFY src/main/resources/templates/layout.html +1 -1
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html
index ba83ad0..5167798 100644
--- a/src/main/resources/templates/layout.html
+++ b/src/main/resources/templates/layout.html
@@ -18,7 +18,7 @@
18 18 {#insert nav}
19 19 <a href="/settings/keys">SSH keys</a>
20 20 <a href="/settings/tokens">Access tokens</a>
21 - <a href="/logout">Logout</a>
21 + <form class="logout" method="post" action="/logout"><button type="submit">Logout</button></form>
22 22 {/}
23 23 </nav>
24 24 </header>
ADD src/test/java/de/workaround/account/LogoutResourceTest.java +29 -0
diff --git a/src/test/java/de/workaround/account/LogoutResourceTest.java b/src/test/java/de/workaround/account/LogoutResourceTest.java
new file mode 100644
index 0000000..006a8a9
--- /dev/null
+++ b/src/test/java/de/workaround/account/LogoutResourceTest.java
@@ -0,0 +1,29 @@
1 +package de.workaround.account;
2 +
3 +import static io.restassured.RestAssured.given;
4 +import static org.hamcrest.Matchers.endsWith;
5 +import static org.hamcrest.Matchers.anyOf;
6 +import static org.hamcrest.Matchers.is;
7 +
8 +import org.junit.jupiter.api.Test;
9 +
10 +import io.quarkus.test.junit.QuarkusTest;
11 +
12 +/**
13 + * Local logout: kanidm advertises no end_session_endpoint, so Quarkus RP-Initiated Logout is disabled.
14 + * /logout must instead clear the local OIDC session and redirect home, so the template's Logout link works.
15 + */
16 +@QuarkusTest
17 +class LogoutResourceTest
18 +{
19 + @Test
20 + void logoutClearsSessionAndRedirectsHome()
21 + {
22 + given()
23 + .redirects().follow(false)
24 + .when().post("/logout")
25 + .then()
26 + .statusCode(anyOf(is(302), is(303)))
27 + .header("Location", endsWith("/"));
28 + }
29 +}
MODIFY src/test/java/de/workaround/account/OidcPkceConfigTest.java +14 -0
diff --git a/src/test/java/de/workaround/account/OidcPkceConfigTest.java b/src/test/java/de/workaround/account/OidcPkceConfigTest.java
index 987daf5..48ff7e9 100644
--- a/src/test/java/de/workaround/account/OidcPkceConfigTest.java
+++ b/src/test/java/de/workaround/account/OidcPkceConfigTest.java
@@ -29,4 +29,18 @@
29 29 .orElse("");
30 30 assertTrue(secret.length() >= 32, "state-secret must be >= 32 chars; was " + secret.length());
31 31 }
32 +
33 + /**
34 + * RP-Initiated Logout must NOT be configured: kanidm does not advertise an end_session_endpoint, and
35 + * when quarkus.oidc.logout.path is set Quarkus validates that endpoint at startup and aborts boot if
36 + * it is missing. Leaving logout.path unset keeps the app booting (local session logout only).
37 + */
38 + @Test
39 + void rpInitiatedLogoutIsNotConfigured() {
40 + String logoutPath = ConfigProvider.getConfig()
41 + .getOptionalValue("quarkus.oidc.logout.path", String.class)
42 + .orElse("");
43 + assertTrue(logoutPath.isEmpty(),
44 + "quarkus.oidc.logout.path must be unset (kanidm has no end_session_endpoint); was " + logoutPath);
45 + }
32 46 }

Keyboard shortcuts

?Show this help
g hGo home
EscClose dialog