/oauth2/rest_token impl
							parent
							
								
									df8113d18a
								
							
						
					
					
						commit
						beac2d1f00
					
				| 
						 | 
				
			
			@ -53,7 +53,7 @@ public class WebSecurityConfigurer {
 | 
			
		|||
        http.authorizeHttpRequests(matcherRegistry -> {
 | 
			
		||||
            // permitAll() 的URL路径属于公开访问,不需要权限
 | 
			
		||||
            matcherRegistry
 | 
			
		||||
                    .requestMatchers("/favicon.ico*", "/oauth/rest_token*", "*.js", "*.css").permitAll()
 | 
			
		||||
                    .requestMatchers("/favicon.ico*", "/oauth2/rest_token*", "*.js", "*.css").permitAll()
 | 
			
		||||
                    .requestMatchers("/api/public/**").permitAll()
 | 
			
		||||
                    .requestMatchers(HttpMethod.GET, "/login*").anonymous()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2Error;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:35
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractAuthenticationRestConverter implements AuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
    static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    protected void throwError(String errorCode, String parameterName, String errorUri) {
 | 
			
		||||
        OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri);
 | 
			
		||||
        throw new OAuth2AuthenticationException(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:27
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.web.authentication.AuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public interface AuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 从请求参数中转化到  Authentication
 | 
			
		||||
     *
 | 
			
		||||
     * @param parameters 请求参数
 | 
			
		||||
     * @return Authentication or null
 | 
			
		||||
     */
 | 
			
		||||
    Authentication convert(Map<String, String> parameters);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.web.authentication.AuthenticationConverter;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:30
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.oauth2.server.authorization.web.authentication.DelegatingAuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public final class DelegatingAuthenticationRestConverter implements AuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
    private final List<AuthenticationRestConverter> converters;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs a {@code DelegatingAuthenticationConverter} using the provided parameters.
 | 
			
		||||
     *
 | 
			
		||||
     * @param converters a {@code List} of {@link AuthenticationConverter}(s)
 | 
			
		||||
     */
 | 
			
		||||
    public DelegatingAuthenticationRestConverter(List<AuthenticationRestConverter> converters) {
 | 
			
		||||
        Assert.notEmpty(converters, "converters cannot be empty");
 | 
			
		||||
        this.converters = Collections.unmodifiableList(new LinkedList<>(converters));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication convert(Map<String, String> parameters) {
 | 
			
		||||
        Assert.notNull(parameters, "parameters cannot be null");
 | 
			
		||||
        for (AuthenticationRestConverter converter : this.converters) {
 | 
			
		||||
            Authentication authentication = converter.convert(parameters);
 | 
			
		||||
            if (authentication != null) {
 | 
			
		||||
                return authentication;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 | 
			
		||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:33
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public final class OAuth2AuthorizationCodeAuthenticationRestConverter extends AbstractAuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication convert(Map<String, String> parameters) {
 | 
			
		||||
        // grant_type (REQUIRED)
 | 
			
		||||
        String grantType = parameters.get(OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
        if (!AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equals(grantType)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
 | 
			
		||||
//        MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
 | 
			
		||||
 | 
			
		||||
        // code (REQUIRED)
 | 
			
		||||
        String code = parameters.get(OAuth2ParameterNames.CODE);
 | 
			
		||||
        if (!StringUtils.hasText(code)) {
 | 
			
		||||
            throwError(
 | 
			
		||||
                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
                    OAuth2ParameterNames.CODE,
 | 
			
		||||
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // redirect_uri (REQUIRED)
 | 
			
		||||
        // Required only if the "redirect_uri" parameter was included in the authorization request
 | 
			
		||||
        String redirectUri = parameters.get(OAuth2ParameterNames.REDIRECT_URI);
 | 
			
		||||
        if (!StringUtils.hasText(redirectUri)) {
 | 
			
		||||
            throwError(
 | 
			
		||||
                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
                    OAuth2ParameterNames.REDIRECT_URI,
 | 
			
		||||
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> additionalParameters = new HashMap<>();
 | 
			
		||||
        parameters.forEach((key, value) -> {
 | 
			
		||||
            if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.CLIENT_ID) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.CODE) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.REDIRECT_URI)) {
 | 
			
		||||
//                additionalParameters.put(key, (value.size() == 1) ? value.get(0) : value.toArray(new String[0]));
 | 
			
		||||
                additionalParameters.put(key, value);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return new OAuth2AuthorizationCodeAuthenticationToken(
 | 
			
		||||
                code, clientPrincipal, redirectUri, additionalParameters);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 | 
			
		||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationToken;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:33
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2ClientCredentialsAuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public final class OAuth2ClientCredentialsAuthenticationRestConverter extends AbstractAuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication convert(Map<String, String> parameters) {
 | 
			
		||||
        // grant_type (REQUIRED)
 | 
			
		||||
        String grantType = parameters.get(OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
        if (!AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equals(grantType)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
 | 
			
		||||
//        MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
 | 
			
		||||
 | 
			
		||||
        // scope (OPTIONAL)
 | 
			
		||||
        String scope = parameters.get(OAuth2ParameterNames.SCOPE);
 | 
			
		||||
//        if (StringUtils.hasText(scope) &&
 | 
			
		||||
//                parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
 | 
			
		||||
//            throwError(
 | 
			
		||||
//                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
//                    OAuth2ParameterNames.SCOPE,
 | 
			
		||||
//                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
//        }
 | 
			
		||||
        Set<String> requestedScopes = null;
 | 
			
		||||
        if (StringUtils.hasText(scope)) {
 | 
			
		||||
            requestedScopes = new HashSet<>(
 | 
			
		||||
                    Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> additionalParameters = new HashMap<>();
 | 
			
		||||
        parameters.forEach((key, value) -> {
 | 
			
		||||
            if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.SCOPE)) {
 | 
			
		||||
                additionalParameters.put(key, value);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return new OAuth2ClientCredentialsAuthenticationToken(
 | 
			
		||||
                clientPrincipal, requestedScopes, additionalParameters);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 | 
			
		||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2DeviceCodeAuthenticationToken;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:33
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceCodeAuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public final class OAuth2DeviceCodeAuthenticationRestConverter extends AbstractAuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication convert(Map<String, String> parameters) {
 | 
			
		||||
        // grant_type (REQUIRED)
 | 
			
		||||
        String grantType = parameters.get(OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
        if (!AuthorizationGrantType.DEVICE_CODE.getValue().equals(grantType)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
 | 
			
		||||
//        MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
 | 
			
		||||
 | 
			
		||||
        // device_code (REQUIRED)
 | 
			
		||||
        String deviceCode = parameters.get(OAuth2ParameterNames.DEVICE_CODE);
 | 
			
		||||
        if (!StringUtils.hasText(deviceCode)) {
 | 
			
		||||
            throwError(
 | 
			
		||||
                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
                    OAuth2ParameterNames.DEVICE_CODE,
 | 
			
		||||
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> additionalParameters = new HashMap<>();
 | 
			
		||||
        parameters.forEach((key, value) -> {
 | 
			
		||||
            if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.CLIENT_ID) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.DEVICE_CODE)) {
 | 
			
		||||
                additionalParameters.put(key, value);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return new OAuth2DeviceCodeAuthenticationToken(deviceCode, clientPrincipal, additionalParameters);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
package com.monkeyk.sos.web.authentication;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 | 
			
		||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2RefreshTokenAuthenticationToken;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 2023/10/31 10:33
 | 
			
		||||
 *
 | 
			
		||||
 * @author Shengzhao Li
 | 
			
		||||
 * @see org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2RefreshTokenAuthenticationConverter
 | 
			
		||||
 * @since 3.0.0
 | 
			
		||||
 */
 | 
			
		||||
public final class OAuth2RefreshTokenAuthenticationRestConverter extends AbstractAuthenticationRestConverter {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication convert(Map<String, String> parameters) {
 | 
			
		||||
        // grant_type (REQUIRED)
 | 
			
		||||
        String grantType = parameters.get(OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
        if (!AuthorizationGrantType.REFRESH_TOKEN.getValue().equals(grantType)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
 | 
			
		||||
 | 
			
		||||
//        MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
 | 
			
		||||
 | 
			
		||||
        // refresh_token (REQUIRED)
 | 
			
		||||
        String refreshToken = parameters.get(OAuth2ParameterNames.REFRESH_TOKEN);
 | 
			
		||||
        if (!StringUtils.hasText(refreshToken)) {
 | 
			
		||||
            throwError(
 | 
			
		||||
                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
                    OAuth2ParameterNames.REFRESH_TOKEN,
 | 
			
		||||
                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // scope (OPTIONAL)
 | 
			
		||||
        String scope = parameters.get(OAuth2ParameterNames.SCOPE);
 | 
			
		||||
//        if (!StringUtils.hasText(scope)) {
 | 
			
		||||
//            throwError(
 | 
			
		||||
//                    OAuth2ErrorCodes.INVALID_REQUEST,
 | 
			
		||||
//                    OAuth2ParameterNames.SCOPE,
 | 
			
		||||
//                    ACCESS_TOKEN_REQUEST_ERROR_URI);
 | 
			
		||||
//        }
 | 
			
		||||
        Set<String> requestedScopes = null;
 | 
			
		||||
        if (StringUtils.hasText(scope)) {
 | 
			
		||||
            requestedScopes = new HashSet<>(
 | 
			
		||||
                    Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> additionalParameters = new HashMap<>();
 | 
			
		||||
        parameters.forEach((key, value) -> {
 | 
			
		||||
            if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.REFRESH_TOKEN) &&
 | 
			
		||||
                    !key.equals(OAuth2ParameterNames.SCOPE)) {
 | 
			
		||||
                additionalParameters.put(key, value);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return new OAuth2RefreshTokenAuthenticationToken(
 | 
			
		||||
                refreshToken, clientPrincipal, requestedScopes, additionalParameters);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,23 +11,38 @@
 | 
			
		|||
 */
 | 
			
		||||
package com.monkeyk.sos.web.controller;
 | 
			
		||||
 | 
			
		||||
import com.monkeyk.sos.web.WebUtils;
 | 
			
		||||
import com.monkeyk.sos.web.authentication.*;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.beans.BeansException;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.ApplicationContext;
 | 
			
		||||
import org.springframework.context.ApplicationContextAware;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.converter.HttpMessageConverter;
 | 
			
		||||
import org.springframework.http.server.ServletServerHttpResponse;
 | 
			
		||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
 | 
			
		||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
			
		||||
import org.springframework.security.crypto.password.PasswordEncoder;
 | 
			
		||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.AuthenticationException;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.oauth2.core.*;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
 | 
			
		||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 | 
			
		||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
 | 
			
		||||
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
 | 
			
		||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
 | 
			
		||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestBody;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMethod;
 | 
			
		||||
import org.springframework.web.bind.annotation.ResponseBody;
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.temporal.ChronoUnit;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -45,165 +60,115 @@ public class OAuthRestController implements InitializingBean, ApplicationContext
 | 
			
		|||
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(OAuthRestController.class);
 | 
			
		||||
 | 
			
		||||
//    @Autowired
 | 
			
		||||
//    private ClientDetailsService clientDetailsService;
 | 
			
		||||
//
 | 
			
		||||
//    // consumerTokenServices,defaultAuthorizationServerTokenServices
 | 
			
		||||
//    @Autowired
 | 
			
		||||
//    @Qualifier("defaultAuthorizationServerTokenServices")
 | 
			
		||||
//    private AuthorizationServerTokenServices tokenServices;
 | 
			
		||||
//    @Autowired
 | 
			
		||||
//    private AuthorizationCodeServices authorizationCodeServices;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private PasswordEncoder passwordEncoder;
 | 
			
		||||
 | 
			
		||||
//    private AuthenticationManager authenticationManager;
 | 
			
		||||
 | 
			
		||||
//    private OAuth2RequestFactory oAuth2RequestFactory;
 | 
			
		||||
//
 | 
			
		||||
//    private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
 | 
			
		||||
//    private WebResponseExceptionTranslator providerExceptionHandler = new DefaultWebResponseExceptionTranslator();
 | 
			
		||||
    private static final String DEFAULT_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @RequestMapping(value = "/oauth2/rest_token", method = RequestMethod.POST)
 | 
			
		||||
    private final AuthenticationRestConverter authenticationConverter;
 | 
			
		||||
 | 
			
		||||
    private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
 | 
			
		||||
            new OAuth2AccessTokenResponseHttpMessageConverter();
 | 
			
		||||
    private final HttpMessageConverter<OAuth2Error> errorHttpResponseConverter =
 | 
			
		||||
            new OAuth2ErrorHttpMessageConverter();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private AuthenticationManager authenticationManager;
 | 
			
		||||
 | 
			
		||||
    public OAuthRestController() {
 | 
			
		||||
 | 
			
		||||
        this.authenticationConverter = new DelegatingAuthenticationRestConverter(
 | 
			
		||||
                Arrays.asList(
 | 
			
		||||
                        new OAuth2AuthorizationCodeAuthenticationRestConverter(),
 | 
			
		||||
                        new OAuth2RefreshTokenAuthenticationRestConverter(),
 | 
			
		||||
                        new OAuth2ClientCredentialsAuthenticationRestConverter(),
 | 
			
		||||
                        new OAuth2DeviceCodeAuthenticationRestConverter()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replace OAuth2TokenEndpointFilter flow use restful API
 | 
			
		||||
     *
 | 
			
		||||
     * @param parameters request params
 | 
			
		||||
     */
 | 
			
		||||
    @PostMapping("/oauth2/rest_token")
 | 
			
		||||
    @ResponseBody
 | 
			
		||||
    public OAuth2AccessToken postAccessToken(@RequestBody Map<String, String> parameters) {
 | 
			
		||||
    public void postAccessToken(@RequestBody Map<String, String> parameters, HttpServletResponse response) throws IOException {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//        String clientId = getClientId(parameters);
 | 
			
		||||
//        ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(clientId);
 | 
			
		||||
//
 | 
			
		||||
//        //validate client_secret
 | 
			
		||||
//        String clientSecret = getClientSecret(parameters);
 | 
			
		||||
//        if (clientSecret == null || clientSecret.equals("")) {
 | 
			
		||||
//            throw new InvalidClientException("Bad client credentials");
 | 
			
		||||
//        } else {
 | 
			
		||||
//            if (!this.passwordEncoder.matches(clientSecret, authenticatedClient.getClientSecret())) {
 | 
			
		||||
//                throw new InvalidClientException("Bad client credentials");
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        TokenRequest tokenRequest = oAuth2RequestFactory.createTokenRequest(parameters, authenticatedClient);
 | 
			
		||||
 | 
			
		||||
//        if (clientId != null && !clientId.equals("")) {
 | 
			
		||||
//            // Only validate the client details if a client authenticated during this
 | 
			
		||||
//            // request.
 | 
			
		||||
//            if (!clientId.equals(tokenRequest.getClientId())) {
 | 
			
		||||
//                // double check to make sure that the client ID in the token request is the same as that in the
 | 
			
		||||
//                // authenticated client
 | 
			
		||||
//                throw new InvalidClientException("Given client ID does not match authenticated client");
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);
 | 
			
		||||
 | 
			
		||||
//        final String grantType = tokenRequest.getGrantType();
 | 
			
		||||
//        if (!StringUtils.hasText(grantType)) {
 | 
			
		||||
//            throw new InvalidRequestException("Missing grant type");
 | 
			
		||||
//        }
 | 
			
		||||
//        if (grantType.equals("implicit")) {
 | 
			
		||||
//            throw new InvalidGrantException("Implicit grant type not supported from token endpoint");
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        if (isAuthCodeRequest(parameters)) {
 | 
			
		||||
//            // The scope was requested or determined during the authorization step
 | 
			
		||||
//            if (!tokenRequest.getScope().isEmpty()) {
 | 
			
		||||
//                LOG.debug("Clearing scope of incoming token request");
 | 
			
		||||
//                tokenRequest.setScope(Collections.<String>emptySet());
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//        if (isRefreshTokenRequest(parameters)) {
 | 
			
		||||
//            // A refresh token has its own default scopes, so we should ignore any added by the factory here.
 | 
			
		||||
//            tokenRequest.setScope(OAuth2Utils.parseParameterList(parameters.get(OAuth2Utils.SCOPE)));
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        OAuth2AccessToken token = getTokenGranter(grantType).grant(grantType, tokenRequest);
 | 
			
		||||
//        if (token == null) {
 | 
			
		||||
//            throw new UnsupportedGrantTypeException("Unsupported grant type: " + grantType);
 | 
			
		||||
//        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//        return token;
 | 
			
		||||
        throw new UnsupportedOperationException("Not yet implements");
 | 
			
		||||
        try {
 | 
			
		||||
            String grantType = parameters.get(OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
            if (grantType == null) {
 | 
			
		||||
                throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
//    protected TokenGranter getTokenGranter(String grantType) {
 | 
			
		||||
//
 | 
			
		||||
//        if ("authorization_code".equals(grantType)) {
 | 
			
		||||
//            return new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetailsService, this.oAuth2RequestFactory);
 | 
			
		||||
//        } else if ("password".equals(grantType)) {
 | 
			
		||||
//            return new ResourceOwnerPasswordTokenGranter(getAuthenticationManager(), tokenServices, clientDetailsService, this.oAuth2RequestFactory);
 | 
			
		||||
//        } else if ("refresh_token".equals(grantType)) {
 | 
			
		||||
//            return new RefreshTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
 | 
			
		||||
//        } else if ("client_credentials".equals(grantType)) {
 | 
			
		||||
//            return new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
 | 
			
		||||
//        } else if ("implicit".equals(grantType)) {
 | 
			
		||||
//            return new ImplicitTokenGranter(tokenServices, clientDetailsService, this.oAuth2RequestFactory);
 | 
			
		||||
//        } else {
 | 
			
		||||
//            throw new UnsupportedGrantTypeException("Unsupport grant_type: " + grantType);
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
            Authentication authorizationGrantAuthentication = this.authenticationConverter.convert(parameters);
 | 
			
		||||
            if (authorizationGrantAuthentication == null) {
 | 
			
		||||
                throwError(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE, OAuth2ParameterNames.GRANT_TYPE);
 | 
			
		||||
            }
 | 
			
		||||
            if (authorizationGrantAuthentication instanceof AbstractAuthenticationToken) {
 | 
			
		||||
                ((AbstractAuthenticationToken) authorizationGrantAuthentication)
 | 
			
		||||
//                        .setDetails(this.authenticationDetailsSource.buildDetails(request));
 | 
			
		||||
                        .setDetails(new WebAuthenticationDetails(WebUtils.getIp(), null));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    @ExceptionHandler(Exception.class)
 | 
			
		||||
//    public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
 | 
			
		||||
//        LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
 | 
			
		||||
//        return getExceptionTranslator().translate(e);
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
//    @ExceptionHandler(ClientRegistrationException.class)
 | 
			
		||||
//    public ResponseEntity<OAuth2Exception> handleClientRegistrationException(Exception e) throws Exception {
 | 
			
		||||
//        LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
 | 
			
		||||
//        return getExceptionTranslator().translate(new BadClientCredentialsException());
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    @ExceptionHandler(OAuth2Exception.class)
 | 
			
		||||
//    public ResponseEntity<OAuth2Exception> handleException(OAuth2Exception e) throws Exception {
 | 
			
		||||
//        LOG.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
 | 
			
		||||
//        return getExceptionTranslator().translate(e);
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    private boolean isRefreshTokenRequest(Map<String, String> parameters) {
 | 
			
		||||
//        return "refresh_token".equals(parameters.get(OAuth2Utils.GRANT_TYPE)) && parameters.get("refresh_token") != null;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    private boolean isAuthCodeRequest(Map<String, String> parameters) {
 | 
			
		||||
//        return "authorization_code".equals(parameters.get(OAuth2Utils.GRANT_TYPE)) && parameters.get("code") != null;
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    protected String getClientId(Map<String, String> parameters) {
 | 
			
		||||
//        return parameters.get(OAuth2Utils.CLIENT_ID);
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    protected String getClientSecret(Map<String, String> parameters) {
 | 
			
		||||
        return parameters.get("client_secret");
 | 
			
		||||
            OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
 | 
			
		||||
                    (OAuth2AccessTokenAuthenticationToken) this.authenticationManager.authenticate(authorizationGrantAuthentication);
 | 
			
		||||
            this.sendAccessTokenResponse(response, accessTokenAuthentication);
 | 
			
		||||
        } catch (OAuth2AuthenticationException ex) {
 | 
			
		||||
            SecurityContextHolder.clearContext();
 | 
			
		||||
            if (LOG.isTraceEnabled()) {
 | 
			
		||||
                LOG.trace("Token request failed: {}", ex.getError(), ex);
 | 
			
		||||
            }
 | 
			
		||||
            this.sendErrorResponse(response, ex);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    private AuthenticationManager getAuthenticationManager() {
 | 
			
		||||
//        return this.authenticationManager;
 | 
			
		||||
//    }
 | 
			
		||||
    private void sendErrorResponse(HttpServletResponse response,
 | 
			
		||||
                                   AuthenticationException exception) throws IOException {
 | 
			
		||||
 | 
			
		||||
        OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
 | 
			
		||||
        ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
 | 
			
		||||
        httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
 | 
			
		||||
        this.errorHttpResponseConverter.write(error, null, httpResponse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void sendAccessTokenResponse(HttpServletResponse response, Authentication authentication) throws IOException {
 | 
			
		||||
 | 
			
		||||
        OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
 | 
			
		||||
                (OAuth2AccessTokenAuthenticationToken) authentication;
 | 
			
		||||
 | 
			
		||||
        OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
 | 
			
		||||
        OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
 | 
			
		||||
        Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
 | 
			
		||||
 | 
			
		||||
        OAuth2AccessTokenResponse.Builder builder =
 | 
			
		||||
                OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
 | 
			
		||||
                        .tokenType(accessToken.getTokenType())
 | 
			
		||||
                        .scopes(accessToken.getScopes());
 | 
			
		||||
        if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
 | 
			
		||||
            builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
 | 
			
		||||
        }
 | 
			
		||||
        if (refreshToken != null) {
 | 
			
		||||
            builder.refreshToken(refreshToken.getTokenValue());
 | 
			
		||||
        }
 | 
			
		||||
        if (!CollectionUtils.isEmpty(additionalParameters)) {
 | 
			
		||||
            builder.additionalParameters(additionalParameters);
 | 
			
		||||
        }
 | 
			
		||||
        OAuth2AccessTokenResponse accessTokenResponse = builder.build();
 | 
			
		||||
        ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
 | 
			
		||||
        this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private static void throwError(String errorCode, String parameterName) {
 | 
			
		||||
        OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, DEFAULT_ERROR_URI);
 | 
			
		||||
        throw new OAuth2AuthenticationException(error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception {
 | 
			
		||||
 | 
			
		||||
//        Assert.state(clientDetailsService != null, "ClientDetailsService must be provided");
 | 
			
		||||
//        Assert.state(authenticationManager != null, "AuthenticationManager must be provided");
 | 
			
		||||
 | 
			
		||||
        Assert.notNull(this.passwordEncoder, "PasswordEncoder is null");
 | 
			
		||||
 | 
			
		||||
//        oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    protected WebResponseExceptionTranslator getExceptionTranslator() {
 | 
			
		||||
//        return providerExceptionHandler;
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 | 
			
		||||
| 
						 | 
				
			
			@ -211,4 +176,5 @@ public class OAuthRestController implements InitializingBean, ApplicationContext
 | 
			
		|||
//            this.authenticationManager = (AuthenticationManager) applicationContext.getBean("authenticationManagerBean");
 | 
			
		||||
//        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue