protocl fix
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package org.maxkey.authz.oauth2.provider.approval.controller;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
|
||||
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
import org.maxkey.authz.oauth2.provider.approval.Approval;
|
||||
import org.maxkey.authz.oauth2.provider.approval.ApprovalStore;
|
||||
import org.maxkey.authz.oauth2.provider.approval.Approval.ApprovalStatus;
|
||||
import org.maxkey.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Controller for retrieving the model for and displaying the confirmation page
|
||||
* for access to a protected resource.
|
||||
*
|
||||
* @author Ryan Heaton
|
||||
*/
|
||||
@Controller
|
||||
@SessionAttributes("authorizationRequest")
|
||||
public class OAuth20AccessConfirmationController {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20JdbcClientDetailsService")
|
||||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20ApprovalStore")
|
||||
private ApprovalStore approvalStore;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20UserApprovalHandler")
|
||||
OAuth20UserApprovalHandler oauth20UserApprovalHandler;
|
||||
|
||||
|
||||
@RequestMapping("/oauth/v20/approval_confirm")
|
||||
public ModelAndView getAccessConfirmation(@RequestParam Map<String, Object> model) throws Exception {
|
||||
model.remove("authorizationRequest");
|
||||
Map<String, String> modelRequest=new HashMap<String, String>();
|
||||
for(Object key:model.keySet()){
|
||||
modelRequest.put(key.toString(), model.get(key).toString());
|
||||
}
|
||||
Principal principal=(Principal)WebContext.getAuthentication().getPrincipal();
|
||||
|
||||
//Map<String, Object> model
|
||||
AuthorizationRequest clientAuth = (AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
|
||||
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||
model.put("auth_request", clientAuth);
|
||||
model.put("client", client);
|
||||
model.put("oauth_version", "oauth 2.0");
|
||||
Map<String, String> scopes = new LinkedHashMap<String, String>();
|
||||
for (String scope : clientAuth.getScope()) {
|
||||
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
|
||||
}
|
||||
for (Approval approval : approvalStore.getApprovals(principal.getName(), client.getClientId())) {
|
||||
if (clientAuth.getScope().contains(approval.getScope())) {
|
||||
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
|
||||
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
|
||||
}
|
||||
}
|
||||
model.put("scopes", scopes);
|
||||
|
||||
ModelAndView modelAndView=new ModelAndView("authorize/oauth_access_confirmation");
|
||||
modelAndView.addObject("model",model);
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@RequestMapping("/oauth/v20/error")
|
||||
public String handleError(Map<String,Object> model) throws Exception {
|
||||
// We can add more stuff to the model here for JSP rendering. If the client was a machine then
|
||||
// the JSON will already have been rendered.
|
||||
model.put("message", "There was a problem with the OAuth2 protocol");
|
||||
return "oauth_error";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.maxkey.authz.oauth2.provider.approval.controller;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
import org.maxkey.authz.oauth2.provider.ClientRegistrationException;
|
||||
import org.maxkey.authz.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
|
||||
import org.maxkey.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class OAuth20UserApprovalHandler extends ApprovalStoreUserApprovalHandler {
|
||||
|
||||
private boolean useApprovalStore = true;
|
||||
|
||||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
/**
|
||||
* Service to load client details (optional) for auto approval checks.
|
||||
*
|
||||
* @param clientDetailsService a client details service
|
||||
*/
|
||||
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
||||
this.clientDetailsService = clientDetailsService;
|
||||
super.setClientDetailsService(clientDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param useApprovalStore the useTokenServices to set
|
||||
*/
|
||||
public void setUseApprovalStore(boolean useApprovalStore) {
|
||||
this.useApprovalStore = useApprovalStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows automatic approval for a white list of clients in the implicit grant case.
|
||||
*
|
||||
* @param authorizationRequest The authorization request.
|
||||
* @param userAuthentication the current user authentication
|
||||
*
|
||||
* @return An updated request if it has already been approved by the current user.
|
||||
*/
|
||||
@Override
|
||||
public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
|
||||
Authentication userAuthentication) {
|
||||
|
||||
boolean approved = false;
|
||||
// If we are allowed to check existing approvals this will short circuit the decision
|
||||
if (useApprovalStore) {
|
||||
authorizationRequest = super.checkForPreApproval(authorizationRequest, userAuthentication);
|
||||
approved = authorizationRequest.isApproved();
|
||||
}
|
||||
else {
|
||||
if (clientDetailsService != null) {
|
||||
Collection<String> requestedScopes = authorizationRequest.getScope();
|
||||
try {
|
||||
ClientDetails client = clientDetailsService
|
||||
.loadClientByClientId(authorizationRequest.getClientId());
|
||||
for (String scope : requestedScopes) {
|
||||
if (client.isAutoApprove(scope) || client.isAutoApprove("all")) {
|
||||
approved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ClientRegistrationException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
authorizationRequest.setApproved(approved);
|
||||
|
||||
return authorizationRequest;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,13 +16,26 @@
|
||||
package org.maxkey.authz.oauth2.provider.endpoint;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
import org.maxkey.authz.oauth2.provider.CompositeTokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2RequestFactory;
|
||||
import org.maxkey.authz.oauth2.provider.TokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.client.ClientCredentialsTokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeServices;
|
||||
import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeTokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.code.InMemoryAuthorizationCodeServices;
|
||||
import org.maxkey.authz.oauth2.provider.implicit.ImplicitTokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.refresh.RefreshTokenGranter;
|
||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
|
||||
import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -34,14 +47,46 @@ public class AbstractEndpoint implements InitializingBean {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private TokenGranter tokenGranter;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20AuthorizationCodeServices")
|
||||
protected AuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices();
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20TokenServices")
|
||||
AuthorizationServerTokenServices tokenServices ;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20JdbcClientDetailsService")
|
||||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oAuth2RequestFactory")
|
||||
private OAuth2RequestFactory oAuth2RequestFactory;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oAuth2RequestFactory")
|
||||
private OAuth2RequestFactory defaultOAuth2RequestFactory;
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (tokenGranter == null) {
|
||||
//ClientDetailsService clientDetails = clientDetailsService();
|
||||
//AuthorizationServerTokenServices tokenServices = tokenServices();
|
||||
//AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
|
||||
//OAuth2RequestFactory requestFactory = requestFactory();
|
||||
|
||||
List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
|
||||
tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices,
|
||||
clientDetailsService, oAuth2RequestFactory));
|
||||
tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory));
|
||||
ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory);
|
||||
tokenGranters.add(implicit);
|
||||
tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory));
|
||||
/*if (authenticationManager != null) {
|
||||
tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
|
||||
clientDetails, requestFactory));
|
||||
}*/
|
||||
tokenGranter = new CompositeTokenGranter(tokenGranters);
|
||||
}
|
||||
Assert.state(tokenGranter != null, "TokenGranter must be provided");
|
||||
Assert.state(clientDetailsService != null, "ClientDetailsService must be provided");
|
||||
defaultOAuth2RequestFactory = new DefaultOAuth2RequestFactory(getClientDetailsService());
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.maxkey.authz.oauth2.provider.code.InMemoryAuthorizationCodeServices;
|
||||
import org.maxkey.authz.oauth2.provider.implicit.ImplicitTokenRequest;
|
||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
||||
import org.maxkey.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -82,7 +83,7 @@ import org.springframework.web.util.UriTemplate;
|
||||
@SessionAttributes("authorizationRequest")
|
||||
public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
|
||||
private AuthorizationCodeServices authorizationCodeServices = new InMemoryAuthorizationCodeServices();
|
||||
|
||||
|
||||
private RedirectResolver redirectResolver = new DefaultRedirectResolver();
|
||||
|
||||
@@ -92,7 +93,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
|
||||
private OAuth2RequestValidator oauth2RequestValidator = new DefaultOAuth2RequestValidator();
|
||||
|
||||
private String userApprovalPage = "forward:/oauth/v20/confirm_access";
|
||||
private String userApprovalPage = "forward:/oauth/v20/approval_confirm";
|
||||
|
||||
private String errorPage = "forward:/oauth/error";
|
||||
|
||||
@@ -108,8 +109,8 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
|
||||
@RequestMapping(value = "/oauth/v20/authorize", method = RequestMethod.GET)
|
||||
public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
|
||||
SessionStatus sessionStatus, Principal principal) {
|
||||
|
||||
SessionStatus sessionStatus) {
|
||||
Principal principal=(Principal)WebContext.getAuthentication().getPrincipal();
|
||||
// Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
|
||||
// query off of the authorization request instead of referring back to the parameters map. The contents of the
|
||||
// parameters map will be stored without change in the AuthorizationRequest object once it is created.
|
||||
@@ -187,8 +188,8 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
||||
|
||||
@RequestMapping(value = "/oauth/v20/authorize", method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
|
||||
public View approveOrDeny(@RequestParam Map<String, String> approvalParameters, Map<String, ?> model,
|
||||
SessionStatus sessionStatus, Principal principal) {
|
||||
|
||||
SessionStatus sessionStatus) {
|
||||
Principal principal=(Principal)WebContext.getAuthentication().getPrincipal();
|
||||
if (!(principal instanceof Authentication)) {
|
||||
sessionStatus.setComplete();
|
||||
throw new InsufficientAuthenticationException(
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.maxkey.authz.oauth2.provider.TokenRequest;
|
||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
||||
import org.maxkey.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -81,18 +82,21 @@ public class TokenEndpoint extends AbstractEndpoint {
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
*/
|
||||
@RequestMapping(value = "/oauth/v20/token", method=RequestMethod.GET)
|
||||
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam
|
||||
public ResponseEntity<OAuth2AccessToken> getAccessToken(@RequestParam
|
||||
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
|
||||
if (!allowedRequestMethods.contains(HttpMethod.GET)) {
|
||||
throw new HttpRequestMethodNotSupportedException("GET");
|
||||
}
|
||||
return postAccessToken(principal, parameters);
|
||||
return postAccessToken(parameters);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "/oauth/v20/token", method=RequestMethod.POST)
|
||||
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam
|
||||
public ResponseEntity<OAuth2AccessToken> postAccessToken(@RequestParam
|
||||
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
// TokenEndpointAuthenticationFilter
|
||||
Principal principal=(Principal)WebContext.getAuthentication().getPrincipal();
|
||||
|
||||
if (!(principal instanceof Authentication)) {
|
||||
throw new InsufficientAuthenticationException(
|
||||
"There is no client authentication. Try adding an appropriate authentication filter.");
|
||||
@@ -161,7 +165,7 @@ public class TokenEndpoint extends AbstractEndpoint {
|
||||
if (!client.isAuthenticated()) {
|
||||
throw new InsufficientAuthenticationException("The client is not authenticated.");
|
||||
}
|
||||
String clientId = client.getName();
|
||||
String clientId = client.getPrincipal().toString();
|
||||
if (client instanceof OAuth2Authentication) {
|
||||
// Might be a client and user combined authentication
|
||||
clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId();
|
||||
|
||||
@@ -32,11 +32,13 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.maxkey.authn.BasicAuthentication;
|
||||
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
|
||||
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2Request;
|
||||
import org.maxkey.authz.oauth2.provider.OAuth2RequestFactory;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
@@ -45,9 +47,11 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -74,11 +78,16 @@ public class TokenEndpointAuthenticationFilter implements Filter {
|
||||
private static final Log logger = LogFactory.getLog(TokenEndpointAuthenticationFilter.class);
|
||||
|
||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
boolean allowOnlyPost;
|
||||
|
||||
private final OAuth2RequestFactory oAuth2RequestFactory;
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
private OAuth2RequestFactory oAuth2RequestFactory;
|
||||
|
||||
public TokenEndpointAuthenticationFilter() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param authenticationManager an AuthenticationManager for the incoming request
|
||||
@@ -102,49 +111,29 @@ public class TokenEndpointAuthenticationFilter implements Filter {
|
||||
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
|
||||
ServletException {
|
||||
|
||||
logger.debug("Authentication TokenEndpoint ");
|
||||
if(authenticationManager==null) {
|
||||
authenticationManager=(AuthenticationManager)WebContext.getBean("oauth20ClientAuthenticationManager");
|
||||
}
|
||||
if(oAuth2RequestFactory==null) {
|
||||
oAuth2RequestFactory=(OAuth2RequestFactory)WebContext.getBean("oAuth2RequestFactory");
|
||||
}
|
||||
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
final HttpServletRequest request = (HttpServletRequest) req;
|
||||
final HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
try {
|
||||
Authentication credentials = extractCredentials(request);
|
||||
|
||||
if (credentials != null) {
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Authentication credentials found for '" + credentials.getName() + "'");
|
||||
}
|
||||
|
||||
Authentication authResult = authenticationManager.authenticate(credentials);
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Authentication success: " + authResult.getName());
|
||||
}
|
||||
|
||||
Authentication clientAuth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (clientAuth == null) {
|
||||
throw new BadCredentialsException(
|
||||
"No client authentication found. Remember to put a filter upstream of the TokenEndpointAuthenticationFilter.");
|
||||
}
|
||||
|
||||
Map<String, String> map = getSingleValueMap(request);
|
||||
map.put(OAuth2Utils.CLIENT_ID, clientAuth.getName());
|
||||
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(map);
|
||||
|
||||
authorizationRequest.setScope(getScope(request));
|
||||
if (clientAuth.isAuthenticated()) {
|
||||
// Ensure the OAuth2Authentication is authenticated
|
||||
authorizationRequest.setApproved(true);
|
||||
}
|
||||
|
||||
OAuth2Request storedOAuth2Request = oAuth2RequestFactory.createOAuth2Request(authorizationRequest);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new OAuth2Authentication(storedOAuth2Request, authResult));
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
|
||||
String grantType = request.getParameter("grant_type");
|
||||
if (grantType != null && grantType.equals("password")) {
|
||||
usernamepassword(request,response);
|
||||
}else {
|
||||
Authentication authentication=ClientCredentials(request,response);
|
||||
BasicAuthentication auth =new BasicAuthentication();
|
||||
auth.setJ_username(((User)authentication.getPrincipal()).getUsername());
|
||||
auth.setAuthenticated(true);
|
||||
UsernamePasswordAuthenticationToken simpleUserAuthentication = new UsernamePasswordAuthenticationToken(auth, authentication.getCredentials(), authentication.getAuthorities());
|
||||
WebContext.setAuthentication(simpleUserAuthentication);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -163,6 +152,86 @@ public class TokenEndpointAuthenticationFilter implements Filter {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
public void usernamepassword(HttpServletRequest request, HttpServletResponse response) throws IOException,ServletException {
|
||||
logger.debug("Authentication TokenEndpoint ");
|
||||
|
||||
try {
|
||||
Authentication credentials = extractCredentials(request);
|
||||
|
||||
if (credentials != null) {
|
||||
logger.debug("Authentication credentials found for '" + credentials.getName() + "'");
|
||||
|
||||
Authentication authResult = authenticationManager.authenticate(credentials);
|
||||
|
||||
logger.debug("Authentication success: " + authResult.getName());
|
||||
|
||||
Authentication clientAuth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (clientAuth == null) {
|
||||
throw new BadCredentialsException(
|
||||
"No client authentication found. Remember to put a filter upstream of the TokenEndpointAuthenticationFilter.");
|
||||
}
|
||||
|
||||
Map<String, String> map = getSingleValueMap(request);
|
||||
map.put(OAuth2Utils.CLIENT_ID, clientAuth.getName());
|
||||
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(map);
|
||||
|
||||
authorizationRequest.setScope(getScope(request));
|
||||
if (clientAuth.isAuthenticated()) {
|
||||
// Ensure the OAuth2Authentication is authenticated
|
||||
authorizationRequest.setApproved(true);
|
||||
}
|
||||
|
||||
OAuth2Request storedOAuth2Request = oAuth2RequestFactory.createOAuth2Request(authorizationRequest);
|
||||
|
||||
WebContext.setAuthentication(new OAuth2Authentication(storedOAuth2Request, authResult));
|
||||
|
||||
onSuccessfulAuthentication(request, response, authResult);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (AuthenticationException failed) {
|
||||
SecurityContextHolder.clearContext();
|
||||
|
||||
logger.debug("Authentication request for failed: " + failed);
|
||||
|
||||
onUnsuccessfulAuthentication(request, response, failed);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public Authentication ClientCredentials(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException, ServletException {
|
||||
|
||||
if (allowOnlyPost && !"POST".equalsIgnoreCase(request.getMethod())) {
|
||||
throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[] { "POST" });
|
||||
}
|
||||
|
||||
String clientId = request.getParameter("client_id");
|
||||
String clientSecret = request.getParameter("client_secret");
|
||||
|
||||
// If the request is already authenticated we can assume that this
|
||||
// filter is not needed
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.isAuthenticated()) {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
if (clientId == null) {
|
||||
throw new BadCredentialsException("No client credentials presented");
|
||||
}
|
||||
|
||||
if (clientSecret == null) {
|
||||
clientSecret = "";
|
||||
}
|
||||
|
||||
clientId = clientId.trim();
|
||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(clientId,clientSecret);
|
||||
|
||||
return this.authenticationManager.authenticate(authRequest);
|
||||
}
|
||||
|
||||
private Map<String, String> getSingleValueMap(HttpServletRequest request) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
Map<String, String[]> parameters = request.getParameterMap();
|
||||
@@ -209,5 +278,42 @@ public class TokenEndpointAuthenticationFilter implements Filter {
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected static class ClientCredentialsRequestMatcher implements RequestMatcher {
|
||||
|
||||
private String path;
|
||||
|
||||
public ClientCredentialsRequestMatcher(String path) {
|
||||
this.path = path;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
int pathParamIndex = uri.indexOf(';');
|
||||
|
||||
if (pathParamIndex > 0) {
|
||||
// strip everything after the first semi-colon
|
||||
uri = uri.substring(0, pathParamIndex);
|
||||
}
|
||||
|
||||
String clientId = request.getParameter("client_id");
|
||||
|
||||
if (clientId == null) {
|
||||
// Give basic auth a chance to work instead (it's preferred anyway)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("".equals(request.getContextPath())) {
|
||||
return uri.endsWith(path);
|
||||
}
|
||||
|
||||
return uri.endsWith(request.getContextPath() + path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.util.DateUtils;
|
||||
import org.maxkey.util.JsonUtils;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
public class OAuthDefaultUserInfoAdapter extends AbstractAuthorizeAdapter {
|
||||
|
||||
@Override
|
||||
public String generateInfo(UserInfo userInfo,Object app) {
|
||||
HashMap<String, Object> beanMap = new HashMap<String, Object>();
|
||||
beanMap.put("randomId",(new StringGenerator()).uuidGenerate());
|
||||
beanMap.put("uid", userInfo.getId());
|
||||
beanMap.put("username", userInfo.getUsername());
|
||||
beanMap.put("employeeNumber", userInfo.getEmployeeNumber());
|
||||
beanMap.put("email", userInfo.getEmail());
|
||||
beanMap.put("mobile", userInfo.getMobile());
|
||||
beanMap.put("realname", userInfo.getDisplayName());
|
||||
beanMap.put("birthday", userInfo.getBirthDate());
|
||||
beanMap.put("department", userInfo.getDepartment());
|
||||
beanMap.put("createdate", userInfo.getCreatedDate());
|
||||
beanMap.put("title", userInfo.getJobTitle());
|
||||
beanMap.put("state", userInfo.getWorkRegion());
|
||||
beanMap.put("gender", userInfo.getGender());
|
||||
|
||||
String info= JsonUtils.object2Json(beanMap);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encrypt(String data, String algorithmKey, String algorithm) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView authorize(UserInfo userInfo, Object app, String data,ModelAndView modelAndView) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.maxkey.authz.endpoint.adapter.AbstractAuthorizeAdapter;
|
||||
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.BOOLEAN;
|
||||
import org.maxkey.crypto.ReciprocalUtils;
|
||||
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.dao.service.ApplicationsService;
|
||||
import org.maxkey.dao.service.UserInfoService;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.domain.apps.Applications;
|
||||
import org.maxkey.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.util.Instance;
|
||||
import org.maxkey.util.JsonUtils;
|
||||
import org.maxkey.util.StringGenerator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWEHeader;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.EncryptedJWT;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = { "/api" })
|
||||
public class UserInfoEndpoint {
|
||||
final static Logger _logger = LoggerFactory.getLogger(UserInfoEndpoint.class);
|
||||
@Autowired
|
||||
@Qualifier("oauth20JdbcClientDetailsService")
|
||||
private ClientDetailsService clientDetailsService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauth20TokenServices")
|
||||
private DefaultTokenServices oauth20tokenServices;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("userInfoService")
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("applicationsService")
|
||||
protected ApplicationsService applicationsService;
|
||||
|
||||
@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();
|
||||
|
||||
@RequestMapping(value="/oauth/v20/me",produces="text/plain;charset=UTF-8")
|
||||
@ResponseBody
|
||||
public String apiV20UserInfo(
|
||||
@RequestParam(value = "access_token", required = true) String access_token) {
|
||||
String principal="";
|
||||
if (!StringGenerator.uuidMatches(access_token)) {
|
||||
return accessTokenFormatError(access_token);
|
||||
}
|
||||
OAuth2Authentication oAuth2Authentication =null;
|
||||
try{
|
||||
oAuth2Authentication = oauth20tokenServices.loadAuthentication(access_token);
|
||||
|
||||
principal=oAuth2Authentication.getPrincipal().toString();
|
||||
|
||||
String client_id= oAuth2Authentication.getOAuth2Request().getClientId();
|
||||
UserInfo userInfo=queryUserInfo(principal);
|
||||
Applications app=applicationsService.get(client_id);
|
||||
|
||||
String userJson="";
|
||||
|
||||
AbstractAuthorizeAdapter adapter;
|
||||
if(BOOLEAN.isTrue(app.getIsAdapter())){
|
||||
adapter =(AbstractAuthorizeAdapter)Instance.newInstance(app.getAdapter());
|
||||
}else{
|
||||
adapter =(AbstractAuthorizeAdapter)defaultOAuthUserInfoAdapter;
|
||||
}
|
||||
|
||||
String jsonData=adapter.generateInfo(userInfo, null);
|
||||
userJson=adapter.sign(jsonData, app);
|
||||
|
||||
return userJson;
|
||||
|
||||
}catch(OAuth2Exception e){
|
||||
HashMap<String,Object>authzException=new HashMap<String,Object>();
|
||||
authzException.put(OAuth2Exception.ERROR, e.getOAuth2ErrorCode());
|
||||
authzException.put(OAuth2Exception.DESCRIPTION,e.getMessage());
|
||||
return JsonUtils.object2Json(authzException);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value="/connect/v10/userinfo",produces="text/plain;charset=UTF-8")
|
||||
@ResponseBody
|
||||
public String apiConnect10aUserInfo(
|
||||
@RequestHeader(value = "Authorization", required = true) String access_token) {
|
||||
String principal="";
|
||||
if (!StringGenerator.uuidMatches(access_token)) {
|
||||
return accessTokenFormatError(access_token);
|
||||
}
|
||||
OAuth2Authentication oAuth2Authentication =null;
|
||||
try{
|
||||
oAuth2Authentication = oauth20tokenServices.loadAuthentication(access_token);
|
||||
|
||||
principal=oAuth2Authentication.getPrincipal().toString();
|
||||
|
||||
Set<String >scopes=oAuth2Authentication.getOAuth2Request().getScope();
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(oAuth2Authentication.getOAuth2Request().getClientId());
|
||||
|
||||
UserInfo userInfo=queryUserInfo(principal);
|
||||
String userJson="";
|
||||
HashMap<String, Object> claimsFields = new HashMap<String, Object>();
|
||||
|
||||
claimsFields.put("sub", userInfo.getId());
|
||||
|
||||
if(scopes.contains("profile")){
|
||||
claimsFields.put("name", userInfo.getUsername());
|
||||
claimsFields.put("preferred_username", userInfo.getDisplayName());
|
||||
claimsFields.put("given_name", userInfo.getGivenName());
|
||||
claimsFields.put("family_name", userInfo.getFamilyName());
|
||||
claimsFields.put("middle_name", userInfo.getMiddleName());
|
||||
claimsFields.put("nickname", userInfo.getNickName());
|
||||
claimsFields.put("profile", "profile");
|
||||
claimsFields.put("picture", "picture");
|
||||
claimsFields.put("website", userInfo.getWebSite());
|
||||
|
||||
String gender;
|
||||
switch(userInfo.getGender()){
|
||||
case UserInfo.GENDER.MALE :
|
||||
gender="male";break;
|
||||
case UserInfo.GENDER.FEMALE :
|
||||
gender="female";break;
|
||||
default:
|
||||
gender="unknown";
|
||||
}
|
||||
claimsFields.put("gender", gender);
|
||||
claimsFields.put("zoneinfo", userInfo.getTimeZone());
|
||||
claimsFields.put("locale", userInfo.getLocale());
|
||||
claimsFields.put("updated_time", userInfo.getModifiedDate());
|
||||
claimsFields.put("birthdate", userInfo.getBirthDate());
|
||||
}
|
||||
|
||||
if(scopes.contains("email")){
|
||||
claimsFields.put("email", userInfo.getWorkEmail());
|
||||
claimsFields.put("email_verified", false);
|
||||
}
|
||||
|
||||
if(scopes.contains("phone")){
|
||||
claimsFields.put("phone_number", userInfo.getWorkPhoneNumber());
|
||||
claimsFields.put("phone_number_verified", false);
|
||||
}
|
||||
|
||||
if(scopes.contains("address")){
|
||||
HashMap<String, String> addressFields = new HashMap<String, String>();
|
||||
addressFields.put("country", userInfo.getWorkCountry());
|
||||
addressFields.put("region", userInfo.getWorkRegion());
|
||||
addressFields.put("locality", userInfo.getWorkLocality());
|
||||
addressFields.put("street_address", userInfo.getWorkStreetAddress());
|
||||
addressFields.put("formatted", userInfo.getWorkAddressFormatted());
|
||||
addressFields.put("postal_code", userInfo.getWorkPostalCode());
|
||||
|
||||
claimsFields.put("address", addressFields);
|
||||
}
|
||||
|
||||
JWTClaimsSet userInfoJWTClaims = new JWTClaimsSet.Builder()
|
||||
.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))
|
||||
.claim(claimsFields)
|
||||
.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
|
||||
) {
|
||||
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")) {
|
||||
// unsigned ID token
|
||||
//userInfoJWT = new PlainJWT(userInfoJWTClaims);
|
||||
userJson=JsonUtils.gson2Json(claimsFields);
|
||||
} else {
|
||||
// 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=ReciprocalUtils.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);
|
||||
}
|
||||
userJson=userInfoJWT.serialize();
|
||||
}
|
||||
}
|
||||
|
||||
return userJson;
|
||||
|
||||
}catch(OAuth2Exception e){
|
||||
HashMap<String,Object>authzException=new HashMap<String,Object>();
|
||||
authzException.put(OAuth2Exception.ERROR, e.getOAuth2ErrorCode());
|
||||
authzException.put(OAuth2Exception.DESCRIPTION,e.getMessage());
|
||||
return JsonUtils.object2Json(authzException);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String accessTokenFormatError(String access_token){
|
||||
HashMap<String,Object>atfe=new HashMap<String,Object>();
|
||||
atfe.put(OAuth2Exception.ERROR, "token Format Invalid");
|
||||
atfe.put(OAuth2Exception.DESCRIPTION, "access Token Format Invalid , access_token : "+access_token);
|
||||
|
||||
return JsonUtils.object2Json(atfe);
|
||||
}
|
||||
|
||||
|
||||
public UserInfo queryUserInfo(String uid){
|
||||
_logger.debug("uid : "+uid);
|
||||
UserInfo queryUserInfo=new UserInfo();
|
||||
queryUserInfo.setUsername(uid);
|
||||
UserInfo userInfo = (UserInfo) userInfoService.load(queryUserInfo);
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
|
||||
public void setOauth20tokenServices(DefaultTokenServices oauth20tokenServices) {
|
||||
this.oauth20tokenServices = oauth20tokenServices;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setUserInfoService(UserInfoService userInfoService) {
|
||||
this.userInfoService = userInfoService;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// public void setJwtSignerValidationService(
|
||||
// JwtSigningAndValidationService jwtSignerValidationService) {
|
||||
// this.jwtSignerValidationService = jwtSignerValidationService;
|
||||
// }
|
||||
//
|
||||
// public void setJwtEnDecryptionService(
|
||||
// JwtEncryptionAndDecryptionService jwtEnDecryptionService) {
|
||||
// this.jwtEnDecryptionService = jwtEnDecryptionService;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author Crystal.Sea
|
||||
*
|
||||
*/
|
||||
package org.maxkey.authz.oauth2.provider.userinfo.endpoint;
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.connsec.authz.oidc.idtoken;
|
||||
package org.maxkey.authz.oidc.idtoken;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -10,25 +10,25 @@ import java.util.UUID;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.maxkey.authz.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
|
||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||
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.config.oidc.OIDCProviderMetadata;
|
||||
import org.maxkey.crypto.ReciprocalUtils;
|
||||
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.domain.apps.oauth2.provider.ClientDetails;
|
||||
import org.maxkey.web.WebContext;
|
||||
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.connsec.authz.oauth2.common.DefaultOAuth2AccessToken;
|
||||
import com.connsec.authz.oauth2.common.OAuth2AccessToken;
|
||||
import com.connsec.authz.oauth2.provider.ClientDetailsService;
|
||||
import com.connsec.authz.oauth2.provider.OAuth2Authentication;
|
||||
import com.connsec.authz.oauth2.provider.OAuth2Request;
|
||||
import com.connsec.authz.oauth2.provider.token.TokenEnhancer;
|
||||
import com.connsec.config.oidc.OIDCProviderMetadata;
|
||||
import com.connsec.crypto.ReciprocalUtils;
|
||||
import com.connsec.crypto.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import com.connsec.crypto.jwt.encryption.service.impl.RecipientJwtEncryptionAndDecryptionServiceBuilder;
|
||||
import com.connsec.crypto.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import com.connsec.crypto.jwt.signer.service.impl.SymmetricSigningAndValidationServiceBuilder;
|
||||
import com.connsec.domain.apps.oauth2.provider.ClientDetails;
|
||||
import com.connsec.web.WebContext;
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
@@ -87,22 +87,22 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
if (request.getScope().contains(ID_TOKEN_SCOPE)) {//Enhance for OpenID Connect
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authentication.getOAuth2Request().getClientId());
|
||||
|
||||
JWTClaimsSet.Builder builder=new JWTClaimsSet.Builder();
|
||||
builder.subject(authentication.getName())
|
||||
.expirationTime(accessToken.getExpiration())
|
||||
.claim(providerMetadata.getIssuer(), true)
|
||||
.issueTime(new Date())
|
||||
.audience(Arrays.asList(authentication.getOAuth2Request().getClientId()))
|
||||
.jwtID(UUID.randomUUID().toString());
|
||||
|
||||
JWTClaimsSet idClaims = new JWTClaimsSet.Builder()
|
||||
.subject(authentication.getName())
|
||||
.expirationTime(accessToken.getExpiration())
|
||||
.claim(providerMetadata.getIssuer(), true)
|
||||
.issueTime(new Date())
|
||||
.audience(Arrays.asList(authentication.getOAuth2Request().getClientId()))
|
||||
.jwtID(UUID.randomUUID().toString())
|
||||
.build();
|
||||
/**
|
||||
* https://self-issued.me
|
||||
* @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")){
|
||||
idClaims.setCustomClaim("sub_jwk", jwtSignerService.getAllPublicKeys().get(jwtSignerService.getDefaultSignerKeyId()));
|
||||
builder.claim("sub_jwk", jwtSignerService.getAllPublicKeys().get(jwtSignerService.getDefaultSignerKeyId()));
|
||||
}
|
||||
|
||||
// if the auth time claim was explicitly requested OR if the client always wants the auth time, put it in
|
||||
@@ -110,24 +110,24 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
|| (request.getExtensions().containsKey("idtoken")) // TODO: 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"));
|
||||
idClaims.setClaim("auth_time", loginDate.getMillis()/ 1000);
|
||||
builder.claim("auth_time", loginDate.getMillis()/ 1000);
|
||||
}
|
||||
|
||||
String nonce = (String)request.getExtensions().get("nonce");
|
||||
if (!Strings.isNullOrEmpty(nonce)) {
|
||||
idClaims.setCustomClaim("nonce", nonce);
|
||||
builder.claim("nonce", nonce);
|
||||
}
|
||||
|
||||
JWSAlgorithm signingAlg = jwtSignerService.getDefaultSigningAlgorithm();
|
||||
SignedJWT signed = new SignedJWT(new JWSHeader(signingAlg), idClaims);
|
||||
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);
|
||||
idClaims.setClaim("at_hash", at_hash);
|
||||
builder.claim("at_hash", at_hash);
|
||||
}
|
||||
logger.debug("idClaims "+idClaims);
|
||||
logger.debug("idClaims "+builder.build());
|
||||
|
||||
JWT idToken=null;
|
||||
if (clientDetails.getIdTokenEncryptedAlgorithm() != null && !clientDetails.getIdTokenEncryptedAlgorithm().equals("none")
|
||||
@@ -140,7 +140,7 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
if (recipientJwtEnDecryptionService != null) {
|
||||
JWEAlgorithm jweAlgorithm=new JWEAlgorithm(clientDetails.getIdTokenEncryptedAlgorithm());
|
||||
EncryptionMethod encryptionMethod=new EncryptionMethod(clientDetails.getIdTokenEncryptionMethod());
|
||||
EncryptedJWT encryptedJWT = new EncryptedJWT(new JWEHeader(jweAlgorithm, encryptionMethod), idClaims);
|
||||
EncryptedJWT encryptedJWT = new EncryptedJWT(new JWEHeader(jweAlgorithm, encryptionMethod), builder.build());
|
||||
recipientJwtEnDecryptionService.encryptJwt(encryptedJWT);
|
||||
idToken=encryptedJWT;
|
||||
}else{
|
||||
@@ -149,7 +149,7 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
} else {
|
||||
if (signingAlg==null||signingAlg.equals("none")) {
|
||||
// unsigned ID token
|
||||
idToken = new PlainJWT(idClaims);
|
||||
idToken = new PlainJWT(builder.build());
|
||||
} else {
|
||||
// signed ID token
|
||||
if (signingAlg.equals(JWSAlgorithm.HS256)
|
||||
@@ -160,15 +160,15 @@ public class OIDCIdTokenEnhancer implements TokenEnhancer {
|
||||
|
||||
JwtSigningAndValidationService symmetricJwtSignerService =symmetricJwtSignerServiceBuilder.serviceBuilder(client_secret);
|
||||
if(symmetricJwtSignerService!=null){
|
||||
idClaims.setCustomClaim("kid", "SYMMETRIC-KEY");
|
||||
idToken = new SignedJWT(new JWSHeader(signingAlg), idClaims);
|
||||
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 {
|
||||
idClaims.setCustomClaim("kid", jwtSignerService.getDefaultSignerKeyId());
|
||||
idToken = new SignedJWT(new JWSHeader(signingAlg), idClaims);
|
||||
builder.claim("kid", jwtSignerService.getDefaultSignerKeyId());
|
||||
idToken = new SignedJWT(new JWSHeader(signingAlg), builder.build());
|
||||
// sign it with the server's key
|
||||
jwtSignerService.signJwt((SignedJWT) idToken);
|
||||
}
|
||||
Reference in New Issue
Block a user