Automatically create new user account on login - spring-security

I managed to get my application working with Active Directory (basically LDAP) using spring-security, like this:
<authentication-manager>
<authentication-provider ref="ldapActiveDirectoryAuthProvider" />
</authentication-manager>
<beans:bean id="grantedAuthoritiesMapper" class="mypackage.ActiveDirectoryGrantedAuthoritiesMapper"/>
<beans:bean id="ldapActiveDirectoryAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="xxxx.xxx.xxxx" />
<beans:constructor-arg value="ldap://xxx.xxx.xxx.xxx:389" />
<beans:property name="authoritiesMapper" ref="grantedAuthoritiesMapper" />
<beans:property name="useAuthenticationRequestCredentials" value="true" />
<beans:property name="convertSubErrorCodesToExceptions" value="true" />
</beans:bean>
But by doing only this I need to have the users registered both in my application and in the Active Directory before-hand. I would like to be able to before the user logs in (but after the Active Directory validation) to see if he exists in my database and if he doesn't create a new user in my application and then proceed as normal.
I believe I need to create a preAuthentication provider, but I don't know exactly where I can insert my own class to code the checking and registration of the user.
Optimally I would also like to check for a specific authority before creating the user.
Can anyone give me a hand?

In the end I had to change my authentication handler onAuthenticationSuccess. In spring there are authentication and login in the lifecycle of the login process. During authentication the user is, well, authenticated, but not yet logged into the application (ie only its credentials were deemed valid, but the rest of the application is not aware of the user yet.)
I changed my security.xml to:
<beans:bean id="authHandler" class="mypackage.activedirectory.ActiveDirectoryAuthenticationHandler"
...
<form-login login-page="/login" authentication-failure-handler-ref="authHandler"
authentication-success-handler-ref="authHandler" />
And here is the class:
public class ActiveDirectoryAuthenticationHandler extends MyAuthenticationHandler {
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth)
throws IOException, ServletException {
String username= auth.getName();
User user= userService.findByUsername(username);
if (user == null) {
user= new User();
//set user properties
}
try {
userService.save(user);
} catch (EntityException e) {
System.out.println(e.getMessage());
}
super.onAuthenticationSuccess(req, resp, auth);
}
}
I still haven't figured out how to handle AD specific errors (like user is blocked, or password expired), right now it shows my application default login error message.

Related

Spring security access denied message when accessing login page after login successfully.It should redirect to default page

