소스 검색

oauth2 Approval fix & sso login history

MaxKey 3 년 전
부모
커밋
6cad9f0ca2

+ 19 - 5
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/approval/TokenApprovalStore.java

@@ -25,6 +25,8 @@ import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
 import org.maxkey.authz.oauth2.provider.approval.Approval.ApprovalStatus;
 import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
 import org.maxkey.authz.oauth2.provider.token.TokenStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * An {@link ApprovalStore} that works with an existing {@link TokenStore}, extracting implicit {@link Approval
@@ -38,6 +40,8 @@ import org.maxkey.authz.oauth2.provider.token.TokenStore;
  */
 public class TokenApprovalStore implements ApprovalStore {
 
+	static final Logger _logger = LoggerFactory.getLogger(TokenApprovalStore.class);
+			
 	private TokenStore store;
 
 	/**
@@ -55,6 +59,7 @@ public class TokenApprovalStore implements ApprovalStore {
 	 */
 	@Override
 	public boolean addApprovals(Collection<Approval> approvals) {
+		_logger.debug("add Approvals...");
 		return true;
 	}
 
@@ -65,6 +70,7 @@ public class TokenApprovalStore implements ApprovalStore {
 	 */
 	@Override
 	public boolean revokeApprovals(Collection<Approval> approvals) {
+		_logger.debug("revoke Approvals " + approvals);
 		boolean success = true;
 		for (Approval approval : approvals) {
 			Collection<OAuth2AccessToken> tokens = store.findTokensByClientIdAndUserName(approval.getClientId(), approval.getUserId());
@@ -87,14 +93,22 @@ public class TokenApprovalStore implements ApprovalStore {
 	 */
 	@Override
 	public Collection<Approval> getApprovals(String userId, String clientId) {
+		_logger.trace("userId " + userId+" , clientId " + clientId);
 		Collection<Approval> result = new HashSet<Approval>();
 		Collection<OAuth2AccessToken> tokens = store.findTokensByClientIdAndUserName(clientId, userId);
+		_logger.trace("tokens Collection " + tokens);
 		for (OAuth2AccessToken token : tokens) {
-			OAuth2Authentication authentication = store.readAuthentication(token);
-			if (authentication != null) {
-				Date expiresAt = token.getExpiration();
-				for (String scope : token.getScope()) {
-					result.add(new Approval(userId, clientId, scope, expiresAt, ApprovalStatus.APPROVED));
+			_logger.trace("token " + token);
+			if(token != null) {
+				OAuth2Authentication authentication = store.readAuthentication(token);
+				_logger.trace("authentication " + authentication);
+				if (authentication != null) {
+					Date expiresAt = token.getExpiration();
+					for (String scope : token.getScope()) {
+						Approval approval = new Approval(userId, clientId, scope, expiresAt, ApprovalStatus.APPROVED);
+						result.add(approval);
+						_logger.trace("add approval " + approval);
+					}
 				}
 			}
 		}

+ 44 - 40
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/approval/endpoint/OAuth20AccessConfirmationEndpoint.java

@@ -77,48 +77,52 @@ public class OAuth20AccessConfirmationEndpoint {
      */
     @RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_APPROVAL_CONFIRM)
     public ModelAndView getAccessConfirmation(
-            @RequestParam Map<String, Object> model) throws Exception {
-        model.remove("authorizationRequest");
-        
-        // Map<String, Object> model
-        AuthorizationRequest clientAuth = 
-                (AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
-        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
-        Apps  app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
-        //session中为空或者id不一致重新加载
-        if (app == null || !app.getId().equalsIgnoreCase(clientAuth.getClientId())) {
-            app = appsService.get(clientAuth.getClientId()); 
-            WebContext.setAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP, app);
-            WebContext.setAttribute(app.getId(), app.getIcon());
-        }
-       
-        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()) {
-            scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
-        }
-        String principal = 
-                ((SigninPrincipal) WebContext.getAuthentication().getPrincipal()).getUsername();
-        for (Approval approval : approvalStore.getApprovals(principal, 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);
-
-        if(!model.containsKey(OAuth2Constants.PARAMETER.APPROVAL_PROMPT)) {
-        	model.put(OAuth2Constants.PARAMETER.APPROVAL_PROMPT, client.getApprovalPrompt());
-        }
-        
+            @RequestParam Map<String, Object> model) {
+    	try {
+	        model.remove("authorizationRequest");
+	        
+	        // Map<String, Object> model
+	        AuthorizationRequest clientAuth = 
+	                (AuthorizationRequest) WebContext.getAttribute("authorizationRequest");
+	        ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
+	        Apps  app = (Apps)WebContext.getAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP);
+	        //session中为空或者id不一致重新加载
+	        if (app == null || !app.getId().equalsIgnoreCase(clientAuth.getClientId())) {
+	            app = appsService.get(clientAuth.getClientId()); 
+	            WebContext.setAttribute(WebConstants.AUTHORIZE_SIGN_ON_APP, app);
+	            WebContext.setAttribute(app.getId(), app.getIcon());
+	        }
+	       
+	        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()) {
+	            scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
+	        }
+	        String principal = 
+	                ((SigninPrincipal) WebContext.getAuthentication().getPrincipal()).getUsername();
+	        for (Approval approval : approvalStore.getApprovals(principal, 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);
+	
+	        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);
+    	}
+	        
         ModelAndView modelAndView = new ModelAndView("authorize/oauth_access_confirmation");
-        _logger.debug("Confirmation details ");
+        _logger.trace("Confirmation details ");
         for (Object key : model.keySet()) {
-            _logger.debug("key " + key +"=" + model.get(key));
+            _logger.trace("key " + key +"=" + model.get(key));
         }
         modelAndView.addObject("model", model);
         return modelAndView;

+ 57 - 27
maxkey-protocols/maxkey-protocol-oauth-2.0/src/main/java/org/maxkey/authz/oauth2/provider/token/store/RedisTokenStore.java

@@ -32,6 +32,8 @@ import org.maxkey.authz.oauth2.provider.token.TokenStore;
 import org.maxkey.persistence.redis.RedisConnection;
 import org.maxkey.persistence.redis.RedisConnectionFactory;
 import org.maxkey.util.ObjectTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Date;
 
@@ -39,16 +41,17 @@ import java.util.Date;
  * @author efenderbosch
  */
 public class RedisTokenStore implements TokenStore {
-
-	private static final String ACCESS = "REDIS_OAUTH_V20_access:";
-	private static final String AUTH_TO_ACCESS = "REDIS_OAUTH_V20_auth_to_access:";
-	private static final String AUTH = "REDIS_OAUTH_V20_auth:";
-	private static final String REFRESH_AUTH = "REDIS_OAUTH_V20_refresh_auth:";
-	private static final String ACCESS_TO_REFRESH = "REDIS_OAUTH_V20_access_to_refresh:";
-	private static final String REFRESH = "REDIS_OAUTH_V20_refresh:";
-	private static final String REFRESH_TO_ACCESS = "REDIS_OAUTH_V20_refresh_to_access:";
-	private static final String CLIENT_ID_TO_ACCESS = "REDIS_OAUTH_V20_client_id_to_access:";
-	private static final String UNAME_TO_ACCESS = "REDIS_OAUTH_V20_uname_to_access:";
+	static final Logger _logger = LoggerFactory.getLogger(RedisTokenStore.class);
+	
+	private static final String ACCESS = "REDIS_OAUTH_V20_ACCESS_";
+	private static final String AUTH_TO_ACCESS = "REDIS_OAUTH_V20_AUTH_TO_ACCESS_";
+	private static final String AUTH = "REDIS_OAUTH_V20_AUTH_";
+	private static final String REFRESH_AUTH = "REDIS_OAUTH_V20_REFRESH_AUTH_";
+	private static final String ACCESS_TO_REFRESH = "REDIS_OAUTH_V20_ACCESS_TO_REFRESH_";
+	private static final String REFRESH = "REDIS_OAUTH_V20_REFRESH_";
+	private static final String REFRESH_TO_ACCESS = "REDIS_OAUTH_V20_REFRESH_TO_ACCESS_";
+	private static final String CLIENT_ID_TO_ACCESS = "REDIS_OAUTH_V20_CLIENT_ID_TO_ACCESS_";
+	private static final String UNAME_TO_ACCESS = "REDIS_OAUTH_V20_UNAME_TO_ACCESS_";
 
 	private final RedisConnectionFactory connectionFactory;
 	private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
@@ -77,15 +80,19 @@ public class RedisTokenStore implements TokenStore {
 		String key = authenticationKeyGenerator.extractKey(authentication);
 		String serializedKey = (AUTH_TO_ACCESS + key);
 		RedisConnection conn = getConnection();
-		OAuth2AccessToken accessToken =conn.getObject(serializedKey);
-		if (accessToken != null
-				&& !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
-			// Keep the stores consistent (maybe the same user is
-			// represented by this authentication but the details have
-			// changed)
-			storeAccessToken(accessToken, authentication);
+		try {
+			OAuth2AccessToken accessToken =conn.getObject(serializedKey);
+			if (accessToken != null
+					&& !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
+				// Keep the stores consistent (maybe the same user is
+				// represented by this authentication but the details have
+				// changed)
+				storeAccessToken(accessToken, authentication);
+			}
+			return accessToken;
+		} finally {
+			conn.close();
 		}
-		return accessToken;
 	}
 
 	@Override
@@ -95,9 +102,14 @@ public class RedisTokenStore implements TokenStore {
 
 	@Override
 	public OAuth2Authentication readAuthentication(String token) {
+		_logger.trace("read Authentication by token " + token + " , token key " + AUTH + token);
 		RedisConnection conn = getConnection();
-		OAuth2Authentication auth = conn.getObject(AUTH + token);
-		return auth;
+		try {
+			OAuth2Authentication auth = conn.getObject(AUTH + token);
+			return auth;
+		} finally {
+			conn.close();
+		}
 	}
 
 	@Override
@@ -122,6 +134,11 @@ public class RedisTokenStore implements TokenStore {
 		String authToAccessKey = (AUTH_TO_ACCESS + authenticationKeyGenerator.extractKey(authentication));
 		String approvalKey = (UNAME_TO_ACCESS + getApprovalKey(authentication));
 		String clientId = (CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
+		_logger.trace("accessKey " + accessKey);
+		_logger.trace("authKey " + authKey);
+		_logger.trace("authToAccessKey " + authToAccessKey);
+		_logger.trace("approvalKey " + approvalKey);
+		_logger.trace("clientId " + clientId);
 
 		RedisConnection conn = getConnection();
 		try {
@@ -146,8 +163,10 @@ public class RedisTokenStore implements TokenStore {
 				String refresh = (token.getRefreshToken().getValue());
 				String auth = (token.getValue());
 				String refreshToAccessKey = (REFRESH_TO_ACCESS + token.getRefreshToken().getValue());
+				_logger.trace("refreshToAccessKey " + refreshToAccessKey);
 				conn.set(refreshToAccessKey, auth);
 				String accessToRefreshKey = (ACCESS_TO_REFRESH + token.getValue());
+				_logger.trace("accessToRefreshKey " + accessToRefreshKey);
 				conn.set(accessToRefreshKey, refresh);
 				if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
 					ExpiringOAuth2RefreshToken expiringRefreshToken = (ExpiringOAuth2RefreshToken) refreshToken;
@@ -173,7 +192,7 @@ public class RedisTokenStore implements TokenStore {
 	}
 
 	private static String getApprovalKey(String clientId, String userName) {
-		return clientId + (userName == null ? "" : ":" + userName);
+		return clientId + (userName == null ? "" : "_" + userName);
 	}
 
 	@Override
@@ -184,9 +203,13 @@ public class RedisTokenStore implements TokenStore {
 	@Override
 	public OAuth2AccessToken readAccessToken(String tokenValue) {
 		RedisConnection conn = getConnection();
-		String key = (ACCESS + tokenValue);
-		OAuth2AccessToken accessToken = conn.getObject(key);
-		return accessToken;
+		try {
+			String key = (ACCESS + tokenValue);
+			OAuth2AccessToken accessToken = conn.getObject(key);
+			return accessToken;
+		} finally {
+			conn.close();
+		}
 	}
 
 	public void removeAccessToken(String tokenValue) {
@@ -251,9 +274,13 @@ public class RedisTokenStore implements TokenStore {
 	public OAuth2RefreshToken readRefreshToken(String tokenValue) {
 		String key = (REFRESH + tokenValue);
 		RedisConnection conn = getConnection();
-		OAuth2RefreshToken refreshToken = conn.getObject(key);
-		conn.close();
-		return refreshToken;
+		try {
+			OAuth2RefreshToken refreshToken = conn.getObject(key);
+			conn.close();
+			return refreshToken;
+		} finally {
+			conn.close();
+		}
 	}
 
 	@Override
@@ -309,6 +336,7 @@ public class RedisTokenStore implements TokenStore {
 	@Override
 	public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
 		String approvalKey = (UNAME_TO_ACCESS + getApprovalKey(clientId, userName));
+		_logger.trace("approvalKey " + approvalKey);
 		List<String> stringList = null;
 		RedisConnection conn = getConnection();
 		try {
@@ -321,6 +349,7 @@ public class RedisTokenStore implements TokenStore {
 		}
 		List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>(stringList.size());
 		for (String str : stringList) {
+			//accessToken may expired
 			OAuth2AccessToken accessToken = conn.getObject(str);
 			accessTokens.add(accessToken);
 		}
@@ -330,6 +359,7 @@ public class RedisTokenStore implements TokenStore {
 	@Override
 	public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
 		String key = (CLIENT_ID_TO_ACCESS + clientId);
+		_logger.trace("TokensByClientId  " + key);
 		List<String> stringList = null;
 		RedisConnection conn = getConnection();
 		try {

+ 2 - 1
maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyMvcConfig.java

@@ -211,12 +211,13 @@ public class MaxKeyMvcConfig implements WebMvcConfigurer {
         registry.addInterceptor(historyLoginAppAdapter)
                 .addPathPatterns("/authz/basic/*")
                 .addPathPatterns("/authz/ltpa/*")
-                .addPathPatterns("/authz/desktop/*")
+                .addPathPatterns("/authz/api/*")
                 .addPathPatterns("/authz/formbased/*")
                 .addPathPatterns("/authz/tokenbased/*")
                 .addPathPatterns("/authz/saml20/idpinit/*")
                 .addPathPatterns("/authz/saml20/assertion")
                 .addPathPatterns("/authz/cas/granting")
+                .addPathPatterns("/authz/oauth/v20/approval_confirm")
         ;
         _logger.debug("add HistoryLoginAppAdapter");