UserDetailsService bean missing since Spring Security migration from XML to JavaConfig - spring-security

I use Spring Security 3.2.0.RELEASE.
I am currently migrating my application's XML-based Spring Security configuration to a JavaConfig-based Spring Security configuration.
In the old security.xml, I configured a JDBC-based UserDetailsService like this:
<authentication-manager alias="authenticationManager">
<authentication-provider>
<password-encoder ref="passwordEncoder" />
<!-- parsed by JdbcUserServiceBeanDefinitionParser -->
<!-- the following creates a JdbcUserDetailsManager -->
<jdbc-user-service data-source-ref="dataSource" />
</authentication-provider>
</authentication-manager>
Among other effects, above XML configuration automatically registered a Spring Bean of type JdbcUserDetailsManager (a subtype of UserDetailsService) that I could inject into other components like so:
#Service
public class MyCustomService {
#Inject
private JdbcUserDetailsManager judm;
//...
}
My JavaConfig-based adaption of above XML looks like this:
#Configuration
// #ImportResource("classpath:to/no/longer/needed/security.xml")
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.passwordEncoder( somePasswordEncoder )
.dataSource( someDataSource );
}
// ...
}
Above JavaConfig configuration does not seem to additionally register a Spring Bean of type JdbcUserDetailsManager. This means that MyCustomService does not get injected with such a bean, and therefore I get a NoSuchBeanDefinitionException:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.provisioning.JdbcUserDetailsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#javax.inject.Inject()}
Using the JavaConfig approach, how can I get hold of a bean of type JdbcUserDetailsManager?

have you tried to add
#Bean
public JdbcUserDetailsManager jdbcUserDetailsManager(){
return new JdbcUserDetailsManager();
}
to your SecurityConfig class?

Related

#Secured is not working while integrating Spring Security in Jersey project

