Skip to content

Commit d95e0b0

Browse files
authored
Merge pull request #4 from majusko/hotfix/refresh-internal-token-expiration
Hotfix/refresh internal token expiration
2 parents b4e1219 + d81a405 commit d95e0b0

File tree

11 files changed

+85
-34
lines changed

11 files changed

+85
-34
lines changed

src/main/java/io/github/majusko/grpc/jwt/collector/Allowed.java renamed to src/main/java/io/github/majusko/grpc/jwt/data/Allowed.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.github.majusko.grpc.jwt.collector;
1+
package io.github.majusko.grpc.jwt.data;
22

33
import java.util.Set;
44

src/main/java/io/github/majusko/grpc/jwt/interceptor/AuthContextData.java renamed to src/main/java/io/github/majusko/grpc/jwt/data/AuthContextData.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.github.majusko.grpc.jwt.interceptor;
1+
package io.github.majusko.grpc.jwt.data;
22

33
import io.jsonwebtoken.Claims;
44
import lombok.AllArgsConstructor;

src/main/java/io/github/majusko/grpc/jwt/interceptor/GrpcHeader.java renamed to src/main/java/io/github/majusko/grpc/jwt/data/GrpcHeader.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
package io.github.majusko.grpc.jwt.interceptor;
1+
package io.github.majusko.grpc.jwt.data;
22

33
import io.grpc.Metadata;
44

55
import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;
66