Configured spring security successfully
Authentication properly working
Problem is that after login successfully if user access login page, access denied message appears.It must redirect to default page as user already login.
When i access login.html after login successfully , access denied message appears.
Here's my code
<http auto-config="true">
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/services/**" filters="none"/>
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<form-login login-page="/login.html" default-target-url="/stations.html" always-use-default-target="true" />
<logout logout-url="/logout" logout-success-url="/login.html"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/js/**" filters="none"/>
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/common/**" filters="none"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT USERNAME,PASSWORD,USER_STATUS as ENABLED
from USERS where USERNAME=?"
authorities-by-username-query="
SELECT USERNAME, USER_ROLE from USERS
where USERNAME =? "
/>
</authentication-provider>
</authentication-manager>
When the user successfully loggs in this means he/she has some role (admin for example). This is different than ROLE_ANONYMOUS. You can try:
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS, ROLE_ADMIN,..any other role" />
or even better
<intercept-url pattern="/login.html" filters="none" />
One suggestion: Spring Security evaluate the intercept-url elements in the order you write them in the xml, so you should put the most "greedy" intercept-url at the end. E.g. <intercept-url pattern="/**" access="ROLE_ADMIN" /> will catch everything. The intercept-url for css, js... will never be reached. You should place them first.
I face the same problem,
I have already search many resources and did not found what I looking for.
At last, I'm doing this:
public class SSOInit extends HandlerInterceptorAdapter {
private static final Logger logger = Logger.getLogger(SSOInit.class.getName());
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("### SSO : doInit, read page");
logger.info("### SSO : request url = " + request.getRequestURL());
logger.info("### SSO : request method = " + request.getMethod());
CredentialVO credential = SSOService.getUserCredential();
if (credential != null) {
logger.info("### SSO : credential found, do check point");
String status = SSOService.checkSSOSessionKey();
if (status == null || status.equals("T")) {
logger.info("### SSO : Check point didn't passed, redirect");
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
new SecurityContextLogoutHandler().logout(request, response, auth);
}
SecurityContextHolder.getContext().setAuthentication(null);
} else {
logger.info("### SSO : Check point passed");
if (request.getServletPath().equals(SSOConstant.getREDIRECT_URL())) {
logger.info("### SSO : Check point passed, user trying access login form but already authenticated, redirect");
response.sendRedirect(request.getContextPath() + SSOConstant.getMAIN_URL());
return false;
}
}
}
return super.preHandle(request, response, handler);
}
}
and add this xml configuration to dispatcher-servlet.xml
<mvc:interceptors>
<bean class="ptpn4.rawi.sso.client.authentication.SSOInit" />
</mvc:interceptors>
In class SSOInit, I do some checking to database, I'm trying to build Custom SSO Solution.
I hope another better solution regarding my current approach.

Spring Security Get Authentication on Session TimeOut : Authentication object is returning NULL on session timeout

I'm using spring/spring-security 3.1 and want to take some action depends on the authorities in ATHENTICATION object whenever session is timed out.AUTHENTICATION object is null on session timeout.
Here are the files for reference:
security config:
<logout invalidate-session="true" logout-url="/j_spring_security_logout" success-handler-ref="logoutSuccessHandler"/>
<!-- Custom filter to deny unwanted users even though registered -->
<custom-filter ref="blacklistFilter" before="FILTER_SECURITY_INTERCEPTOR" />
<!-- Custom filter for username, password and domain. The real customization is done in the customAuthenticationManager -->
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
</http>
Note: tried with "invalidate-session="false"" as well.
and my custom LogoutSuccessHandler:
public class EnterpriseLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler{
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
for(GrantedAuthority authority: authentication.getAuthorities()){
if(authority.getAuthority()!=null)
logger.debug("THE CURRENT AUTHORITY FOR THE SESSION IS : {} ",authority.getAuthority().toString());
else
logger.debug("THE CURRENT AUTHORITY FOR THE SESSION IS authority.getAuthority(): NULL ");
if(authority.getAuthority()!=null && authority.getAuthority().equalsIgnoreCase(Operational.SPRING_SECURITY.LOGIN_SOURCE_BEACON)){
loginSource = authority.getAuthority().toString();
break;
}
}
}
}
So, there is the question how I can obtain Authentication object on the session timeout.
Can some help me to find out the solution for the above problem.
Thanks in advance.

Spring security auto login after registeration

I create a spring MVC application that uses spring security for authentication, here's the spring-security.xml
<http use-expressions="true">
<form-login login-page="/homepage.jsp" default-target-url="/homepage.jsp" authentication-failure-url="/homepage.jsp?login-success=false" />
<logout logout-success-url="/homepage.jsp" />
</http>
<authentication-manager alias="authenticationManager" >
<authentication-provider>
<password-encoder hash="sha" />
<jdbc-user-service data-source-ref="marketDataSource"
users-by-username-query="
select email_address, password, '1'
from user where email_address=?"
authorities-by-username-query="
select email_address, 'ROLE_USER' from user
where email_address=?"
/>
</authentication-provider>
</authentication-manager>
when a new user try to register, he fill in registration from and press submit, that will create a new user, if the registration successfully completed, I try to authenticate the registered user using this method:
private void authenticateUserAndSetSession(User user, HttpServletRequest request) {
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
user.getEmailAddress(), user.getPasswordSha(), grantedAuthorities);
request.getSession();
token.setDetails(new WebAuthenticationDetails(request));
try {
Authentication authenticatedUser = authenticationManager
.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
} catch (Exception e) {
e.printStackTrace();
}
}
I checked this post Auto login after successful registration to make the previous method, but when I try to use it, it throws Bad Credential Exception, what's wrong with this solution?
I had been faced with the similar problem. In legacy code the password was hashed by hand.
The better choice is to store object of User class (may be it is a plain form binding) with the plain password and clear it later. Clearing credencials is the responsibility of spring-security too (interface org.springframework.security.core.CredentialsContainer).
If it isn't possible remove tag of encoder or use the plain text encoder <password-encoder hash="plaintext"/>.

Configuring spring security to redirect user to previous location after session timeout

I have a slight issue with my configuration of spring security and the InvalidSessionStrategy implementation I use.
Say a user is connected to the app and is viewing page: /userArea/thePage and their session times out, the user will first be redirected to the /signin page. Then, upon successful signin, they will be redirected to the home page of they personal area (/userArea) whereas I want them to come back to where they were located when the session timed out i.e. /userArea/thePage.
Is this possible?
If so how do I need to alter my config/app?
Here is my current config:
<beans:bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" />
<beans:property name="invalidSessionStrategy" ref="simpleRedirectInvalidSessionStrategy" />
</beans:bean>
<beans:bean id="simpleRedirectInvalidSessionStrategy" class="org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy">
<beans:constructor-arg name="invalidSessionUrl" value="/signin" />
<beans:property name="createNewSession" value="true" />
</beans:bean>
<http auto-config="true" use-expressions="true">
<custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/signin" authentication-failure-url="/signin?login_error=t" default-target-url="/userArea" />
<logout logout-url="/resources/j_spring_security_logout" logout-success-url="/signin" />
...
edit 1: Let me better specify my requirements:
When a user session times out, I want the user to be redirected to the saved request (the url they requested before being redirected to the signin page).
However, when they initially signin with the app, I want them to be redirected to the home page of the personal area.
Are my requirements possible to implement using solution suggested by Carsten (see below)?
You could set the always-use-default-target="true" in the form-login tag. This redirects the user to the url they where trying to access before being intercepted to login.
But this will be the standard behaviour and not only in the case of a session timeout. Depending on the application this might not be what you want.
Edit:
To do what you want you need to find a way to save the information on which page the user was when the session timedout. I don't know of any out of the box solution for this problem, since there is no state that indicates whether or not the user timed out or logged out manually.
What needs to be done ist to:
set a flag or save the page-url on session timeout
check in a custom AuthenticationSuccesHandler and redirect accordingling
If I would implement somehing like that I would most likely store the page-url. Also there are a few tricky things with this from an UX perspective. What happens if the saved page relies on a state achieved earlier? (I assume thats the reason you want the User to go to the default-url on normal login?) What happens if the user just does not log out shuts down sleeps for the night and logs in navigating to the login page (does the flag/page-url time out?)? etc.
In general I think it would be better use the always-use-default-target="true" since this adds the comfort of bookmarking any page and not having to navigate there at each login.
Looks like it's common issue for any Spring project.
Spring developers thought that this is undocumented behavior https://github.com/spring-projects/spring-security/issues/1981, my business users are thinking that it's a bug.
So, as a result we need to do some custom implementation)))
Personally for me it's a bug and after making a custom implementation I don't understand why it's not fixed at Spring Framework.
As in a lot of other cases we have no choice and just copy-paste SimpleRedirectInvalidSessionStrategy and add our custom code.
You can even more simplify this code(I just make a customization which can be used OOTB in Spring):
public class CustomInvalidSessionStrategy implements InvalidSessionStrategy {
private final Log logger = LogFactory.getLog(this.getClass());
private String destinationUrl = null;
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private boolean createNewSession = true;
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException {
this.logger.debug("Starting new session (if required) and redirecting to '" + this.destinationUrl + "'");
if (this.createNewSession) {
request.getSession();
}
if (destinationUrl == null) {
this.redirectStrategy.sendRedirect(request, response, request.getRequestURI());
} else {
this.redirectStrategy.sendRedirect(request, response, this.destinationUrl);
}
}
public void setCreateNewSession(final boolean createNewSession) {
this.createNewSession = createNewSession;
}
public void setInvalidSessionUrl(final String invalidSessionUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
this.destinationUrl = invalidSessionUrl;
}
}
And some extra configuration for Spring security:
<security:http ...>
...
<security:session-management invalid-session-strategy-ref="customInvalidSessionStrategy" />
...
</security:http>
<bean id="customInvalidSessionStrategy" class="com.custom.web.security.CustomInvalidSessionStrategy"/>

Spring Security - Get username while logout

How to get username or UserDetail object in logout-success-url? Below is my configuration:
<form-login default-target-url="/security/loginSuccess.action"
always-use-default-target="false"
authentication-failure-url="/security/loginFailed.action"
login-page="/security/restrictUser.action"/>
<logout invalidate-session="true" logout-success-url="/security/logoutUser.action" />
<session-management
session-authentication-strategy-ref="customMsgAwareConcurrentSessionControlStartegy"
invalid-session-url="/security/logoutUser.action"/>
I want to get the username who has requested for logout within logout-success-url (for me it is a Struts 2 action method). I have checked SecurityContextHolder, but it seems that SecurityContextHolder is cleared when the control reaches my action method in logout-success-url.
Use custom LogoutSuccessHandler for that. Inside your configuration define bean and use success-handler-ref attribute of <logout> tag.
<logout success-handler-ref="customLogoutSuccessHandler" />
<beans:bean id="customLogoutSuccessHandler" class="..." />
And inside CustomLogoutSuccessHandler there is onLogoutSuccess method which has Authentication argument.
public class CustomLogoutSuccessHandler extends
AbstractAuthenticationTargetUrlRequestHandler implements
LogoutSuccessHandler {
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
// use authentication to get user name
}
}

Resources