P get() { 18 | return (P)THREAD_LOCAL.get(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/DefaultJwtCookiePrincipal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2023 Dhatim 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import com.fasterxml.jackson.annotation.JsonProperty;
19 | import io.jsonwebtoken.Claims;
20 | import io.jsonwebtoken.ClaimsBuilder;
21 | import io.jsonwebtoken.Jwts;
22 |
23 | import java.util.Collection;
24 | import java.util.Collections;
25 | import java.util.Optional;
26 |
27 | /**
28 | * Default implementation of JwtCookiePrincipal
29 | */
30 | public class DefaultJwtCookiePrincipal implements JwtCookiePrincipal {
31 |
32 | private final static String PERSISTENT = "pst"; // long-term token == rememberme
33 | private final static String ROLES = "rls";
34 |
35 | protected final ClaimsBuilder claimsBuilder;
36 |
37 | /**
38 | * Builds a new instance of DefaultJwtCookiePrincipal
39 | *
40 | * @param name the principal name
41 | * @param persistent if the cookie must be persistent
42 | * @param roles the roles the principal is in
43 | * @param claims custom data associated with the principal
44 | */
45 | public DefaultJwtCookiePrincipal(
46 | @JsonProperty("name") String name,
47 | @JsonProperty("persistent") boolean persistent,
48 | @JsonProperty("roles") Collection
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import jakarta.ws.rs.NameBinding;
19 |
20 | import java.lang.annotation.ElementType;
21 | import java.lang.annotation.Retention;
22 | import java.lang.annotation.RetentionPolicy;
23 | import java.lang.annotation.Target;
24 |
25 | /**
26 | * An annotation that can be used to avoid reseting the session TTL when an API is called
27 | */
28 | @NameBinding
29 | @Retention(RetentionPolicy.RUNTIME)
30 | @Target({ElementType.METHOD, ElementType.TYPE})
31 | public @interface DontRefreshSession {
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/DontRefreshSessionFilter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import jakarta.ws.rs.container.ContainerRequestContext;
19 | import jakarta.ws.rs.container.ContainerRequestFilter;
20 |
21 | import java.io.IOException;
22 |
23 | @DontRefreshSession
24 | public class DontRefreshSessionFilter implements ContainerRequestFilter {
25 |
26 | public static String DONT_REFRESH_SESSION_PROPERTY = "dontRefreshSession";
27 |
28 | @Override
29 | public void filter(ContainerRequestContext requestContext) throws IOException {
30 | requestContext.setProperty(DONT_REFRESH_SESSION_PROPERTY, Boolean.TRUE);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookieAuthBundle.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import com.fasterxml.jackson.databind.module.SimpleModule;
19 | import com.google.common.hash.Hashing;
20 | import com.google.common.primitives.Ints;
21 | import io.dropwizard.auth.*;
22 | import io.dropwizard.core.Configuration;
23 | import io.dropwizard.core.ConfiguredBundle;
24 | import io.dropwizard.core.setup.Bootstrap;
25 | import io.dropwizard.core.setup.Environment;
26 | import io.dropwizard.jersey.setup.JerseyEnvironment;
27 | import io.jsonwebtoken.Claims;
28 | import io.jsonwebtoken.SignatureAlgorithm;
29 | import io.jsonwebtoken.impl.DefaultClaims;
30 | import jakarta.ws.rs.container.ContainerResponseFilter;
31 | import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
32 |
33 | import javax.crypto.KeyGenerator;
34 | import javax.crypto.SecretKey;
35 | import javax.crypto.spec.SecretKeySpec;
36 | import java.nio.charset.StandardCharsets;
37 | import java.security.NoSuchAlgorithmException;
38 | import java.time.Duration;
39 | import java.util.Optional;
40 | import java.util.function.BiFunction;
41 | import java.util.function.Function;
42 |
43 | /**
44 | * Dopwizard bundle
45 | *
46 | * @param the class of the principal that will be serialized in / deserialized from JWT cookies
48 | */
49 | public class JwtCookieAuthBundle principalType;
55 | private final Function serializer;
56 | private final Function principalType, Function serializer, Function ) (principal, role, requestContext) -> principal.isInRole(role))
160 | .setUnauthorizedHandler(unauthorizedHandler)
161 | .buildAuthFilter();
162 | }
163 |
164 | /**
165 | * Get a filter that will deserialize the principal from JWT cookies found in HTTP requests,
166 | * using the default cookie name.
167 | *
168 | * @param key the key used to validate the JWT
169 | * @return the request filter
170 | */
171 | public AuthFilter
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import jakarta.annotation.Nullable;
19 | import jakarta.validation.constraints.NotEmpty;
20 |
21 | import static org.dhatim.dropwizard.jwt.cookie.authentication.JwtCookieAuthBundle.JWT_COOKIE_DEFAULT_NAME;
22 |
23 | /**
24 | * Bundle configuration class
25 | */
26 | public class JwtCookieAuthConfiguration {
27 |
28 | private String secretSeed;
29 |
30 | private String cookieName = JWT_COOKIE_DEFAULT_NAME;
31 |
32 | private boolean secure = false;
33 |
34 | private boolean httpOnly = true;
35 |
36 | @Nullable
37 | private SameSite sameSite = null;
38 |
39 | @Nullable
40 | private String domain = null;
41 |
42 | @NotEmpty
43 | private String sessionExpiryVolatile = "PT30m";
44 |
45 | @NotEmpty
46 | private String sessionExpiryPersistent = "P7d";
47 |
48 | /**
49 | * The secret seed use to generate the signing key.
50 | * It can be used to keep the same key value across application reboots.
51 | *
52 | * @return the signing key seed
53 | */
54 | public String getSecretSeed() {
55 | return secretSeed;
56 | }
57 |
58 | /**
59 | * The name of the cookie holding the JWT. Its default value is "sessionToken".
60 | *
61 | * @return the cookie name
62 | */
63 | public String getCookieName() {
64 | return cookieName;
65 | }
66 |
67 | /**
68 | * Check if the {@code Secure} cookie attribute is set, as described here.
69 | *
70 | * @return {@code true} if the {@code Secure} cookie attribute is set.
71 | */
72 | public boolean isSecure() {
73 | return secure;
74 | }
75 |
76 | /**
77 | * Check if the {@code HttpOnly} cookie attribute is set, as described here.
78 | *
79 | * @return {@code true} if the {@code HttpOnly} cookie attribute is set.
80 | */
81 | public boolean isHttpOnly() {
82 | return httpOnly;
83 | }
84 |
85 | /**
86 | * Duration of cookie, if volatile (in ISO 8601 format).
87 | *
88 | * @return the duration of a volatile cookie.
89 | */
90 | public String getSessionExpiryVolatile() {
91 | return sessionExpiryVolatile;
92 | }
93 |
94 | /**
95 | * Duration of cookie, if persistent (in ISO 8601 format).
96 | *
97 | * @return the duration of a persistent cookie.
98 | */
99 | public String getSessionExpiryPersistent() {
100 | return sessionExpiryPersistent;
101 | }
102 |
103 | /**
104 | * {@code SameSite} cookie attribute value, as described here.
105 | *
106 | * @return {@code SameSite} cookie attribute value, or {@code null} if not set
107 | */
108 | public SameSite getSameSite() {
109 | return sameSite;
110 | }
111 |
112 | /**
113 | * {@code Domain} cookie attribute value, as described here.
114 | *
115 | * @return {@code Domain} cookie attribute value, or {@code null} if not set
116 | */
117 | public String getDomain() {
118 | return domain;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookieAuthRequestFilter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import io.dropwizard.auth.AuthFilter;
19 | import io.dropwizard.auth.AuthenticationException;
20 | import jakarta.annotation.Priority;
21 | import jakarta.ws.rs.InternalServerErrorException;
22 | import jakarta.ws.rs.Priorities;
23 | import jakarta.ws.rs.container.ContainerRequestContext;
24 | import jakarta.ws.rs.core.Cookie;
25 |
26 | import java.io.IOException;
27 | import java.util.Objects;
28 | import java.util.Optional;
29 |
30 | @Priority(Priorities.AUTHENTICATION)
31 | class JwtCookieAuthRequestFilter extends AuthFilter subject = authenticator.authenticate(accessToken);
47 | if (subject.isPresent()) {
48 | CurrentPrincipal.set(subject.get());
49 | crc.setSecurityContext(new JwtCookieSecurityContext(subject.get(), crc.getSecurityContext().isSecure()));
50 | return;
51 | }
52 | } catch (AuthenticationException e) {
53 | throw new InternalServerErrorException(e);
54 | }
55 | }
56 | }
57 | throw unauthorizedHandler.buildException(prefix, realm);
58 | }
59 |
60 | public static class Builder extends AuthFilterBuilder newInstance() {
71 | return new JwtCookieAuthRequestFilter(Objects.requireNonNull(cookieName, "cookieName is not set"));
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookieAuthResponseFilter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import io.jsonwebtoken.Claims;
19 | import io.jsonwebtoken.Jwts;
20 | import io.jsonwebtoken.SignatureAlgorithm;
21 | import jakarta.ws.rs.container.ContainerRequestContext;
22 | import jakarta.ws.rs.container.ContainerResponseContext;
23 | import jakarta.ws.rs.container.ContainerResponseFilter;
24 |
25 | import java.io.IOException;
26 | import java.security.Key;
27 | import java.security.Principal;
28 | import java.time.Instant;
29 | import java.time.temporal.ChronoUnit;
30 | import java.util.Date;
31 | import java.util.function.Function;
32 |
33 | class JwtCookieAuthResponseFilter implements ContainerResponseFilter {
34 |
35 | private static final String COOKIE_TEMPLATE = "=%s; Path=/";
36 | private static final String SECURE_FLAG = "; Secure";
37 | private static final String HTTP_ONLY_FLAG = "; HttpOnly";
38 | private static final String DOMAIN_FLAG = "; Domain=";
39 | private static final String SAME_SITE_FLAG = "; SameSite=";
40 | private static final String DELETE_COOKIE_TEMPLATE = "=; Path=/; expires=Thu, 01-Jan-70 00:00:00 GMT";
41 |
42 | private final Class principalType;
43 | private final Function serializer;
44 | private final String cookieName;
45 | private final String sessionCookieFormat;
46 | private final String persistentCookieFormat;
47 | private final String deleteCookie;
48 |
49 | private final Key signingKey;
50 | private final int volatileSessionDuration; //in seconds
51 | private final int persistentSessionDuration;
52 |
53 | public JwtCookieAuthResponseFilter(
54 | Class principalType,
55 | Function serializer,
56 | String cookieName,
57 | boolean secure,
58 | boolean httpOnly,
59 | String domain,
60 | SameSite sameSite,
61 | Key signingKey,
62 | int volatileSessionDuration,
63 | int persistentSessionDuration) {
64 |
65 | this.principalType = principalType;
66 | this.serializer = serializer;
67 | this.cookieName = cookieName;
68 | StringBuilder cookieFormatBuilder = new StringBuilder(cookieName).append(COOKIE_TEMPLATE);
69 | if (secure) {
70 | cookieFormatBuilder.append(SECURE_FLAG);
71 | }
72 | if (httpOnly) {
73 | cookieFormatBuilder.append(HTTP_ONLY_FLAG);
74 | }
75 | if (domain != null) {
76 | cookieFormatBuilder.append(DOMAIN_FLAG).append(domain);
77 | }
78 | if (sameSite != null) {
79 | cookieFormatBuilder.append(SAME_SITE_FLAG).append(sameSite.value);
80 | }
81 | this.sessionCookieFormat = cookieFormatBuilder.toString();
82 | this.persistentCookieFormat = sessionCookieFormat + "; Max-Age=%d;";
83 | StringBuilder deleteCookieBuilder = new StringBuilder(cookieName).append(DELETE_COOKIE_TEMPLATE);
84 | if (domain != null) {
85 | deleteCookieBuilder.append(DOMAIN_FLAG).append(domain);
86 | }
87 | this.deleteCookie = deleteCookieBuilder.toString();
88 | this.signingKey = signingKey;
89 | this.volatileSessionDuration = volatileSessionDuration;
90 | this.persistentSessionDuration = persistentSessionDuration;
91 | }
92 |
93 | @Override
94 | public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
95 | Principal principal = request.getSecurityContext().getUserPrincipal();
96 | if (request.getSecurityContext() instanceof JwtCookieSecurityContext) {
97 | if (principalType.isInstance(principal)) {
98 | if (request.getProperty(DontRefreshSessionFilter.DONT_REFRESH_SESSION_PROPERTY) != Boolean.TRUE) {
99 | P cookiePrincipal = (P) principal;
100 | String cookie = cookiePrincipal.isPersistent()
101 | ? String.format(persistentCookieFormat, getJwt(cookiePrincipal, persistentSessionDuration), persistentSessionDuration)
102 | : String.format(sessionCookieFormat, getJwt(cookiePrincipal, volatileSessionDuration));
103 |
104 | response.getHeaders().add("Set-Cookie", cookie);
105 | CurrentPrincipal.remove();
106 | }
107 | } else if (request.getCookies().containsKey(cookieName)) {
108 | //the principal has been unset during the response, delete the cookie
109 | response.getHeaders().add("Set-Cookie", deleteCookie);
110 | }
111 | }
112 | }
113 |
114 | private String getJwt(P subject, int expiresIn) {
115 | return Jwts.builder()
116 | .signWith(signingKey, SignatureAlgorithm.HS256)
117 | .setClaims(serializer.apply(subject))
118 | .setExpiration(Date.from(Instant.now().plus(expiresIn, ChronoUnit.SECONDS)))
119 | .compact();
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookiePrincipal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 Dhatim.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import jakarta.ws.rs.container.ContainerRequestContext;
19 |
20 | import java.security.Principal;
21 |
22 | /**
23 | * A principal persisted in JWT cookies
24 | */
25 | public interface JwtCookiePrincipal extends Principal {
26 |
27 | /**
28 | * Indicates if the cookie will be persistent (aka 'remember me')
29 | *
30 | * @return if the cookie must be persistent
31 | */
32 | boolean isPersistent();
33 |
34 | /**
35 | * Indicates if this principal has the given role
36 | *
37 | * @param role the role
38 | * @return true if the principal is in the given role, false otherwise
39 | */
40 | boolean isInRole(String role);
41 |
42 | /**
43 | * Add this principal in the request context.
44 | * It will serialized in a JWT cookie and can be reused in subsequent queries
45 | *
46 | * @param context the request context
47 | */
48 | default void addInContext(ContainerRequestContext context) {
49 | context.setSecurityContext(new JwtCookieSecurityContext(this, context.getSecurityContext().isSecure()));
50 | }
51 |
52 | public static void removeFromContext(ContainerRequestContext context) {
53 | context.setSecurityContext(new JwtCookieSecurityContext(null, context.getSecurityContext().isSecure()));
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookiePrincipalAuthenticator.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import io.dropwizard.auth.AuthenticationException;
19 | import io.dropwizard.auth.Authenticator;
20 | import io.jsonwebtoken.Claims;
21 | import io.jsonwebtoken.ExpiredJwtException;
22 | import io.jsonwebtoken.Jwts;
23 | import io.jsonwebtoken.security.SecurityException;
24 |
25 | import javax.crypto.SecretKey;
26 | import java.util.Optional;
27 | import java.util.function.Function;
28 |
29 | class JwtCookiePrincipalAuthenticator implements Authenticator authenticate(String credentials) throws AuthenticationException {
41 | try {
42 | return Optional.of(deserializer.apply(Jwts.parser().verifyWith(key).build().parseClaimsJws(credentials).getBody()));
43 | } catch (ExpiredJwtException | SecurityException e) {
44 | return Optional.empty();
45 | }
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookieSecurityContext.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import jakarta.ws.rs.core.SecurityContext;
19 |
20 | import java.security.Principal;
21 | import java.util.Optional;
22 |
23 | /**
24 | * Security context set after a JWT cookie authentication
25 | */
26 | class JwtCookieSecurityContext implements SecurityContext {
27 |
28 | private final JwtCookiePrincipal subject;
29 | private final boolean secure;
30 |
31 | public JwtCookieSecurityContext(JwtCookiePrincipal subject, boolean secure) {
32 | this.subject = subject;
33 | this.secure = secure;
34 | }
35 |
36 | @Override
37 | public Principal getUserPrincipal() {
38 | return subject;
39 | }
40 |
41 | @Override
42 | public boolean isUserInRole(String role) {
43 | return Optional.ofNullable(subject)
44 | .map(s -> s.isInRole(role))
45 | .orElse(false);
46 | }
47 |
48 | @Override
49 | public boolean isSecure() {
50 | return secure;
51 | }
52 |
53 | @Override
54 | public String getAuthenticationScheme() {
55 | return "JWT_COOKIE";
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/dhatim/dropwizard/jwt/cookie/authentication/SameSite.java:
--------------------------------------------------------------------------------
1 | package org.dhatim.dropwizard.jwt.cookie.authentication;
2 |
3 | public enum SameSite {
4 |
5 | NONE("None"), LAX("Lax"), STRICT("Strict");
6 |
7 | public final String value;
8 |
9 | SameSite(String value) {
10 | this.value = value;
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return value;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/org/dhatim/dropwizard/jwt/cookie/authentication/JwtCookieAuthenticationTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2023 Dhatim
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | package org.dhatim.dropwizard.jwt.cookie.authentication;
17 |
18 | import io.dropwizard.client.HttpClientBuilder;
19 | import io.dropwizard.client.JerseyClientBuilder;
20 | import io.dropwizard.core.Configuration;
21 | import io.dropwizard.jackson.Jackson;
22 | import io.dropwizard.testing.junit5.DropwizardAppExtension;
23 | import io.dropwizard.testing.junit5.DropwizardExtensionsSupport;
24 | import io.jsonwebtoken.lang.Strings;
25 | import jakarta.ws.rs.client.Client;
26 | import jakarta.ws.rs.client.Entity;
27 | import jakarta.ws.rs.client.WebTarget;
28 | import jakarta.ws.rs.core.MediaType;
29 | import jakarta.ws.rs.core.NewCookie;
30 | import jakarta.ws.rs.core.Response;
31 | import org.apache.hc.client5.http.cookie.BasicCookieStore;
32 | import org.junit.jupiter.api.Assertions;
33 | import org.junit.jupiter.api.BeforeAll;
34 | import org.junit.jupiter.api.Test;
35 | import org.junit.jupiter.api.extension.ExtendWith;
36 |
37 | import java.io.IOException;
38 | import java.io.InputStream;
39 | import java.io.InputStreamReader;
40 | import java.nio.charset.StandardCharsets;
41 | import java.time.Instant;
42 | import java.util.Collections;
43 | import java.util.Date;
44 | import java.util.UUID;
45 |
46 | @ExtendWith(DropwizardExtensionsSupport.class)
47 | public class JwtCookieAuthenticationTest {
48 |
49 | private static final DropwizardAppExtension