Optimize
This commit is contained in:
@@ -32,6 +32,6 @@ public interface ClientDetailsService {
|
||||
* @return The client details (never null).
|
||||
* @throws ClientRegistrationException If the client account is locked, expired, disabled, or invalid for any other reason.
|
||||
*/
|
||||
ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException;
|
||||
ClientDetails loadClientByClientId(String clientId,boolean cached) throws ClientRegistrationException;
|
||||
|
||||
}
|
||||
@@ -111,7 +111,7 @@ public class ApprovalStoreUserApprovalHandler implements UserApprovalHandler, In
|
||||
|
||||
if (clientDetailsService != null) {
|
||||
try {
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId,true);
|
||||
for (String scope : requestedScopes) {
|
||||
if (client.isAutoApprove(scope) || client.isAutoApprove("all")) {
|
||||
approvedScopes.add(scope);
|
||||
|
||||
@@ -110,7 +110,7 @@ public class TokenStoreUserApprovalHandler implements UserApprovalHandler, Initi
|
||||
Set<String> scopes = authorizationRequest.getScope();
|
||||
if (clientDetailsService!=null) {
|
||||
try {
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId,true);
|
||||
approved = true;
|
||||
for (String scope : scopes) {
|
||||
if (!client.isAutoApprove(scope)) {
|
||||
|
||||
@@ -83,7 +83,7 @@ public class OAuth20AccessConfirmationEndpoint {
|
||||
// Map<String, Object> model
|
||||
AuthorizationRequest clientAuth =
|
||||
(AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
|
||||
Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
|
||||
WebContext.setAttribute(app.getId(), app.getIcon());
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class OAuth20UserApprovalHandler extends ApprovalStoreUserApprovalHandler
|
||||
Collection<String> requestedScopes = authorizationRequest.getScope();
|
||||
try {
|
||||
ClientDetails client = clientDetailsService
|
||||
.loadClientByClientId(authorizationRequest.getClientId());
|
||||
.loadClientByClientId(authorizationRequest.getClientId(),true);
|
||||
for (String scope : requestedScopes) {
|
||||
if (client.isAutoApprove(scope) || client.isAutoApprove("all")) {
|
||||
approved = true;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ClientDetailsUserDetailsService implements UserDetailsService {
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
ClientDetails clientDetails;
|
||||
try {
|
||||
clientDetails = clientDetailsService.loadClientByClientId(username);
|
||||
clientDetails = clientDetailsService.loadClientByClientId(username,true);
|
||||
} catch (NoSuchClientException e) {
|
||||
throw new UsernameNotFoundException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
@@ -69,9 +69,8 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
|
||||
private static final String CLIENT_FIELDS_FOR_UPDATE = "RESOURCE_IDS, SCOPE, "
|
||||
+ "AUTHORIZED_GRANT_TYPES, WEB_SERVER_REDIRECT_URI, AUTHORITIES, ACCESS_TOKEN_VALIDITY, "
|
||||
+ "REFRESH_TOKEN_VALIDITY, ADDITIONAL_INFORMATION, AUTOAPPROVE, APPROVALPROMPT , "
|
||||
+ "IDTOKENSIGNINGALGORITHM, IDTOKENENCRYPTEDALGORITHM, IDTOKENENCRYPTIONMETHOD, "
|
||||
+ "USERINFOSIGNINGALGORITHM, USERINFOCRYPTEDALGORITHM, USERINFOENCRYPTIONMETHOD,"
|
||||
+" JWKSURI, PKCE, PROTOCOL , INSTID ";
|
||||
+ "ALGORITHM, ALGORITHMKEY, ENCRYPTIONMETHOD, SIGNATURE, SIGNATUREKEY, SUBJECT, "
|
||||
+ "USERINFORESPONSE, ISSUER, AUDIENCE, PKCE, PROTOCOL , INSTID ";
|
||||
|
||||
private static final String CLIENT_FIELDS = "client_secret, " + CLIENT_FIELDS_FOR_UPDATE;
|
||||
|
||||
@@ -83,7 +82,7 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
|
||||
private static final String DEFAULT_SELECT_STATEMENT = BASE_FIND_STATEMENT + " where client_id = ?";
|
||||
|
||||
private static final String DEFAULT_INSERT_STATEMENT = "insert into mxk_apps_oauth_client_details (" + CLIENT_FIELDS
|
||||
+ ", client_id) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
+ ", client_id) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
|
||||
private static final String DEFAULT_UPDATE_STATEMENT = "update mxk_apps_oauth_client_details " + "set "
|
||||
+ CLIENT_FIELDS_FOR_UPDATE.replaceAll(", ", "=?, ") + "=? where client_id = ?";
|
||||
@@ -126,13 +125,18 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
public ClientDetails loadClientByClientId(String clientId) {
|
||||
public ClientDetails loadClientByClientId(String clientId,boolean cached) {
|
||||
// cache in memory
|
||||
ClientDetails details = clientDetailsCache.getIfPresent(clientId);
|
||||
ClientDetails details = null;
|
||||
if(cached) {
|
||||
details = clientDetailsCache.getIfPresent(clientId);
|
||||
}
|
||||
if(details == null) {
|
||||
try {
|
||||
details = jdbcTemplate.queryForObject(selectClientDetailsSql, new ClientDetailsRowMapper(), clientId);
|
||||
clientDetailsCache.put(clientId, details);
|
||||
if(cached) {
|
||||
clientDetailsCache.put(clientId, details);
|
||||
}
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
throw new NoSuchClientException("No client with requested id: " + clientId);
|
||||
}
|
||||
@@ -208,10 +212,11 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
|
||||
: null,
|
||||
clientDetails.getAccessTokenValiditySeconds(), clientDetails.getRefreshTokenValiditySeconds(), json,
|
||||
getAutoApproveScopes(clientDetails),clientDetails.getApprovalPrompt(),
|
||||
clientDetails.getIdTokenSigningAlgorithm(),
|
||||
clientDetails.getIdTokenEncryptedAlgorithm(), clientDetails.getIdTokenEncryptionMethod(),
|
||||
clientDetails.getUserInfoSigningAlgorithm(), clientDetails.getUserInfoEncryptedAlgorithm(),
|
||||
clientDetails.getUserInfoEncryptionMethod(), clientDetails.getJwksUri(),
|
||||
clientDetails.getAlgorithm(),
|
||||
clientDetails.getAlgorithmKey(), clientDetails.getEncryptionMethod(),
|
||||
clientDetails.getSignature(), clientDetails.getSignatureKey(),
|
||||
clientDetails.getSubject(),clientDetails.getUserInfoResponse(),
|
||||
clientDetails.getIssuer(), clientDetails.getAudience(),
|
||||
clientDetails.getPkce(), clientDetails.getProtocol(),clientDetails.getInstId(),
|
||||
|
||||
clientDetails.getClientId()
|
||||
@@ -290,14 +295,16 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
|
||||
details.setRefreshTokenValiditySeconds(rs.getInt(9));
|
||||
}
|
||||
|
||||
details.setIdTokenEncryptedAlgorithm(rs.getString("IDTOKENENCRYPTEDALGORITHM"));
|
||||
details.setIdTokenEncryptionMethod(rs.getString("IDTOKENENCRYPTIONMETHOD"));
|
||||
details.setIdTokenSigningAlgorithm(rs.getString("IDTOKENSIGNINGALGORITHM"));
|
||||
details.setAlgorithm(rs.getString("algorithm"));
|
||||
details.setAlgorithmKey(rs.getString("algorithmKey"));
|
||||
details.setEncryptionMethod(rs.getString("encryptionMethod"));
|
||||
|
||||
details.setUserInfoEncryptedAlgorithm(rs.getString("USERINFOCRYPTEDALGORITHM"));
|
||||
details.setUserInfoEncryptionMethod(rs.getString("USERINFOENCRYPTIONMETHOD"));
|
||||
details.setUserInfoSigningAlgorithm(rs.getString("USERINFOSIGNINGALGORITHM"));
|
||||
details.setJwksUri(rs.getString("JWKSURI"));
|
||||
details.setSignature(rs.getString("signature"));
|
||||
details.setSignatureKey(rs.getString("signatureKey"));
|
||||
details.setSubject(rs.getString("subject"));
|
||||
details.setUserInfoResponse(rs.getString("userInfoResponse"));
|
||||
details.setAudience(rs.getString("audience"));
|
||||
details.setIssuer(rs.getString("issuer"));
|
||||
details.setApprovalPrompt(rs.getString("APPROVALPROMPT"));
|
||||
details.setPkce(rs.getString("PKCE"));
|
||||
details.setProtocol(rs.getString("PROTOCOL"));
|
||||
|
||||
@@ -117,7 +117,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("id") String id){
|
||||
ClientDetails clientDetails =getClientDetailsService().loadClientByClientId(id);
|
||||
ClientDetails clientDetails =getClientDetailsService().loadClientByClientId(id,true);
|
||||
_logger.debug(""+clientDetails);
|
||||
String authorizationUrl = "";
|
||||
try {
|
||||
@@ -169,7 +169,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
"User must be authenticated with Spring Security before authorization can be completed.");
|
||||
}
|
||||
|
||||
ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());
|
||||
ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId(),true);
|
||||
|
||||
// The resolved redirect URI is either the redirect_uri from the parameters or the one from
|
||||
// clientDetails. Either way we need to store it on the AuthorizationRequest.
|
||||
|
||||
@@ -122,7 +122,7 @@ public class TokenEndpoint extends AbstractEndpoint {
|
||||
}
|
||||
|
||||
String clientId = getClientId((Authentication)principal);
|
||||
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
|
||||
ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId,true);
|
||||
|
||||
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
|
||||
Collections.<String, String> emptyMap(), clientId, scopes, null, null, false, state, redirectUri,
|
||||
responseTypes,codeChallenge,codeChallengeMethod);
|
||||
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId,true);
|
||||
request.setResourceIdsAndAuthoritiesFromClientDetails(clientDetails);
|
||||
|
||||
return request;
|
||||
@@ -133,7 +133,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
|
||||
|
||||
private Set<String> extractScopes(Map<String, String> requestParameters, String clientId) {
|
||||
Set<String> scopes = OAuth2Utils.parseParameterList(requestParameters.get(OAuth2Constants.PARAMETER.SCOPE));
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId,true);
|
||||
|
||||
if ((scopes == null || scopes.isEmpty())) {
|
||||
// If no scopes are specified in the incoming data, use the default values registered with the client
|
||||
|
||||
@@ -57,7 +57,7 @@ public abstract class AbstractTokenGranter implements TokenGranter {
|
||||
}
|
||||
|
||||
String clientId = tokenRequest.getClientId();
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientId,true);
|
||||
validateGrantType(grantType, client);
|
||||
|
||||
logger.debug("Getting access token for: " + clientId);
|
||||
|
||||
@@ -244,7 +244,7 @@ public class DefaultTokenServices implements AuthorizationServerTokenServices, R
|
||||
if (clientDetailsService != null) {
|
||||
String clientId = result.getOAuth2Request().getClientId();
|
||||
try {
|
||||
clientDetailsService.loadClientByClientId(clientId);
|
||||
clientDetailsService.loadClientByClientId(clientId,true);
|
||||
}
|
||||
catch (ClientRegistrationException e) {
|
||||
throw new InvalidTokenException("Client not valid: " + clientId, e);
|
||||
@@ -310,7 +310,7 @@ public class DefaultTokenServices implements AuthorizationServerTokenServices, R
|
||||
*/
|
||||
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
|
||||
if (clientDetailsService != null) {
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
|
||||
Integer validity = client.getAccessTokenValiditySeconds();
|
||||
if (validity != null) {
|
||||
return validity;
|
||||
@@ -327,7 +327,7 @@ public class DefaultTokenServices implements AuthorizationServerTokenServices, R
|
||||
*/
|
||||
protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
|
||||
if (clientDetailsService != null) {
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
|
||||
Integer validity = client.getRefreshTokenValiditySeconds();
|
||||
if (validity != null) {
|
||||
return validity;
|
||||
@@ -345,7 +345,7 @@ public class DefaultTokenServices implements AuthorizationServerTokenServices, R
|
||||
*/
|
||||
protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
|
||||
if (clientDetailsService != null) {
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
|
||||
return client.getAuthorizedGrantTypes().contains("refresh_token");
|
||||
}
|
||||
return this.supportRefreshToken;
|
||||
|
||||
@@ -19,24 +19,41 @@ package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.authn.SigninPrincipal;
|
||||
import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.util.JsonUtils;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
import org.maxkey.web.WebConstants;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class OAuthDefaultUserInfoAdapter extends AbstractAuthorizeAdapter {
|
||||
final static Logger _logger = LoggerFactory.getLogger(OAuthDefaultUserInfoAdapter.class);
|
||||
ClientDetails clientDetails;
|
||||
|
||||
public OAuthDefaultUserInfoAdapter() {}
|
||||
|
||||
public OAuthDefaultUserInfoAdapter(ClientDetails clientDetails) {
|
||||
this.clientDetails = clientDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateInfo(SigninPrincipal authentication,UserInfo userInfo,Object app) {
|
||||
public Object generateInfo() {
|
||||
String subject = AbstractAuthorizeAdapter.getValueByUserAttr(userInfo, clientDetails.getSubject());
|
||||
_logger.debug("userId : {} , username : {} , displayName : {} , subject : {}" ,
|
||||
userInfo.getId(),
|
||||
userInfo.getUsername(),
|
||||
userInfo.getDisplayName(),
|
||||
subject);
|
||||
|
||||
HashMap<String, Object> beanMap = new HashMap<String, Object>();
|
||||
beanMap.put("randomId",(new StringGenerator()).uuidGenerate());
|
||||
beanMap.put("userId", userInfo.getId());
|
||||
//for spring security oauth2
|
||||
beanMap.put("user", userInfo.getUsername());
|
||||
beanMap.put("username", userInfo.getUsername());
|
||||
beanMap.put("user", subject);
|
||||
beanMap.put("username", subject);
|
||||
|
||||
beanMap.put("displayName", userInfo.getDisplayName());
|
||||
beanMap.put("employeeNumber", userInfo.getEmployeeNumber());
|
||||
beanMap.put("email", userInfo.getEmail());
|
||||
beanMap.put("mobile", userInfo.getMobile());
|
||||
@@ -56,15 +73,11 @@ public class OAuthDefaultUserInfoAdapter extends AbstractAuthorizeAdapter {
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String data, String algorithmKey, String algorithm) {
|
||||
return null;
|
||||
public ClientDetails getClientDetails() {
|
||||
return clientDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) {
|
||||
|
||||
return null;
|
||||
public void setClientDetails(ClientDetails clientDetails) {
|
||||
this.clientDetails = clientDetails;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
|
||||
package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.maxkey.authn.SigninPrincipal;
|
||||
import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
||||
import org.maxkey.authz.oauth2.common.OAuth2Constants;
|
||||
@@ -29,12 +33,9 @@ import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
|
||||
import org.maxkey.authz.oauth2.provider.token.DefaultTokenServices;
|
||||
import org.maxkey.constants.ConstsBoolean;
|
||||
import org.maxkey.crypto.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.RecipientJwtEncryptionAndDecryptionServiceBuilder;
|
||||
import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.entity.apps.Apps;
|
||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.persistence.service.AppsService;
|
||||
import org.maxkey.persistence.service.UserInfoService;
|
||||
import org.maxkey.util.AuthorizationHeaderUtils;
|
||||
@@ -51,6 +52,7 @@ import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@@ -66,7 +68,6 @@ public class UserInfoEndpoint {
|
||||
@Qualifier("oauth20TokenServices")
|
||||
private DefaultTokenServices oauth20tokenServices;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("userInfoService")
|
||||
private UserInfoService userInfoService;
|
||||
@@ -74,25 +75,7 @@ public class UserInfoEndpoint {
|
||||
@Autowired
|
||||
@Qualifier("appsService")
|
||||
protected AppsService appsService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("jwtSignerValidationService")
|
||||
private JwtSigningAndValidationService jwtSignerValidationService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("jwtEncryptionService")
|
||||
private JwtEncryptionAndDecryptionService jwtEnDecryptionService;
|
||||
|
||||
|
||||
|
||||
private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder
|
||||
=new SymmetricSigningAndValidationServiceBuilder();
|
||||
|
||||
private RecipientJwtEncryptionAndDecryptionServiceBuilder recipientJwtEnDecryptionServiceBuilder
|
||||
=new RecipientJwtEncryptionAndDecryptionServiceBuilder();
|
||||
|
||||
OAuthDefaultUserInfoAdapter defaultOAuthUserInfoAdapter=new OAuthDefaultUserInfoAdapter();
|
||||
|
||||
@Autowired
|
||||
protected HttpResponseAdapter httpResponseAdapter;
|
||||
|
||||
@@ -128,20 +111,29 @@ public class UserInfoEndpoint {
|
||||
principal=((SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal()).getUsername();
|
||||
|
||||
String client_id= oAuth2Authentication.getOAuth2Request().getClientId();
|
||||
ClientDetails clientDetails =
|
||||
clientDetailsService.loadClientByClientId(client_id,true);
|
||||
|
||||
UserInfo userInfo=queryUserInfo(principal);
|
||||
Apps app=appsService.get(client_id);
|
||||
Apps app = appsService.get(client_id);
|
||||
|
||||
AbstractAuthorizeAdapter adapter;
|
||||
if(ConstsBoolean.isTrue(app.getIsAdapter())){
|
||||
adapter =(AbstractAuthorizeAdapter)Instance.newInstance(app.getAdapter());
|
||||
try {
|
||||
BeanUtils.setProperty(adapter, "clientDetails", clientDetails);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
_logger.error("setProperty error . ", e);
|
||||
}
|
||||
}else{
|
||||
adapter =(AbstractAuthorizeAdapter)defaultOAuthUserInfoAdapter;
|
||||
adapter =(AbstractAuthorizeAdapter)new OAuthDefaultUserInfoAdapter(clientDetails);
|
||||
}
|
||||
adapter.setAuthentication((SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal());
|
||||
adapter.setUserInfo(userInfo);
|
||||
adapter.setApp(app);
|
||||
|
||||
String jsonData=adapter.generateInfo(
|
||||
(SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal(),
|
||||
userInfo, app);
|
||||
httpResponseAdapter.write(response,jsonData,"json");
|
||||
Object jsonData = adapter.generateInfo();
|
||||
httpResponseAdapter.write(response,jsonData.toString(),"json");
|
||||
}catch(OAuth2Exception e){
|
||||
HashMap<String,Object>authzException=new HashMap<String,Object>();
|
||||
authzException.put(OAuth2Exception.ERROR, e.getOAuth2ErrorCode());
|
||||
@@ -175,15 +167,4 @@ public class UserInfoEndpoint {
|
||||
this.userInfoService = userInfoService;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// public void setJwtSignerValidationService(
|
||||
// JwtSigningAndValidationService jwtSignerValidationService) {
|
||||
// this.jwtSignerValidationService = jwtSignerValidationService;
|
||||
// }
|
||||
//
|
||||
// public void setJwtEnDecryptionService(
|
||||
// JwtEncryptionAndDecryptionService jwtEnDecryptionService) {
|
||||
// this.jwtEnDecryptionService = jwtEnDecryptionService;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -24,18 +26,19 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.maxkey.authn.SigninPrincipal;
|
||||
import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
||||
import org.maxkey.authz.oauth2.common.OAuth2Constants;
|
||||
import org.maxkey.authz.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
|
||||
import org.maxkey.authz.oauth2.provider.token.DefaultTokenServices;
|
||||
import org.maxkey.constants.ContentType;
|
||||
import org.maxkey.crypto.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.RecipientJwtEncryptionAndDecryptionServiceBuilder;
|
||||
import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.maxkey.entity.UserInfo;
|
||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.persistence.service.AppsService;
|
||||
@@ -54,14 +57,18 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWEHeader;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.EncryptedJWT;
|
||||
import com.nimbusds.jose.Payload;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTClaimsSet.Builder;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
@@ -69,8 +76,8 @@ import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
@Tag(name = "2-1-OAuth v2.0 API文档模块")
|
||||
@Controller
|
||||
public class OpenIdConnectUserInfoEndpoint {
|
||||
final static Logger _logger = LoggerFactory.getLogger(OpenIdConnectUserInfoEndpoint.class);
|
||||
public class UserInfoOIDCEndpoint {
|
||||
final static Logger _logger = LoggerFactory.getLogger(UserInfoOIDCEndpoint.class);
|
||||
@Autowired
|
||||
@Qualifier("oauth20JdbcClientDetailsService")
|
||||
private ClientDetailsService clientDetailsService;
|
||||
@@ -88,22 +95,6 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
@Qualifier("appsService")
|
||||
protected AppsService appsService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("jwtSignerValidationService")
|
||||
private JwtSigningAndValidationService jwtSignerValidationService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("jwtEncryptionService")
|
||||
private JwtEncryptionAndDecryptionService jwtEnDecryptionService;
|
||||
|
||||
|
||||
|
||||
private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder
|
||||
=new SymmetricSigningAndValidationServiceBuilder();
|
||||
|
||||
private RecipientJwtEncryptionAndDecryptionServiceBuilder recipientJwtEnDecryptionServiceBuilder
|
||||
=new RecipientJwtEncryptionAndDecryptionServiceBuilder();
|
||||
|
||||
OAuthDefaultUserInfoAdapter defaultOAuthUserInfoAdapter=new OAuthDefaultUserInfoAdapter();
|
||||
|
||||
@Autowired
|
||||
@@ -127,23 +118,31 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
|
||||
principal=((SigninPrincipal)oAuth2Authentication.getPrincipal()).getUsername();
|
||||
|
||||
Set<String >scopes=oAuth2Authentication.getOAuth2Request().getScope();
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(oAuth2Authentication.getOAuth2Request().getClientId());
|
||||
Set<String >scopes = oAuth2Authentication.getOAuth2Request().getScope();
|
||||
ClientDetails clientDetails =
|
||||
clientDetailsService.loadClientByClientId(oAuth2Authentication.getOAuth2Request().getClientId(),true);
|
||||
|
||||
UserInfo userInfo=queryUserInfo(principal);
|
||||
String userJson="";
|
||||
UserInfo userInfo = queryUserInfo(principal);
|
||||
String userJson = "";
|
||||
Builder jwtClaimsSetBuilder= new JWTClaimsSet.Builder();
|
||||
|
||||
SigninPrincipal authentication = (SigninPrincipal)oAuth2Authentication.getUserAuthentication().getPrincipal();
|
||||
|
||||
jwtClaimsSetBuilder.claim("sub", userInfo.getId());
|
||||
String subject = AbstractAuthorizeAdapter.getValueByUserAttr(userInfo, clientDetails.getSubject());
|
||||
_logger.debug("userId : {} , username : {} , displayName : {} , subject : {}" ,
|
||||
userInfo.getId(),
|
||||
userInfo.getUsername(),
|
||||
userInfo.getDisplayName(),
|
||||
subject);
|
||||
|
||||
jwtClaimsSetBuilder.claim("sub", subject);
|
||||
jwtClaimsSetBuilder.claim("institution", userInfo.getInstId());
|
||||
jwtClaimsSetBuilder.claim(WebConstants.ONLINE_TICKET_NAME, authentication.getOnlineTicket().getTicketId());
|
||||
|
||||
if(scopes.contains("profile")){
|
||||
jwtClaimsSetBuilder.claim("userId", userInfo.getId());
|
||||
jwtClaimsSetBuilder.claim("user", userInfo.getUsername());
|
||||
jwtClaimsSetBuilder.claim("name", userInfo.getUsername());
|
||||
jwtClaimsSetBuilder.claim("name", userInfo.getDisplayName());
|
||||
jwtClaimsSetBuilder.claim("preferred_username", userInfo.getDisplayName());
|
||||
jwtClaimsSetBuilder.claim("given_name", userInfo.getGivenName());
|
||||
jwtClaimsSetBuilder.claim("family_name", userInfo.getFamilyName());
|
||||
@@ -151,7 +150,8 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
jwtClaimsSetBuilder.claim("nickname", userInfo.getNickName());
|
||||
jwtClaimsSetBuilder.claim("profile", "profile");
|
||||
jwtClaimsSetBuilder.claim("picture", "picture");
|
||||
jwtClaimsSetBuilder.claim("website", userInfo.getWebSite());
|
||||
//jwtClaimsSetBuilder.claim("website", userInfo.getWebSite());
|
||||
jwtClaimsSetBuilder.claim("displayName", userInfo.getDisplayName());
|
||||
|
||||
jwtClaimsSetBuilder.claim("departmentId", userInfo.getDepartmentId());
|
||||
jwtClaimsSetBuilder.claim("department", userInfo.getDepartment());
|
||||
@@ -198,69 +198,88 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
.jwtID(UUID.randomUUID().toString())// set a random NONCE in the middle of it
|
||||
.audience(Arrays.asList(clientDetails.getClientId()))
|
||||
.issueTime(new Date())
|
||||
.expirationTime(new Date(new Date().getTime()+clientDetails.getAccessTokenValiditySeconds()*1000));
|
||||
.expirationTime(new Date(new Date().getTime() + clientDetails.getAccessTokenValiditySeconds() * 1000));
|
||||
|
||||
//default ContentType
|
||||
response.setContentType(ContentType.APPLICATION_JWT_UTF8);
|
||||
|
||||
JWTClaimsSet userInfoJWTClaims = jwtClaimsSetBuilder.build();
|
||||
JWT userInfoJWT=null;
|
||||
JWSAlgorithm signingAlg = jwtSignerValidationService.getDefaultSigningAlgorithm();
|
||||
if (clientDetails.getUserInfoEncryptedAlgorithm() != null
|
||||
&& !clientDetails.getUserInfoEncryptedAlgorithm().equals("none")
|
||||
&& clientDetails.getUserInfoEncryptionMethod() != null
|
||||
&& !clientDetails.getUserInfoEncryptionMethod().equals("none")
|
||||
&&clientDetails.getJwksUri()!=null&&clientDetails.getJwksUri().length()>4
|
||||
) {
|
||||
//需要加密
|
||||
response.setContentType(ContentType.APPLICATION_JWT_UTF8);
|
||||
JwtEncryptionAndDecryptionService recipientJwtEnDecryptionService =
|
||||
recipientJwtEnDecryptionServiceBuilder.serviceBuilder(clientDetails.getJwksUri());
|
||||
|
||||
if (recipientJwtEnDecryptionService != null) {
|
||||
JWEAlgorithm jweAlgorithm=new JWEAlgorithm(clientDetails.getUserInfoEncryptedAlgorithm());
|
||||
EncryptionMethod encryptionMethod=new EncryptionMethod(clientDetails.getUserInfoEncryptionMethod());
|
||||
EncryptedJWT encryptedJWT = new EncryptedJWT(new JWEHeader(jweAlgorithm, encryptionMethod), userInfoJWTClaims);
|
||||
recipientJwtEnDecryptionService.encryptJwt(encryptedJWT);
|
||||
userJson=encryptedJWT.serialize();
|
||||
}else{
|
||||
_logger.error("Couldn't find encrypter for client: " + clientDetails.getClientId());
|
||||
HashMap<String,Object>authzException=new HashMap<String,Object>();
|
||||
authzException.put(OAuth2Exception.ERROR, "error");
|
||||
authzException.put(OAuth2Exception.DESCRIPTION,"Couldn't find encrypter for client: " + clientDetails.getClientId());
|
||||
return JsonUtils.gson2Json(authzException);
|
||||
}
|
||||
}else if (clientDetails.getUserInfoSigningAlgorithm()!=null
|
||||
&& !clientDetails.getUserInfoSigningAlgorithm().equals("none")) {
|
||||
//需要签名
|
||||
response.setContentType(ContentType.APPLICATION_JWT_UTF8);
|
||||
// signed ID token
|
||||
if (signingAlg.equals(JWSAlgorithm.HS256)
|
||||
|| signingAlg.equals(JWSAlgorithm.HS384)
|
||||
|| signingAlg.equals(JWSAlgorithm.HS512)) {
|
||||
// sign it with the client's secret
|
||||
String client_secret=PasswordReciprocal.getInstance().decoder(clientDetails.getClientSecret());
|
||||
|
||||
JwtSigningAndValidationService symmetricJwtSignerService =symmetricJwtSignerServiceBuilder.serviceBuilder(client_secret);
|
||||
if(symmetricJwtSignerService!=null){
|
||||
userInfoJWTClaims = new JWTClaimsSet.Builder(userInfoJWTClaims).claim("kid", "SYMMETRIC-KEY").build();
|
||||
userInfoJWT = new SignedJWT(new JWSHeader(signingAlg), userInfoJWTClaims);
|
||||
symmetricJwtSignerService.signJwt((SignedJWT) userInfoJWT);
|
||||
}else{
|
||||
_logger.error("Couldn't create symmetric validator for client " + clientDetails.getClientId() + " without a client secret");
|
||||
}
|
||||
} else {
|
||||
userInfoJWTClaims = new JWTClaimsSet.Builder(userInfoJWTClaims).claim("kid", jwtSignerValidationService.getDefaultSignerKeyId()).build();
|
||||
userInfoJWT = new SignedJWT(new JWSHeader(signingAlg), userInfoJWTClaims);
|
||||
// sign it with the server's key
|
||||
jwtSignerValidationService.signJwt((SignedJWT) userInfoJWT);
|
||||
|
||||
if(clientDetails.getUserInfoResponse().equalsIgnoreCase("NORMAL")) {
|
||||
response.setContentType(ContentType.APPLICATION_JSON_UTF8);
|
||||
userJson = userInfoJWTClaims.toString();
|
||||
}else if (StringUtils.isNotBlank(clientDetails.getSignature())
|
||||
&& !clientDetails.getSignature().equalsIgnoreCase("none")
|
||||
&& clientDetails.getUserInfoResponse().equalsIgnoreCase("ENCRYPTION")) {
|
||||
//需要签名 signed ID token
|
||||
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getSignatureKey()+"]}");
|
||||
DefaultJwtSigningAndValidationService jwtSignerService = null;
|
||||
try {
|
||||
jwtSignerService = new DefaultJwtSigningAndValidationService(jwkSetKeyStore);
|
||||
}catch(Exception e) {
|
||||
_logger.error("Couldn't create Jwt Signing Service",e);
|
||||
}
|
||||
|
||||
jwtSignerService.setDefaultSignerKeyId(clientDetails.getClientId() + "_sig");
|
||||
jwtSignerService.setDefaultSigningAlgorithmName(clientDetails.getSignature());
|
||||
|
||||
JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
|
||||
_logger.trace(" signingAlg {}" , signingAlg);
|
||||
userInfoJWTClaims = new JWTClaimsSet
|
||||
.Builder(userInfoJWTClaims)
|
||||
.claim("kid", jwtSignerService.getDefaultSignerKeyId())
|
||||
.build();
|
||||
|
||||
userInfoJWT = new SignedJWT(new JWSHeader(signingAlg), userInfoJWTClaims);
|
||||
// sign it with the server's key
|
||||
jwtSignerService.signJwt((SignedJWT) userInfoJWT);
|
||||
|
||||
userJson = userInfoJWT.serialize();
|
||||
}else if (StringUtils.isNotBlank(clientDetails.getAlgorithm())
|
||||
&& !clientDetails.getAlgorithm().equalsIgnoreCase("none")
|
||||
&& clientDetails.getUserInfoResponse().equalsIgnoreCase("SIGNING")
|
||||
) {
|
||||
//TODO: 需要加密
|
||||
JWKSetKeyStore jwkSetKeyStore_Enc = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getAlgorithmKey()+"]}");
|
||||
try {
|
||||
DefaultJwtEncryptionAndDecryptionService jwtEncryptionService =
|
||||
new DefaultJwtEncryptionAndDecryptionService(jwkSetKeyStore_Enc);
|
||||
jwtEncryptionService.setDefaultEncryptionKeyId(clientDetails.getClientId() + "_enc");
|
||||
jwtEncryptionService.setDefaultAlgorithm(clientDetails.getAlgorithm());
|
||||
JWEAlgorithm encryptAlgorithm = null;
|
||||
if(clientDetails.getAlgorithm().startsWith("RSA")) {
|
||||
encryptAlgorithm = jwtEncryptionService.getDefaultAlgorithm();
|
||||
}else {
|
||||
encryptAlgorithm = JWEAlgorithm.DIR;
|
||||
}
|
||||
_logger.trace(" encryptAlgorithm {}" , encryptAlgorithm);
|
||||
EncryptionMethod encryptionMethod =
|
||||
jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod());
|
||||
|
||||
Payload payload = userInfoJWTClaims.toPayload();
|
||||
|
||||
// Example Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM
|
||||
//JWEHeader jweHeader = new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM);
|
||||
|
||||
JWEObject jweObject = new JWEObject(
|
||||
new JWEHeader.Builder(new JWEHeader(encryptAlgorithm,encryptionMethod))
|
||||
.contentType("JWT") // required to indicate nested JWT
|
||||
.build(),
|
||||
payload);
|
||||
|
||||
jwtEncryptionService.encryptJwt(jweObject);
|
||||
userJson = jweObject.serialize();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException | JOSEException e) {
|
||||
_logger.error("Couldn't create Jwt Encryption Exception", e);
|
||||
}
|
||||
userJson=userInfoJWT.serialize();
|
||||
}else {
|
||||
//不需要加密和签名
|
||||
response.setContentType(ContentType.APPLICATION_JSON_UTF8);
|
||||
// unsigned ID token
|
||||
//userInfoJWT = new PlainJWT(userInfoJWTClaims);
|
||||
userJson=JsonUtils.gson2Json(jwtClaimsSetBuilder.getClaims());
|
||||
//不需要加密和签名 unsigned ID token
|
||||
userInfoJWT = new PlainJWT(userInfoJWTClaims);
|
||||
userJson = userInfoJWT.serialize();
|
||||
}
|
||||
|
||||
|
||||
_logger.trace("OpenID Connect Response {}",userJson);
|
||||
return userJson;
|
||||
|
||||
}catch(OAuth2Exception e){
|
||||
@@ -280,9 +299,7 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
}
|
||||
|
||||
public UserInfo queryUserInfo(String userId){
|
||||
_logger.debug("userId : "+userId);
|
||||
UserInfo userInfo = (UserInfo) userInfoService.findByUsername(userId);
|
||||
return userInfo;
|
||||
return (UserInfo) userInfoService.findByUsername(userId);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,16 +312,4 @@ public class OpenIdConnectUserInfoEndpoint {
|
||||
public void setUserInfoService(UserInfoService userInfoService) {
|
||||
this.userInfoService = userInfoService;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// public void setJwtSignerValidationService(
|
||||
// JwtSigningAndValidationService jwtSignerValidationService) {
|
||||
// this.jwtSignerValidationService = jwtSignerValidationService;
|
||||
// }
|
||||
//
|
||||
// public void setJwtEnDecryptionService(
|
||||
// JwtEncryptionAndDecryptionService jwtEnDecryptionService) {
|
||||
// this.jwtEnDecryptionService = jwtEnDecryptionService;
|
||||
// }
|
||||
}
|
||||
@@ -20,11 +20,14 @@
|
||||
*/
|
||||
package org.maxkey.authz.oidc.idtoken;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.maxkey.authz.oauth2.common.DefaultOAuth2AccessToken;
|
||||
@@ -34,11 +37,9 @@ import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2Request;
|
||||
import org.maxkey.authz.oauth2.provider.token.TokenEnhancer;
|
||||
import org.maxkey.configuration.oidc.OIDCProviderMetadata;
|
||||
import org.maxkey.crypto.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.RecipientJwtEncryptionAndDecryptionServiceBuilder;
|
||||
import org.maxkey.crypto.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
|
||||
import org.maxkey.crypto.password.PasswordReciprocal;
|
||||
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
|
||||
import org.maxkey.crypto.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService;
|
||||
import org.maxkey.crypto.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.web.WebContext;
|
||||
|
||||
@@ -47,16 +48,16 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.Algorithm;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWEHeader;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.EncryptedJWT;
|
||||
import com.nimbusds.jose.Payload;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
@@ -64,37 +65,20 @@ import com.nimbusds.jwt.SignedJWT;
|
||||
*
|
||||
*/
|
||||
public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
private final static Logger logger = LoggerFactory.getLogger(OIDCIdTokenEnhancer.class);
|
||||
private final static Logger _logger = LoggerFactory.getLogger(OIDCIdTokenEnhancer.class);
|
||||
|
||||
public final static String ID_TOKEN_SCOPE="openid";
|
||||
|
||||
private OIDCProviderMetadata providerMetadata;
|
||||
|
||||
private JwtSigningAndValidationService jwtSignerService;
|
||||
|
||||
private JwtEncryptionAndDecryptionService jwtEnDecryptionService;
|
||||
|
||||
|
||||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
private SymmetricSigningAndValidationServiceBuilder symmetricJwtSignerServiceBuilder
|
||||
=new SymmetricSigningAndValidationServiceBuilder();
|
||||
|
||||
private RecipientJwtEncryptionAndDecryptionServiceBuilder recipientJwtEnDecryptionServiceBuilder
|
||||
=new RecipientJwtEncryptionAndDecryptionServiceBuilder();
|
||||
|
||||
|
||||
public void setProviderMetadata(OIDCProviderMetadata providerMetadata) {
|
||||
this.providerMetadata = providerMetadata;
|
||||
}
|
||||
|
||||
public void setJwtSignerService(JwtSigningAndValidationService jwtSignerService) {
|
||||
this.jwtSignerService = jwtSignerService;
|
||||
}
|
||||
|
||||
public void setJwtEnDecryptionService(
|
||||
JwtEncryptionAndDecryptionService jwtEnDecryptionService) {
|
||||
this.jwtEnDecryptionService = jwtEnDecryptionService;
|
||||
}
|
||||
|
||||
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
||||
this.clientDetailsService = clientDetailsService;
|
||||
}
|
||||
@@ -103,12 +87,28 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
|
||||
OAuth2Request request=authentication.getOAuth2Request();
|
||||
if (request.getScope().contains(ID_TOKEN_SCOPE)) {//Enhance for OpenID Connect
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authentication.getOAuth2Request().getClientId());
|
||||
ClientDetails clientDetails =
|
||||
clientDetailsService.loadClientByClientId(authentication.getOAuth2Request().getClientId(),true);
|
||||
|
||||
DefaultJwtSigningAndValidationService jwtSignerService = null;
|
||||
JWSAlgorithm signingAlg = null;
|
||||
try {//jwtSignerService
|
||||
if (StringUtils.isNotBlank(clientDetails.getSignature()) && !clientDetails.getSignature().equalsIgnoreCase("none")) {
|
||||
JWKSetKeyStore jwkSetKeyStore = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getSignatureKey()+"]}");
|
||||
jwtSignerService = new DefaultJwtSigningAndValidationService(jwkSetKeyStore);
|
||||
jwtSignerService.setDefaultSignerKeyId(clientDetails.getClientId() + "_sig");
|
||||
jwtSignerService.setDefaultSigningAlgorithmName(clientDetails.getSignature());
|
||||
signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
|
||||
_logger.trace(" signingAlg {}" , signingAlg);
|
||||
}
|
||||
}catch(Exception e) {
|
||||
_logger.error("Couldn't create Jwt Signing Service",e);
|
||||
}
|
||||
|
||||
JWTClaimsSet.Builder builder=new JWTClaimsSet.Builder();
|
||||
builder.subject(authentication.getName())
|
||||
.expirationTime(accessToken.getExpiration())
|
||||
.claim(providerMetadata.getIssuer(), true)
|
||||
.issuer(clientDetails.getIssuer())
|
||||
.issueTime(new Date())
|
||||
.audience(Arrays.asList(authentication.getOAuth2Request().getClientId()))
|
||||
.jwtID(UUID.randomUUID().toString());
|
||||
@@ -118,8 +118,7 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
* @see http://openid.net/specs/openid-connect-core-1_0.html#SelfIssuedDiscovery
|
||||
* 7. Self-Issued OpenID Provider
|
||||
*/
|
||||
|
||||
if(providerMetadata.getIssuer().equalsIgnoreCase("https://self-issued.me")){
|
||||
if(providerMetadata.getIssuer().equalsIgnoreCase("https://self-issued.me") && jwtSignerService != null){
|
||||
builder.claim("sub_jwk", jwtSignerService.getAllPublicKeys().get(jwtSignerService.getDefaultSignerKeyId()));
|
||||
}
|
||||
|
||||
@@ -127,76 +126,79 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
if (request.getExtensions().containsKey("max_age")
|
||||
|| (request.getExtensions().containsKey("idtoken")) // parse the ID Token claims (#473) -- for now assume it could be in there
|
||||
) {
|
||||
DateTime loginDate=DateTime.parse(WebContext.getUserInfo().getLastLoginTime(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
builder.claim("auth_time", loginDate.getMillis()/ 1000);
|
||||
DateTime loginDate = DateTime.parse(WebContext.getUserInfo().getLastLoginTime(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
builder.claim("auth_time", loginDate.getMillis()/1000);
|
||||
}
|
||||
|
||||
String nonce = (String)request.getExtensions().get("nonce");
|
||||
if (!Strings.isNullOrEmpty(nonce)) {
|
||||
builder.claim("nonce", nonce);
|
||||
}
|
||||
|
||||
JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
|
||||
SignedJWT signed = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
Set<String> responseTypes = request.getResponseTypes();
|
||||
|
||||
if (responseTypes.contains("token")) {
|
||||
// calculate the token hash
|
||||
Base64URL at_hash = IdTokenHashUtils.getAccessTokenHash(signingAlg, signed);
|
||||
builder.claim("at_hash", at_hash);
|
||||
}
|
||||
logger.debug("idClaims "+builder.build());
|
||||
|
||||
JWT idToken=null;
|
||||
if (clientDetails.getIdTokenEncryptedAlgorithm() != null && !clientDetails.getIdTokenEncryptedAlgorithm().equals("none")
|
||||
&& clientDetails.getIdTokenEncryptionMethod() != null && !clientDetails.getIdTokenEncryptionMethod().equals("none")
|
||||
&&clientDetails.getJwksUri()!=null&&clientDetails.getJwksUri().length()>4) {
|
||||
|
||||
JwtEncryptionAndDecryptionService recipientJwtEnDecryptionService =
|
||||
recipientJwtEnDecryptionServiceBuilder.serviceBuilder(clientDetails.getJwksUri());
|
||||
|
||||
if (recipientJwtEnDecryptionService != null) {
|
||||
JWEAlgorithm jweAlgorithm=new JWEAlgorithm(clientDetails.getIdTokenEncryptedAlgorithm());
|
||||
EncryptionMethod encryptionMethod=new EncryptionMethod(clientDetails.getIdTokenEncryptionMethod());
|
||||
EncryptedJWT encryptedJWT = new EncryptedJWT(new JWEHeader(jweAlgorithm, encryptionMethod), builder.build());
|
||||
recipientJwtEnDecryptionService.encryptJwt(encryptedJWT);
|
||||
idToken=encryptedJWT;
|
||||
}else{
|
||||
logger.error("Couldn't create Jwt Encryption Service");
|
||||
if(jwtSignerService != null) {
|
||||
SignedJWT signed = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
Set<String> responseTypes = request.getResponseTypes();
|
||||
|
||||
if (responseTypes.contains("token")) {
|
||||
// calculate the token hash
|
||||
Base64URL at_hash = IdTokenHashUtils.getAccessTokenHash(signingAlg, signed);
|
||||
builder.claim("at_hash", at_hash);
|
||||
}
|
||||
} else {
|
||||
if (signingAlg==null||signingAlg.equals(Algorithm.NONE)) {
|
||||
// unsigned ID token
|
||||
idToken = new PlainJWT(builder.build());
|
||||
} else {
|
||||
_logger.debug("idClaims {}",builder.build());
|
||||
}
|
||||
String idTokenString = "";
|
||||
if (StringUtils.isNotBlank(clientDetails.getSignature())
|
||||
&& !clientDetails.getSignature().equalsIgnoreCase("none")) {
|
||||
try {
|
||||
builder.claim("kid", jwtSignerService.getDefaultSignerKeyId());
|
||||
// signed ID token
|
||||
if (signingAlg.equals(JWSAlgorithm.HS256)
|
||||
|| signingAlg.equals(JWSAlgorithm.HS384)
|
||||
|| signingAlg.equals(JWSAlgorithm.HS512)) {
|
||||
// sign it with the client's secret
|
||||
String client_secret=PasswordReciprocal.getInstance().decoder(clientDetails.getClientSecret());
|
||||
|
||||
JwtSigningAndValidationService symmetricJwtSignerService =symmetricJwtSignerServiceBuilder.serviceBuilder(client_secret);
|
||||
if(symmetricJwtSignerService!=null){
|
||||
builder.claim("kid", "SYMMETRIC-KEY");
|
||||
idToken = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
symmetricJwtSignerService.signJwt((SignedJWT) idToken);
|
||||
}else {
|
||||
logger.error("Couldn't create symmetric validator for client " + clientDetails.getClientId() + " without a client secret");
|
||||
}
|
||||
} else {
|
||||
builder.claim("kid", jwtSignerService.getDefaultSignerKeyId());
|
||||
idToken = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
// sign it with the server's key
|
||||
jwtSignerService.signJwt((SignedJWT) idToken);
|
||||
}
|
||||
JWT idToken = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
// sign it with the server's key
|
||||
jwtSignerService.signJwt((SignedJWT) idToken);
|
||||
idTokenString = idToken.serialize();
|
||||
_logger.debug("idToken {}",idTokenString);
|
||||
}catch(Exception e) {
|
||||
_logger.error("Couldn't create Jwt Signing Exception",e);
|
||||
}
|
||||
}else if (StringUtils.isNotBlank(clientDetails.getAlgorithm())
|
||||
&& !clientDetails.getAlgorithm().equalsIgnoreCase("none")) {
|
||||
JWKSetKeyStore jwkSetKeyStore_Enc = new JWKSetKeyStore("{\"keys\": ["+clientDetails.getAlgorithmKey()+"]}");
|
||||
try {
|
||||
DefaultJwtEncryptionAndDecryptionService jwtEncryptionService =
|
||||
new DefaultJwtEncryptionAndDecryptionService(jwkSetKeyStore_Enc);
|
||||
jwtEncryptionService.setDefaultEncryptionKeyId(clientDetails.getClientId() + "_enc");
|
||||
jwtEncryptionService.setDefaultAlgorithm(clientDetails.getAlgorithm());
|
||||
JWEAlgorithm encryptAlgorithm = null;
|
||||
if(clientDetails.getAlgorithm().startsWith("RSA")) {
|
||||
encryptAlgorithm = jwtEncryptionService.getDefaultAlgorithm();
|
||||
}else {
|
||||
encryptAlgorithm = JWEAlgorithm.DIR;
|
||||
}
|
||||
_logger.trace(" encryptAlgorithm {}" , encryptAlgorithm);
|
||||
EncryptionMethod encryptionMethod =
|
||||
jwtEncryptionService.parseEncryptionMethod(clientDetails.getEncryptionMethod());
|
||||
|
||||
Payload payload = builder.build().toPayload();
|
||||
// Example Request JWT encrypted with RSA-OAEP-256 and 128-bit AES/GCM
|
||||
//JWEHeader jweHeader = new JWEHeader(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM);
|
||||
JWEObject jweObject = new JWEObject(
|
||||
new JWEHeader.Builder(new JWEHeader(encryptAlgorithm,encryptionMethod))
|
||||
.contentType("JWT") // required to indicate nested JWT
|
||||
.build(),
|
||||
payload);
|
||||
jwtEncryptionService.encryptJwt(jweObject);
|
||||
idTokenString = jweObject.serialize();
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException | JOSEException e) {
|
||||
_logger.error("Couldn't create Jwt Encryption Exception", e);
|
||||
}
|
||||
}else {
|
||||
//not need a PlainJWT idToken
|
||||
//JWT idToken = new PlainJWT(builder.build());
|
||||
//idTokenString = idToken.serialize();
|
||||
}
|
||||
logger.debug("idToken "+idToken);
|
||||
|
||||
accessToken = new DefaultOAuth2AccessToken(accessToken);
|
||||
if(idToken!=null){
|
||||
accessToken.getAdditionalInformation().put("id_token", idToken.serialize());
|
||||
if(StringUtils.isNotBlank(idTokenString)){
|
||||
accessToken.getAdditionalInformation().put("id_token", idTokenString);
|
||||
}
|
||||
}
|
||||
return accessToken;
|
||||
|
||||
@@ -166,13 +166,9 @@ public class Oauth20AutoConfiguration implements InitializingBean {
|
||||
*/
|
||||
@Bean(name = "tokenEnhancer")
|
||||
public OIDCIdTokenEnhancer tokenEnhancer(
|
||||
DefaultJwtSigningAndValidationService jwtSignerValidationService,
|
||||
DefaultJwtEncryptionAndDecryptionService jwtEncryptionService,
|
||||
OIDCProviderMetadataDetails oidcProviderMetadata,
|
||||
ClientDetailsService oauth20JdbcClientDetailsService) {
|
||||
OIDCIdTokenEnhancer tokenEnhancer = new OIDCIdTokenEnhancer();
|
||||
tokenEnhancer.setJwtSignerService(jwtSignerValidationService);
|
||||
tokenEnhancer.setJwtEnDecryptionService(jwtEncryptionService);
|
||||
tokenEnhancer.setClientDetailsService(oauth20JdbcClientDetailsService);
|
||||
tokenEnhancer.setProviderMetadata(oidcProviderMetadata);
|
||||
_logger.debug("OIDC IdToken Enhancer init.");
|
||||
|
||||
Reference in New Issue
Block a user