77
public class GrpcHeader {
8-
private GrpcHeader(){}
8+
private GrpcHeader() {
9+
}
10+
911
private final static String AUTHORIZATION_KEY = "Authorization";
1012
public static Metadata.Key<String> AUTHORIZATION =
1113
Metadata.Key.of(AUTHORIZATION_KEY, ASCII_STRING_MARSHALLER);

src/main/java/io/github/majusko/grpc/jwt/interceptor/GrpcJwtContext.java renamed to src/main/java/io/github/majusko/grpc/jwt/data/GrpcJwtContext.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
package io.github.majusko.grpc.jwt.interceptor;
1+
package io.github.majusko.grpc.jwt.data;
22

33
import java.util.Optional;
44

55
public class GrpcJwtContext {
66

7-
private GrpcJwtContext(){}
7+
private GrpcJwtContext() {
8+
}
89

910
private static final String CONTEXT_DATA = "context_data";
1011

src/main/java/io/github/majusko/grpc/jwt/exception/AuthException.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.github.majusko.grpc.jwt.exception;
22

33
public class AuthException extends RuntimeException {
4-
54
public AuthException(String message) {
65
super(message);
76
}

src/main/java/io/github/majusko/grpc/jwt/exception/UnauthenticatedException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package io.github.majusko.grpc.jwt.exception;
22

33
public class UnauthenticatedException extends RuntimeException {
4-
public UnauthenticatedException(String message) {
5-
super(message);
6-
}
74
public UnauthenticatedException(String message, Throwable cause) {
85
super(message, cause);
96
}

src/main/java/io/github/majusko/grpc/jwt/interceptor/AllowedCollector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import com.google.common.collect.Sets;
44
import io.github.majusko.grpc.jwt.annotation.Allow;
55
import io.github.majusko.grpc.jwt.annotation.Exposed;
6-
import io.github.majusko.grpc.jwt.collector.Allowed;
6+
import io.github.majusko.grpc.jwt.data.Allowed;
77
import org.lognet.springboot.grpc.GRpcService;
88
import org.springframework.beans.factory.config.BeanPostProcessor;
99
import org.springframework.stereotype.Component;

src/main/java/io/github/majusko/grpc/jwt/interceptor/AuthClientInterceptor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.majusko.grpc.jwt.interceptor;
22

3+
import io.github.majusko.grpc.jwt.data.GrpcHeader;
34
import io.github.majusko.grpc.jwt.service.JwtService;
45
import io.grpc.*;
56
import org.slf4j.Logger;

src/main/java/io/github/majusko/grpc/jwt/interceptor/AuthServerInterceptor.java

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package io.github.majusko.grpc.jwt.interceptor;
22

33
import com.google.common.collect.Sets;
4-
import io.github.majusko.grpc.jwt.collector.Allowed;
4+
import io.github.majusko.grpc.jwt.data.Allowed;
5+
import io.github.majusko.grpc.jwt.data.AuthContextData;
6+
import io.github.majusko.grpc.jwt.data.GrpcHeader;
7+
import io.github.majusko.grpc.jwt.data.GrpcJwtContext;
58
import io.github.majusko.grpc.jwt.exception.AuthException;
69
import io.github.majusko.grpc.jwt.exception.UnauthenticatedException;
710
import io.github.majusko.grpc.jwt.service.JwtService;
811
import io.grpc.*;
9-
import io.jsonwebtoken.*;
10-
import io.jsonwebtoken.security.SignatureException;
12+
import io.jsonwebtoken.Claims;
13+
import io.jsonwebtoken.JwtException;
14+
import io.jsonwebtoken.Jwts;
1115
import org.lognet.springboot.grpc.GRpcGlobalInterceptor;
1216
import org.springframework.core.env.Environment;
1317

@@ -46,7 +50,7 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
4650
final Context context = Context.current().withValue(GrpcJwtContext.CONTEXT_DATA_KEY, contextData);
4751

4852
return buildListener(call, metadata, next, context, contextData);
49-
} catch (UnauthenticatedException e) {
53+
} catch(UnauthenticatedException e) {
5054
call.close(Status.UNAUTHENTICATED.withDescription(e.getMessage()).withCause(e.getCause()), metadata);
5155
//noinspection unchecked
5256
return NOOP_LISTENER;
@@ -75,14 +79,14 @@ protected ServerCall.Listener<ReqT> delegate() {
7579
@Override
7680
public void onMessage(ReqT request) {
7781
try {
78-
if (delegate == NOOP_LISTENER) {
82+
if(delegate == NOOP_LISTENER) {
7983
final String methodName = call.getMethodDescriptor().getFullMethodName().toLowerCase();
8084

8185
validateAnnotatedMethods(request, contextData, methodName);
8286

8387
delegate = customDelegate;
8488
}
85-
} catch (AuthException e) {
89+
} catch(AuthException e) {
8690
call.close(Status.PERMISSION_DENIED
8791
.withDescription(e.getMessage())
8892
.withCause(e.getCause()), metadata);
@@ -93,7 +97,7 @@ public void onMessage(ReqT request) {
9397
}
9498

9599
private <ReqT> void validateAnnotatedMethods(ReqT request, AuthContextData contextData, String methodName) {
96-
if (!validateExposedAnnotation(contextData, methodName)) {
100+
if(!validateExposedAnnotation(contextData, methodName)) {
97101
validateAllowedAnnotation(request, contextData, methodName);
98102
}
99103
}
@@ -104,12 +108,13 @@ private boolean validateExposedAnnotation(AuthContextData contextData, String me
104108
final boolean methodIsExposed = Arrays.stream(environment.getActiveProfiles())
105109
.anyMatch(exposedToEnvironments::contains);
106110

107-
if (methodIsExposed) {
111+
if(methodIsExposed) {
108112
if(contextData == null) throw new AuthException("Missing JWT data.");
113+
109114
final List<String> rawEnvironments = (List<String>) contextData
110115
.getJwtClaims().get(JwtService.TOKEN_ENV, List.class);
111-
112116
final Set<String> environments = rawEnvironments.stream().map(Object::toString).collect(Collectors.toSet());
117+
113118
return exposedToEnvironments.stream().anyMatch(environments::contains);
114119
}
115120

@@ -123,38 +128,43 @@ private <ReqT> void validateAllowedAnnotation(ReqT request, AuthContextData cont
123128

124129
private <ReqT> void authorizeOwnerOrRoles(ReqT request, AuthContextData contextData, Allowed allowed) {
125130
if(contextData == null) throw new AuthException("Missing JWT data.");
126-
if (allowed.getUserId() != null && !allowed.getUserId().isEmpty()) {
131+
if(allowed.getUserId() != null && !allowed.getUserId().isEmpty()) {
127132
try {
128-
final Field field = request.getClass().getDeclaredField(allowed.getUserId() + GRPC_FIELD_MODIFIER);
129-
field.setAccessible(true);
130-
final String userId = String.valueOf(field.get(request));
133+
final String userId = parseOwner(request, allowed.getUserId());
131134

132135
authorizeOwner(userId, new HashSet<>(allowed.getRoles()), contextData);
133-
} catch (NoSuchFieldException | IllegalAccessException e) {
136+
} catch(NoSuchFieldException | IllegalAccessException e) {
134137
throw new AuthException("Missing field.");
135138
}
136139
} else {
137140
validateRoles(new HashSet<>(allowed.getRoles()), contextData.getRoles());
138141
}
139142
}
140143

144+
private <ReqT> String parseOwner(ReqT request, String fieldName) throws NoSuchFieldException,
145+
IllegalAccessException {
146+
final Field field = request.getClass().getDeclaredField(fieldName + GRPC_FIELD_MODIFIER);
147+
field.setAccessible(true);
148+
return String.valueOf(field.get(request));
149+
}
150+
141151
private void authorizeOwner(String uid, Set<String> required, AuthContextData contextData) {
142-
if (contextData == null || contextData.getUserId() == null || contextData.getUserId().isEmpty()) {
152+
if(contextData == null || contextData.getUserId() == null || contextData.getUserId().isEmpty()) {
143153
throw new AuthException("Owner field is missing.");
144154
}
145155

146-
if (!contextData.getUserId().equals(uid)) validateRoles(required, contextData.getRoles());
156+
if(!contextData.getUserId().equals(uid)) validateRoles(required, contextData.getRoles());
147157
}
148158

149159
private void validateRoles(Set<String> requiredRoles, Set<String> userRoles) {
150160

151-
if (requiredRoles.isEmpty()) {
161+
if(requiredRoles.isEmpty()) {
152162
throw new AuthException("Endpoint does not have specified roles.");
153163
}
154164

155165
requiredRoles.retainAll(Objects.requireNonNull(userRoles));
156166

157-
if (requiredRoles.isEmpty()) {
167+
if(requiredRoles.isEmpty()) {
158168
throw new AuthException("Missing required permission roles.");
159169
}
160170
}
@@ -164,7 +174,7 @@ private AuthContextData parseAuthContextData(Metadata metadata) {
164174
try {
165175
final String authHeaderData = metadata.get(GrpcHeader.AUTHORIZATION);
166176

167-
if (authHeaderData == null) {
177+
if(authHeaderData == null) {
168178
return null;
169179
}
170180

@@ -173,7 +183,7 @@ private AuthContextData parseAuthContextData(Metadata metadata) {
173183
final List<String> roles = (List<String>) jwtBody.get(JwtService.JWT_ROLES, List.class);
174184

175185
return new AuthContextData(token, jwtBody.getSubject(), Sets.newHashSet(roles), jwtBody);
176-
} catch (JwtException | IllegalArgumentException e) {
186+
} catch(JwtException | IllegalArgumentException e) {
177187
throw new UnauthenticatedException(e.getMessage(), e);
178188
}
179189
}

src/main/java/io/github/majusko/grpc/jwt/service/JwtService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public String getInternal() {
6161

6262
final long refreshThresholdValue = Double.valueOf(properties.getExpirationSec() * REFRESH_TIME_THRESHOLD).longValue();
6363

64-
if (LocalDateTime.now().minusSeconds(refreshThresholdValue).isAfter(internal.getExpiration())) {
64+
if (LocalDateTime.now().plusSeconds(refreshThresholdValue).isAfter(internal.getExpiration())) {
6565
refreshInternalToken();
6666
}
6767

0 commit comments

Comments
 (0)