7
7
import java .lang .reflect .Method ;
8
8
import java .util .Arrays ;
9
9
import java .util .List ;
10
- import java .util .Map ;
11
10
import java .util .Objects ;
12
- import java .util .stream . Collectors ;
11
+ import java .util .Optional ;
13
12
14
13
import org .slf4j .Logger ;
15
14
import org .slf4j .LoggerFactory ;
26
25
27
26
public class JwtTokenAnnotationHandler {
28
27
29
- private static final Logger log = LoggerFactory .getLogger (JwtTokenAnnotationHandler .class );
28
+ private static final List <Class <? extends Annotation >> SUPPORTED_ANNOTATIONS = List .of (RequiredIssuers .class , ProtectedWithClaims .class ,
29
+ Protected .class , Unprotected .class );
30
+ private static final Logger LOG = LoggerFactory .getLogger (JwtTokenAnnotationHandler .class );
30
31
private final TokenValidationContextHolder tokenValidationContextHolder ;
31
32
32
33
public JwtTokenAnnotationHandler (TokenValidationContextHolder tokenValidationContextHolder ) {
33
34
this .tokenValidationContextHolder = tokenValidationContextHolder ;
34
35
}
35
36
36
- public boolean assertValidAnnotation (Method method ) throws AnnotationRequiredException {
37
- Annotation annotation = getAnnotation (method ,
38
- List .of (RequiredIssuers .class , ProtectedWithClaims .class , Protected .class , Unprotected .class ));
39
- if (annotation == null ) {
40
- throw new AnnotationRequiredException ("Server misconfigured - controller/method ["
41
- + method .getClass ().getName () + "." + method .getName ()
42
- + "] not annotated @Unprotected, @Protected or added to ignore list" );
43
- }
44
- return assertValidAnnotation (annotation );
37
+ public boolean assertValidAnnotation (Method m ) throws AnnotationRequiredException {
38
+ return Optional .ofNullable (getAnnotation (m , SUPPORTED_ANNOTATIONS ))
39
+ .map (this ::assertValidAnnotation )
40
+ .orElseThrow (() -> new AnnotationRequiredException (m ));
45
41
}
46
42
47
- private boolean assertValidAnnotation (Annotation annotation ) {
48
- if (annotation instanceof Unprotected ) {
49
- log .debug ("annotation is of type={}, no token validation performed." , Unprotected .class .getSimpleName ());
43
+ private boolean assertValidAnnotation (Annotation a ) {
44
+ if (a instanceof Unprotected ) {
45
+ LOG .debug ("annotation is of type={}, no token validation performed." , Unprotected .class .getSimpleName ());
50
46
return true ;
51
47
}
52
- if (annotation instanceof RequiredIssuers ) {
53
- boolean hasToken = false ;
54
- var ann = RequiredIssuers .class .cast (annotation );
55
- for (var sub : ann .value ()) {
56
- var jwtToken = getJwtToken (sub .issuer (), tokenValidationContextHolder );
57
- if (jwtToken .isEmpty ()) {
58
- continue ;
59
- }
60
- hasToken = true ;
61
- if (handleProtectedWithClaimsAnnotation (sub , jwtToken .get ())) {
62
- return true ;
63
- }
64
- }
65
- if (!hasToken ) {
66
- throw new JwtTokenMissingException ("no valid token found in validation context for any of the issuers " + issuers (ann ));
67
- }
68
- throw new JwtTokenInvalidClaimException ("required claims not present in token for any of " + issuersAndClaims (ann ));
48
+ if (a instanceof RequiredIssuers ) {
49
+ handleRequiredIssuers (RequiredIssuers .class .cast (a ));
69
50
}
70
- if (annotation instanceof ProtectedWithClaims ) {
71
- log .debug ("annotation is of type={}, do token validation and claim checking." , ProtectedWithClaims .class .getSimpleName ());
72
- var ann = ProtectedWithClaims .class .cast (annotation );
73
- var jwtToken = getJwtToken (ann .issuer (), tokenValidationContextHolder );
74
- if (jwtToken .isEmpty ()) {
75
- throw new JwtTokenMissingException ("no valid token found in validation context" );
76
- }
77
- if (!handleProtectedWithClaimsAnnotation (ann , jwtToken .get ())) {
78
- throw new JwtTokenInvalidClaimException ("required claims not present in token." + Arrays .asList (ann .claimMap ()));
79
- }
80
- return true ;
51
+ if (a instanceof ProtectedWithClaims ) {
52
+ return handleProtectedWithClaims (ProtectedWithClaims .class .cast (a ));
81
53
}
82
- if (annotation instanceof Protected ) {
83
- log .debug ("annotation is of type={}, check if context has valid token." , Protected .class .getSimpleName ());
84
- if (contextHasValidToken (tokenValidationContextHolder )) {
85
- return true ;
86
- }
87
- throw new JwtTokenMissingException ("no valid token found in validation context" );
88
-
54
+ if (a instanceof Protected ) {
55
+ return handleProtected ();
89
56
}
90
- log .debug ("annotation is unknown, type={}, no token validation performed. but possible bug so throw exception" , annotation .annotationType ());
57
+ LOG .debug ("annotation is unknown, type={}, no token validation performed. but possible bug so throw exception" , a .annotationType ());
91
58
return false ;
92
-
93
59
}
94
60
95
- private static Map <String , String []> issuersAndClaims (RequiredIssuers ann ) {
96
- return Arrays .stream (ann .value ())
97
- .collect (Collectors .toMap (ProtectedWithClaims ::issuer , ProtectedWithClaims ::claimMap ));
61
+ private boolean handleProtected () {
62
+ LOG .debug ("annotation is of type={}, check if context has valid token." , Protected .class .getSimpleName ());
63
+ if (contextHasValidToken (tokenValidationContextHolder )) {
64
+ return true ;
65
+ }
66
+ throw new JwtTokenMissingException ();
98
67
}
99
68
100
- private static List <String > issuers (RequiredIssuers ann ) {
101
- return Arrays .stream (ann .value ()).map (ProtectedWithClaims ::issuer ).collect (Collectors .toList ());
69
+ private boolean handleProtectedWithClaims (ProtectedWithClaims a ) {
70
+ LOG .debug ("annotation is of type={}, do token validation and claim checking." , ProtectedWithClaims .class .getSimpleName ());
71
+ var jwtToken = getJwtToken (a .issuer (), tokenValidationContextHolder );
72
+ if (jwtToken .isEmpty ()) {
73
+ throw new JwtTokenMissingException ();
74
+ }
75
+ if (!handleProtectedWithClaimsAnnotation (a , jwtToken .get ())) {
76
+ throw new JwtTokenInvalidClaimException (a );
77
+ }
78
+ return true ;
102
79
}
103
80
104
- protected Annotation getAnnotation (Method method , List <Class <? extends Annotation >> types ) {
105
- Annotation annotation = findAnnotation (method .getAnnotations (), types );
106
- if (annotation != null ) {
107
- log .debug ("method " + method + " marked @{}" , annotation .annotationType ());
108
- return annotation ;
81
+ private boolean handleRequiredIssuers (RequiredIssuers a ) {
82
+ boolean hasToken = false ;
83
+ for (var sub : a .value ()) {
84
+ var jwtToken = getJwtToken (sub .issuer (), tokenValidationContextHolder );
85
+ if (jwtToken .isEmpty ()) {
86
+ continue ;
87
+ }
88
+ if (handleProtectedWithClaimsAnnotation (sub , jwtToken .get ())) {
89
+ return true ;
90
+ }
91
+ hasToken = true ;
109
92
}
110
- Class <?> declaringClass = method .getDeclaringClass ();
111
- annotation = findAnnotation (declaringClass .getAnnotations (), types );
112
- if (annotation != null ) {
113
- log .debug ("method {} marked @{} through annotation on class" , method , annotation .annotationType ());
114
- return annotation ;
93
+ if (!hasToken ) {
94
+ throw new JwtTokenMissingException (a );
115
95
}
116
- return null ;
96
+ throw new JwtTokenInvalidClaimException (a );
97
+ }
98
+
99
+ protected Annotation getAnnotation (Method method , List <Class <? extends Annotation >> types ) {
100
+ return Optional .ofNullable (findAnnotation (types , method .getAnnotations ()))
101
+ .orElseGet (() -> findAnnotation (types , method .getDeclaringClass ().getAnnotations ()));
117
102
}
118
103
119
- private static Annotation findAnnotation (Annotation [] annotations , List <Class <? extends Annotation >> types ) {
120
- return annotations != null ? Arrays .stream (annotations )
104
+ private static Annotation findAnnotation (List <Class <? extends Annotation >> types , Annotation ... annotations ) {
105
+ return Arrays .stream (annotations )
121
106
.filter (a -> types .contains (a .annotationType ()))
122
107
.findFirst ()
123
- .orElse (null ) : null ;
108
+ .orElse (null );
124
109
}
125
110
126
- protected boolean handleProtectedWithClaimsAnnotation (ProtectedWithClaims annotation , JwtToken jwtToken ) {
127
- return handleProtectedWithClaims (annotation .issuer (), annotation .claimMap (), annotation .combineWithOr (), jwtToken );
111
+ protected boolean handleProtectedWithClaimsAnnotation (ProtectedWithClaims a , JwtToken jwtToken ) {
112
+ return handleProtectedWithClaims (a .issuer (), a .claimMap (), a .combineWithOr (), jwtToken );
128
113
}
129
114
130
115
protected boolean handleProtectedWithClaims (String issuer , String [] requiredClaims , boolean combineWithOr , JwtToken jwtToken ) {
131
116
if (Objects .nonNull (issuer ) && issuer .length () > 0 ) {
132
- if (!containsRequiredClaims (jwtToken , combineWithOr , requiredClaims )) {
133
- return false ;
134
- }
117
+ return containsRequiredClaims (jwtToken , combineWithOr , requiredClaims );
135
118
}
136
119
return true ;
137
120
}
138
121
139
- protected boolean containsRequiredClaims (JwtToken jwtBearerToken , boolean combineWithOr , String ... claims ) {
140
- log .debug ("choose matching logic based on combineWithOr=" + combineWithOr );
141
- return combineWithOr ? containsAnyClaim (jwtBearerToken , claims )
142
- : containsAllClaims (jwtBearerToken , claims );
122
+ protected boolean containsRequiredClaims (JwtToken jwtToken , boolean combineWithOr , String ... claims ) {
123
+ LOG .debug ("choose matching logic based on combineWithOr=" + combineWithOr );
124
+ return combineWithOr ? containsAnyClaim (jwtToken , claims )
125
+ : containsAllClaims (jwtToken , claims );
143
126
}
144
127
145
128
private boolean containsAllClaims (JwtToken jwtToken , String ... claims ) {
@@ -159,8 +142,7 @@ private boolean containsAnyClaim(JwtToken jwtToken, String... claims) {
159
142
.filter (pair -> pair .length == 2 )
160
143
.anyMatch (pair -> jwtToken .containsClaim (pair [0 ].trim (), pair [1 ].trim ()));
161
144
}
162
- log .debug ("no claims listed, so claim checking is ok." );
145
+ LOG .debug ("no claims listed, so claim checking is ok." );
163
146
return true ;
164
147
}
165
-
166
148
}
0 commit comments