Skip to content

Commit

Permalink
Enforce OIDC code flow access token verification only if JWT is in th…
Browse files Browse the repository at this point in the history
…e application code
  • Loading branch information
sberyozkin committed Mar 26, 2024
1 parent 5ceb6a0 commit 5f60a6d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public class OidcBuildStep {
private static final DotName JSON_WEB_TOKEN_NAME = DotName.createSimple(JsonWebToken.class);
private static final DotName ID_TOKEN_NAME = DotName.createSimple(IdToken.class);

private static final String QUARKUS_TOKEN_PROPAGATION_PACKAGE = "io.quarkus.oidc.token.propagation";
private static final String SMALLRYE_JWT_PACKAGE = "io.smallrye.jwt";

@BuildStep
public void provideSecurityInformation(BuildProducer<SecurityInformationBuildItem> securityInformationProducer) {
// TODO: By default quarkus.oidc.application-type = service
Expand Down Expand Up @@ -323,13 +326,21 @@ private static boolean isInjected(BeanRegistrationPhaseBuildItem beanRegistratio
DotName withoutQualifier) {
for (InjectionPointInfo injectionPoint : beanRegistrationPhaseBuildItem.getInjectionPoints()) {
if (requiredType.equals(injectionPoint.getRequiredType().name())
&& isApplicationPackage(injectionPoint.getTargetInfo())
&& (withoutQualifier == null || injectionPoint.getRequiredQualifier(withoutQualifier) == null)) {
LOG.debugf("%s injection point: %s", requiredType.toString(), injectionPoint.getTargetInfo());
return true;
}
}
return false;
}

private static boolean isApplicationPackage(String injectionPointTargetInfo) {
return injectionPointTargetInfo != null
&& !injectionPointTargetInfo.startsWith(QUARKUS_TOKEN_PROPAGATION_PACKAGE)
&& !injectionPointTargetInfo.startsWith(SMALLRYE_JWT_PACKAGE);
}

private static String toTargetName(AnnotationTarget target) {
if (target.kind() == CLASS) {
return target.asClass().name().toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.quarkus.oidc.test;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.keycloak.server.KeycloakTestResourceLifecycleManager;

@QuarkusTestResource(KeycloakTestResourceLifecycleManager.class)
public class CodeFlowVerifyAccessTokenDisabled {

@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(ProtectedResourceWithoutJwtAccessToken.class)
.addAsResource("application-verify-access-token-disabled.properties", "application.properties"));

@Test
public void testVerifyAccessTokenDisabled() throws IOException, InterruptedException {
try (final WebClient webClient = createWebClient()) {

HtmlPage page = webClient.getPage("http://localhost:8081/protected");

assertEquals("Sign in to quarkus", page.getTitleText());

HtmlForm loginForm = page.getForms().get(0);

loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");

page = loginForm.getInputByName("login").click();

assertEquals("alice:false", page.getBody().asNormalizedText());

webClient.getCookieManager().clearCookies();
}
}

private WebClient createWebClient() {
WebClient webClient = new WebClient();
webClient.setCssErrorHandler(new SilentCssErrorHandler());
return webClient;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.quarkus.oidc.test;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.runtime.OidcConfig;
import io.quarkus.security.Authenticated;

@Path("/protected")
@Authenticated
public class ProtectedResourceWithoutJwtAccessToken {

@Inject
@IdToken
JsonWebToken idToken;

@Inject
OidcConfig config;

@GET
public String getName() {
return idToken.getName() + ":" + config.defaultTenant.authentication.verifyAccessToken;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
quarkus.oidc.auth-server-url=${keycloak.url}/realms/quarkus
quarkus.oidc.client-id=quarkus-web-app
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app

0 comments on commit 5f60a6d

Please sign in to comment.