For legacy reasons we're using servlet-api-2.3.jar, in which HttpServletRequest not yet had the logout method. What do I do instead? We're also using an old version of Oracle's ATG, which contains a class called DynamoHttpServletRequest as well, but I don't know what to do with that either. What to try/read?
It depends on what the semantics of logging in are in your application.
Typically, this should do it unless you're doing something exotic:
request.getSession().invalidate();
I'm not familiar with Dynamo, so you may want to see if it has any specifics about session management, as some frameworks do.
And if you're using any security frameworks, you may need to clear/de-autenticate an authentication token.
atg.servlet.ServletUtil.invalidateSessionNameContext(request, atg.servlet.ServletUtil.getCurrentRequest().getSession(false));
atg.servlet.ServletUtil.invalidateSession(request, atg.servlet.ServletUtil.getCurrentRequest().getSession(false));
// Redirect, the profile is null from here on.
response.sendRedirect("login");
I encountered this problem too and found this in the ATG documentation:
Some application servers maintain a single session ID between web applications for the same client (browser), in which case the session name context ID is the current web application’s session ID. This behavior is controlled by the /atg/dynamo/
servlet/sessiontracking/GenericSessionManager.singleSessionIdPerUser property, which is set to one of the following default values in the DafEar sub-module configuration layer:
WebLogic – false <--
JBoss – true
WebSphere - true
Note: Do not change these values from their defaults.
This means that on jboss and websphere you can safely use session.invalidate() however on WebLogic you will need to use something along the lines of:
protected void forceLogout(DynamoHttpServletRequest pRequest) {
HttpSession session= pRequest.getSession(false);
if (session != null ) {
// When ATG runs on weblogic you need to ensure the parent session is invalidated
// session.invalidate() does not work.
atg.servlet.ServletUtil.invalidateSession(pRequest, session);
}
}
I hope this helps explain why.
Related
In an server application I use bare websockets without the spring messaging layer and sockjs/stomp. I need my own messaging layer on top, but I want to use for example spring session to leverage the servlet HttpSession replacement to keep the http session alive which is beneath the websocket session, to prevent timeouts. The websocket is opened from a static HTML-page using JavaScript.
In the spring-framework documentation there is all the necessary information to setup bare websocket support with e.g. a basic BinaryWebSocketHandler or TextWebSocketHandler as well as how to
provide your own HandshakeInterceptor.
I've added spring session 1.1.0.RC1 with hazelcast for storing sessions and replacing the servlet container HttpSession implementation with the Session/ExpiringSession proivided by spring session. I just followed the given instructions to do this.
So far everything is fine, but as I'm serving a static HTML page from which I open the websocket using JavaScript without using spring security or any other mechanism to trigger a processing by the servlet container, no http session is intialized so far.
So the question is: How do I intitialze the custom HttpSession which is then stored in a the SessionRepository provided by spring session?
Note: I will provide an answer myself as I think I solved the issue for my case and it may be helpful for others facing a similar problem.
As can be seen from the spring-framework documentation, it is possible to add a custom HandshakeInterceptor. Spring session offers the
// example for reference:
org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor
which targets the spring messaging layer. It shows how to reset the timer of the HttpSession prior to sending a message within the method preSend(...) as well as how to optain the HttpSession from the request in the method beforeHandshake(...).
I implemented my own HandshakeInterceptor based on this with an almost identical beforeHandshake(...) method, but with one minor difference and of course leaving out the ChannelInterceptorAdapter stuff. The reset of the HttpSession time has to be done somewhere else, but that is out-of-scope.
Because in my case no HttpSession has been created so far, I changed the line obtaining the session from the request to look like this:
HttpSession session = servletRequest.getServletRequest().getSession(true);
Changing the boolean parameter from false to true in the method getSession(...). Now this call will trigger the creation of a new HttpSession (provided by spring session) if none is available so far.
This solution seems to do what is required in my case. Please correct me if I'm missing something or using anything the wrong way.
I have a custom AuthenticationProvider with the authenticate method.
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
> Check username, password, throw exceptions where needed
return new CustomAuthenticationToken(username, grantedAuthorities);
}
And the token:
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken
{
public CustomAuthenticationToken(ICurrentUserContext currentUser, List<GrantedAuthority> authorities) {
super(currentUser.getUsername(), currentUser.getPassword(), authorities);
}
}
When I login with Chrome, Firefox, there is no problem whatsoever.
In IE 8/9 I have a very weird problem. Sometimes it will only call the method authenticate one time, it will login and everything works as expected. But from time to time, it will call authenticate twice, and fails to log in.
Does anybody have any clue?
I've tested it on Tomcat btw.
I've found the problem, with careful tracing the debug log of the Spring Security.. Hopefully this will help someone in the future.
Apparantly, spring security default migrates sessions after login. But in IE it does not migrate the authentication cookie to the new session, resulting in presenting of the login page.
The fix is easy, and can be done in the Spring Security xml:
<http use-expressions="true">
<!--
This settings is for IE. Default this setting is on migrateSession.
When IE tries to migrate the session, the auth cookie does not migrate,
resulting in a nice login screen again, after you've logged in.
This setting ensures that the session will not be invalidated, and thus IE will still work as expected.
-->
<session-management session-fixation-protection="none" />
</http>
Look at this please Internet Explorer buggy when accessing a custom weblogic provider.
Maybe you habe to disable cookies no your Tomcat
Migrating the session is entirely a server-side process and should be invisible to the browser. All it should see is a new Set-Cookie header for the JSESSIONID, which it should respect.
My best guess is that you are seeing this tomcat bug, which will cause different effects depending on how a browser interprets the duplicate headers. It was originally reported because of this issue with a Blackberry browser which is closely related to what you're seeing here.
But you don't say which versions of either Spring Security or Tomcat you are using (always a good idea :-)), so it's hard to say for sure.
Table of contents
Quick Reference
Spring Security Core plugin
<< 17IP Address Restrictions19Logout Handlers >>
18 Session Fixation Prevention - Reference Documentation
Authors: Burt Beckwith, Beverley Talbott
Version: 2.0-RC3
18 Session Fixation Prevention
To guard against session-fixation attacks set the useSessionFixationPrevention attribute to true:
grails.plugin.springsecurity.useSessionFixationPrevention = true
Upon successful authentication a new HTTP session is created and the previous session's attributes are copied into it. If you start your session by clicking a link that was generated by someone trying to hack your account, which contained an active session id, you are no longer sharing the previous session after login. You have your own session.
Session fixation is less of a problem now that Grails by default does not include jsessionid in URLs (see this JIRA issue), but it's still a good idea to use this feature.
Note that there is an issue when using the cookie-session plugin; see this issue for more details.
The table shows configuration options for session fixation.
Property Default Value Meaning
useSessionFixationPrevention true Whether to use session fixation prevention.
sessionFixationPrevention.migrate true Whether to copy the session attributes of the existing session to the new session after login.
sessionFixationPrevention.alwaysCreateSession false Whether to always create a session even if one did not exist at the start of the request.
http://grails-plugins.github.io/grails-spring-security-core/guide/sessionFixation.html
I'm using JEE6 security annotations #RolesAllowed("Admin") and a programmatic login:
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
request.login(loginUser.getUserName(), loginUser.getPassword());
However, for testing, I'd like to be able to 'simulate' a user login, and fool the app that a user logged in, without actually executing the above code. request.login(...) will ping the container for a login, I just want to tell the container that foo user has logged in and there is no need to check the password. I really don't want a solution that involves writing a login module or changing the settings of the entire container.
Thanks guys!
EDIT #1: What appserver am I using?
I'm using GlassFish 3.1.1. However, if possible, I'd like a solution that is 'container independent' using any available JEE6 api.
EDIT #2: Mr. Balus (a well regarded expert) is unaware of any api-neutral way bypassing the actual login. I supposed I could write my own "Yes-Man" login module, but I'm curious if anyone knows how to bypass the restriction specifically in the GlassFish environment.
Thanks!
EDIT #3: To anyone who finds this question later, I'm switched to Apache Shiro. I've used Spring Security in the past, but it's overkill for this app.
There's no API-provided facility for that. You could create a Filter which checks a certain VM argument or environment variable or even a JNDI variable and then does the login automagically.
E.g.
String login = System.getProperty("development.login");
if (login != null && request.getRemoteUser() == null) {
String[] nameAndPassword = login.split(":"); // Assuming "name:password".
request.login(nameAndPassword[0], nameAndPassword[1]);
}
This is not a simple question its just because i'm rethinking our architecture for securing our EJB 3.0 service by a login and security.
We have a EJB3.0 application on JBoss 5.1 that offers various services to a SWT client to read and write data. To use a service, the client must login with a valid user and password which is looked up by SpringSecurity in a LDAP server. SpringSecurity generates a session id which is passed back to the client to be resused in any further service call.
client server
| |
|-> login(user/password)-------->|
| |
| <------- sessionId ------------|
| |
|-->serviceXy(sessionId,param1)->|
The situation seems clear. We store the sessionId in our own context object which is the first parameter of each service method. There is an interceptor on each service method which reads the sessionId from the given context object and checks if the session is still valid. The client needs to call the login service first to get a context object filled with the sessionId and reusue this context object in further service calls.
public class OurContext {
private String sessionId;
}
#Stateless
#Interceptors(SecurityInterceptor.class)
public OurServiceImpl implements OurService {
public void doSomething(OurContext context, String param1) {
[...]
}
}
The thing i don't like at this solution is the polution of each service method with the context parameter.
Isn't there a similar mechanism like a http session in rmi calls? I'm thinking of putting our context object in some kind of session that is created in the client(?) right after the login and is passed to the server on each service call so that the SecurityInterceptor can read the sessionId from this "magic context".
Something like this:
OurContext ctx = service.login("user","password");
Magical(Jboss)Session.put("securContext", ctx);
service.doSomething("just the string param");
Since you are already using an app server, it seems that you should be using the built-in EJB security mechanisms, generally provided through JAAS. On the 4.x jboss line, if you implemented your own JAAS plugin for jboss, you could get access to a "special" context map (similar to what you describe) which is passed along on remote requests (by the jboss remote invocation framework). I haven't used jboss in a while, so not sure how this maps to the 5.1 product, but i have to imagine it has similar facilities. This assumes, of course, that you are willing to implement something jboss specific.
There are some kinds of session mechanisms in EJB, but they all start when the remote call starts, and ends when that ends. On old one is the transaction context ( Adam Bien wrote about this some time ago), and a newer one the CDI Session Scope.
Contrary to popular belief, this scope doesn't just mirror the http session scope, but in absence of an http session (like for remote calls), it represents a single call chain or message delivery (for mdbs).
With such a session, your remote SWT client still has to pass the sessionId to the remote service, but any local beans called from there can pick it up from this "cdi" session.
The other option is kinda like what jtahlborn says: with your own login module you can return a custom principal, instead of the default one. Your code can first request the normal principal and then try to cast it.
The problem is that this stuff is container specific and JBoss always forgets about it. It pretty much breaks after every update, and users have to kick and scream to get it fixed in some next version (only to see it break again in the version after that). Without JBoss really supporting this it's an endless battle.
Yet another option is to let the user login with the sessionId as name. The login module behind that could be a simple module that accepts everything and just puts a principal in the security context with the sessionId as 'name'. It's a little weird, but we've used this succesfully to get any data that can be expressed by a string into the security context. Of course, you would need to let your client do a regular container authentication here, which kinda defeats using Spring security in the first place.
We went for another approach which is portable and does not rely on a specific app server. In addition our security implementation frees us from the restrictions of the EJB approach (which by the way I thought were closed 2 decades ago ... but came up again).
Looking top down:
There is a server providing classes with methods to work on same data.
The client(s) provide the data and invoke specific methods.
Our approach is to put all data (and therefore communication between client and server) into a "Business Object". Every BO extends a superclass. This superclass contains a session id. The login method provides and returns that id. Every client only has to ensure to copy the id received in one BO into the next one it sends to the server. Every method which can be remotely (or locally) invoked, first obtains the session object with the received id. The method to return the session object also checks security constraints (which are based on permissions and not on roles like in the EKB approach).
Let's say I have a running Java-based web application with 0 or more valid HttpSession objects associated with it. I want a way to access the current list of valid HttpSession objects. I was thinking that I could implement an HttpSessionListener and use it to append to a list of session id values that are stored in an application-scoped attribute, but then I'm on the hook to update the list as sessions are invalidated and who knows what else.
Before I start baking my own solution I thought I should ask the question:
Does the servlet API provide some means of getting access to the complete list of non-invalidated session objects?
I am using Tomcat 6.x as my web application container, and the MyFaces 1.2.x (JSF) library.
SOLUTION
I followed an approach similar to what BalusC discussed in these existing questions:
How to easily implement "who is
online" in Grails or Java Application
?
JSF: How to invalidate an
user session when he logs twice with
the same credentials
I modified by SessionData class to implement HttpSessionBindingListener. When a binding event happens, the object will either add or remove itself from the set of all the SessionData objects.
#Override
public void valueBound(HttpSessionBindingEvent event) {
// Get my custom application-scoped attribute
ApplicationData applicationData = getApplicationData();
// Get the set of all SessionData objects and add myself to it
Set<SessionData> activeSessions = applicationData.getActiveSessions();
if (!activeSessions.contains(this)) {
activeSessions.add(this);
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ApplicationData applicationData = getApplicationData();
Set<SessionData> activeSessions = applicationData.getActiveSessions();
if (activeSessions.contains(this)) {
activeSessions.remove(this);
}
}
The one thing that continues to irritate me is what happens when Tomcat is restarted. Unless Tomcat has been properly configured to NOT serialize sessions to disk, it will do so. When Tomcat starts up again, the HttpSession objects (and the SessionData objects along with them) are deserialized and the sessions are made valid again. However, the serialization/deserialization totally sidesteps the HttpSession listener events, so I do not have the opportunity to gracefully put the deserialized reference to the SessionData back in my managed Set of objects after the restart.
I don't have any control over the production configuration of Tomcat in my customer's organization, so I cannot assume that it will be done the way I expect it.
My workaround is to compare the HttpSession creation time with the application startup time when a request is received. If the session was created before the application startup time, then I call invalidate() and the user is sent to an error/warning page with an explanation of what happened.
I get the application startup time by implementing a ServletContextListener and storing the current time inside an application-scoped object from within the contextInitialized() method of my listener.
No, the Servlet API doesn't provide a way. You really have to get hold of them all with help of a HttpSessionListener. You can find several examples in the following answers:
How to find HttpSession by jsessionid?
How to find number of active sessions per IP?
How to check Who's Online?
How to invalidate another session when a user is logged in twice?
There is no straight forward way. It depends on deployment. Above will fail once you decide to introduce distributed deployment and load balancing.
Not really an answer, but in the good ol' days there was "javax.servlet.http.HttpSessionContext", but it was dropped as of version 2.1, explicitly with no replacement: https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSessionContext.html