CongressService & MomentaryService

This commit is contained in:
MaxKey
2022-04-17 07:04:28 +08:00
parent 5e4923d6b4
commit d9af91de4a
82 changed files with 732 additions and 3665 deletions

View File

@@ -17,28 +17,36 @@
package org.maxkey.authz.oauth2.provider.approval.endpoint;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
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.Approval.ApprovalStatus;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.entity.Message;
import org.maxkey.entity.UserInfo;
import org.maxkey.entity.apps.Apps;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
import org.maxkey.authz.oauth2.provider.approval.ApprovalStore;
import org.maxkey.persistence.MomentaryService;
import org.maxkey.persistence.service.AppsService;
import org.maxkey.web.WebConstants;
import org.maxkey.util.StringUtils;
import org.maxkey.web.WebContext;
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.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
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;
/**
@@ -48,7 +56,6 @@ import org.springframework.web.servlet.ModelAndView;
* @author Ryan Heaton
*/
@Controller
@SessionAttributes("authorizationRequest")
public class OAuth20AccessConfirmationEndpoint {
static final Logger _logger = LoggerFactory.getLogger(OAuth20AccessConfirmationEndpoint.class);
@@ -68,6 +75,12 @@ public class OAuth20AccessConfirmationEndpoint {
@Qualifier("oauth20UserApprovalHandler")
OAuth20UserApprovalHandler oauth20UserApprovalHandler;
@Autowired
protected MomentaryService momentaryService;
@Autowired
protected ApplicationConfig applicationConfig;
/**
* getAccessConfirmation.
* @param model Map
@@ -76,20 +89,15 @@ public class OAuth20AccessConfirmationEndpoint {
*/
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_APPROVAL_CONFIRM)
public ModelAndView getAccessConfirmation(
@RequestParam Map<String, Object> model) {
@RequestParam Map<String, Object> model,@CurrentUser UserInfo currentUser) {
try {
model.remove("authorizationRequest");
// Map<String, Object> model
AuthorizationRequest clientAuth =
(AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
(AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
Apps app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
WebContext.setAttribute(app.getId(), app.getIcon());
model.put("oauth_approval", WebContext.genId());
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("app", app);
model.put("oauth_version", "oauth 2.0");
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
@@ -117,9 +125,60 @@ public class OAuth20AccessConfirmationEndpoint {
for (Object key : model.keySet()) {
_logger.trace("key " + key +"=" + model.get(key));
}
model.put("authorizeApproveUri", applicationConfig.getFrontendUri()+"/#/authz/oauth2approve");
modelAndView.addObject("model", model);
return modelAndView;
}
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_APPROVAL_CONFIRM+"/get/{oauth_approval}")
public ResponseEntity<?> getAccess(
@PathVariable("oauth_approval") String oauth_approval,
@CurrentUser UserInfo currentUser) {
Map<String, Object> model = new HashMap<String, Object>();
if(StringUtils.isNotBlank(oauth_approval)) {
try {
AuthorizationRequest clientAuth =
(AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId(),true);
Apps app = appsService.get(client.getClientId(),true);
app.transIconBase64();
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("clientId", clientAuth.getClientId());
model.put("appName", app.getName());
model.put("iconBase64", app.getIconBase64());
model.put("oauth_version", "oauth 2.0");
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + scope, "false");
}
String principal = AuthorizationUtils.getPrincipal().getUsername();
for (Approval approval : approvalStore.getApprovals(principal, client.getClientId())) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
}
}
model.put("scopes", scopes);
if(!model.containsKey(OAuth2Constants.PARAMETER.APPROVAL_PROMPT)) {
model.put(OAuth2Constants.PARAMETER.APPROVAL_PROMPT, client.getApprovalPrompt());
}
}catch(Exception e) {
_logger.debug("OAuth Access Confirmation process error." ,e);
}
_logger.trace("Confirmation details ");
for (Object key : model.keySet()) {
_logger.trace("key " + key +"=" + model.get(key));
}
}
return new Message<Map<String, Object>>(model).buildResponse();
}
/**
* handleError.

View File

@@ -35,6 +35,7 @@ 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.maxkey.configuration.ApplicationConfig;
import org.maxkey.persistence.MomentaryService;
import org.maxkey.persistence.service.AppsService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -84,6 +85,9 @@ public class AbstractEndpoint implements InitializingBean {
@Qualifier("applicationConfig")
protected ApplicationConfig applicationConfig;
@Autowired
protected MomentaryService momentaryService;
public void afterPropertiesSet() throws Exception {
if (tokenGranter == null) {

View File

@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.mybatis.jpa.util.JpaWebContext;
import org.maxkey.authn.annotation.CurrentUser;
import org.maxkey.authn.web.AuthorizationUtils;
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
@@ -48,6 +49,8 @@ import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.maxkey.constants.ContentType;
import org.maxkey.crypto.jose.keystore.JWKSetKeyStore;
import org.maxkey.util.HttpEncoder;
import org.maxkey.entity.Message;
import org.maxkey.entity.UserInfo;
import org.maxkey.entity.apps.Apps;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
import org.maxkey.web.HttpRequestAdapter;
@@ -55,6 +58,7 @@ import org.maxkey.web.WebConstants;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@@ -65,7 +69,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
@@ -96,7 +99,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
*/
@Tag(name = "2-1-OAuth v2.0 API文档模块")
@Controller
@SessionAttributes("authorizationRequest")
public class AuthorizationEndpoint extends AbstractEndpoint {
final static Logger _logger = LoggerFactory.getLogger(AuthorizationEndpoint.class);
@@ -120,7 +122,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
@Operation(summary = "OAuth 2.0 认证接口", description = "传递参数应用ID自动完成跳转认证拼接",method="GET")
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}")
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}"},method = RequestMethod.GET)
public ModelAndView authorize(
HttpServletRequest request,
HttpServletResponse response,
@@ -152,6 +154,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
public ModelAndView authorize(
Map<String, Object> model,
@RequestParam Map<String, String> parameters,
@CurrentUser UserInfo currentUser,
SessionStatus sessionStatus) {
Principal principal=(Principal)AuthorizationUtils.getAuthentication();
@@ -207,7 +210,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
// Validation is all done, so we can check for auto approval...
if (authorizationRequest.isApproved()) {
if (responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)) {
return getImplicitGrantResponse(authorizationRequest);
return new ModelAndView(getImplicitGrantResponse(authorizationRequest));
}
if (responseTypes.contains(OAuth2Constants.PARAMETER.CODE)) {
return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
@@ -224,8 +227,8 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
// Place auth request into the model so that it is stored in the session
// for approveOrDeny to use. That way we make sure that auth request comes from the session,
// so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
model.put("authorizationRequest", authorizationRequest);
momentaryService.put(currentUser.getOnlineTicket(), "authorizationRequest", authorizationRequest);
return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);
}
@@ -237,22 +240,22 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
//approval must post
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE},
@RequestMapping(value = {OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE+"/approval"},
params = OAuth2Constants.PARAMETER.USER_OAUTH_APPROVAL,
method = RequestMethod.POST)
public View approveOrDeny(
public ResponseEntity<?> authorizeApproveOrDeny(
@RequestParam Map<String, String> approvalParameters,
Map<String, ?> model,
@CurrentUser UserInfo currentUser,
SessionStatus sessionStatus) {
Principal principal=(Principal)AuthorizationUtils.getAuthentication();
Principal principal = (Principal)AuthorizationUtils.getAuthentication();
if (!(principal instanceof Authentication)) {
sessionStatus.setComplete();
throw new InsufficientAuthenticationException(
"User must be authenticated with Spring Security before authorizing an access token.");
}
AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
AuthorizationRequest authorizationRequest = (AuthorizationRequest) momentaryService.get(currentUser.getOnlineTicket(), "authorizationRequest");
if (authorizationRequest == null) {
sessionStatus.setComplete();
@@ -274,20 +277,22 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
if (!authorizationRequest.isApproved()) {
return new RedirectView(
getUnsuccessfulRedirect(
authorizationRequest,
new UserDeniedAuthorizationException("User denied access"),
responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)
),
false, true, false);
return new Message< Object>(Message.FAIL,(Object)
getUnsuccessfulRedirect(
authorizationRequest,
new UserDeniedAuthorizationException("User denied access"),
responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)
)
).buildResponse();
}
if (responseTypes.contains(OAuth2Constants.PARAMETER.TOKEN)) {
return getImplicitGrantResponse(authorizationRequest).getView();
return new Message< Object>((Object)
getImplicitGrantResponse(authorizationRequest)).buildResponse();
}
return getAuthorizationCodeResponse(authorizationRequest, (Authentication) principal);
return new Message< Object>((Object)
getAuthorizationCodeResponse(authorizationRequest, (Authentication) principal)).buildResponse();
}
finally {
sessionStatus.setComplete();
@@ -340,7 +345,7 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
// We can grant a token and return it with implicit approval.
private ModelAndView getImplicitGrantResponse(AuthorizationRequest authorizationRequest) {
private String getImplicitGrantResponse(AuthorizationRequest authorizationRequest) {
try {
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(authorizationRequest, "implicit");
OAuth2Request storedOAuth2Request = getOAuth2RequestFactory().createOAuth2Request(authorizationRequest);
@@ -349,24 +354,10 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
if (accessToken == null) {
throw new UnsupportedResponseTypeException("Unsupported response type: token");
}
return new ModelAndView(
new RedirectView(
appendAccessToken(authorizationRequest, accessToken),
false,
true,
false
)
);
return appendAccessToken(authorizationRequest, accessToken);
}
catch (OAuth2Exception e) {
return new ModelAndView(
new RedirectView(
getUnsuccessfulRedirect(authorizationRequest, e, true),
false,
true,
false
)
);
return getUnsuccessfulRedirect(authorizationRequest, e, true);
}
}
@@ -382,17 +373,17 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
// Authorization Code Response
private View getAuthorizationCodeResponse(AuthorizationRequest authorizationRequest, Authentication authUser) {
private String getAuthorizationCodeResponse(AuthorizationRequest authorizationRequest, Authentication authUser) {
try {
String successfulRedirect = getSuccessfulRedirect(
authorizationRequest,
generateCode(authorizationRequest, authUser)
);
_logger.debug("successfulRedirect " + successfulRedirect);
return new RedirectView(successfulRedirect, false, true, false);
return successfulRedirect;
}
catch (OAuth2Exception e) {
return new RedirectView(getUnsuccessfulRedirect(authorizationRequest, e, false), false, true, false);
return getUnsuccessfulRedirect(authorizationRequest, e, false);
}
}