Skip to content

Commit

Permalink
OIDC id token authentication and access token refreshing
Browse files Browse the repository at this point in the history
Signed-off-by: David Kral <[email protected]>
  • Loading branch information
Verdent committed Dec 15, 2023
1 parent e19d535 commit 1cb4581
Show file tree
Hide file tree
Showing 12 changed files with 785 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import io.helidon.security.integration.common.SecurityTracing;
import io.helidon.security.internal.SecurityAuditEvent;
import io.helidon.security.providers.common.spi.AnnotationAnalyzer;
import io.helidon.webserver.security.SecurityHttpFeature;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Priority;
Expand All @@ -56,6 +57,7 @@
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.Response;
import org.glassfish.jersey.server.ExtendedUriInfo;
import org.glassfish.jersey.server.model.AbstractResourceModelVisitor;
Expand Down Expand Up @@ -182,6 +184,16 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont
} else {
return;
}
io.helidon.common.context.Context helidonContext = Contexts.context()
.orElseThrow(() -> new IllegalStateException("Context must be available in Jersey"));
helidonContext.get(SecurityHttpFeature.CONTEXT_RESPONSE_HEADERS, Map.class)
.map(it -> (Map<String, List<String>>) it)
.ifPresent(it -> {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
for (Map.Entry<String, List<String>> entry : it.entrySet()) {
entry.getValue().forEach(value -> headers.add(entry.getKey(), value));
}
});

SecurityFilterContext fc = (SecurityFilterContext) requestContext.getProperty(PROP_FILTER_CONTEXT);
SecurityDefinition methodSecurity = jerseySecurityContext.methodSecurity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import io.helidon.common.HelidonServiceLoader;
import io.helidon.common.config.Config;
import io.helidon.common.context.Contexts;
import io.helidon.common.uri.UriQuery;
import io.helidon.microprofile.security.spi.SecurityResponseMapper;
import io.helidon.security.AuthenticationResponse;
Expand All @@ -37,6 +38,7 @@
import io.helidon.security.integration.common.AtnTracing;
import io.helidon.security.integration.common.AtzTracing;
import io.helidon.security.integration.common.SecurityTracing;
import io.helidon.webserver.security.SecurityHttpFeature;

import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.container.ContainerRequestContext;
Expand Down Expand Up @@ -198,6 +200,9 @@ protected void processAuthentication(SecurityFilterContext context,
switch (responseStatus) {
case SUCCESS -> {
//everything is fine, we can continue with processing
io.helidon.common.context.Context helidonContext = Contexts.context()
.orElseThrow(() -> new IllegalStateException("Context must be available in Jersey"));
helidonContext.register(SecurityHttpFeature.CONTEXT_RESPONSE_HEADERS, response.responseHeaders());
}
case FAILURE_FINISH -> {
if (methodSecurity.authenticationOptional()) {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ public final class OidcFeature implements HttpFeature {
private final OidcConfig oidcConfig;
private final OidcCookieHandler tokenCookieHandler;
private final OidcCookieHandler idTokenCookieHandler;
private final OidcCookieHandler refreshTokenCookieHandler;
private final OidcCookieHandler tenantCookieHandler;
private final boolean enabled;
private final CorsSupport corsSupport;
Expand All @@ -160,6 +161,7 @@ private OidcFeature(Builder builder) {
this.enabled = builder.enabled;
this.tokenCookieHandler = oidcConfig.tokenCookieHandler();
this.idTokenCookieHandler = oidcConfig.idTokenCookieHandler();
this.refreshTokenCookieHandler = oidcConfig.refreshTokenCookieHandler();
this.tenantCookieHandler = oidcConfig.tenantCookieHandler();
this.corsSupport = prepareCrossOriginSupport(oidcConfig.redirectUri(), oidcConfig.crossOriginConfig());
this.oidcConfigFinders = List.copyOf(builder.tenantConfigFinders);
Expand Down Expand Up @@ -321,6 +323,7 @@ private void logoutWithTenant(ServerRequest req, ServerResponse res, Tenant tena
headers.addCookie(tokenCookieHandler.removeCookie().build());
headers.addCookie(idTokenCookieHandler.removeCookie().build());
headers.addCookie(tenantCookieHandler.removeCookie().build());
headers.addCookie(refreshTokenCookieHandler.removeCookie().build());

res.status(Status.TEMPORARY_REDIRECT_307)
.header(HeaderNames.LOCATION, sb.toString())
Expand Down Expand Up @@ -450,14 +453,18 @@ private String processJsonResponse(ServerRequest req,
ServerResponse res,
JsonObject json,
String tenantName) {
String tokenValue = json.getString("access_token");
String accessToken = json.getString("access_token");
String idToken = json.getString("id_token", null);
String refreshToken = json.getString("refresh_token", null);

//redirect to "state"
String state = req.query().first(STATE_PARAM_NAME).orElse(DEFAULT_REDIRECT);
res.status(Status.TEMPORARY_REDIRECT_307);
if (oidcConfig.useParam()) {
state += (state.contains("?") ? "&" : "?") + oidcConfig.paramName() + "=" + tokenValue;
state += (state.contains("?") ? "&" : "?") + encode(oidcConfig.paramName()) + "=" + accessToken;
if (idToken != null) {
state += "&" + encode(oidcConfig.idTokenParamName()) + "=" + idToken;
}
if (!DEFAULT_TENANT_ID.equals(tenantName)) {
state += "&" + encode(oidcConfig.tenantParamName()) + "=" + encode(tenantName);
}
Expand All @@ -473,9 +480,10 @@ private String processJsonResponse(ServerRequest req,
OidcCookieHandler tenantCookieHandler = oidcConfig.tenantCookieHandler();

headers.addCookie(tenantCookieHandler.createCookie(tenantName).build()); //Add tenant name cookie
headers.addCookie(tokenCookieHandler.createCookie(tokenValue).build()); //Add token cookie
headers.addCookie(tokenCookieHandler.createCookie(accessToken).build()); //Add token cookie
headers.addCookie(refreshTokenCookieHandler.createCookie(refreshToken).build()); //Add refresh token cookie

if (idToken != null && oidcConfig.logoutEnabled()) {
if (idToken != null) {
headers.addCookie(idTokenCookieHandler.createCookie(idToken).build()); //Add token id cookie
}
res.send();
Expand Down
Loading

0 comments on commit 1cb4581

Please sign in to comment.