Oauth authorization server with custom authentication manager in Java config - java

I have multiple authentication managers in the application. I distinguish them by bean name. Part of my xml configuration related to oauth authorization server looks like and it works fine:
<oauth:expression-handler id="oauthExpressionHandler" />
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler" >
<oauth:authorization-code disabled="true" />
<oauth:implicit disabled="false" />
<oauth:refresh-token disabled="false" />
<oauth:client-credentials disabled="false" />
<oauth:password authentication-manager-ref="authenticationManager" />
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter" resource-id="resource-id" token-services-ref="tokenServices" />
<sec:authentication-manager id="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="oauthClientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
I'm trying to move it to Java based configuration (in some SecurityConfig class), without lack so far. I've tried something like:
#Configuration
#EnableAuthorizationServer
protected static class OAuth2AuthConfig extends AuthorizationServerConfigurerAdapter {
#Resource(name = "authenticationManager")
private AuthenticationManager authenticationManager;
#Resource
private OAuth2AuthenticationEntryPoint authenticationEntryPoint;
#Resource(name = "clientDetails")
private ClientDetailsService clientDetailsService;
#Resource
private TokenStore tokenStore;
#Resource
private TokenStoreUserApprovalHandler userApprovalHandler;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.authenticationEntryPoint(authenticationEntryPoint);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.userApprovalHandler(userApprovalHandler)
.tokenStore(tokenStore);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
}
#Configuration
#EnableResourceServer
protected static class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter {
#Resource
private DefaultTokenServices tokenServices;
#Resource(name = "authenticationManager")
private AuthenticationManager authenticationManager;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).tokenServices(tokenServices).authenticationManager(authenticationManager);
}
}
however it still complains about multiple authentication managers, although I explicitly set endpoints.authenticationManager(authenticationManager).
With some debugging I can see it tries to configure it within class WebSecurityConfigurerAdapter and it meets multiple authentication manager within authenticationManager(). Am I able to override it or what am I missing?

AuthorizationServer - here there is a way to prevent Spring to fail on
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager by simply overriding method
org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration#configure(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder) - explanation
ResourceServer - unfortunately there is no way for similar handling corresponding problem. Best what you can do is decreasing number of instances of global authentication managers to exactly one.

Related

How can I add two security policies in Spring MVC App?

