Does calling the method "SecurityUtils.getSubject();" will always hit the redis database? - java

I am implementing a redis-shiro session management feature in my project and currently I have very little information about Shiro & Redis.
I want to know whether calling the below will hit the redis database everytime to check whether any sessionId exist in the redis database or not.
Code in Service
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
Code in Controller:
public String getSomrthing(#CookieValue("JSESSIONID") String fooCookie){
callingSomeServiceMethod(fooCookie);
return "It does not matter";
}
Does we have to match the sessionId manually like below in our service or does Shiro will match it automatically, since my application will be running in a multi instance environment.?
Subject currentUser = SecurityUtils.getSubject();
if(currentUser.getId.equals(fooCookie)){
//.....Some Code
//.....Some Code
}

The session will looked up a max of once per request, less depending on any additional caching you have configured.
You wouldn't manage/lookup the sessionId directly from your controller though. All of this logic would be transparent and handled by Shiro and/or your servlet container's session management.

Related

Difference between session handling locally and on server with Google App Engine

I am using sessions and have enabled sessions in my GAE app
<sessions-enabled>true</sessions-enabled>
<async-session-persistence enabled="true" />
I am using sessions for the purpose of a simple user login. Locally, this works just fine, my session is maintained until I logout and all my pages that are "protected" are viewable with a valid session.
The problem with my live/production server on appspot is that it doesn't work at all. When I login and authenticate, I redirect to another page. This page checks if I have a valid session (using standard HttpSession) and somehow this fails and then redirects me back to the login screen.
Does anyone have any idea why it doesn't work in the GAE production environment but works just fine locally?
Here is the code I use to check validity of current session:
public static boolean isValidSession(HttpServletRequest request) {
return (request.isRequestedSessionIdValid());
}
Update:
I'm creating session ID like this:
public static void createNewSession(HttpServletRequest request, final String username) {
HttpSession session = request.getSession(true);
session.setAttribute("username", username);
}
There is no difference between handling sessions locally and in production as such on Google App Engine. They work the same in both the environment. The only difference that I can think of is that when you create sessions (say at or after Login) locally and you set some attribute in the session say the access level of the user, it will not change even when attribute's value change(say if it is pulled dynamically from some database where it got changed after Login) until you close the tab and Login again, however in production if the attribute changes in the database and then if you refresh the page it will take the new value from the database. Well that's in my experience. Hope it helps.

Keeping "current user" in threadlocal

I have a spring-mvc application that currently has two channels - web application and a REST service. Both have user's http session and I can easily get the "current user" in my service classes.
Now I need to develop another REST service where there are no http sessions and the current user depends on a request parameter. So the controller would read that request parameter and would find the current user.
Now I either need to:
1. modify my service layer methods to accept current user as parameter
or
2. just modify the class that gets the current user from the http session.
I also have the requirement to create an audit log and I'm going to use Spring AOP for that. The Aspect will need access to the "current user" too. So option #1 probably won't work for me and I will go with #2.
For option #2 I'll create an interceptor that will put the current user in a ThreadLocal variable. The controller for the new REST service will do the same and then in my service layer and in the audit log aspect I can get the current user from there.
I haven't done anything like this before and was wondering if there is a better approach. Or what kind of issues I should expect with this approach.
I will appreciate any comments and ideas.
Oz
Here is how I currently get the current user:
#Override
public User getCurrentUser()
{
Authentication currentUser = getAuthentication();
return userService.getByLoginName(currentUser.getName());
}
protected Authentication getAuthentication()
{
return SecurityContextHolder.getContext().getAuthentication();
}
I think a simple way to do what you need is to configure a servlet filter for your new REST webservice to populate the SecurityContextHolder with an Authentication object build from request parameters.
You can read this : http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#d0e2171 for more details.
With this solution you don't need to modify the code to retrieve the current user. (note that the SecurityContextHolder is already using a ThreadLocal to store the SecurityContext and so the Authentication)

Should a Shiro Authenticating Realm be transactional?

I'm using Shiro to secure my Spring MVC webapp. I'm using Hibernate for persistence and so I have a HibernateRealm to get and populate an AuthenticationInfo object.
#Override
#Transactional
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
Account account = accountDao.findByUsername((String)token.getPrincipal());
SimplePrincipalCollection principals = new SimplePrincipalCollection(account, getName());
SimpleAccount info = new SimpleAccount(principals, account.getPassword());
return info;
}
Account is my custom user class. I use the DAO to retrieve an Account by username. I was wondering if there is any point in making this method #Transactional. This is a read only operation after all.
I'm also having the following problem: the DAO does sessionFactory.getCurrentSession() to get a session, but I'm getting a
HibernateException: No Session found for current thread
when the method gets called. I have these in my application context:
<tx:annotation-driven transaction-manager = "transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I can't understand why Spring isn't opening a session for me.
Edit: To login, we do this in a Spring #Controller method using Shiro's Subject
#RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(#RequestParam("username") String username, #RequestParam("password") String password) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
currentUser.login(token);
return "profile";
}
return "home";
}
Internally, Shiro uses the realm method I have above to get the stored username/password information. It uses an #Autowired DAO to check my database for the right account. It then matches the passwords with a CredentialsMatcher implementation.
So you have two problems. It is usually better to split such questions into two, since these problems are not really connected to each other.
No Session found for current thread
It seems that #Transactional annotations does not work. To be sure you may run you code or tests in Debug mode and look for the JdkDynamicAopProxy or something similar in the stack - if it is present, than your Realm is invoked through transactions-intercepting proxy, but I suppose that there is no proxy curently. For it to work you need to take from the SpringContext not the HibernateRealm directly but the interface that this realm is implementing. This is due to the fact that built-in standard java library proxies can deal only with interfaces.
As for making the read-only service methods transactional.
There are several valid reasons to do so:
Since you are using Hibernate it is really possible that you actually use more than one query to get your Account object. And if this account is modified concurrently it may lead to inconsistent state:
first query for Account retrieval
Account is modified or deleted
second query for Account retrieval - this query will see the results of modification that together with the results of the first query may lead to inconsistent behavior, but if first and second query were in the same transaction with the proper level of transaction isolation second query would not see the modifications.
Uniform access to the database - it is really helpful when all your database connectivity layer access the DB in one and the same way - I greatly simplifies maintaining and extending of the application.
Using some transactional hints like #Transactional(readOnly=true) may improve your performance with proper configuration (e.g. for the really high-loaded application readOnly queries may use secondary replica of the DB Server). It is really easier to setup the java.sql.Connection.setReadOnly() method as part of the Spring transactions, than in the other way.
It appears that Spring isn't creating a transactional proxy for your Realm bean. This is the only reason that I can see why a Hibernate Session isn't available - because the backing infrastructure isn't there (on the thread) ready for use.
As to your question, if you do want to mark it #Transactional, you might consider specifying #Transactional(readOnly=true)
Shiro creates it's own instance of my Realm and therefore Spring has no power over it to wrap it in a proxy. That's why it can't add the transactional behavior.

