Shiro authentication with sessionId or username+password

bezmax picture bezmax · Dec 14, 2011 · Viewed 12k times · Source

I do not have much experience in Java authentication frameworks and authentication workflow in general (only some theoretical knowledge), so for educational purposes I'm trying to create this type of authentication for my HTTP application:

  1. Client Posts login+password to /login.
  2. Shiro logs in the user by given credentials. Server returns client his sessionId.
  3. Client requests some kind of resource /myresource?sessionId=1234567.
  4. Shiro logs in the Subject by given sessionId. Then server does the regular workflow of getting the /myresource (with Shiro managing method-level access rights).

Basically I have these questions:

  1. I guess I have no need for HTTP sessions nor Servlet sessions. Shiro has it's own session manager which is enough for my needs. Am I wrong?
  2. Is it good practice to give client the real sessionId or should I send some kind of sessionToken (which is resolved to sessionId on server side)?
  3. How do I login the Subject using sessionId (which the client should store locally)?
  4. Are there any other things I need to know before doing this kind of authentication?

Thanks in advance.

Answer

Nishant picture Nishant · Dec 16, 2011

I guess I have no need for HTTP sessions nor Servlet sessions. Shiro has it's own session manager which is enough for my needs. Am I wrong?

No, you're right. That's why Shiro is awesome. From documentation:

Shiro's Session support is much simpler to use and manage than either of these two [web container or EJB Stateful Session Beans] mechanisms, and it is available in any application, regardless of container.

e.g.

Subject currentUser = SecurityUtils.getSubject();    
Session session = currentUser.getSession();
session.setAttribute( "someKey", someValue);

quoting from the doc: getSession calls work in any application, even non-web applications

Is it good practice to give client the real sessionId or should I send some kind of sessionToken (which is resolved to sessionId on server side)?

It is a bad idea to send plain sessionId. Specially, if you're sending data over unencrypted network. Either use something like HTTPS or use something line NONCE.

And, a side note, if over http/s POST data instead of having it in URL.

How do I login the Subject using sessionId (which the client should store locally)?

You meant how could you authenticate the subject once you have session ID? You can simply, from the doc,

Subject requestSubject = new Subject.Builder().sessionId(sessionId).buildSubject();

Are there any other things I need to know before doing this kind of authentication?

Yes.

  1. Read Shiro's Session Management
  2. Lean about MITM Attack
  3. About HTTPS and SSL
  4. Some on Hash functions this, Apache Commons DigestUtils and may be this

Updates

About that subject authentication part - will it make the newly created Subject the currently authenticated subject? If not, how do I make it the "current" subject?

If you're talking about new Subject.Builder().sessionId(sessionId).buildSubject(), it will not. And I do not know how to set it as currentUser for the thread. Shiro's JavaDoc says,

[this way] returned Subject instance is not automatically bound to the application (thread) for further use. That is, SecurityUtils.getSubject() will not automatically return the same instance as what is returned by the builder. It is up to the framework developer to bind the built Subject for continued use if desired.

so, it's upto you how you bind the subject in current thread or further use.

If you were worried about how SecurityUtils.getSubject(); thingy works, well, in web-container context, it uses simple cookie to store your session-data. When your request comes through Shiro filter, it attached the current subject to request for it's life cycle (current thread). And when you as getSubject() it simply gets the Subject from request. I found an interesting thread here.

about nonce part: If he sends me some kind of hash instead of his sessionId - I won't be able to decode it to get real sessionId (to authorize him with that). Am I missing something here?

Nonce part -- it's a pain in the neck. Now rethinking, I think doing NONCE is just overkill. Let me explain some, anyways,

  1. User logs in first time with his user-name and password. Set userid, nonce (say, UUID), and HASH(sessionID+nonce) ,call it hash1, on client side. Say, in cookie. Store this nonce on server side, may be in DB or in a Map as user_id <--> nonce,session_id

  2. On subsequent request, make sure you passback userid, nonce and the HASH.

  3. On server side, the first thing you will do is validate the request. Get the sessionId and nonce stored in the hashmap or DB based on user_id that was sent by the client. Create a hash, HASH(sessionId_from_db+nonce_from_db), call it hash2.

  4. Now, if hash1 matches hash2, you can validate the request and since you have stored current sessionId on server side, you can use it. On request completion, set new nonce in cookie and on server side.

If you go through 1 -- 4, you'll realize you wouldn't require Shiro for authentication. (: So, I am taking my words back, NONCE is not applied in this case unless you are too freaky about security over performance.

Why do MITM attack matter to me? My client (javascript ajax code) fetches data from it's server via ajax. So I do not think I should care about MITM in any way.

I think it should matter to you. MITM Attack means your requests/responses are being chained via a machine (MITM) to your router. If it's an unencrypted request, it's all plain text to the MITM. He can see all your requests... and possibly spoof the requests and may hijack session. let me find some example.... http://michael-coates.blogspot.com/2010/03/man-in-middle-attack-explained.html