I'm writing spring application to serve mobile as well as web portal requests.
I have added Controller to handle web portal requests and RestController to handle mobile requests. This all stuff I have done in single project.
I've configured auth.xml for authetication and all.
<security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" auto-config="false" create-session="stateless" >
<security:intercept-url pattern="/api/auth" access="permitAll" />
<security:intercept-url pattern="/api/token" access="permitAll" />
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/api/**" access="isAuthenticated()" />
<security:logout />
</security:http>
<bean class="com.auth.TokenAuthenticationFilter"
id="authenticationTokenProcessingFilter">
<constructor-arg type="java.lang.String"><value>/api/**</value></constructor-arg>
</bean>
<!-- Code for REST API Authentication -->
<!-- create-session="stateless" -->
<security:http auto-config="false" use-expressions="true" entry-point-ref="ajaxAwareAuthenticationEntryPoint" disable-url-rewriting="true">
<security:intercept-url pattern="/login" access="permitAll()" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<security:logout logout-url="/logout" logout-success-url="/login.do" invalidate-session="true" />
<security:remember-me services-ref="rememberMeService" />
<security:session-management session-authentication-strategy-ref="sas" />
<security:csrf disabled="true"/>
</security:http>
But I want to integrate Spring OAuth 2.0 in it.
Can anyone has idea about the same ?
You can configure 2 different security filters for 2 different paths. That way, you can have differents paths of you application secured differently. Typically, you would want to have "/public/" accessible to anyone while "/api/" being secured by authentication.
I would strongly recommend to configure Spring Security in Java by extending WebSecurityConfigurerAdapter.
Here is an example Java configuration which protects only some endpoints while leaving others accessible publicly.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
new AntPathRequestMatcher("/**", OPTIONS.toString()),
new AntPathRequestMatcher("/public/**"),
new AntPathRequestMatcher("/health"),
// Spring Social
new AntPathRequestMatcher("/signin/**"),
new AntPathRequestMatcher("/auth/**"),
// Swagger Documentation
new AntPathRequestMatcher("/swagger-ui.html"),
new AntPathRequestMatcher("/v2/api-docs"),
new AntPathRequestMatcher("/swagger-resources/**"),
new AntPathRequestMatcher("/webjars/**")
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
#Autowired
private RESTAuthenticationProvider authenticationProvider;
#Autowired
private TokenService credentials;
#Autowired
private UserSecurityService users;
#Override
protected void configure(final AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().requestMatchers(PUBLIC_URLS);
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.exceptionHandling()
// this entry point handles when you request a protected page and you are not yet
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(restAuthenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable()
.sessionManagement().disable();
}
#Bean
RESTAuthenticationFilter restAuthenticationFilter() throws Exception {
final RESTAuthenticationFilter filter =
new RESTAuthenticationFilter(PROTECTED_URLS, credentials);
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationSuccessHandler(getSuccessHandler());
return filter;
}
// Upon successful authentication, Spring will attempt to try and move you to another URL
// We have to prevent this because the request for the resource and the authentication all get done in the same request!
#Bean
SimpleUrlAuthenticationSuccessHandler getSuccessHandler() {
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy(new NoRedirectStrategy());
return successHandler;
}
#Bean
AuthenticationEntryPoint forbiddenEntryPoint() {
return new Http401AuthenticationEntryPoint("Bearer");
}
}
Try out spring security. It has built in functionalities also you can always override existing behavior for your purposes.

How to call bean with #Autowiring from app context in security context

After a research, I still dont found a solution for this problem.
My aim is to validate user in Custom Authentication Provider using database but the #Autowiring always throw Null Pointer Exception.
Here my code:
Custom Authentication Provider:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private Validator iValidate;
#Override
public Authentication authenticate(Authentication auth) throws AuthenticationException{
if (iValidate.userNameCheck(auth.getName()) != "00") {
auth=null;
}
return auth:
}
#Override
public boolean supports(Class<?> auth) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(auth));
}
}
Validator.java:
#Component
public class Validator implements IsamSvc {
private StopWatch sw = new StopWatch();
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public String userNameCheck(String mercid, String caller) {
/////validating code/////
}
}
Spring Security XML:
<global-method-security pre-post-annotations="enabled" />
<http pattern="/resources/**" security="none" />
<http auto-config="false" use-expressions="true" disable-url-rewriting="true" >
<session-management session-fixation-protection="newSession" session-authentication-error-url="/login.do?sessionalreadyexist">
<concurrency-control max-sessions="1" expired-url="/login.do?expired" error-if-maximum-exceeded="true" />
</session-management>
<intercept-url pattern="/clearcache" access="permitAll()" />
<intercept-url pattern="/login.do" access="permitAll()" />
<intercept-url pattern="/**" access="isFullyAuthenticated()" />
<logout logout-success-url="/login.do?logout" delete-cookies="JSESSIONID" invalidate-session="true" />
<access-denied-handler error-page="/403" />
<form-login login-page='/login.do' login-processing-url="/login" default-target-url="/main" always-use-default-target="true" authentication-failure-url="/login.do?error" username-parameter="username" password-parameter="password" authentication-details-source-ref="CustomAuthInfoSource" /> -->
</http>
<authentication-manager>
<authentication-provider ref="CustomAuthenticationProvider" />
</authentication-manager>
<beans:bean id="CustomAuthenticationProvider" class="xx.xxx.xxxx.xxxxx.CustomAuthenticationProvider" />
beans.xml:
<beans:bean id="iValidate" class="xx.xxx.xxxx.xxxxx.Validator" scope="prototype" />
/////// Other beans ////////
when i call #Autowired private Validator iValidate; in #Controller class, it work normally,but in CustomAuthenticationProvider, it will return null ...
Any Solution?
annotate the CustomAuthenticationProvider with #Component annotation

Spring OAuth2 "Full authentication is required to access this resource"

I'm trying to use Spring OAuth2 for my rest app.
But looks like I made a mistake and I can find where I did it.
The flow should be:
1. get token from /oauth/token with username and password
2. make request to /security with provided token
MethodSecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Autowired
private SecurityConfiguration securityConfig;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
OAuth2ServerConfig:
#Configuration
public class OAuth2ServerConfig {
private static final String RESOURCE_ID = "nessnity";
#Configuration
#Order(10)
protected static class UiResourceConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/security")
.and()
.authorizeRequests()
.antMatchers("/security").access("hasRole('USER')");
}
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/security/")
.and()
.authorizeRequests()
.antMatchers("/security").access("#oauth2.hasScope('read')");
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client")
.resourceIds(RESOURCE_ID)
.authorizedGrantTypes("client_credentials")
.authorities("ROLE_CLIENT")
.scopes("read")
.secret("password")
.accessTokenValiditySeconds(60);
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("sparklr2/client");
}
}
protected static class Stuff {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private TokenStore tokenStore;
#Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
#Bean
#Lazy
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
public SparklrUserApprovalHandler userApprovalHandler() throws Exception {
SparklrUserApprovalHandler handler = new SparklrUserApprovalHandler();
handler.setApprovalStore(approvalStore());
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
handler.setUseApprovalStore(true);
return handler;
}
}
}
SecurityConfiguration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root")
.password("password")
.roles("USER");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/oauth/uncache_approvals", "/oauth/cache_approvals");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().hasRole("USER");
}
}
Problem: when I tried to get token
curl --user root:password --data "grant_type=client_credentials" http://localhost:8080/oauth/token
I got message:
{"error":"invalid_client","error_description":"Bad client
credentials"}
The second question is how to pass username/password in the url params like /oauth/token?username=root&password=password ?
Thanks.
UPDATE
I decided to start from scratch and use xml configuration.
The following configuration works perfect:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<bean id="clientDetails" class="com.nessnity.api.security.OAuthClienDetailsService">
<property name="id" value="testuser"/>
<property name="secretKey" value="secret" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="springsec/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<oauth:authorization-server
client-details-service-ref="clientDetails"
token-services-ref="tokenServices">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password authentication-manager-ref="userAuthenticationManager"/>
</oauth:authorization-server>
<authentication-manager id="userAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customUserAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<bean id="customUserAuthenticationProvider"
class="com.nessnity.api.security.OAuthUserAuthenticationProvider">
</bean>
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="accessTokenValiditySeconds" value="900000000"/>
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="tokenStore"
class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore"/>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
</bean>
<http pattern="/resources/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/resources/**" method="GET"/>
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<oauth:resource-server id="resourceServerFilter"
resource-id="springsec" token-services-ref="tokenServices"/>
</beans>
I have faced similar for me it worked after doing the following change
In your AuthorizationServerConfiguration class replace
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm("sparklr2/client");
}
with the below code
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//oauthServer.realm("sparklr2/client");
oauthServer.allowFormAuthenticationForClients();
}
and request should like
/oauth/token?grant_type=password&scope=read+write&client_id=yourclientId&client_secret=secret&username=userName&password=pwd
In your access token request you are using client credentials grant type. OAuth spec says that in case of client_credentials grant type you need to provide base64 encoded client_id:client_secret as Basic Authorization header.
For example if your client_id is google and client_secret is x23r-ss56-rfg8-6yt6, then you need to add these string as google:x23r-ss56-rfg8-6yt6, encode it using Base64 encoder and make request as
curl --header "Authorization: Basic <base64 encoded_string>" --data "grant_type=client_credentials" http://localhost:8080/oauth/token

How To Inject AuthenticationManager using Java Configuration in a Custom Filter

I'm using Spring Security 3.2 and Spring 4.0.1
I'm working on converting an xml config into a Java config. When I annotate AuthenticationManager with #Autowired in my Filter, I'm getting an exception
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.authentication.AuthenticationManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
I've tried injecting AuthenticationManagerFactoryBean but that also fails with a similar exception.
Here is the XML configuration I'm working from
<?xml version="1.0" encoding="UTF-8"?> <beans ...>
<security:authentication-manager id="authenticationManager">
<security:authentication-provider user-service-ref="userDao">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<security:http
realm="Protected API"
use-expressions="true"
auto-config="false"
create-session="stateless"
entry-point-ref="unauthorizedEntryPoint"
authentication-manager-ref="authenticationManager">
<security:access-denied-handler ref="accessDeniedHandler"/>
<security:custom-filter ref="tokenAuthenticationProcessingFilter" position="FORM_LOGIN_FILTER"/>
<security:custom-filter ref="tokenFilter" position="REMEMBER_ME_FILTER"/>
<security:intercept-url method="GET" pattern="/rest/news/**" access="hasRole('user')"/>
<security:intercept-url method="PUT" pattern="/rest/news/**" access="hasRole('admin')"/>
<security:intercept-url method="POST" pattern="/rest/news/**" access="hasRole('admin')"/>
<security:intercept-url method="DELETE" pattern="/rest/news/**" access="hasRole('admin')"/>
</security:http>
<bean class="com.unsubcentral.security.TokenAuthenticationProcessingFilter"
id="tokenAuthenticationProcessingFilter">
<constructor-arg value="/rest/user/authenticate"/>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
<property name="authenticationFailureHandler" ref="authenticationFailureHandler"/>
</bean>
</beans>
Here is the Java Config I'm attempting
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and();
//TODO: Custom Filters
}
}
And this is the Custom Filter class. The line giving me trouble is the setter for AuthenticationManager
#Component
public class TokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
public TokenAuthenticationProcessingFilter(#Value("/rest/useAuthenticationManagerr/authenticate") String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
...
}
private String obtainPassword(HttpServletRequest request) {
return request.getParameter("password");
}
private String obtainUsername(HttpServletRequest request) {
return request.getParameter("username");
}
#Autowired
#Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
#Autowired
#Override
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
super.setAuthenticationSuccessHandler(successHandler);
}
#Autowired
#Override
public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
super.setAuthenticationFailureHandler(failureHandler);
}
}
Override method authenticationManagerBean in WebSecurityConfigurerAdapter to expose the AuthenticationManager built using configure(AuthenticationManagerBuilder) as a Spring bean:
For example:
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
In addition to what Angular University said above you may want to use #Import to aggregate #Configuration classes to the other class (AuthenticationController in my case) :
#Import(SecurityConfig.class)
#RestController
public class AuthenticationController {
#Autowired
private AuthenticationManager authenticationManager;
//some logic
}
Spring doc about Aggregating #Configuration classes with #Import: link
When I #Bean'ed AuthenticationManager and #Autowired it in same class then needed to activate circular references but that is rather as for CDI.

Spring security - different SALTs at user creation and login time

I am facing again the same problem with Spring Security: "password does not match stored value".
I import 4 accounts in my graph (I'm using SpringData/Neo4J) with my custom GraphPopulator class and try to log in with one ("fbiville"/"s3cret").
The authentication is configured as follows:
<beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<beans:constructor-arg value="******" />
</beans:bean>
<beans:bean id="userService" class="com.lateralthoughts.devinlove.service.LoginService" />
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
And the class in charge of persisting accounts is partially based on a custom SpringData repository implementation:
class PersonRepositoryImpl implements PersonRepositoryCustom {
private final PasswordEncoder passwordEncoder;
private final Neo4jOperations template;
#Autowired
public PersonRepositoryImpl(PasswordEncoder passwordEncoder,
Neo4jOperations template) {
this.passwordEncoder = passwordEncoder;
this.template = template;
}
#Override
#Transactional
public void persist(Person person) {
person.setPassword(passwordEncoder.encode(person.getPassword()));
template.save(person);
}
}
Finally, the login process is configured as follows:
<http auto-config='true' use-expressions='true' realm="devinlove: love is just another algorithm">
<form-login login-page="/login"
default-target-url="/"
authentication-failure-url="/login" />
<intercept-url pattern="/login" access="isAnonymous()" />
<intercept-url pattern="/**" access="hasRole('USER')" />
</http>
I debugged the StandardPasswordEncoder at account creation and user login attempt, and I noticed the salts don't match, which obviously leads to an authentication error.
You can clone the repository if you wanna reproduce the problem.
Thanks in advance !
Rolf
You need to use org.springframework.security.authentication.encoding.PasswordEncoder implementation, rather then org.springframework.security.crypto.password.PasswordEncoder.
So you can simply use as the follows:
<authentication-manager>
<authentication-provider user-service-ref="userService">
<password-encoder hash="sha" base64="true">
<!--Single salt - the very same as you are using in `encoder` instance-->
<salt-source system-wide="********"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
Note, that this will work properly with #Autowired properties, though there shouldn't be #Qualifier and beans have to be represented only once.
It exposes implementation of such interfaces: org.springframework.security.authentication.encoding.PasswordEncoder and org.springframework.security.authentication.dao.SaltSource.
So in your particular case it would look like as follows:
class PersonRepositoryImpl implements PersonRepositoryCustom {
private final PasswordEncoder passwordEncoder;
private final Neo4jOperations template;
#Autowired
public PersonRepositoryImpl(PasswordEncoder passwordEncoder,
SaltSource saltSource
Neo4jOperations template) {
this.passwordEncoder = passwordEncoder;
this.saltSource = saltSource;
this.template = template;
}
#Override
#Transactional
public void persist(Person person) {
person.setPassword(passwordEncoder.encode(person.getPassword(), saltSource));
template.save(person);
}
}

Categories