package ca.corefacility.bioinformatics.irida.web.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.vote.ScopeVoter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;

import ca.corefacility.bioinformatics.irida.web.controller.api.exception.CustomOAuth2ExceptionTranslator;

/**
 * Configuration for web security using OAuth2
 * 
 * @author Thomas Matthews <thomas.matthews@phac-aspc.gc.ca>
 * @author Franklin Bristow <franklin.bristow@phac-aspc.gc.ca>
 *
 */
@Configuration
@EnableWebSecurity
@ImportResource("classpath:oauth2-web-config.xml")
public class IridaRestApiSecurityConfig extends WebSecurityConfigurerAdapter {
	@Bean
	public AuthenticationEntryPoint oauthAuthenticationEntryPoint() {
		OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
		entryPoint.setExceptionTranslator(new CustomOAuth2ExceptionTranslator());
		return entryPoint;
	}

	@Bean
	public AccessDeniedHandler oauthAccessDeniedHandler() {
		OAuth2AccessDeniedHandler handler = new OAuth2AccessDeniedHandler();
		handler.setExceptionTranslator(new CustomOAuth2ExceptionTranslator());
		return handler;
	}

	@Bean
	public AuthenticationEntryPoint clientAuthenticationEntryPoint() {
		OAuth2AuthenticationEntryPoint clientAuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
		clientAuthenticationEntryPoint.setRealmName("NmlIrida/client");
		clientAuthenticationEntryPoint.setTypeName("Basic");
		return clientAuthenticationEntryPoint;
	}

	@Bean
	public ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(
			AuthenticationManager clientAuthenticationManager) {
		ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter = new ClientCredentialsTokenEndpointFilter();
		clientCredentialsTokenEndpointFilter.setAuthenticationManager(clientAuthenticationManager);
		return clientCredentialsTokenEndpointFilter;
	}

	@Bean
	public AccessDecisionManager accessDecisionManager() {
		@SuppressWarnings("rawtypes")
		List<AccessDecisionVoter> voters = new ArrayList<>();
		voters.add(new ScopeVoter());
		voters.add(new RoleVoter());
		voters.add(new AuthenticatedVoter());
		UnanimousBased unanimousBased = new UnanimousBased(voters);
		return unanimousBased;
	}
}

@@ -103,16 +103,119 @@
 .List;%0A%0A
+import javax.annotation.PostConstruct;%0A%0Aimport org.springframework.beans.factory.annotation.Autowired;%0A
 import o
@@ -258,16 +258,16 @@
 n.Bean;%0A
-
 import o
@@ -1062,24 +1062,100 @@
 ointFilter;%0A
+import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;%0A
 import org.s
@@ -1309,32 +1309,122 @@
 tionEntryPoint;%0A
+import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;%0A
 import org.sprin
@@ -2068,16 +2068,703 @@
 apter %7B%0A
+%0A%09@Autowired%0A%09private TokenEndpoint tokenEndpoint;%0A%0A%09@PostConstruct%0A%09public void configureTokenEndpoint() %7B%0A%09%09// since Spring Security OAuth2 sets up this bean automagically%0A%09%09// somewhere in the bowels of its XML config and no apparent way to%0A%09%09// change the exception handler property, the easiest way for us to get%0A%09%09// our own custom error handling set up is to get the token endpoint%0A%09%09// autowired into our config bean, then set the exception handler%0A%09%09// ourself.%0A%09%09tokenEndpoint.setProviderExceptionHandler(webResponseExceptionTranslator());%0A%09%7D%0A%0A%09@Bean%0A%09public WebResponseExceptionTranslator webResponseExceptionTranslator() %7B%0A%09%09return new CustomOAuth2ExceptionTranslator();%0A%09%7D%0A%0A
 %09@Bean%0A%09
@@ -2949,32 +2949,27 @@
 nslator(
-new CustomOAuth2
+webResponse
 Exceptio
@@ -3177,32 +3177,27 @@
 nslator(
-new CustomOAuth2
+webResponse
 Exceptio
@@ -3479,16 +3479,16 @@
 ient%22);%0A
-
 %09%09client
@@ -3534,16 +3534,107 @@
 asic%22);%0A
+%09%09clientAuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());%0A
 %09%09return

Configure the TokenEndpoint to use our custom exception handler.