Spring security: How to persist each anonymous user? - java

What I need:
For each new user visiting my site I create a MyUser object (doesn't matter what this class consists of) and persist it to DB.
And I want this object to be used each time user with same sessionId come on my site.
For me it looks almost like anonymousAuthentication. So I disabled it and replaced with my own filter:
<http auto-config="true">
...
<anonymous enabled="false"/>
<custom-filter ref="userGeneratorFilter" position="ANONYMOUS_FILTER"/>
</http>
I thought that securityContext contains principal for previously authenticated user but it looks like one of the filters in filterchain adds it manually for each request.
In other words each time I get into my UserGeneratorFilter.doFilter
SecurityContextHolder.getContext().getAuthentication() == null;
So how can I understand whether I need to create a new MyUser object or take an existing one from data base?
ps. I think I've choosen kind of a wrong way=( Few words about my task: I want unauthorized user to have limited access to my resource but when he registers I want all the data he entered while being unauthorized to be merged into his normal account.
Thank you for your attention. Each time I write that sentence moderators remove it. But I will never stop writing it=)

Just set a cookie which does not expire with something like a CookieID or a VisitorID that identifies the user. check for this cookie when people visit your site, it should identify the user.

There are options in spring security that tells how security should handle session migration, maybe that would be helpful for you.

Related

Allowing access for specific users in Spring Security

I'm using Spring Security to Secure my Web App.
I have a page where I show foo objects for administrators.
<intercept-url pattern="/show_foo/**" access="hasRole('ROLE_ADMIN')" />
But now I have a requirement that a foo cannot be seen by all the Administrators, for example only administrators with city="New York" can access to the element.
I've did something in my controller to solve this :
#RequestMapping(method=RequestMethod.GET,value="/show_foo"
public ModelAndView showfunction(Principal user)
{
User user2 = userService.getUserByName(user.getName());
if(/* some checks on user2 */)
/* show page */
else
/* show error page*/
}
So my question is : can I avoid the database call, because I need this almost in all of my pages and I find it ugly to check each time at the top of any controller the same thing over and over. Is there a Spring Security feature for this kind of use cases?.
With Expression based rules you can accesss principal even on rule. See: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
For example if you can include needed information on principal object.
<intercept-url pattern="/show_foo/**" access="hasRole('ROLE_ADMIN') and principal.name=='xyzzy' " />
you have to put in some logic.
1.) Either load the user and country mapping and store somewhere in Static HashMap, remember to update the map if any changes done in mapping, can store same at session level.
2.) Load entries in 2nd level cache, or make queries cacheable, enable query caching as well.
You need to integrate Spring Security with Domain-ACLs. See a full explanation here.
Yo can consider mapping the relationship between Administrators and Cities using
ACL_OBJECT_IDENTITY instances.

EJB authentication

Here is what I'm trying to do: I have an authentication EJB that can grant user a "ticket" (pair of key and token) by validating username and password. Clients should pass the ticket every call to remote EJB and such ticket should be able to be fetched by EJB (method, or interceptor) and EJB/ or interceptor should validate the ticket and determine whether the call is valid or not.
I don't want to add ticket as parameter to each function that requires authentication, and I believe there should be a way to implement this. I've looked through several articles about JAAS custom login module, but still can't find a non-vendor specific way to do this. (And I am trying to avoid vendor specific implementation)
If JAAS can't do the job, is there anything like "header" in EJB?
Couldn't you just use roles to perform this authorization? Instead of granting a ticket to a user, assign him a role.
Then, it's just a matter of using the inbuilt functionality of checking whether a user is in a role or not.
Although I agree with #EdH, i.e. use #RunAs, you can accomplish what you want by adding to the EJB context your token.
Red Hat does something similar here by using the interface EJBClientInterceptor.
By looking the code of ReceiverInterceptor (which implements the EJBClientInterceptor) you can see how to modify the EJB context (on the client-side) and add your token:
context.setReceiverInvocationContext(new
EJBReceiverInvocationContext(context, receiverContext));
context.sendRequest();

How do I implement a custom UserDetails object when authenticating against Active Directory via LDAP in Spring Security?

