OIDCIdTokenEnhancer.java.backup.20190420 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /**
  2. *
  3. */
  4. package com.connsec.authz.oidc.idtoken;
  5. import java.util.Arrays;
  6. import java.util.Date;
  7. import java.util.Set;
  8. import java.util.UUID;
  9. import org.joda.time.DateTime;
  10. import org.joda.time.format.DateTimeFormat;
  11. import com.nimbusds.jose.util.Base64URL;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import com.connsec.authz.oauth2.common.DefaultOAuth2AccessToken;
  15. import com.connsec.authz.oauth2.common.OAuth2AccessToken;
  16. import com.connsec.authz.oauth2.provider.ClientDetailsService;
  17. import com.connsec.authz.oauth2.provider.OAuth2Authentication;
  18. import com.connsec.authz.oauth2.provider.OAuth2Request;
  19. import com.connsec.authz.oauth2.provider.token.TokenEnhancer;
  20. import com.connsec.config.oidc.OIDCProviderMetadata;
  21. import com.connsec.crypto.ReciprocalUtils;
  22. import com.connsec.crypto.jwt.encryption.service.JwtEncryptionAndDecryptionService;
  23. import com.connsec.crypto.jwt.encryption.service.impl.RecipientJwtEncryptionAndDecryptionServiceBuilder;
  24. import com.connsec.crypto.jwt.signer.service.JwtSigningAndValidationService;
  25. import com.connsec.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
  26. import com.connsec.domain.apps.oauth2.provider.ClientDetails;
  27. import com.connsec.web.WebContext;
  28. import com.google.common.base.Strings;
  29. import com.nimbusds.jose.EncryptionMethod;
  30. import com.nimbusds.jose.JWEAlgorithm;
  31. import com.nimbusds.jose.JWEHeader;
  32. import com.nimbusds.jose.JWSAlgorithm;
  33. import com.nimbusds.jose.JWSHeader;
  34. import com.nimbusds.jwt.EncryptedJWT;
  35. import com.nimbusds.jwt.JWT;
  36. import com.nimbusds.jwt.JWTClaimsSet;
  37. import com.nimbusds.jwt.PlainJWT;
  38. import com.nimbusds.jwt.SignedJWT;
  39. /**
  40. * @author Crystal.Sea
  41. *
  42. */
  43. public class OIDCIdTokenEnhancer implements TokenEnhancer {
  44. private final static Logger logger = LoggerFactory.getLogger(OIDCIdTokenEnhancer.class);
  45. public final static String ID_TOKEN_SCOPE="openid";
  46. private OIDCProviderMetadata providerMetadata;
  47. private JwtSigningAndValidationService jwtSignerService;
  48. private JwtEncryptionAndDecryptionService jwtEnDecryptionService;
  49. private ClientDetailsService clientDetailsService;
  50. private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder
  51. =new SymmetricSigningAndValidationServiceBuilder();
  52. private RecipientJwtEncryptionAndDecryptionServiceBuilder recipientJwtEnDecryptionServiceBuilder
  53. =new RecipientJwtEncryptionAndDecryptionServiceBuilder();
  54. public void setProviderMetadata(OIDCProviderMetadata providerMetadata) {
  55. this.providerMetadata = providerMetadata;
  56. }
  57. public void setJwtSignerService(JwtSigningAndValidationService jwtSignerService) {
  58. this.jwtSignerService = jwtSignerService;
  59. }
  60. public void setJwtEnDecryptionService(
  61. JwtEncryptionAndDecryptionService jwtEnDecryptionService) {
  62. this.jwtEnDecryptionService = jwtEnDecryptionService;
  63. }
  64. public void setClientDetailsService(ClientDetailsService clientDetailsService) {
  65. this.clientDetailsService = clientDetailsService;
  66. }
  67. @Override
  68. public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
  69. OAuth2Request request=authentication.getOAuth2Request();
  70. if (request.getScope().contains(ID_TOKEN_SCOPE)) {//Enhance for OpenID Connect
  71. ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authentication.getOAuth2Request().getClientId());
  72. JWTClaimsSet idClaims = new JWTClaimsSet.Builder()
  73. .subject(authentication.getName())
  74. .expirationTime(accessToken.getExpiration())
  75. .claim(providerMetadata.getIssuer(), true)
  76. .issueTime(new Date())
  77. .audience(Arrays.asList(authentication.getOAuth2Request().getClientId()))
  78. .jwtID(UUID.randomUUID().toString())
  79. .build();
  80. /**
  81. * https://self-issued.me
  82. * @see http://openid.net/specs/openid-connect-core-1_0.html#SelfIssuedDiscovery
  83. * 7. Self-Issued OpenID Provider
  84. */
  85. if(providerMetadata.getIssuer().equalsIgnoreCase("https://self-issued.me")){
  86. idClaims.setCustomClaim("sub_jwk", jwtSignerService.getAllPublicKeys().get(jwtSignerService.getDefaultSignerKeyId()));
  87. }
  88. // if the auth time claim was explicitly requested OR if the client always wants the auth time, put it in
  89. if (request.getExtensions().containsKey("max_age")
  90. || (request.getExtensions().containsKey("idtoken")) // TODO: parse the ID Token claims (#473) -- for now assume it could be in there
  91. ) {
  92. DateTime loginDate=DateTime.parse(WebContext.getUserInfo().getLastLoginTime(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
  93. idClaims.setClaim("auth_time", loginDate.getMillis()/ 1000);
  94. }
  95. String nonce = (String)request.getExtensions().get("nonce");
  96. if (!Strings.isNullOrEmpty(nonce)) {
  97. idClaims.setCustomClaim("nonce", nonce);
  98. }
  99. JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
  100. SignedJWT signed = new SignedJWT(new JWSHeader(signingAlg), idClaims);
  101. Set<String> responseTypes = request.getResponseTypes();
  102. if (responseTypes.contains("token")) {
  103. // calculate the token hash
  104. Base64URL at_hash = IdTokenHashUtils.getAccessTokenHash(signingAlg, signed);
  105. idClaims.setClaim("at_hash", at_hash);
  106. }
  107. logger.debug("idClaims "+idClaims);
  108. JWT idToken=null;
  109. if (clientDetails.getIdTokenEncryptedAlgorithm() != null && !clientDetails.getIdTokenEncryptedAlgorithm().equals("none")
  110. && clientDetails.getIdTokenEncryptionMethod() != null && !clientDetails.getIdTokenEncryptionMethod().equals("none")
  111. &&clientDetails.getJwksUri()!=null&&clientDetails.getJwksUri().length()>4) {
  112. JwtEncryptionAndDecryptionService recipientJwtEnDecryptionService =
  113. recipientJwtEnDecryptionServiceBuilder.serviceBuilder(clientDetails.getJwksUri());
  114. if (recipientJwtEnDecryptionService != null) {
  115. JWEAlgorithm jweAlgorithm=new JWEAlgorithm(clientDetails.getIdTokenEncryptedAlgorithm());
  116. EncryptionMethod encryptionMethod=new EncryptionMethod(clientDetails.getIdTokenEncryptionMethod());
  117. EncryptedJWT encryptedJWT = new EncryptedJWT(new JWEHeader(jweAlgorithm, encryptionMethod), idClaims);
  118. recipientJwtEnDecryptionService.encryptJwt(encryptedJWT);
  119. idToken=encryptedJWT;
  120. }else{
  121. logger.error("Couldn't create Jwt Encryption Service");
  122. }
  123. } else {
  124. if (signingAlg==null||signingAlg.equals("none")) {
  125. // unsigned ID token
  126. idToken = new PlainJWT(idClaims);
  127. } else {
  128. // signed ID token
  129. if (signingAlg.equals(JWSAlgorithm.HS256)
  130. || signingAlg.equals(JWSAlgorithm.HS384)
  131. || signingAlg.equals(JWSAlgorithm.HS512)) {
  132. // sign it with the client's secret
  133. String client_secret=ReciprocalUtils.decoder(clientDetails.getClientSecret());
  134. JwtSigningAndValidationService symmetricJwtSignerService =symmetricJwtSignerServiceBuilder.serviceBuilder(client_secret);
  135. if(symmetricJwtSignerService!=null){
  136. idClaims.setCustomClaim("kid", "SYMMETRIC-KEY");
  137. idToken = new SignedJWT(new JWSHeader(signingAlg), idClaims);
  138. symmetricJwtSignerService.signJwt((SignedJWT) idToken);
  139. }else {
  140. logger.error("Couldn't create symmetric validator for client " + clientDetails.getClientId() + " without a client secret");
  141. }
  142. } else {
  143. idClaims.setCustomClaim("kid", jwtSignerService.getDefaultSignerKeyId());
  144. idToken = new SignedJWT(new JWSHeader(signingAlg), idClaims);
  145. // sign it with the server's key
  146. jwtSignerService.signJwt((SignedJWT) idToken);
  147. }
  148. }
  149. }
  150. logger.debug("idToken "+idToken);
  151. accessToken = new DefaultOAuth2AccessToken(accessToken);
  152. if(idToken!=null){
  153. accessToken.getAdditionalInformation().put("id_token", idToken.serialize());
  154. }
  155. }
  156. return accessToken;
  157. }
  158. }