SpringSecurity - Custom automatic authentication - java

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!

Related

Spring #Secured and #PreAuthorize have no effect in plain (non-web) application

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.

Custom authenticationFilter Spring Security 3.2

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.

Spring security vaadin Authetication manager bean

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.

Using jdbc-user-service inside user-service-ref

I am using spring security and for database based authentication I used following configuration and its working fine
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT ...... U.email_address=?"
authorities-by-username-query="SELECT ... U.email_address=?">
</authentication-provider>
</authentication-manager>
now I wanted to add extra info to the session and came across Adding user to session, spring security default login, I tried it and now I have a problem.
XML says I cant use user-service-ref and jdbc-user-service combined. Is there a way to sort it out or else what I have to do if I have to use user-service-ref tag only to authenticate users? What can be the other way to add extra info say a whole Users object to the session.?
Your help will be appreciated.
After hours of searching and experimenting I was able to do it like this.
Make a new service say MyUserService that will implement org.springframework.security.core.userdetails.UserDetailsService and has annotation #Service. UserDetailsService only has one method loadUserByUserName. Implementation of this method will be in MyUserService. It will look like this.
#Service
public class MyUserService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String arg0)
throws UsernameNotFoundException {
MyUser user=new MyUser();
/*get details of user and authorities from database whose username is
arg0 and place them in user instance */
return user;
}
}
MyUser is also a new class that implements org.springframework.security.core.userdetails.UserDetails and all its methods are implemented inside MyUser class. It will look like this.
public class MyUser implements UserDetails {
private static final long serialVersionUID = 1L;
/*All the variables their getter setters that you wish to store in session. And
implementation of all the methods of UserDetails go here.*/
}
Define a bean like this
<bean id="customUserDetailsService" class="org.aurora.timeexpense.service.MyUserService"/>
Where org.aurora.timeexpense.service.MyUserService is the path of my defined service that implements UserDetailsService.
4.And Spring Security Configuration will go like this
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
</authentication-provider>
</authentication-manager>
You are good to go.

Switching authentication approaches at runtime with Spring Security?

Typically, when you declare different "<authentication-provider>" for your application (webapp in my case), Spring Security takes care of invoking providers one after another, incase of failure. So, say I have DatabaseAuthenticationProvider and LDAPAuthenticationProvider with DatabaseAuthenticationProvider declared first in the config file, at runtime, DatabaseAuthenticationProvider is invoked first and if authentication fails, LDAPAuthentication is tried. This is cool - However, what I need is a runtime switch.
I would like to have an option of chosing between these two approaches (database based authentication / ldap based authentication) and somehow swith the implementation based on thsi global setting.
How do I do it? Is it even possible with Spring-Security?
I will leave how to inject your own custom authentication provider to the other myriad of examples from Googleland and here on StackOverflow. It looks like it has to do with marking a particular bean with the xml. But hopefully I can fill in some of the other details for you.
So you've defined the class somewhat like above and I'll add more of the details that you'll need for Spring (i.e. merge the stuff from above as well.
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
....
public List<AuthenticationProvider> getProviders() { return delegateList; }
public void setProviders(List<AuthenticationProvider> providers) {
this.delegateList = providers;
}
....
}
This will allow you to inject a host of providers using spring:
<bean id="customAuthProvider1" class=".....CustomProvider1"> ... </bean>
<bean id="customAuthProvider2" class=".....CustomProvider2"> ... </bean>
...
<bean id="customAuthProviderX" class=".....CustomProviderX"> ... </bean>
<bean id="authenticationProvider" class="....SwitchingAuthenticationProvider">
<security:custom-authentication-provider/>
<!-- using property injection (get/setProviders) in the bean class -->
<property name="providers">
<list>
<ref local="customAuthProvider1"/> <!-- Ref of 1st authenticator -->
<ref local="customAuthProvider2"/> <!-- Ref of 2nd authenticator -->
...
<ref local="customAuthProviderX"/> <!-- and so on for more -->
</list>
</property>
</bean>
In the end how you populate the providers could be any means of getting the delegator a collection of providers. How they map up to which one to use is up to you. The collection could be a named mapped, based on the current state of the delegator. It could be a list of more than one to try. It could be two properties, "get/setPrimary" and "get/setSecondary" for fail-over like functionality. Once you have the delegator injected the possibilities are up to you.
Let me know if this isn't answering your question.
How about writing a delegating AuthenticationProvider that knows how to access your runtime switch and the actual instances of Database/LDAP AuthenticationProvider.
I'm thinking of something like:
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
private List<AuthenticationProvider> delegateList;
private int selectedProvider;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException
{
AuthenticationProvider delegateTo = delegateList.get(selectedProvider);
return delegateTo.authenticate(authentication);
}
....
}

Categories

Resources