Skip to content

Commit 91da393

Browse files
committed
Made ID tokens ephemeral, made access token’s “additional information” extensible
1 parent 91ed758 commit 91da393

File tree

20 files changed

+50
-205
lines changed

20 files changed

+50
-205
lines changed

openid-connect-common/src/main/java/org/mitre/oauth2/model/OAuth2AccessTokenEntity.java

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@
6969
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_EXPIRED_BY_DATE, query = "select a from OAuth2AccessTokenEntity a where a.expiration <= :" + OAuth2AccessTokenEntity.PARAM_DATE),
7070
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_REFRESH_TOKEN, query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :" + OAuth2AccessTokenEntity.PARAM_REFERSH_TOKEN),
7171
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_CLIENT, query = "select a from OAuth2AccessTokenEntity a where a.client = :" + OAuth2AccessTokenEntity.PARAM_CLIENT),
72-
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_ID_TOKEN, query = "select a from OAuth2AccessTokenEntity a where a.idToken = :" + OAuth2AccessTokenEntity.PARAM_ID_TOKEN),
7372
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_TOKEN_VALUE, query = "select a from OAuth2AccessTokenEntity a where a.jwt = :" + OAuth2AccessTokenEntity.PARAM_TOKEN_VALUE),
7473
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_APPROVED_SITE, query = "select a from OAuth2AccessTokenEntity a where a.approvedSite = :" + OAuth2AccessTokenEntity.PARAM_APPROVED_SITE),
7574
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_RESOURCE_SET, query = "select a from OAuth2AccessTokenEntity a join a.permissions p where p.resourceSet.id = :" + OAuth2AccessTokenEntity.PARAM_RESOURCE_SET_ID)
@@ -82,15 +81,13 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
8281

8382
public static final String QUERY_BY_APPROVED_SITE = "OAuth2AccessTokenEntity.getByApprovedSite";
8483
public static final String QUERY_BY_TOKEN_VALUE = "OAuth2AccessTokenEntity.getByTokenValue";
85-
public static final String QUERY_BY_ID_TOKEN = "OAuth2AccessTokenEntity.getByIdToken";
8684
public static final String QUERY_BY_CLIENT = "OAuth2AccessTokenEntity.getByClient";
8785
public static final String QUERY_BY_REFRESH_TOKEN = "OAuth2AccessTokenEntity.getByRefreshToken";
8886
public static final String QUERY_EXPIRED_BY_DATE = "OAuth2AccessTokenEntity.getAllExpiredByDate";
8987
public static final String QUERY_ALL = "OAuth2AccessTokenEntity.getAll";
9088
public static final String QUERY_BY_RESOURCE_SET = "OAuth2AccessTokenEntity.getByResourceSet";
9189

9290
public static final String PARAM_TOKEN_VALUE = "tokenValue";
93-
public static final String PARAM_ID_TOKEN = "idToken";
9491
public static final String PARAM_CLIENT = "client";
9592
public static final String PARAM_REFERSH_TOKEN = "refreshToken";
9693
public static final String PARAM_DATE = "date";
@@ -107,8 +104,6 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
107104

108105
private JWT jwtValue; // JWT-encoded access token value
109106

110-
private OAuth2AccessTokenEntity idToken; // JWT-encoded OpenID Connect IdToken
111-
112107
private Date expiration;
113108

114109
private String tokenType = OAuth2AccessToken.BEARER_TYPE;
@@ -120,6 +115,8 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
120115
private Set<Permission> permissions;
121116

122117
private ApprovedSite approvedSite;
118+
119+
private Map<String, Object> additionalInformation = new HashMap<>(); // ephemeral map of items to be added to the OAuth token response
123120

124121
/**
125122
* Create a new, blank access token
@@ -146,16 +143,13 @@ public void setId(Long id) {
146143
}
147144

148145
/**
149-
* Get all additional information to be sent to the serializer. Inserts a copy of the IdToken (in JWT String form).
146+
* Get all additional information to be sent to the serializer as part of the token response.
147+
* This map is not persisted to the database.
150148
*/
151149
@Override
152150
@Transient
153151
public Map<String, Object> getAdditionalInformation() {
154-
Map<String, Object> map = new HashMap<>(); //super.getAdditionalInformation();
155-
if (getIdToken() != null) {
156-
map.put(ID_TOKEN_FIELD_NAME, getIdTokenString());
157-
}
158-
return map;
152+
return additionalInformation;
159153
}
160154