As in my previous questions, I continue to wade through the murky waters of integrating Spring Security into an existing application, which must ultimately authenticate against Active Directory via LDAP (over TLS), and populate the user's permissions based either on group membership or on a string stored in a custom AD field on the user object.
My current problem is that while I have successfully managed all of the above, I have not managed to get the User object with my custom permissions stored onto the session. This means that without additional work, every user will enjoy the permissions available to the most recently logged-in user.
I've worked around this issue by storing user permissions in a Hashtable<username, permissions> object, which I can secure by annotating its getters/setters with #PreAuthorize("isAuthenticated() and principal.name == #username"), but this is clearly not ideal. I'd much rather store the custom information gleaned from AD into the session as part of a custom user object. But how?
The relevant portions of my security.xml and ldap.xml configurations are as follows, respectively:
<security:authentication-manager>
<security:authentication-provider ref="ldapAuthenticationProvider"/>
</security:authentication-manager>
and
<bean id="ldapAuthenticationProvider"
class="my.project.package.OverrideActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="test.server"/>
<constructor-arg value="ldap://192.168.0.2:389"/>
<property name="convertSubErrorCodesToExceptions" value="true"/>
</bean>
One of the problems I have foreseen is that when the loadUserAuthorities() method (overridden for my custom use of AD fiels) is called, SecurityContextHolder.getContext().getAuthentication() returns null. This is a problem -- it indicates (to me, as I understand Spring's handling of sessions) that the authentication process has not completed, and the session ID pertaining to the to-be-authenticated user has not been generated. That is, Spring clears the anonymous session upon authentication in favor of a new session ID, but that session is apparently unavailable when loadUserAuthorities() is run.
So what shall I do? As I said, my hack works, and it seems to be secure (provided the right annotation), but it is hardly ideal. How can I properly store my custom user information onto a session-scoped user object while also maintaining authentication against AD via LDAP (over TLS)?
As always, I love and appreciate all the help I receive from the SO community.

Allow only one session per user

We have a web-application developed using struts2, spring & hibernate.
The application needs a functionality that one user can login from only one browser.
Say if user x, is logged in on pc-1 browser ff, then he cannot be logged in from any other place.
I tried it by implemention session map and store the sessions in global map, but this fails when user logs off and tries to login again.
Even it fails critically if the user does not logs off and session time-outs, but the map is not cleared.
Any better idea to implement this functionality.
We do not want to obstruct the user to login but do not want users to exploit the application by allowing him to share the creditionals and allow multiple users with same login to happen.
Since you are already using Spring, I would recommend you to integrate your application with Spring Security.
Spring security lets you define maximum sessions allowed per user concurrently.
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
If set when user having valid session tries to login again it will inform user that maximum concurrent access is set to 1.
Read more at the reference documentation of Spring Security: v3.2.x, v4.2.x or v5.1.x.
If spring security is not an option for you then:
Use a SessionInterceptor which will check for session validity, if session is valid it will check if user is already logged in to the application (for this you will have to maintain session somewhere for eg database for every successful login), if valid login is found, redirect user again to login page with custom message, or logout already valid session and then redirect him to login again. If you logout earlier session it would mean any successive action in that browser session will have to deal with invalid session.
If case you are also using Servlet in your application then Interceptor wont work for you, in this case you should use a Filter and follow the same steps as detailed above for Interceptor.
The best solution is to log-off user from other session when he logs in in new session. It is often that user would not logoff when closing browser and restricting him from logging in other window would be the pitfall.
Automaticly closing any previous user sessions is good, because in normal usage, it is no problem, but when sharing login and password, no two persons can work simultanously with your application.
At the login give the user a generated ID/cookie (sessionid suffices) stored with the user data. If a user does a request to the server with an old ID/cookie, say that he logged in elsewhere.
The other way round, forbidding the new login attempt, has its drawbacks - as you've experienced.
Create a map.
At the time of logging check that user id is present into that map or not.
If its not exist then put user id into map, at the time of logout remove that user id.
To be honest I would revisit the reasons why you have to restrict a user to a single login. Whilst preventing them from logging in from two different browsers is easy enough - any of the suggestions provided would work - with the Spring Security option being the easiest to implement if you can - they all break down when your user opens a second tab in the same browser. That is considered to be part of the same session.
Maintain user stack in servlet context,as it will be one for web container.perform a check before user getting logged in, if user name found in servlet context redirect him to login page.
All you should do is add a field in database userprofile table saying: alreadyLogin.
If user logins, make it Y. If user logs out, make it N. Now every time when user tries to login from new location, check this value and prevent login if Value is Y.
As many said, you can have a Map<String, User> (static Map or better an attribute in ServletContext) of (sessionId, user) of active users.
When a user tries to login, first check the existence in theMap.values(), and if it is okay add it to theMap.
Instead of removing from theMap on logout, implement a javax.servlet.http.HttpSessionListener, and on sessionDestroyed method, remove the item from it (the parameter of the method gives you the sessionId). This way if a user closes the browser, after session timeout period, it will be removed automatically.
On logout, invalidate the session, so it will be destroyed, and again this listener get executed.
Don't forget adding the listener to your web.xml.

Programmatic use of Spring Security

I am using Wicket with the Wicket Auth Project for my presentation layer and I have therefore integrated it with Spring Security. This is the method which is called by Wicket for authentication for me:
#Override
public boolean authenticate(String username, String password) {
try {
Authentication request = new UsernamePasswordAuthenticationToken(
username, password);
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (AuthenticationException e) {
return false;
}
return true;
}
The contents (inside ) of my Spring Security XML configuration are:
<http path-type="regex">
<form-login login-page="/signin"/>
<logout logout-url="/logout" />
</http>
<global-method-security secured-annotations="enabled" />
<authentication-manager alias="authenticationManager"/>
<authentication-provider user-service-ref="userService">
<password-encoder ref="bcryptpasswordencoder" />
</authentication-provider>
The section 2.3.6. Session Fixation Attack Protection of the reference documentation says:
Session fixation attacks are a potential risk where it is possible
for a malicious attacker to create a
session by accessing a site, then
persuade another user to log in with
the same session (by sending them a
link containing the session identifier
as a parameter, for example). Spring
Security protects against this
automatically by creating a new
session when a user logs in. If you
don't require this protection, or it
conflicts with some other requirement,
you can control the behaviour using
the session-fixation-protection
attribute on , which has three
options:
migrateSession - creates a new session and copies the existing
session attributes to the new session. This is the default.
none - Don't do anything. The original session will be retained.
newSession - Create a new "clean" session, without copying the
existing session data.
The authentication works, but I as I'm fairly new to Spring Security I have some questions which I need answers too:
Normally for login, I would POST the authentication information to j_spring_security_check and let Spring Security perform the actual authentication code. I would like to have protection against session fixation attacks, will I get it when I perform a programmatic login as I do? And if not, what would I have to do to get it?
How do I perform programmatic logout?
As I will use programmatic login and logout, how do I disable Spring from intercepting those URL's?
Update:
For session fixation attack protection it seems that I need to call the method in the SessionUtils class with the signature startNewSessionIfRequired(HttpServletRequest request, boolean migrateAttributes, SessionRegistry sessionRegistry).
How do I get the SessionRegistry instance which I need to pass in? I can't find any way to create an alias ID for it, or how to get it's ID or name.
Maybe it's not a full answer to your questions, but maybe it might help you.
The code being called when you do NOT use programmatic login, but a standard one is to be found here:
org.springframework.security.ui.webapp.AuthenticationProcessingFilter
I guess you were inspired by this in your code. It looks quite similar.
Similarly the code executed when you access the /j_spring_security_logout in the standard approach, is to be found here:
org.springframework.security.ui.logout.LogoutFilter
The LogoutFilter calls multiple handlers. The handler we are using is called:
org.springframework.security.ui.logout.SecurityContextLogoutHandler, so you might call the same code in your approach.
You will indeed be open to session fixations attacks. To remedy this you could again be "inspired" by the Spring code. To create a new session you'll obviously need access to the httpsession so you may have to do some refactoring.
If you see the method SessionUtils.startNewSessionIfRequired.
This will migrate the authentication to a new session. You might be able to call this method directly or else just refactor the code a little.
As for programmatic logout you can't go too far wrong by simply calling session.invalidate() when you need to log the person out. This will do everything necessary from a general security perspective but bear in mind though you might need to cleanup some things on the session. If you have a very complicated set of filters etc. and you need to ensure that that the user is logged out for the rest of the request then you could add:
SecurityContextHolder.getContext().setAuthentication(null);
As for interception of the url's you could just set them to something unused and ignore it! I'm not sure if you can turn off the interception in configuration - if you really want to remove it then have a look at the AuthenticationProcessingFilter - you could customise this. If you do this then you'll have to manually setup the spring security xml and not use the provided namespaces. It's not too hard though - look at some older documentation and you'll see how to do this.
Hope this helps!
1) Programmatic Logout
call HttpServletRequest.getSession(false).invalidate
call SecurityContextHolder.clearContext()
2) Tell Spring Security NOT to intercept certain URLs, this one kind of depends on how your application url space is setup. If all your pages (except /logIn and /logout) lived at the context /myApp then you could do this:
<http ....>
<intercept-url pattern="/myApp/**" ..>
....
</http>
I had an issue with programmatic login. I called all the authenticationManager.authenticate(...) and SecurityContextHolder.getContext().setAuthentication(...) methods but had some issues with the Session. I had to add the following lines to properly manage the session:
HttpSession session = request.getSession();
session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
This was not clear from the example code posted above. For more look at http://forum.springsource.org/showthread.php?t=69761
To do programmatic logout it's also possible to throw an org.springframework.security.core.AuthenticationException. For example, SessionAuthenticationException. In this case ExceptionTranslationFilter initiate logout.
You can try this
try {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
SecurityContextHolder.clearContext();
} catch (Exception e) {
logger.log(LogLevel.INFO, "Problem logging out.");
}

Categories

Resources