/**
 * Copyright (c) 2022 cloud Authors. All Rights Reserved.
 *
 * 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 com.lutao.cloud.auth.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lutao.cloud.common.security.component.CloudCommenceAuthExceptionEntryPoint;
import com.lutao.cloud.common.security.component.CloudWebResponseExceptionTranslator;
import com.lutao.cloud.common.security.service.CloudCustomTokenServices;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;

import java.util.Collections;

/**
 * 授权认证配置
 */
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

	private final ClientDetailsService cloudClientDetailsServiceImpl;

	private final AuthenticationManager authenticationManagerBean;

	private final UserDetailsService cloudUserDetailsService;

	private final AuthorizationCodeServices authorizationCodeServices;

	private final TokenStore redisTokenStore;

	private final TokenEnhancer tokenEnhancer;

	private final ObjectMapper objectMapper;

	private final CloudCommenceAuthExceptionEntryPoint cloudCommenceAuthExceptionEntryPoint;

	/**
	 * 授权服配置端点信息
	 * @param clients
	 */
	@Override
	@SneakyThrows
	public void configure(ClientDetailsServiceConfigurer clients){
		clients.withClientDetails(cloudClientDetailsServiceImpl);
	}

	/**
	 *
	 * @param oauthServer 授权服务
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer){
		oauthServer.allowFormAuthenticationForClients()
				.authenticationEntryPoint(cloudCommenceAuthExceptionEntryPoint)
				.checkTokenAccess("isAuthenticated()");
	}

	/**
	 * 授权服配置密码模式
	 * @param endpoints
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints){
		endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenServices(tokenServices()).tokenStore(redisTokenStore)
				.tokenEnhancer(tokenEnhancer).userDetailsService(cloudUserDetailsService)
				.authorizationCodeServices(authorizationCodeServices).authenticationManager(authenticationManagerBean)
				.reuseRefreshTokens(false).pathMapping("/oauth/confirm_access", "/token/confirm_access")
				.exceptionTranslator(new CloudWebResponseExceptionTranslator());
	}


	/**
	 * 加载token服务
	 * @return
	 */
	@Bean
	public CloudCustomTokenServices tokenServices(){
		CloudCustomTokenServices tokenServices = new CloudCustomTokenServices();
		tokenServices.setTokenStore(redisTokenStore);
		tokenServices.setSupportRefreshToken(true);
		tokenServices.setReuseRefreshToken(false);
		tokenServices.setClientDetailsService(cloudClientDetailsServiceImpl);
		tokenServices.setTokenEnhancer(tokenEnhancer);
		addUserDetailsService(tokenServices, cloudUserDetailsService);
		return tokenServices;
	}

	/**
	 * 用户详情服务
	 * @param tokenServices
	 * @param userDetailsService
	 */
	private void addUserDetailsService(CloudCustomTokenServices tokenServices, UserDetailsService userDetailsService){
		if (userDetailsService != null){
			PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
			provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
			tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
		}
	}

}