I have a demo JAX-RS project using Jersey. Now I am trying add Spring Security's method level security but unfortunately its not working although intercept-url xml way is working fine.
Added all the dependency in my pom.xml
Updating web.xml as
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/security.xml,
/WEB-INF/beans.xml
</param-value>
</context-param>
<!-- this is default security impl name used by deletetingFiterProxy -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Updating /WEB-INF/security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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">
<!-- kind of authentication applied 1) Basic 2) form-based etc.. auto-config="true" use-expressions="true"-->
<http auto-config="true">
<http-basic />
</http>
<!-- this allow to enable security annotations in restful resoruces -->
<global-method-security secured-annotations="enabled" />
<!-- for defining users and roles -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_CUSTOMER,ROLE_ADMIN"/>
<user name="student" password="student" authorities="ROLE_CUSTOMER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Annotating service inteface methods
public interface StudentServiceInterface {
#GET
#Path("/students")
#Secured("ROLE_CUSTOMER")
public Response getStudents();
#GET
#Path("/students/{id}")
#Secured("ROLE_CUSTOMER")
public Response getStudent(#PathParam("id") int id);
#POST
#Path("/students")
#Consumes(MediaType.APPLICATION_JSON)
#Secured("ROLE_ADMIN")
public Response addStudent(Student stu);
}
Now when I try to access the resource student (/student) class it opens without asking password.
http://localhost:3126/securitydemo/webapi/db/students
StudentServiceInterface interface implementation
#Path("/db")
#Produces(MediaType.APPLICATION_JSON)
public class StudentService implements StudentServiceInterface{
static StudentDao data= new StudentDaoImpl();
#Override
public Response getStudents(){
GenericEntity<List<Student>> entity = new GenericEntity<List<Student>>(data.getAllStudents()){};
return Response.ok(entity).build();
}
#Override
public Response getStudent(#PathParam("id") int id){
return Response.ok(data.getStudent(id)).build();
}
#Override
public Response addStudent(Student stu) {
data.addStudent(stu);
return Response.ok(stu).build();
}
}
You have to use the extention for Spring DI, see Jersey 2.25.1 User Guide:
Jersey provides an extension to support Spring DI. This enables Jersey to use Spring beans as JAX-RS components (e.g. resources and providers) and also allows Spring to inject into Jersey managed components.
The Spring extension module configuration is based on annotations. Spring beans are injected and JAX-RS classes are made Spring managed using annotations. Injected Spring beans can have further dependencies injected using Spring XML configuration. Spring singleton and request scopes are supported.
To enable JAX-RS resources to work Spring functionality that requires proxying, such as Spring transaction management (with #Transactional), Spring Security and aspect oriented programming (such as #Aspect), the resources must themselves be managed by Spring, by annotating with #Component, #Service, #Controller or #Repository:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.springframework.stereotype.Component;
#Component
#Path("/")
public class SomeResource {
#Transactional
#GET
public void updateResource() {
// ...
}
}
Limitations:
Spring beans can't be injected directly into JAX-RS classes by using Spring XML configuration
25.1. Dependencies
If you want to use Jersey Spring DI support you will need to add the jersey-spring3 module into the list of your dependencies:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.25.1</version>
</dependency>
The above module adds transitive dependencies on Spring modules. See jersey-spring3 module dependencies for more details about list and scope of dependencies. Please note the module depends on The Spring/HK2 Bridge that is used to inject Spring services into HK2 services or inject HK2 services into Spring services.

Neo4jTemplate error when using standalone mode

In my project I'm using Spring 3 with Neo4j 2.0.1, I was using the embedded mode and everything was working fine.
In my code I use the Neo4jTemplate (#Autowired in my services) as well as the GraphRepository and RelationshipOperationsRepository.
I wanted to migrate my coode to use the standalone mode. Here's what I did :
In spring-context.xml, I made it like this :
<!-- Neo4J -->
<!-- neo4j:config storeDirectory="${neo.storeDir}" base-package="net.nextep.nextenergy.domain.graph" /-->
<bean id="graphDatabase" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg value="http://localhost:7474/db/data/" index="0"/>
</bean>
<neo4j:repositories base-package="net.nextep.nextenergy.repository.graph" />
I tried to run it, I got this error :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' is defined
I tried then to remove the #Autowired Neo4jTemplate from my services, use #Autowired private SpringRestGraphDatabase graphDB and create a new Template this way private Neo4jTemplate template = new Neo4jTemplate((GraphDatabase) graphDB)
And I still get the same error :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userNodeRepository': Cannot resolve reference to bean 'neo4jTemplate' while setting bean property 'neo4jTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' is defined
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'neo4jTemplate' is defined
...
The UserNodeRepository :
#Repository
public interface UserNodeRepository extends GraphRepository<UserNode>,
RelationshipOperationsRepository<UserNode>{
public UserNode findById(String id);
public Node findNodeById(String id);
#Query("match (u:UserNode)-[:HABILITATED]->(f:Folder) where ID(u) = {0} return f")
public Set<Folder> getAllowedFoldersFirstLevel(UserNode user);
}
Am I doing wrong?
Name your bean "graphDatabaseService" and pass it to the config which you didn't create:
<neo4j:config graphDatabaseService="graphDatabaseService" base-package="net.nextep.nextenergy.domain.graph" />
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg value="http://localhost:7474/db/data/" index="0"/>
</bean>
<neo4j:repositories base-package="net.nextep.nextenergy.repository.graph" />

Migrating a Waffle Spring Security XML configuration to Spring Boot

I'm trying to use Waffle authentication with Spring Security, in a Spring Boot fashion. Expected result is 'block everything if Negotiate fails'.
Waffle project provides a configuration example for this kind of use case (there is in this example a fallback to simple HTTP auth if Negotiate fails, which I don't need), assuming configuration is done through web.xml. But despite many attempts, I don't understand how to plug Waffle with Spring Security using Boot and Java-only configuration. I'm using Spring Boot 1.2.1.RELEASE with starters web and security, Waffle version is 1.7.3.
I realize that this is not a specific question but Spring forum now redirects here and Waffle guys don't know about Spring Boot. Could someone help me translate an XML Spring Security configuration to Spring Boot?
First step is declaring a filter chain and context loader listener.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/waffle-filter.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
I'm assuming (am I wrong?) that this is already handled by #EnableWebMvcSecurity, so nothing to do here.
Next is declaring a couple of provider beans, so I translate this
<bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl" />
<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
<constructor-arg>
<list>
<ref bean="negotiateSecurityFilterProvider" />
<ref bean="basicSecurityFilterProvider" />
</list>
</constructor-arg>
</bean>
<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>
to this
#Bean
public WindowsAuthProviderImpl waffleWindowsAuthProvider() {
return new WindowsAuthProviderImpl();
}
#Bean
#Autowired
public NegotiateSecurityFilterProvider negotiateSecurityFilterProvider(final WindowsAuthProviderImpl windowsAuthProvider) {
return new NegotiateSecurityFilterProvider(windowsAuthProvider);
}
#Bean
#Autowired
public BasicSecurityFilterProvider basicSecurityFilterProvider(final WindowsAuthProviderImpl windowsAuthProvider) {
return new BasicSecurityFilterProvider(windowsAuthProvider);
}
#Bean
#Autowired
public SecurityFilterProviderCollection waffleSecurityFilterProviderCollection(final NegotiateSecurityFilterProvider negotiateSecurityFilterProvider, final BasicSecurityFilterProvider basicSecurityFilterProvider) {
final SecurityFilterProvider[] securityFilterProviders = {
negotiateSecurityFilterProvider,
basicSecurityFilterProvider
};
return new SecurityFilterProviderCollection(securityFilterProviders);
}
#Bean
#Autowired
public NegotiateSecurityFilter waffleNegotiateSecurityFilter(final SecurityFilterProviderCollection securityFilterProviderCollection) {
final NegotiateSecurityFilter negotiateSecurityFilter = new NegotiateSecurityFilter();
negotiateSecurityFilter.setProvider(securityFilterProviderCollection);
return negotiateSecurityFilter;
}
Final step is sec:http section configuration. An entry point is declared and filter is placed before BASIC auth filter.
Example:
<sec:http entry-point-ref="negotiateSecurityFilterEntryPoint">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
<sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>
<bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>
My Boot translation:
#Autowired
private NegotiateSecurityFilterEntryPoint authenticationEntryPoint;
#Autowired
private NegotiateSecurityFilter negotiateSecurityFilter;
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().authenticated()
.and()
.addFilterBefore(this.negotiateSecurityFilter, BasicAuthenticationFilter.class)
.httpBasic().authenticationEntryPoint(this.authenticationEntryPoint);
}
#Bean
#Autowired
public NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint(final SecurityFilterProviderCollection securityFilterProviderCollection) {
final NegotiateSecurityFilterEntryPoint negotiateSecurityFilterEntryPoint = new NegotiateSecurityFilterEntryPoint();
negotiateSecurityFilterEntryPoint.setProvider(securityFilterProviderCollection);
return negotiateSecurityFilterEntryPoint;
}
Running this configuration leads to strange behavior: sometimes NTLM is triggered and succeed, sometimes Negotiate filter crashes with an 'invalid token supplied' error (same credentials, user, browser, configuration).
Provided example works like a charm, which makes me think that my Boot configuration is in question.
Any help appreciated!
Spring Boot auto-registers all Filter beans so in this case the NegotiateSecurityFilter ends up being twice in the filter chain.
You have to disable the auto-registration for this specific Filter by creating a FilterRegistrationBean overriding this behavior:
#Bean
public FilterRegistrationBean registration(NegotiateSecurityFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
Also, as Dave Syer mentioned, you should be setting the authentication entry point bean using the ExceptionHandlingConfigurer.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint);
// ...
}

How to use/configure JAX-RS 2.0, SpringSecurity 3.1.+, EJB 3.2 all together

I am currently trying to setup a project with these main technologies:
Java EE 7
EJB 3.2
JAX-RS (Jersey) 2.0
Glassfish 4
Spring Security 3.1.5
I saw that it is possible to write something like that
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
Then, this means that the SomeService Session Bean is injected by the container and once we call the path: :///apath, everything is working fine.
Now, what I try to achieve is to integrate the SpringSecurity framework in that code. So my code become this:
#Component
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
#PreAuthorized("hasPermission('ROLE_SOMETHING')")
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
But, this does not work. Everything excepted the SpringSecurity annotations continue to work. The authorization annotations are just not taken into account.
In SpringSecurity configuration file, I have something like that:
<security:global-method-security
access-decision-manager-ref="preVoteAccessDecisionManager"
pre-post-annotations="enabled" />
with everything related to the filter chain and so correctly configured. For example, I have that:
<beans:bean id="securityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="securityMetadataSource">
<security:filter-security-metadata-source>
<security:intercept-url pattern="/**" access="ROLE_TEST" />
</security:filter-security-metadata-source>
</beans:property>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
</beans:bean>
And I see in my Glassfish 4 server logs that SpringSecurity managed the ROLE_TEST access for my authenticated user. I also see that my user authenticated has the list of roles that I expect.
I also tried to use this configuration and rely on javax.annotation.security annotations as below:
<security:global-method-security
access-decision-manager-ref="preVoteAccessDecisionManager"
jsr250-annotations="enabled" />
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
#RolesAllowed("ROLE_SOMETHING")
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
This time, the annotation is working and an exception is thrown when the user is authenticated. But in this case, my user has the roles but the SecurityContext used by the container is not filled with the Principal and roles information related to the user authenticated by SpringSecurity.
Finally, my question(s). Is there a way to integrate the JAX-RS / #Stateless / SpringSecurity Authorization together? If not, is there a way to fill a SecurityContext from SrpingSecurity to allow javax.annotation.security to work like a charm?
Thanks in advance for any helps, tips, tricks or anything else that can solve my problems :D
Spring Security's method security annotations will normally only work with Spring beans whose lifecycle is controlled by Spring. This doesn't include EJBs. However, if you wish you can use the AspectJ integration which will work for any object including EJB instances. There's a sample application in the Spring Security codebase which you can use as a reference. It might also be worth considering whether you need to use EJBs at all.

Spring Security: How to customize remember-me request parameter name?

I'm using password-parameter (as below) to customize the name of the request parameter which contains the password. How to do the same with remember-me (default _spring_security_remember_me) ?
<security:form-login password-parameter="j_password_input" ... />
You have a few options which I have explained in further detail below
Use the Security Namespace with a BeanPostProcessor
Use the services-ref and configure RememberMeServices Manually
Use the Security Namespace with a BeanPostProcessor
The namespace does not have support for configuring the remember me parameter, but you can use a tip from the FAQ on how to still use the namespace support, but customise the result. The trick is to use a BeanPostProcessor to set the parameter field on AbstractRememberMeServices. You can find an example of this below:
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String name) {
if (bean instanceof AbstractRememberMeServices) {
AbstractRememberMeServices rememberMe = (AbstractRememberMeServices) bean;
rememberMe.setParameter("myParamname");
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String name) {
return bean;
}
}
Then you would need to use the namespace as you normally would and add MyBeanPostProcessor to your Spring configuration as shown below:
<security:http ..>
...
<security:remember-me/>
</security:http>
<bean class="sample.MyBeanPostProcessor"/>
Use the services-ref and configure RememberMeServices Manually
You can also use the services-ref attribute too, but this involves a little more configuration. For example, if you wanted you could use the following configuration:
<security:http ..>
...
<security:remember-me services-ref="rememberMeServices"/>
</security:http>
<bean id="rememberMeServices"
class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="key" value="mustMatchRememberMeAuthenticationProvidersKey"/>
<property name="parameter" value="myParamName"/>
<!-- You must refer to a bean that implements UserDetailsService
in this example the bean id is userDetailsService -->
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
As of Spring Security 3.2.x, you can set this with the remember-me-parameter parameter on the remember-me element.

Resources