I was converting xml based configuration (from source ) to java configuration. I have placed both the files below, it was working with xml configuration but cannot authenticate after changing to java configuration. Can anyone shed some ideas how to fix it?
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>
<sec:authentication-manager alias="userAuthenticationManager">
<sec:authentication-provider user-service-ref="userService">
<sec:password-encoder ref="passwordEncoder"/>
</sec:authentication-provider>
</sec:authentication-manager>
<sec:authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<sec:authentication-provider user-service-ref="client-details-user-service"/>
</sec:authentication-manager>
<bean id="client-details-user-service" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="client-details-service" />
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http pattern="/v1.0/users" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/v1.0/users" method="POST" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- REST API Endpoints -->
<http pattern="/v1.0/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<context:component-scan base-package="com.porterhead.oauth2.configuration"/>
<!-- Access voters -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
ROLE_USER > ROLE_GUEST
</value>
</property>
</bean>
<bean id="roleVoter" class="com.porterhead.security.HierarchicalJsr250Voter">
<constructor-arg ref="roleHierarchy" />
</bean>
<sec:global-method-security jsr250-annotations="enabled" access-decision-manager-ref="accessDecisionManager"/>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>
</beans>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<oauth:authorization-server client-details-service-ref="client-details-service" token-services-ref="tokenServices">
<oauth:refresh-token/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="client-details-service"/>
</bean>
<bean id="corsFilter" class="com.porterhead.filter.spring.SpringCrossOriginResourceSharingFilter"/>
<bean id="oauthRestEntryPoint" class="com.porterhead.security.OAuthRestEntryPoint"/>
<!-- The token endpoint See org.springframework.security.oauth2.provider.endpoint.TokenEndpoint-->
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<http-basic entry-point-ref="oauthRestEntryPoint" />
<access-denied-handler ref="oauthAccessDeniedHandler"/>
<custom-filter ref="corsFilter" after="LAST"/>
</http>
</beans>
@Configuration
@ComponentScan
@EnableResourceServer
@Import(SecurityConfig.class)
//@ImportResource({
// "classpath:META-INF/spring/oauth/client-details.xml"
//})
public class OAuth2ServerConfig {
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends
AuthorizationServerConfigurerAdapter {
@Autowired
private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(){
ClientCredentialsTokenEndpointFilter clientFilter = new ClientCredentialsTokenEndpointFilter();
return clientFilter;
}
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
public OAuth2AccessTokenRepository oAuth2AccessTokenRepository;
@Autowired
public OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;
@Bean
public DefaultTokenServices tokenServices(){
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setReuseRefreshToken(true);
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setClientDetailsService(clientDetailsService);
return defaultTokenServices;
}
@Bean
public OAuth2RepositoryTokenStore tokenStore() {
return new OAuth2RepositoryTokenStore(oAuth2AccessTokenRepository,
oAuth2RefreshTokenRepository);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess(
"isAnonymous || hasAuthority('ROLE_TRUSTED_CLIENT')")
.realm("test");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.withClientDetails(clientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenServices(tokenServices())
.setClientDetailsService(clientDetailsService);
}
}
}
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository userRepository;
@Autowired
private Validator validator;
@Bean
public PasswordEncoder passwordEncoder(){
return new StandardPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
return new UserServiceImpl(userRepository, validator, passwordEncoder());
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService());
}
@Bean
public OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler(){
return new OAuth2AccessDeniedHandler();
}
@Configuration
@Order(1)
public static class OAuthEndPointConfig extends WebSecurityConfigurerAdapter{
@Autowired
private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
@Autowired
private ClientDetailsService clientDetailsService;
@Bean
public OAuthRestEntryPoint oauthRestEntryPoint()
{
return new OAuthRestEntryPoint();
}
@Bean
public ClientDetailsUserDetailsService clientDetailsUserDetailsService(){
return new ClientDetailsUserDetailsService(clientDetailsService);
}
@Bean
protected AuthenticationEntryPoint authenticationEntryPoint(){
OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setTypeName("Basic");
entryPoint.setRealmName("test");
return entryPoint;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.antMatcher("/oauth/token")
.anonymous().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic().authenticationEntryPoint(oauthRestEntryPoint())
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/token")).disable()
.exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.afterPropertiesSet();
}
}
@Configuration
@Order(2)
protected static class ResourceServerEndpointConfig extends WebSecurityConfigurerAdapter{
@Autowired
private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
@Bean
public OAuth2AuthenticationEntryPoint clientAuthenticationEntryPoint(){
OAuth2AuthenticationEntryPoint clientAuthenticationEntrypoint = new OAuth2AuthenticationEntryPoint();
clientAuthenticationEntrypoint.setTypeName("Basic");
return clientAuthenticationEntrypoint;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
.authenticationEntryPoint(clientAuthenticationEntryPoint())
.and()
.requestMatchers().antMatchers("/v1.0/users")
.and()
.authorizeRequests().antMatchers(HttpMethod.POST, "/v1.0/users").permitAll()
.and()
.csrf().disable();
}
}
}
curl -v -X POST -H "Content-Type: application/json" -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=" -d '{"user":{"emailAddress":"[email protected]"}, "password":"password"}' 'http://localhost:8080/v1.0/users'
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /v1.0/users HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:8080
> Accept: */*
> Content-Type: application/json
> Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=
> Content-Length: 67
>
* upload completely sent off: 67 out of 67 bytes
< HTTP/1.1 401 Unauthorized
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Cache-Control: no-store
< Pragma: no-cache
< WWW-Authenticate: Basic realm="oauth", error="unauthorized", error_description="An Authentication object was not found in the SecurityContext"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Wed, 13 May 2015 16:01:40 GMT
<
* Connection #0 to host localhost left intact
{"error":"unauthorized","error_description":"An Authentication object was not found in the SecurityContext"}Veeras-MacBook-Pro:~ veeramarni$
OAuth2 Authorization Server Support. As we saw, the Spring Security OAuth stack offered the possibility of setting up an Authorization Server as a Spring Application. But the project has been deprecated, and Spring does not support its own authorization server as of now.
The Spring Security OAuth project has reached end of life and is no longer actively maintained by VMware, Inc. This project has been replaced by the OAuth2 support provided by Spring Security and Spring Authorization Server.
The first thing to note is that Spring Security OAuth 2.4. 0 officially deprecates all its classes. The second thing is that according to the Spring Security - OAuth 2.0 Features Matrix - FAQ: We are no longer planning on adding Authorization Server support to Spring Security.
Spring Security handles the Authentication and Spring Security OAuth2 handles the Authorization. To configure and enable the OAuth 2.0 Authorization Server we have to use @EnableAuthorizationServer annotation.
I think the authenticationManager
instance autowired in OAuth2ServerConfig
initializes with the default DaoAuthenticationProvider
. To use the custom beans that you have defined, inject your custom beans, configure AuthenticationManagerBuilder
and expose authenticationManager
as a bean in SecurityConfig
like below
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
@Qualifier("userDetailsManagerImpl")
private UserDetailsManager userDetailsManager;
....
....
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager);
auth.userDetailsService(userDetailsManager);
}
Also Inject the newly exposed bean in OAuth2ServerConfig
and configure it like below
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
...
...
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager)
.setClientDetailsService(clientDetailsService);
.tokenServices(tokenServices());
}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With