Skip to content

Commit

Permalink
Merge pull request #39718 from sberyozkin/oidc_code_flow_access_token…
Browse files Browse the repository at this point in the history
…_for_custom_packages

Enforce OIDC code flow access token verification only if JWT is in the application code
  • Loading branch information
sberyozkin authored Mar 27, 2024
2 parents c23eba2 + 5f60a6d commit 01d1c63
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 01d1c63

Please sign in to comment.