161155
/**
@@ -262,34 +256,6 @@ public boolean isExpired() {
262256
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
263257
}
264258

265-
/**
266-
* @return the idToken
267-
*/
268-
@OneToOne(cascade=CascadeType.ALL, orphanRemoval=true) // one-to-one mapping for now
269-
@JoinColumn(name = "id_token_id")
270-
public OAuth2AccessTokenEntity getIdToken() {
271-
return idToken;
272-
}
273-
274-
/**
275-
* @param idToken the idToken to set
276-
*/
277-
public void setIdToken(OAuth2AccessTokenEntity idToken) {
278-
this.idToken = idToken;
279-
}
280-
281-
/**
282-
* @return the idTokenString
283-
*/
284-
@Transient
285-
public String getIdTokenString() {
286-
if (idToken != null) {
287-
return idToken.getValue(); // get the JWT string value of the id token entity
288-
} else {
289-
return null;
290-
}
291-
}
292-
293259
/**
294260
* @return the jwtValue
295261
*/
@@ -352,4 +318,15 @@ public ApprovedSite getApprovedSite() {
352318
public void setApprovedSite(ApprovedSite approvedSite) {
353319
this.approvedSite = approvedSite;
354320
}
321+
322+
/**
323+
* Add the ID Token to the additionalInformation map for a token response.
324+
* @param idToken
325+
*/
326+
@Transient
327+
public void setIdToken(JWT idToken) {
328+
if (idToken != null) {
329+
additionalInformation.put(ID_TOKEN_FIELD_NAME, idToken.serialize());
330+
}
331+
}
355332
}

openid-connect-common/src/main/java/org/mitre/oauth2/repository/OAuth2TokenRepository.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ public interface OAuth2TokenRepository {
5151

5252
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client);
5353

54-
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
55-
5654
public Set<OAuth2AccessTokenEntity> getAllAccessTokens();
5755

5856
public Set<OAuth2RefreshTokenEntity> getAllRefreshTokens();

openid-connect-common/src/main/java/org/mitre/oauth2/service/OAuth2TokenEntityService.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ public interface OAuth2TokenEntityService extends AuthorizationServerTokenServic
5050
@Override
5151
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication);
5252

53-
/**
54-
* @param incomingToken
55-
* @return
56-
*/
57-
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken);
58-
5953
public OAuth2AccessTokenEntity getAccessTokenById(Long id);
6054

6155
public OAuth2RefreshTokenEntity getRefreshTokenById(Long id);

openid-connect-common/src/main/java/org/mitre/oauth2/service/SystemScopeService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,13 @@ public interface SystemScopeService {
3333

3434
public static final String OFFLINE_ACCESS = "offline_access";
3535
public static final String OPENID_SCOPE = "openid";
36-
public static final String ID_TOKEN_SCOPE = "id-token"; // ID tokens are generated using this scope
3736
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token"; // this scope manages dynamic client registrations
3837
public static final String RESOURCE_TOKEN_SCOPE = "resource-token"; // this scope manages client-style protected resources
3938
public static final String UMA_PROTECTION_SCOPE = "uma_protection";
4039
public static final String UMA_AUTHORIZATION_SCOPE = "uma_authorization";
4140

4241
public static final Set<SystemScope> reservedScopes =
4342
Sets.newHashSet(
44-
new SystemScope(ID_TOKEN_SCOPE),
4543
new SystemScope(REGISTRATION_TOKEN_SCOPE),
4644
new SystemScope(RESOURCE_TOKEN_SCOPE)
4745
);

openid-connect-common/src/main/java/org/mitre/openid/connect/service/OIDCTokenService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
2323
import org.springframework.security.oauth2.provider.OAuth2Request;
2424

25+
import com.nimbusds.jwt.JWT;
26+
2527
/**
2628
* Service to create specialty OpenID Connect tokens.
2729
*
@@ -41,7 +43,7 @@ public interface OIDCTokenService {
4143
* @param accessToken
4244
* @return
4345
*/
44-
public OAuth2AccessTokenEntity createIdToken(
46+
public JWT createIdToken(
4547
ClientDetailsEntity client, OAuth2Request request, Date issueTime,
4648
String sub, OAuth2AccessTokenEntity accessToken);
4749

openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ CREATE TABLE IF NOT EXISTS access_token (
1010
refresh_token_id BIGINT,
1111
client_id BIGINT,
1212
auth_holder_id BIGINT,
13-
id_token_id BIGINT,
1413
approved_site_id BIGINT
1514
);
1615

openid-connect-server/src/main/java/org/mitre/oauth2/repository/impl/JpaOAuth2TokenRepository.java

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,7 @@ public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity token) {
9797
public void removeAccessToken(OAuth2AccessTokenEntity accessToken) {
9898
OAuth2AccessTokenEntity found = getAccessTokenByValue(accessToken.getValue());
9999
if (found != null) {
100-
OAuth2AccessTokenEntity accessTokenForIdToken = getAccessTokenForIdToken(found);
101-
if (accessTokenForIdToken != null) {
102-
accessTokenForIdToken.setIdToken(null);
103-
JpaUtil.saveOrUpdate(accessTokenForIdToken.getId(), manager, accessTokenForIdToken);
104-
} else {
105-
manager.remove(found);
106-
}
100+
manager.remove(found);
107101
} else {
108102
throw new IllegalArgumentException("Access token not found: " + accessToken);
109103
}
@@ -193,17 +187,6 @@ public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEnt
193187
return refreshTokens;
194188
}
195189

196-
/* (non-Javadoc)
197-
* @see org.mitre.oauth2.repository.OAuth2TokenRepository#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
198-
*/
199-
@Override
200-
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
201-
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_ID_TOKEN, OAuth2AccessTokenEntity.class);
202-
queryA.setParameter(OAuth2AccessTokenEntity.PARAM_ID_TOKEN, idToken);
203-
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
204-
return JpaUtil.getSingleResult(accessTokens);
205-
}
206-
207190
@Override
208191
public Set<OAuth2AccessTokenEntity> getAllExpiredAccessTokens() {
209192
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_EXPIRED_BY_DATE, OAuth2AccessTokenEntity.class);

openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public OAuth2AccessTokenEntity createAccessToken(OAuth2Authentication authentica
263263

264264
OAuth2AccessTokenEntity enhancedToken = (OAuth2AccessTokenEntity) tokenEnhancer.enhance(token, authentication);
265265

266-
OAuth2AccessTokenEntity savedToken = tokenRepository.saveAccessToken(enhancedToken);
266+
OAuth2AccessTokenEntity savedToken = saveAccessToken(enhancedToken);
267267

268268
if (savedToken.getRefreshToken() != null) {
269269
tokenRepository.saveRefreshToken(savedToken.getRefreshToken()); // make sure we save any changes that might have been enhanced
@@ -542,7 +542,14 @@ private Collection<AuthenticationHolderEntity> getOrphanedAuthenticationHolders(
542542
*/
543543
@Override
544544
public OAuth2AccessTokenEntity saveAccessToken(OAuth2AccessTokenEntity accessToken) {
545-
return tokenRepository.saveAccessToken(accessToken);
545+
OAuth2AccessTokenEntity newToken = tokenRepository.saveAccessToken(accessToken);
546+
547+
// if the old token has any additional information for the return from the token endpoint, carry it through here after save
548+
if (accessToken.getAdditionalInformation() != null && !accessToken.getAdditionalInformation().isEmpty()) {
549+
newToken.getAdditionalInformation().putAll(accessToken.getAdditionalInformation());
550+
}
551+
552+
return newToken;
546553
}
547554

548555
/* (non-Javadoc)
@@ -567,15 +574,6 @@ public void setTokenEnhancer(TokenEnhancer tokenEnhancer) {
567574
this.tokenEnhancer = tokenEnhancer;
568575
}
569576

570-
/* (non-Javadoc)
571-
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#getAccessTokenForIdToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
572-
*/
573-
@Override
574-
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
575-
return tokenRepository.getAccessTokenForIdToken(idToken);
576-
}
577-
578-
579577
@Override
580578
public OAuth2AccessTokenEntity getRegistrationAccessTokenForClient(ClientDetailsEntity client) {
581579
List<OAuth2AccessTokenEntity> allTokens = getAccessTokensForClient(client);

openid-connect-server/src/main/java/org/mitre/oauth2/view/TokenApiView.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ public JsonElement serialize(OAuth2AccessTokenEntity src,
8484

8585
o.addProperty("value", src.getValue());
8686
o.addProperty("id", src.getId());
87-
o.addProperty("idTokenId", src.getIdToken() != null ? src.getIdToken().getId() : null);
8887
o.addProperty("refreshTokenId", src.getRefreshToken() != null ? src.getRefreshToken().getId() : null);
8988

9089
o.add("scopes", context.serialize(src.getScope()));

openid-connect-server/src/main/java/org/mitre/openid/connect/service/impl/DefaultOIDCTokenService.java

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.google.common.collect.Sets;
5454
import com.nimbusds.jose.Algorithm;
5555
import com.nimbusds.jose.JWEHeader;
56+
import com.nimbusds.jose.JWEObject;
5657
import com.nimbusds.jose.JWSAlgorithm;
5758
import com.nimbusds.jose.JWSHeader;
5859
import com.nimbusds.jose.util.Base64URL;
@@ -94,7 +95,7 @@ public class DefaultOIDCTokenService implements OIDCTokenService {
9495
private OAuth2TokenEntityService tokenService;
9596

9697
@Override
97-
public OAuth2AccessTokenEntity createIdToken(ClientDetailsEntity client, OAuth2Request request, Date issueTime, String sub, OAuth2AccessTokenEntity accessToken) {
98+
public JWT createIdToken(ClientDetailsEntity client, OAuth2Request request, Date issueTime, String sub, OAuth2AccessTokenEntity accessToken) {
9899

99100
JWSAlgorithm signingAlg = jwtService.getDefaultSigningAlgorithm();
100101

@@ -103,7 +104,8 @@ public OAuth2AccessTokenEntity createIdToken(ClientDetailsEntity client, OAuth2R
103104
}
104105

105106

106-
OAuth2AccessTokenEntity idTokenEntity = new OAuth2AccessTokenEntity();
107+
JWT idToken = null;
108+
107109
JWTClaimsSet.Builder idClaims = new JWTClaimsSet.Builder();
108110

109111
// if the auth time claim was explicitly requested OR if the client always wants the auth time, put it in
@@ -128,7 +130,6 @@ public OAuth2AccessTokenEntity createIdToken(ClientDetailsEntity client, OAuth2R
128130
if (client.getIdTokenValiditySeconds() != null) {
129131
Date expiration = new Date(System.currentTimeMillis() + (client.getIdTokenValiditySeconds() * 1000L));
130132
idClaims.expirationTime(expiration);
131-
idTokenEntity.setExpiration(expiration);
132133
}
133134

134135
idClaims.issuer(configBean.getIssuer());
@@ -157,20 +158,16 @@ public OAuth2AccessTokenEntity createIdToken(ClientDetailsEntity client, OAuth2R
157158

158159
if (encrypter != null) {
159160

160-
EncryptedJWT idToken = new EncryptedJWT(new JWEHeader(client.getIdTokenEncryptedResponseAlg(), client.getIdTokenEncryptedResponseEnc()), idClaims.build());
161-
162-
encrypter.encryptJwt(idToken);
161+
idToken = new EncryptedJWT(new JWEHeader(client.getIdTokenEncryptedResponseAlg(), client.getIdTokenEncryptedResponseEnc()), idClaims.build());
163162

164-
idTokenEntity.setJwt(idToken);
163+
encrypter.encryptJwt((JWEObject) idToken);
165164

166165
} else {
167166
logger.error("Couldn't find encrypter for client: " + client.getClientId());
168167
}
169168

170169
} else {
171170

172-
JWT idToken;
173-
174171
if (signingAlg.equals(Algorithm.NONE)) {
175172
// unsigned ID token
176173
idToken = new PlainJWT(idClaims.build());
@@ -206,20 +203,9 @@ public OAuth2AccessTokenEntity createIdToken(ClientDetailsEntity client, OAuth2R
206203
}
207204
}
208205

209-
210-
idTokenEntity.setJwt(idToken);
211206
}
212207

213-
idTokenEntity.setAuthenticationHolder(accessToken.getAuthenticationHolder());
214-
215-
// create a scope set with just the special "id-token" scope
216-
//Set<String> idScopes = new HashSet<String>(token.getScope()); // this would copy the original token's scopes in, we don't really want that
217-
Set<String> idScopes = Sets.newHashSet(SystemScopeService.ID_TOKEN_SCOPE);
218-
idTokenEntity.setScope(idScopes);
219-
220-
idTokenEntity.setClient(accessToken.getClient());
221-
222-
return idTokenEntity;
208+
return idToken;
223209
}
224210

225211
/**

0 commit comments

Comments
 (0)