Skip to content

Commit 955cc81

Browse files
committed
Merge pull request #15 from kimble/cookie-token
JWTAuthFilter will (if configured to do so) look through the cookies …
2 parents eb5f076 + 549a823 commit 955cc81

File tree

3 files changed

+115
-43
lines changed

3 files changed

+115
-43
lines changed

src/main/java/com/github/toastshaman/dropwizard/auth/jwt/JWTAuthFilter.java

Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
import javax.ws.rs.Priorities;
1616
import javax.ws.rs.WebApplicationException;
1717
import javax.ws.rs.container.ContainerRequestContext;
18+
import javax.ws.rs.core.Cookie;
1819
import javax.ws.rs.core.HttpHeaders;
20+
import javax.ws.rs.core.MultivaluedMap;
1921
import javax.ws.rs.core.SecurityContext;
2022
import java.io.IOException;
2123
import java.security.Principal;
24+
import java.util.Map;
2225

2326
@Priority(Priorities.AUTHENTICATION)
2427
public class JWTAuthFilter<P extends Principal> extends AuthFilter<JsonWebToken, P> {
@@ -27,62 +30,114 @@ public class JWTAuthFilter<P extends Principal> extends AuthFilter<JsonWebToken,
2730

2831
private final JsonWebTokenVerifier tokenVerifier;
2932
private final JsonWebTokenParser tokenParser;
33+
private final String cookieName;
3034

31-
private JWTAuthFilter(JsonWebTokenParser tokenParser, JsonWebTokenVerifier tokenVerifier) {
35+
private JWTAuthFilter(JsonWebTokenParser tokenParser, JsonWebTokenVerifier tokenVerifier, String cookieName) {
3236
this.tokenParser = tokenParser;
3337
this.tokenVerifier = tokenVerifier;
38+
this.cookieName = cookieName;
3439
}
3540

3641
@Override
3742
public void filter(final ContainerRequestContext requestContext) throws IOException {
38-
final String header = requestContext.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
43+
Optional<String> optionalToken = getTokenFromCookieOrHeader(requestContext);
44+
45+
if (optionalToken.isPresent()) {
46+
try {
47+
final JsonWebToken token = verifiedToken(optionalToken);
48+
final Optional<P> principal = authenticator.authenticate(token);
49+
50+
if (principal.isPresent()) {
51+
requestContext.setSecurityContext(new SecurityContext() {
52+
53+
@Override
54+
public Principal getUserPrincipal() {
55+
return principal.get();
56+
}
57+
58+
@Override
59+
public boolean isUserInRole(String role) {
60+
return authorizer.authorize(principal.get(), role);
61+
}
62+
63+
@Override
64+
public boolean isSecure() {
65+
return requestContext.getSecurityContext().isSecure();
66+
}
67+
68+
@Override
69+
public String getAuthenticationScheme() {
70+
return SecurityContext.BASIC_AUTH;
71+
}
72+
73+
});
74+
return;
75+
}
76+
}
77+
catch (JsonWebTokenException ex) {
78+
LOGGER.warn("Error decoding credentials: " + ex.getMessage(), ex);
79+
}
80+
catch (AuthenticationException ex) {
81+
LOGGER.warn("Error authenticating credentials", ex);
82+
throw new InternalServerErrorException();
83+
}
84+
}
85+
86+
throw new WebApplicationException(unauthorizedHandler.buildResponse(prefix, realm));
87+
}
88+
89+
private JsonWebToken verifiedToken(Optional<String> optionalToken) {
90+
final String rawToken = optionalToken.get();
91+
final JsonWebToken token = tokenParser.parse(rawToken);
92+
tokenVerifier.verifySignature(token);
93+
return token;
94+
}
95+
96+
public Optional<String> getTokenFromCookieOrHeader(ContainerRequestContext requestContext) {
97+
Optional<String> headerToken = getTokenFromHeader(requestContext.getHeaders());
98+
99+
if (headerToken.isPresent()) {
100+
return headerToken;
101+
}
102+
else {
103+
Optional<String> cookieToken = getTokenFromCookie(requestContext);
104+
105+
if (cookieToken.isPresent()) {
106+
return cookieToken;
107+
}
108+
else {
109+
return Optional.absent();
110+
}
111+
}
112+
}
113+
114+
private Optional<String> getTokenFromHeader(MultivaluedMap<String, String> headers) {
115+
String header = headers.getFirst(HttpHeaders.AUTHORIZATION);
39116
if (header != null) {
40-
final int space = header.indexOf(' ');
117+
int space = header.indexOf(' ');
41118
if (space > 0) {
42-
final String method = header.substring(0, space);
119+
String method = header.substring(0, space);
43120
if (prefix.equalsIgnoreCase(method)) {
44-
try {
45-
final String rawToken = header.substring(space + 1);
46-
final JsonWebToken token = tokenParser.parse(rawToken);
47-
48-
tokenVerifier.verifySignature(token);
49-
50-
final Optional<P> principal = authenticator.authenticate(token);
51-
if (principal.isPresent()) {
52-
requestContext.setSecurityContext(new SecurityContext() {
53-
@Override
54-
public Principal getUserPrincipal() {
55-
return principal.get();
56-
}
57-
58-
@Override
59-
public boolean isUserInRole(String role) {
60-
return authorizer.authorize(principal.get(), role);
61-
}
62-
63-
@Override
64-
public boolean isSecure() {
65-
return requestContext.getSecurityContext().isSecure();
66-
}
67-
68-
@Override
69-
public String getAuthenticationScheme() {
70-
return SecurityContext.BASIC_AUTH;
71-
}
72-
});
73-
return;
74-
}
75-
} catch (JsonWebTokenException e) {
76-
LOGGER.warn("Error decoding credentials: " + e.getMessage(), e);
77-
} catch (AuthenticationException e) {
78-
LOGGER.warn("Error authenticating credentials", e);
79-
throw new InternalServerErrorException();
80-
}
121+
String rawToken = header.substring(space + 1);
122+
return Optional.of(rawToken);
81123
}
82124
}
83125
}
84126

85-
throw new WebApplicationException(unauthorizedHandler.buildResponse(prefix, realm));
127+
return Optional.absent();
128+
}
129+
130+
public Optional<String> getTokenFromCookie(ContainerRequestContext requestContext) {
131+
Map<String, Cookie> cookies = requestContext.getCookies();
132+
133+
if (cookieName != null && cookies.containsKey(cookieName)) {
134+
Cookie tokenCookie = cookies.get(cookieName);
135+
String rawToken = tokenCookie.getValue();
136+
137+
return Optional.of(rawToken);
138+
}
139+
140+
return Optional.absent();
86141
}
87142

88143
/**
@@ -95,6 +150,7 @@ public static class Builder<P extends Principal> extends AuthFilterBuilder<JsonW
95150

96151
private JsonWebTokenParser parser;
97152
private JsonWebTokenVerifier verifier;
153+
private String cookieName;
98154

99155
public Builder<P> setTokenParser(JsonWebTokenParser parser) {
100156
this.parser = parser;
@@ -106,11 +162,17 @@ public Builder<P> setTokenVerifier(JsonWebTokenVerifier verifier) {
106162
return this;
107163
}
108164

165+
public Builder<P> setCookieName(String cookieName) {
166+
this.cookieName = cookieName;
167+
return this;
168+
}
169+
109170
@Override
110171
protected JWTAuthFilter<P> newInstance() {
111172
Preconditions.checkArgument(parser != null, "JsonWebTokenParser is not set");
112173
Preconditions.checkArgument(verifier != null, "JsonWebTokenVerifier is not set");
113-
return new JWTAuthFilter<>(parser, verifier);
174+
return new JWTAuthFilter<>(parser, verifier, cookieName);
114175
}
115176
}
177+
116178
}

src/test/java/com/github/toastshaman/dropwizard/auth/jwt/AuthBaseTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public abstract class AuthBaseTest<T extends DropwizardResourceConfig> extends J
2525
protected static final String ORDINARY_USER = "ordinary-guy";
2626
protected static final String BADGUY_USER = "bad-guy";
2727
protected static final String BEARER_PREFIX = "Bearer";
28+
protected static final String COOKIE_NAME = "jwt-token";
2829

2930
static {
3031
BootstrapLogging.bootstrap();
@@ -137,6 +138,14 @@ public void transformsCredentialsToPrincipals() throws Exception {
137138
.isEqualTo("'" + ADMIN_USER + "' has admin privileges");
138139
}
139140

141+
@Test
142+
public void transformsCredentialsToPrincipalsWithCookie() throws Exception {
143+
assertThat(target("/test/admin").request()
144+
.cookie(COOKIE_NAME, getGoodGuyValidToken())
145+
.get(String.class))
146+
.isEqualTo("'" + ADMIN_USER + "' has admin privileges");
147+
}
148+
140149
@Test
141150
public void transformsCredentialsToPrincipalsWhenAuthAnnotationExistsWithoutMethodAnnotation() throws Exception {
142151
assertThat(target("/test/implicit-permitall").request()

src/test/java/com/github/toastshaman/dropwizard/auth/jwt/JWTAuthProviderTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class JWTAuthProviderTest extends AuthBaseTest<JWTAuthProviderTest.JWTAut
2626
public static class JWTAuthTestResourceConfig extends AuthBaseResourceConfig {
2727
protected ContainerRequestFilter getAuthFilter() {
2828
return new JWTAuthFilter.Builder<>()
29+
.setCookieName(COOKIE_NAME)
2930
.setTokenParser(new DefaultJsonWebTokenParser())
3031
.setTokenVerifier(new HmacSHA512Verifier(SECRET_KEY))
3132
.setPrefix(BEARER_PREFIX)

0 commit comments

Comments
 (0)