Spring Security and Sessions over Web Services

Summary
How do you get the session of a web service client using spring web services and spring security?
Details
After submitting
<form method="POST" action="<c:url value="/j_spring_security_check" />">...</form>
I've noticed that you can:
public class MyUserDetailsService implements UserDetailsService {}
Which will allow you to override methods like loadUserByUsername(String username) therefore being able to retrieve the submitted username and do a database lookup to return a user object.
The issue I have, however, is that I'm unsure where SecurityContextHolder gets set. I'm able to get the user object by using this line of code:
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
But I'm not sure how it gets set in the first place. I would like to know the flow after submitting the above-mentioned form so that I can identify how SecurityContextHolder gets set.
The reason why I want to know this is because I want to use it as a "session" for web service client authentication instead of having the client resubmit credentials with every request.
Spring Version: 3.0.2.RELEASE
/j_spring_security_check is handled by the UsernamePasswordAuthenticationFilter which extends AbstractAuthenticationFilter. The security context is set in the latter's successfulAuthentication method.
However, web-service clients are usually stateless and would be more likely to use something like Basic authentication with a shared secret. I'm not sure there would be much benefit in rolling your own session system based on the security context contents. If you are worried about performance then you could use a cache of authentication information on the server.

How to access HTTP sessions in Java

How to get any http session by id or all currently active http sessions within web application (Java 2 EE) in an elegant way?
Currently I have a WebSessionListener and once session was created I put it in ConcurrentHashMap() (map.put(sessionId, sessionObj)), everything ok, I can retrieve HTTP session from that map in any time by session id, but it looks like the HttpSession objects will never finalize... Even session was invalidated the map still reference on invalidated session object... Also I have read this article and it looks like the WeakHashMap is not acceptable in my case...
In other words I need a possiblity to look in any HttpSession even get all currently active HttpSession and retrieve some attributes from there...
Please advice somebody :)
Update
I need to access HttpSession objects because of follwoing reason:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
My current implementation is: SessionManager which knows about all sessions (ConcurrentMap) and HttpSessionListener which put/remove session into SessionManager.
I was concerned about memory issues that may occure and I wanted to discusse this with someone, but currently I am clearly see that everything should works fine because all invalidated session will be removed from map when sessionDestroyed() method will be called...
Many thanks for your replays, but now I understood that problem was just imagination :)
As per your clarification:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
For this you actually don't need to know anything about the sessions. You just need to know which users are logged in. For that you can perfectly let the model object representing the logged in user implement HttpSessionBindingListener. I of course assume that you're following the normal idiom to login/logout user by setting/removing the User model as a session attribute.
public class User implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.add(this);
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(this);
}
// #Override equals() and hashCode() as well!
}
Then somewhere in your admin app, just obtain the logins from ServletContext:
Set<User> logins = (Set<User>) servletContext.getAttribute("logins");
Generally speaking, your servlet container will have its own session manager, which is responsible both for maintaining the lifecycle of the sessions, and associating incoming requests with the appropriate session (via cookies, anchor parameters, whatever strategy it wants).
The elegant way to do this would be to hook into this session manager in whatever way it allows. You could subclass the default one, for example, to allow you to get access to arbitrary sessions.
However, it sounds like what you're doing belies an underlying problem with your architecture. The data contained within a session should be specific to that session, so in general you shouldn't need to look up an arbitrary one in order to provide the standard logic of your web application. And administrative/housekeeping tasks are usually handled for you by the container - so again, you shouldn't need to interfere with this.
If you gave an indication of why you want access to arbitrary sessions, chances are that an alternative approach is more suited to your goals.
Andrzej Doyle is very right. But if you really, really want to manage your own list of sessions, then the way to connect to your container is via the HttpSessionListener - example code.
The listener is called whenever a new session is created, and importantly, it's also called when a session is destroyed; this will allow you to mimic the container's session bookkeeping.
You use your web.xml to register your session listener as a lifecycle listener for your your app.
You can communicate your session list with other processes in the container using the ServletContext, or you can cook up a more dirty scheme using e.g. static class fields.

Categories

Resources