11package io .github .majusko .grpc .jwt .interceptor ;
22
33import 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 ;
58import io .github .majusko .grpc .jwt .exception .AuthException ;
69import io .github .majusko .grpc .jwt .exception .UnauthenticatedException ;
710import io .github .majusko .grpc .jwt .service .JwtService ;
811import 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 ;
1115import org .lognet .springboot .grpc .GRpcGlobalInterceptor ;
1216import 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 }
0 commit comments