I am new to Vaadin and Spring security. Last few days I was googling for the right example how to integrate spring security into vaadin application (not the servlet) so that the users can authenticate themselves using LoginForm vaadin component. Here is the code snippet that I used inside onlogin event:
login = new LoginForm();
login.addListener(new LoginForm.LoginListener() {
private static final long serialVersionUID = 1L;
#Override
public void onLogin(LoginEvent event) {
if (event.getLoginParameter("username").isEmpty() || event.getLoginParameter("password").isEmpty()) {
getWindow().showNotification("Please enter username and/or password", Notification.TYPE_ERROR_MESSAGE);
} else {
SpringContextHelper helper = new SpringContextHelper(getApplication());
authenticationManager = (ProviderManager)helper.getBean("authenticationManager");
try {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(event.getLoginParameter("username"), event.getLoginParameter("password"));
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
authentication.getDetails();
} catch (Exception e) {
getWindow().showNotification(e.getMessage(), Notification.TYPE_ERROR_MESSAGE);
}
}
}
});
When I try to login with my credentials that I described in applicationContext.xml file I got an error Null Pointer exception at this line:
authenticationManager = (ProviderManager)helper.getBean("authenticationManager");
I know that the error is thrown by the getBean("authenticationManager"); method because it can't locate "**authenticationManager"** bean. The question would be: what is the "**authenticationManager"** in this context. Is it a class or bean that implements some kind of Spring security framework interface with special methods. Does anyone could provide an example of such bean (class, pojo and etc.). I descriped listeners and context-params in my web.xml as I found on the examples in the internet.
WEB.XML
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
Also I am providing a applicationContext.xml in which I describe authentication manager with plain username and password.
APPLICATIONCONTEXT.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-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login />
<logout />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="userrrr" password="passsssword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="otheruser" password="otherpasss" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
So In short. Does anyone could provide me a working bean example, for my case, which can authenticate plain usernames and passwords that are described in applicationContext.xml file. If it helps I am using Vaadin 6, Maven, Hibernate, GlassFish and Sping security 3. I will greatly appreciate help because I am working on this issue for the last three days.
There are plenty examples on the internet but they are all unfinished, unclear, uses Vaadin application servelts or jsp login forms (not the application) and different techniques.
I choosed the way that is described in official vaadin wiki https://vaadin.com/wiki/-/wiki/Main/Spring%20Integration?p%255Fr%255Fp%255F185834411%255Ftitle=Spring%2520Integration. But it is so poor and describes spring framework integration not security.
I found another example which looked me perfect Spring Security + Vaadin: How to create custom non-JSP login form? . But there I can't find detailed info about authenticationManager.
Also here is another nice example https://vaadin.com/forum/-/message_boards/view_message/373038. But it is using HttpServletRequest and HttpServletResponse for passing authetication details. I know that vaadin application class can implement HttpServletRequestListener interface with onRequestStart and onRequestEnd methods but how I can pass/use these requests to/with onLogin event.
So dear JAVA masters please help for a newbie JAVA JEDI programmer to choose a right way:)
Spring Context helper class
public class SpringContextHelper {
private ApplicationContext context;
public SpringContextHelper(Application application) {
ServletContext servletContext = ((WebApplicationContext) application.getContext()).getHttpSession().getServletContext();
context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
}
public Object getBean(final String beanRef) {
return context.getBean(beanRef);
}
}
Try org.springframework.security.authentication.AuthenticationManager interface instead of ProviderManager:
authenticationManager = (AuthenticationManager)helper.getBean("authenticationManager");
EDIT. Replace alias="authenticationManager" by id="authenticationManager in your conf.
Related
I have problem figuring out why My Jersey RESTful entry point can't find the Spring Bean that I configure when the app server starts. It kept getting NullPointerException after trying from
Spring DI - Autowired property is null in a REST service
NullPointerException on #Autowired attribute with Jersey and Spring for REST service
#Autowired is not working with jersey and spring
Integrating both spring mvc and Jersey, getting a null pointer when viewing a jersey endpoint
Jersey 2 + Spring: #Autowired is null
Web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.testing.resource</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Spring-context.xml
<context:annotation-config />
<context:component-scan base-package="com.testing.config, com.testing.repository, com.testing.workflow" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:jdbc.properties</value>
</property>
</bean>
Jersey servlet entry point
#Component
#Produces(MediaType.APPLICATION_JSON)
#Path("/{userId}/items")
public class UserResource
{
#Autowired
private UserWorkFlow userWorkFlow;
#GET
public Response getAllItems(#PathParam("userId") String userId)
{
// ** NullPointerException here complains about the UserWorkFlow
return Response.status(200).entity(userWorkFlow.getItemsFor(userId)).build();
}
}
Service layer
I also tried to make an interface for this but it didn't work.
#Service
public class UserWorkFlow
{
#Autowired
private AllItems allItems;
public List<Item> getItemsFor(String id)
{
return allItems.getItemsFor(id);
}
}
Repository and DAO
#Repository
public class AllItems
{
#Autowired
private ItemSql itemSql;
public List<Item> getItemsFor(String id)
{
return itemSql.getAllItemsFor(id);
}
}
MyBatis Mapper (this has a XML associated with it)
public interface UserSql
{
List<Item> getAllItemsFor(#Param("userId") String userId);
}
I also changed to com.sun.jersey from org.glassfish.jersey but didn't work. I am running out of ideas what could be wrong. Can anyone spot what did I do wrong ?
The link I provided for your previous question had links to four fully working examples. You could have easily just grabbed one of the examples and built on top of it.
I will just walk you through one of the examples. Maybe it was too hard to follow. I will use the Jersey 2.x with Spring XML config.
First, make sure you have the dependencies (only showing versions to ones not shown in the pom)
jersey-container-servlet: 2.22.1
spring-web: 3.2.3.RELEASE
commons-logging
jersey-spring3: 2.22.1. (Notice the snapshot project uses jersey-spring*4*. This is not yet released, and will be released in the next Jersey release)
Second, make sure your web.xml is in order
Third, add your applicationContext.xml to the project class-path.
Fouth, the MyApplication class listed in the previous web.xml.
If you follow the example to the T, you will have a working example. It may not be the exact way you want to configure your Spring components, but you will have a working example you can build off of and tweak around to see what works and what doesn't. When you get more comfortable, you can see the other examples (in the first link of this answer) for other configuration styles/options.
I have extended ServiceImpl and DAOImpl classes with SpringBeanAutowiringSupport, It solved my autowired null pointer exception.
I need to put some values (String and Integer values) in user session after successful login.
I'm using Spring MVC + Spring Security (both v3.2.x) in my web app.
Is there some common approach with Spring to intercept session start? Is it correct to implement a HttpSessionListener and register it in my application?
I finally decided to implement a custom ApplicationListener to handle user login:
public class LoggedUserListener implements
ApplicationListener<AuthenticationSuccessEvent> {
#Autowired
private HttpSession session;
#Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
session.setAttribute("key", "value");
}
}
and declared a bean in my Spring config:
<bean class="it.webapp.LoggedUserListener" />
It works perfectly.
If you are using Spring MVC + Spring Security, it might be worth checking out org.springframework.security.web.session.HttpSessionEventPublisher
The javadoc for the class says:
Publishes HttpSessionApplicationEvents to the Spring Root
WebApplicationContext.
Maps javax.servlet.http.HttpSessionListener.sessionCreated() to
HttpSessionCreatedEvent.
My understanding is that you need to add:
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
And your class needs to extend ApplicationListener in order to receive these events
public class SessionPopulatorThing implements ApplicationListener<HttpSessionCreatedEvent>{
//repository, service attributes go here
public void onApplicationEvent(HttpSessionCreatedEvent httpSessionCreatedEvent){
//populate with defaults
}
}
The main benefit is that it's compatible with Spring Core + Spring Security and with a little bit of extra configuration on top of this you can get concurrency management features in session management with Spring Security as well. There's more about this in the spring security reference documentation:
I created a Application Spring component with two secured methods:
#Component
public class Application {
public void run() {
onlyAdminMethod();
onlyAdminMethod2();
}
#Secured( "ROLE_ADMIN" )
public void onlyAdminMethod() {
System.out.println( "Admin-only method called" );
}
#PreAuthorize( "hasRole('ROLE_ADMIN')" )
public void onlyAdminMethod2() {
System.out.println( "Admin-only method 2 called" );
}
}
I call run() method on that bean, which I take from Spring XML context:
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
context.getBean( Application.class).run();
Nothings happen - methods are called normally even if there is no authentication and SecurityContextHolder.getContext().getAuthentication() returns null
My Spring XML:
<context:annotation-config />
<context:component-scan base-package="practice" />
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="stackoverflow" authorities="ROLE_USER,ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
I use Maven dependencies for Spring 3.2.4
2 Things
Spring uses a proxy based solution for AOP. Which means only external method calls are intercepted, you are making internal method calls and those bypass the proxy.
Second make sure you are using class based proxies (you aren't using interfaces so JDK Dynamic Proxies won't work). Add proxy-target-class="true" to your <global-method-security .. /> element. Make sure you have cglib on your classpath as that is required for classbased proxies.
For a project I try to use Spring Security 3.2 as base security. Because this project is already up and running I do already have a other (own) security layer. Hence I made a custom authenticationprovider to melt the security layers. Works fine, till I also needed to make a custom anonymous authentication (Spring Security Documentation, chapter 13).
So I made a custom filter and removed the orignal filter:
<http request-matcher="regex" use-expressions="true">
<anonymous enabled="false" />
<custom-filter ref="anonymousAuthFilter" position="ANONYMOUS_FILTER"/>
...
</http>
the bean:
<beans:bean id="anonymousAuthFilter" class="own.package.auth.SecurityAnonymousAuthenticationFilter">
<beans:property name="key" value="anonymousKey "/>
<beans:property name="userAttribute" value="anonymous,ROLE_ANONYMOUS"/>
</beans:bean>
and te Java Class:
public class SecurityAnonymousAuthenticationFilter extends GenericFilterBean implements InitializingBean {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
logger.info("Entering doFilter method");
//implementation code here
}
//other methods
}
The problem is that the doFilter method is not called when requesting the server. However the init method afterPropertiesSet() is being called... Does anyone understand why my customFilter is not fired?
P.S. I do have named the delegatingFilterProxy in the web.xml file, so that's not the problem.
Since the ANONYMOUS_FILTER is a namespace related filter. You have to avoid any namespace tag that references to the specific filter psoition:
<http auto-config='false' request-matcher="regex" use-expressions="true">
<custom-filter ref="anonymousAuthFilter" position="ANONYMOUS_FILTER"/>
...
</http>
For further reference see the Spring security documentations in section 2.3.5: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html
Edit: And for sure leave the <anonymous-enabled=false/> tag.
Edit 2: Corrected my answer. This configuration should work. If not, well than we need to start looking at a bigger picture and you'd have to post more of your app, starting with the complete config.
This is my scenario:
a web-app perform a sort-of SSO for many applications
logged-in user than click on a link and the app makes a post with user informations (name, pwd [useless], roles) toward the proper application
I am implementing SpringSecurity on one of these application to benefit from its power (authorities in session, methods provided by its classes, etc)
So, I need to develop a custom filter - I guess - that is able to retrieve user informations from request, retrieve from database, through a custom DetailsUserService, further information about the user (email, etc...) and then perform authentication of that user, according to the role retrieved from the request.
I was looking at Pre-Authentication filters, but I'm not sure that it is the right choice. It seems that those object are expected to be used when the principal is already in session, put by some previous authentication machanism (is it right?).
I think that, once identified the correct filter, I should need to perform within something like:
GrantedAuthority[] ga= new GrantedAuthority[1];
ga[0] = new GrantedAuthorityImpl(myUser.getRole());
SecurityContext sc = SecurityContextHolder.getContext();
Authentication a = new UsernamePasswordAuthenticationToken(userName, userPwd, ga);
a = authenticationManager.authenticate(a);
sc.setAuthentication(a);
Is it the proper direction to solve my problem? Do you have suggestions to help me find what's missing?
Thank you all,
Luca
ADDITION:
Hi Xearxess! Sorry to bother you again but it seems that the translation of your code according to SpringSecurity 2.0.4 is more difficult than I thought :S The problem is the XML... I tried different configuration but I ran always into namespace problems, missing attributes, etc...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<security:http>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:logout logout-url="/logout" logout-success-url="http://milan-ias-vs.usersad.everis.int/DMTest/" invalidate-session="true" />
<security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthenticatedProcessingFilter" />
</security:http>
<bean id="preAuthenticatedProcessingFilter" class="it.novartis.ram.authentication.PreAuthenticatedProcessingFilter">
<custom-filter position="PRE_AUTH_FILTER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean class="it.novartis.ram.authentication.PreAuthenticatedUserDetailsService" />
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
</beans>
The 2 rows referencing CUSTOM-FILTER element are two different tries, both of them signed as error. How can I specify the position of my filter as a property?
Also the authentication provider reference on auth manager definition is marked as error. I think that I need to specify it like a property too, right?
Hope you can give me the last push ;)
Thank you again,
Luca
For sake of completeness, in Spring Security 4 things are slightly changed. For example, the Java configuration is highly recommended. In this way, it's easier to integrate with Spring Boot.
It follows the Java Configuration that is equivalent to the XML configuration given in the above answers.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(customAuthFilter(), AbstractPreAuthenticatedProcessingFilter.class)
.authenticationProvider(preauthAuthProvider())
.authorizeRequests()
.anyRequest().authenticated();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(preauthAuthProvider());
}
#Bean
public PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
PreAuthenticatedAuthenticationProvider preauthAuthProvider =
new PreAuthenticatedAuthenticationProvider();
preauthAuthProvider.setPreAuthenticatedUserDetailsService(
userDetailsServiceWrapper());
return preauthAuthProvider;
}
#Bean
public OnlyRolesPreAuthenticatedUserDetailsService userDetailsServiceWrapper() {
OnlyRolesPreAuthenticatedUserDetailsService service =
new MyPreAuthenticatedUserDetailsService();
return service;
}
#Bean
public MyPreAuthenticatedProcessingFilter customAuthFilter() throws Exception {
MyPreAuthenticatedProcessingFilter filter = new MyPreAuthenticatedProcessingFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
I think that the above code is worth, because examples in internet are very basic and the Spring documentation lacks of such details.
Yes, Pre-Authentication Scenarios are exactly what you are looking for.
It seems that those object are expected to be used when the principal
is already in session, put by some previous authentication machanism
(is it right?).
Not really, you can use Pre-Authentication to create PreAuthenticatedAuthenticationToken from request, as you want. Just do few things I described in another question.
First extend AbstractPreAuthenticatedProcessingFilter to obtain username and roles from request:
public class MyPreAuthenticatedProcessingFilter
extends AbstractPreAuthenticatedProcessingFilter {
public MyPreAuthenticatedProcessingFilter(
AuthenticationManager authenticationManager) {
setAuthenticationDetailsSource(new MyAuthenticationDetailsSource());
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
return "Anonymous";
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return "N/A";
}
public static class MyAuthenticationDetailsSource implements
AuthenticationDetailsSource<HttpServletRequest, MySessionUserDetails> {
// roles probably should be encrypted somehow
static final String ROLES_PARAMETER = "pre_auth_roles";
#Override
public MySessionUserDetails buildDetails(HttpServletRequest req) {
// create container for pre-auth data
return new MySessionUserDetails(req.getParameter(ROLES_PARAMETER));
}
}
}
MySessionUserDetails class will split spring with roles to List of SimpleGrantedAuthority or any other GrantedAuthority implementation. Also, List is recommended and superior to GrantedAuthority[].
Second, implement AuthenticationUserDetailsService:
public class MyPreAuthenticatedUserDetailsService implements
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
#Override
public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token)
throws UsernameNotFoundException {
MySessionUserDetails sessionUserDetails =
(MySessionUserDetails) token.getDetails();
List<GrantedAuthority> authorities = sessionUserDetails.getAuthorities();
return new User(token.getName(), "N/A", true, true, true, true, authorities);
}
}
Then in your XML connect blocks together:
<security:http use-expressions="true">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:custom-filter position="PRE_AUTH_FILTER"
ref="myPreAuthenticationFilter" />
</security:http>
<bean id="myPreAuthenticationFilter"
class="com.example.MyPreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean class="com.example.MyPreAuthenticatedUserDetailsService" />
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
And voila! You should have authenticated User principal to use in your application.
Code I written here requires Spring Security 3.1 which I strongly recommend if you're about to using it (it does requrire Spring 3.0.7+). Also, Spring Security reference manual is your friend!