3

I have an existing Grails application which uses the Nimble plugin (therefore Apache Shiro security underneath).

I am adding a RESTful JSON API to it.

My login method manages to get the session ID from Shiro and returns it to the client:

class ApiController {
    def login(String username, String password) {
        def authToken = new UsernamePasswordToken(username, password)
        SecurityUtils.subject.login(authToken)

        render(contentType:"text/json") {
            [
                sessionId: SecurityUtils.subject.getSession().getId()
            ]
        }
    }

    def getData() {
        SecurityUtils.subject... // either expect to already find a properly populated SecurityUtils.subject or a way to otherwise get it
    }
}

This looks like:

{"sessionId":"61FE89F60F94A4EF7B796783E7A326BC"}

That is quite encouraging, as it is the same one that I see being passed in a cookie when from the browser:

Cookie:auth=Z3Vlc3Q6dGx1c2lz; m=2663:t|34e2:|47ba:t|4e99:t|6ef2:t|370d:t|3c0d:t|64b8:t|2a03:t|18c3:t|79d4:chart|640c:small|678e:3600%7C60|796a:t; OX_plg=swf|sl|wmp|shk|pm; _ga=GA1.1.441292120.1405856016; __atuvc=0%7C47%2C0%7C48%2C0%7C49%2C432%7C50%2C17%7C51; JSESSIONID=61FE89F60F94A4EF7B796783E7A326BC

However, I now cannot quite figure out how to properly pass this JSESSIONID from the mobile application in a way so that the existing Nimble / Shiro / Grails / Servlet (not sure what level) authentication filters recognize it as a proper session identifier and associate the request with the session.

I tried manually passing a Cookie with JSESSIONID=<sessionId> (using Dispatch on Android) but it appeared to have no effect (although perhaps my parameters to newValidCookie aren't all correct):

val cookie = com.ning.http.client.cookie.Cookie.newValidCookie("JSESSIONID", token, null, token, null, -1, -1, false, false)
val svc = host / "api" / "getData" addCookie cookie
Http(svc OK as.String) 

I also tried to append ;jsessionid=<sessionId> to the URL and that also did nothing.

I also tried doing new Subject.Builder().sessionId(sessionId).buildSubject(); in the getData() but the .sessionId() there didn't like a String.

I haven't figured out so far where exactly the processing of the session cookie takes place.

How do I properly assemble a session cookie so that a mobile app can use the application in the same way as the web client?

P.S. My plan B is to simply pass username/password in the authentication headers upon every request and have ApiController do the subject.login every time, but I'd prefer to rather do it using the session ID that's already used for the web application.

John M
  • 1,469
  • 17
  • 41

1 Answers1

0

There seem to be something called Custom Subject Instances (https://shiro.apache.org/subject.html#custom-subject-instances)

There are two steps:

  1. Create the Subject (with a Builder)
  2. Associate the Subject with a thread (many ways to do this)

Untested example:

Serializable sessionId = //acquired from somewhere 
Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject();

ThreadState threadState = new SubjectThreadState(subject);
threadState.bind();
try {
    //execute work as the built Subject
} finally {
    //ensure any state is cleaned so the thread won't be
    //corrupt in a reusable or pooled thread environment
    threadState.clear();
}
Janek Olszak
  • 4,067
  • 1
  • 28
  • 22