Search code examples
javarestthread-safetyejbshiro

Apache Shiro getSubject in REST API's @Singleton EJB bean


I'm developing a web app using Java EE 6 and Shiro for REST backend and this is accessed via an Angular based frontend.

Session creation is disabled in shiro (noSessionCreation in shiro.ini) and I'm authenticating the user on every request based on a token he/she received after he/she provided the credentials for login.

In the custom Authenticating filter I'm calling

SecurityUtils.getSubject().login(bearerToken);

That calls the custom authentication realm and does the validation of the credentials.

I have a Dao where I want to use the ID of the user which is stored in the Shiro Subject's principal information.

final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
final Long currentUserId = userInfo.getId();

The Dao itself is a @Singleton EJB

@Singleton
public class TaskDao {
    ...
    public List<Task> filterActiveTasks() {
    }
}

In this case I want to filter the active tasks that belong to the user that's accessing the service.

My question and concern at the same time:

Is this thread safe? Isn't it possible that upon concurrent usage the subjects might get mixed up?

If so, how could it be avoided?

EDIT:

My concern is not just for the activeTasks but also apply for any @Singleton annotated classes where I want to use the SecurityUtils.getSubject() static method.

public List<SomeData> getSomeDataRelatedToCurrentlyLoggedInUser() {
    // Since the following is a static call in a singleton, how can I be sure
    // that when 10 users are calling this at the same time, each call will get
    // the appropriate UserInfo that was "logged-in" at the AuthenticatingFilter level
    final UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
    Long currentUserId = userInfo.getId();

    return em.createNamedQuery("select s from SomeData s where s.userId = :userId").
        setParameter("userId", currentUserId).
        getResultList();

}

The login part is done in the custom AuthenticatingFilter which is -AFAIK- created for each user.

So the question still remains: Will the calls for SecurityUtils.getSubject() return the proper user or is it possible to mix them up? How can I retrieve the threadcontext in the singletons the user was bound to upon executing the login mechanism?


Solution

  • You could simply introduce a ThreadLocal variable in your singleton ejb.

    This way you put only stuff related to the current thread/user in the variable. For example:

    @Singleton
    public class TaskDao {
    
        private static ThreadLocal<Set<ActiveTasks>> tasksThreadLocal = new ThreadLocal<>(){
            @Override
            protected Set<ActiveTasks> initialValue() {
                return new HashSet<>();
            }
        };
    
        filterActiveTasks() {
             Set<ActiveTasks> tasks = tasksThreadLocal.get();
             //work with the Set
        }
    }
    

    This way the set is local to each thread and no multi-threading issues can arise.

    As for SecurityUtils.getSubject(), this method uses the same mechanism internally, so it always only returns the user on the current thread, thus the user that is logged into the current request. It uses the class ThreadContext which uses a ThreadLocal to store the current user/login session.

    If you somehow want access to that object (which in most cases, you don't) it has a bunch of static public methods you can call directly to set/get stuff like the subject or the security manager for the current thread.