23
23
import java .util .Date ;
24
24
import java .util .UUID ;
25
25
26
+ import org .mitre .jwt .assertion .AssertionValidator ;
26
27
import org .mitre .jwt .signer .service .JWTSigningAndValidationService ;
28
+ import org .mitre .oauth2 .assertion .AssertionOAuth2RequestFactory ;
27
29
import org .mitre .oauth2 .model .ClientDetailsEntity ;
28
30
import org .mitre .oauth2 .model .OAuth2AccessTokenEntity ;
29
31
import org .mitre .oauth2 .service .ClientDetailsEntityService ;
30
32
import org .mitre .oauth2 .service .OAuth2TokenEntityService ;
31
33
import org .mitre .oauth2 .service .SystemScopeService ;
32
34
import org .mitre .openid .connect .config .ConfigurationPropertiesBean ;
33
35
import org .springframework .beans .factory .annotation .Autowired ;
36
+ import org .springframework .beans .factory .annotation .Qualifier ;
34
37
import org .springframework .security .authentication .BadCredentialsException ;
35
38
import org .springframework .security .core .AuthenticationException ;
36
39
import org .springframework .security .oauth2 .common .OAuth2AccessToken ;
37
40
import org .springframework .security .oauth2 .common .exceptions .InvalidClientException ;
38
41
import org .springframework .security .oauth2 .common .exceptions .InvalidTokenException ;
39
42
import org .springframework .security .oauth2 .provider .ClientDetails ;
43
+ import org .springframework .security .oauth2 .provider .OAuth2Authentication ;
40
44
import org .springframework .security .oauth2 .provider .OAuth2RequestFactory ;
41
45
import org .springframework .security .oauth2 .provider .TokenRequest ;
42
46
import org .springframework .security .oauth2 .provider .token .AbstractTokenGranter ;
@@ -65,6 +69,13 @@ public class JWTAssertionTokenGranter extends AbstractTokenGranter {
65
69
66
70
@ Autowired
67
71
private ConfigurationPropertiesBean config ;
72
+
73
+ @ Autowired
74
+ @ Qualifier ("jwtAssertionValidator" )
75
+ private AssertionValidator validator ;
76
+
77
+ @ Autowired
78
+ private AssertionOAuth2RequestFactory assertionFactory ;
68
79
69
80
@ Autowired
70
81
public JWTAssertionTokenGranter (OAuth2TokenEntityService tokenServices , ClientDetailsEntityService clientDetailsService , OAuth2RequestFactory requestFactory ) {
@@ -76,129 +87,30 @@ public JWTAssertionTokenGranter(OAuth2TokenEntityService tokenServices, ClientDe
76
87
* @see org.springframework.security.oauth2.provider.token.AbstractTokenGranter#getOAuth2Authentication(org.springframework.security.oauth2.provider.AuthorizationRequest)
77
88
*/
78
89
@ Override
79
- protected OAuth2AccessToken getAccessToken (ClientDetails client , TokenRequest tokenRequest ) throws AuthenticationException , InvalidTokenException {
90
+ protected OAuth2Authentication getOAuth2Authentication (ClientDetails client , TokenRequest tokenRequest ) throws AuthenticationException , InvalidTokenException {
80
91
// read and load up the existing token
81
- String incomingTokenValue = tokenRequest .getRequestParameters ().get ("assertion" );
82
- OAuth2AccessTokenEntity incomingToken = tokenServices .readAccessToken (incomingTokenValue );
83
-
84
- if (incomingToken .getScope ().contains (SystemScopeService .ID_TOKEN_SCOPE )) {
85
-
86
- if (!client .getClientId ().equals (tokenRequest .getClientId ())) {
87
- throw new InvalidClientException ("Not the right client for this token" );
88
- }
89
-
90
- // it's an ID token, process it accordingly
91
-
92
- try {
93
-
94
- // TODO: make this use a more specific idtoken class
95
- JWT idToken = JWTParser .parse (incomingTokenValue );
96
-
97
- OAuth2AccessTokenEntity accessToken = tokenServices .getAccessTokenForIdToken (incomingToken );
98
-
99
- if (accessToken != null ) {
100
-
101
- //OAuth2AccessTokenEntity newIdToken = tokenServices.get
102
-
103
- OAuth2AccessTokenEntity newIdTokenEntity = new OAuth2AccessTokenEntity ();
104
-
105
- // copy over all existing claims
106
- JWTClaimsSet .Builder claims = new JWTClaimsSet .Builder (idToken .getJWTClaimsSet ());
107
-
108
- if (client instanceof ClientDetailsEntity ) {
109
-
110
- ClientDetailsEntity clientEntity = (ClientDetailsEntity ) client ;
111
-
112
- // update expiration and issued-at claims
113
- if (clientEntity .getIdTokenValiditySeconds () != null ) {
114
- Date expiration = new Date (System .currentTimeMillis () + (clientEntity .getIdTokenValiditySeconds () * 1000L ));
115
- claims .expirationTime (expiration );
116
- newIdTokenEntity .setExpiration (expiration );
117
- }
118
-
119
- } else {
120
- //This should never happen
121
- logger .fatal ("SEVERE: Client is not an instance of OAuth2AccessTokenEntity." );
122
- throw new BadCredentialsException ("SEVERE: Client is not an instance of ClientDetailsEntity; JwtAssertionTokenGranter cannot process this request." );
123
- }
124
-
125
- claims .issueTime (new Date ());
126
- claims .jwtID (UUID .randomUUID ().toString ()); // set a random NONCE in the middle of it
127
-
128
-
129
- SignedJWT newIdToken = new SignedJWT ((JWSHeader ) idToken .getHeader (), claims .build ());
130
- jwtService .signJwt (newIdToken );
131
-
132
- newIdTokenEntity .setJwt (newIdToken );
133
- newIdTokenEntity .setAuthenticationHolder (incomingToken .getAuthenticationHolder ());
134
- newIdTokenEntity .setScope (incomingToken .getScope ());
135
- newIdTokenEntity .setClient (incomingToken .getClient ());
136
-
137
- newIdTokenEntity = tokenServices .saveAccessToken (newIdTokenEntity );
138
-
139
- // attach the ID token to the access token entity
140
- accessToken .setIdToken (newIdTokenEntity );
141
- accessToken = tokenServices .saveAccessToken (accessToken );
142
-
143
- // delete the old ID token
144
- tokenServices .revokeAccessToken (incomingToken );
145
-
146
- return newIdTokenEntity ;
147
-
148
- }
149
- } catch (ParseException e ) {
150
- logger .warn ("Couldn't parse id token" , e );
92
+ try {
93
+ String incomingAssertionValue = tokenRequest .getRequestParameters ().get ("assertion" );
94
+ JWT assertion = JWTParser .parse (incomingAssertionValue );
95
+
96
+ if (validator .isValid (assertion )) {
97
+
98
+ // our validator says it's OK, time to make a token from it
99
+ // the real work happens in the assertion factory and the token services
100
+ return new OAuth2Authentication (assertionFactory .createOAuth2Request (client , tokenRequest , assertion ), null );
101
+
102
+ } else {
103
+ logger .warn ("Incoming assertion did not pass validator, rejecting" );
104
+ return null ;
151
105
}
152
-
106
+
107
+ } catch (ParseException e ) {
108
+ logger .warn ("Unable to parse incoming assertion" );
153
109
}
154
-
155
- // if we got down here, we didn't actually create any tokens, so return null
156
-
110
+
111
+ // if we had made a token, we'd have returned it by now, so return null here to close out with no created token
157
112
return null ;
158
113
159
- /*
160
- * Otherwise, process it like an access token assertion ... which we don't support yet so this is all commented out
161
- * /
162
- if (jwtService.validateSignature(incomingTokenValue)) {
163
-
164
- Jwt jwt = Jwt.parse(incomingTokenValue);
165
-
166
-
167
- if (oldToken.getScope().contains("id-token")) {
168
- // TODO: things
169
- }
170
-
171
- // TODO: should any of these throw an exception instead of returning null?
172
- JwtClaims claims = jwt.getClaims();
173
- if (!config.getIssuer().equals(claims.getIssuer())) {
174
- // issuer isn't us
175
- return null;
176
- }
177
-
178
- if (!authorizationRequest.getClientId().equals(claims.getAudience())) {
179
- // audience isn't the client
180
- return null;
181
- }
182
-
183
- Date now = new Date();
184
- if (!now.after(claims.getExpiration())) {
185
- // token is expired
186
- return null;
187
- }
188
-
189
- // FIXME
190
- // This doesn't work. We need to look up the old token, figure out its scopes and bind it appropriately.
191
- // In the case of an ID token, we need to look up its parent access token and change the reference, and revoke the old one, and
192
- // that's tricky.
193
- // we might need new calls on the token services layer to handle this, and we might
194
- // need to handle id tokens separately.
195
- return new OAuth2Authentication(authorizationRequest, null);
196
-
197
- } else {
198
- return null; // throw error??
199
- }
200
- */
201
-
202
114
}
203
115
204
116
0 commit comments