Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support a silent mode for JWTAuthMechanism #28505

Merged
merged 1 commit into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion extensions/smallrye-jwt/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jsonp-deployment</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt</artifactId>
Expand All @@ -51,6 +50,11 @@
<artifactId>quarkus-resteasy-reactive-jsonb-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-properties-file-deployment</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.quarkus.jwt.test;

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

import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class SilentModeUnitTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClass(DefaultGroupsEndpoint.class)
.addAsResource("publicKey.pem")
.addAsResource("applicationJwtFormAuth.properties", "application.properties"));

@Test
public void testFormChallengeWithoutAuthorizationHeader() {
RestAssured.given().redirects().follow(false)
.get("/endp/echo")
.then().assertThat().statusCode(302);
}

@Test
public void testJwtChallengeWithAuthorizationHeader() {
RestAssured.given().auth()
.oauth2("123")
.get("/endp/routingContext")
.then().assertThat().statusCode(401);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mp.jwt.verify.publickey.location=/publicKey.pem
mp.jwt.verify.issuer=https://server.example.com
quarkus.smallrye-jwt.enabled=true

quarkus.smallrye-jwt.silent=true

quarkus.http.auth.form.enabled=true
quarkus.http.auth.form.login-page=login
quarkus.http.auth.form.landing-page=landing
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.alice=alice
quarkus.security.users.embedded.roles.alice=admin
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public class JWTAuthMechanism implements HttpAuthenticationMechanism {

@Inject
private JWTAuthContextInfo authContextInfo;
private final boolean silent;

public JWTAuthMechanism(SmallRyeJwtConfig config) {
this.silent = config == null ? false : config.silent;
}

@Override
public Uni<SecurityIdentity> authenticate(RoutingContext context,
Expand All @@ -53,6 +58,14 @@ public Uni<SecurityIdentity> authenticate(RoutingContext context,

@Override
public Uni<ChallengeData> getChallenge(RoutingContext context) {
if (silent) {
//if this is silent we only send a challenge if the request contained auth headers
//otherwise we assume another method will send the challenge
String authHeader = context.request().headers().get(HttpHeaderNames.AUTHORIZATION);
if (authHeader == null) {
return Uni.createFrom().optional(Optional.empty());
}
}
ChallengeData result = new ChallengeData(
HttpResponseStatus.UNAUTHORIZED.code(),
HttpHeaderNames.WWW_AUTHENTICATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,19 @@ public class SmallRyeJwtConfig {
*/
@ConfigItem(defaultValue = "false")
public boolean blockingAuthentication;

/**
* Always create HTTP 401 challenge, even for requests containing no authentication credentials.
*
* JWT authentication mechanism will return HTTP 401 when an authentication challenge is required.
* However if it is used alongside one of the interactive authentication mechanisms then returning HTTP 401
* to the users accessing the application from a browser may not be desired.
*
* If you prefer you can request that JWT authentication mechanism does not create a challenge in such cases
* by setting this property to 'true'.
*
*/
@ConfigItem
public boolean silent;

}