I am trying to migrate existing application Spring security configuration written in XML to Java Configuration (with Spring Boot)
Can you please help as to how the Java config needs to be defined for the below xml. I keep getting confused looking at different webpages..
Thanks in advance!
<security:http auto-config="false" entry-point-ref="filterEntryPoint">
<security:custom-filter before="FORM_LOGIN_FILTER" ref="myWebAuthorizationFilter" />
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_EVP"/>
</security:http>
<bean id="filterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl">
<value>https://companyLogin.com</value>
</property>
<property name="forceHttps">
<value>false</value>
</property>
</bean>
For this part, you will need to define a custom filter
<security:http auto-config="false" entry-point-ref="filterEntryPoint">
<security:custom-filter before="FORM_LOGIN_FILTER" ref="myWebAuthorizationFilter" />
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_EVP"/>
</security:http>
such as
public class MyCustomFilter extends GenericFilterBean {
#Override
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
And then register the custom filter
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new MyCustomFilter(), UsernamePasswordAuthenticationFilter.class);
.authorizeRequests()
.antMatchers("/**").access("hasRole('ROLE_USER') and hasRole('ROLE_EVP')");
}
}
To learn more about custom filter click here.
Next, for this one
<bean id="filterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl">
<value>https://companyLogin.com</value>
</property>
<property name="forceHttps">
<value>false</value>
</property>
You need to define a bean
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new MyCustomFilter(), UsernamePasswordAuthenticationFilter.class);
.authorizeRequests()
.antMatchers("/**").access("hasRole('ROLE_USER') and hasRole('ROLE_EVP')");
//defined bean
#Bean
public LoginUrlAuthenticationEntryPoint filterEntryPoint() {
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("https://companyLogin.com");
entryPoint.setForceHttps(false);
return entryPoint;
}
}
I think that's all.
Related
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.
I am trying to intercept the login request before spring security start its processing or it reaches to spring security interceptor. I want to do this because I have to do some validations on the user's input. So, I have created a interceptor from HandlerInterceptorAdapter class but it is not working.
So what I want to do is :
When any user try to login with username and password then this request must reaches to LoginRequestInterceptor first. Do some validation on user inputs and on success pass this request to spring security login processing url other wise to some other url.
But in my case the request is reaching directly to the spring security without visiting the interceptor.
Interceptor class
public class LoginRequestInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LogManager.getLogger(LoginRequestInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
logger.debug("Interceptor working pre");
return super.preHandle(request, response, handler);
}
Spring Security xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/Candidate/**" access="hasRole('ROLE_USER')" />
<!-- access denied page -->
<access-denied-handler error-page="/403" />
<form-login
login-processing-url="/login"
login-page="/"
default-target-url="/Candidate"
authentication-failure-url="/error=1"
username-parameter="registerationid"
password-parameter="password"
/>
<logout logout-success-url="/?logout" />
<custom-filter ref="loginRequestInterceptors" position="FIRST"/>
<!-- enable csrf protection -->
<csrf />
</http>
<authentication-manager id="authenticationManager">
<authentication-provider user-service-ref="candidateDetailServices" />
</authentication-manager>
Spring dispatcher xml
<bean id="loginRequestInterceptor" class="org.ibps.clerk.inteceptors.login.LoginRequestInterceptor"></bean>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login"/>
<ref bean="loginRequestInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
So at last I wanted to know whether it is possible or not? If Yes then please share the link or solution.
You should create a class (for example CustomFilter) extend UsernamePasswordAuthenticationFilter and over ride attemptAuthentication and do your stuff in it and then call super.attemptAuthentication;
Then you should confgiure in your security config class which extends WebSecurityConfigurerAdapter.
#Configuration
#EnableWebSecurity
public class SecurityConfigs extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(getCustomFilter()
,UsernamePasswordAuthenticationFilter.class)
.formLogin()
.and() // more configs ...
}
public CustomFilter getCustomFilter() throws Exception {
CustomFilter filter= new CustomFilter ("/loginuser","POST");
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.sendRedirect("/login?error");
});
return filter;
}
And your CustomFilter class:
public class CustomFilter extends UsernamePasswordAuthenticationFilter {
public CustomFilter (String urlLogin, String method) {
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(urlLogin, method));
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// do your stuff ...
return super.attemptAuthentication(request, response);
}
}
What you're probably looking to do is create a servlet filter that is executed before the Spring Security filterchain. By default the springSecurityFilterChain filter's order value is set to 0, meaning that it is executed before all other filters. One workaround for this is to set the security.filter-order to a higher value than that of the filter you wish to run before its execution in your properties file.
Check Filter order in spring-boot for further discussion on this topic.
Additional resources:
https://github.com/spring-projects/spring-security-oauth/issues/1024
https://mtyurt.net/2015/07/15/spring-how-to-insert-a-filter-before-springsecurityfilterchain/
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.
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
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.