Announcement Announcement Module
Collapse
No announcement yet.
Grails session expires during callbacks from OAuth providers Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Grails session expires during callbacks from OAuth providers

    Hi all. The issue I'm about to raise involves a number of moving parts, but I believe I have definitively isolated it to being a core Grails/Spring issue, and not something due to the third parties in play. The basic problem is that when a user starts a session with my application, the session successfully communicates with an OAuth provider (tested with LinkedIn and Twitter), but expires when the browser redirects to the provider's website for authentication.

    First, my environment: Oracle JDK 1.6.0.29, 64-bit, running on Ubuntu 11.10, with testing done in IntelliJ IDEA 11.0. I have tested what follows in both Grails 1.3.8 and 2.0.1, and they produce identical results, starting from clean projects with only the oauth-scribe plugin added (I did that to make sure none of my other code was at issue).

    Second, the code from the controller that implements the OAuth interaction. It is exactly as written by the plugin author, with only a few print statements added by me:

    Code:
    def authenticate = {
    
            Token requestToken = EMPTY_TOKEN
            if (oauthService.getOauthVersion() == SupportedOauthVersion.ONE) {
                requestToken = oauthService.requestToken
            }
    
            session[OauthService.REQUEST_TOKEN_SESSION_KEY] = requestToken
            println "session.id is ${session.id} in authenticate"
            println "attribute names for session in authenticate:"
            Enumeration<String> names = session.attributeNames
            names.each {
                println it
                Object attribute = session[it]
                println "attribute is a Token? ${attribute instanceof Token}"
            }
            String url = oauthService.getAuthorizationUrl(requestToken)
            print "url is ${url}"
            
            return redirect(url: url)
        }
    
    def callback = {
    
            Verifier verifier = extractVerifier(params)
    
            if (!verifier) {
                return redirect(uri: oauthService.failureUri)
            }
            println "session.id is ${session.id} in callback"
            println "attribute names for session in callback:"
            Enumeration<String> names = session.attributeNames
            names.each {println it}
            Token requestToken = (Token) session[OauthService.REQUEST_TOKEN_SESSION_KEY]
            print "requstToken null? ${requestToken == null} and verifier null? ${verifier == null}"
            Token accessToken = oauthService.getAccessToken(requestToken, verifier)
    
            session[OauthService.ACCESS_TOKEN_SESSION_KEY] = accessToken
            session.removeAttribute(OauthService.REQUEST_TOKEN_SESSION_KEY)
    
            return redirect(uri: oauthService.successUri)
    
        }
    Third, the relevant statements from the authenticate and callback controllers shown above:

    obtaining request token from https://api.linkedin.com/uas/oauth/requestToken
    setting oauth_callback to http://myhost:8080/trunk/oauth/callback
    generating signature...
    ...

    session.id is CF2FCF26E84929E986F59AEFCBE926A8 in authenticate
    attribute names for session in authenticate:
    oasRequestToken
    attribute is a Token? true
    url is https://api.linkedin.com/uas/oauth/a...7-c3fb8a002688
    ...

    session.id is 94A56B5549ABFEB2A550A1F2FCE9E95D in callback
    attribute names for session in callback:
    requstToken null? true and verifier null? false
    obtaining access token from https://api.linkedin.com/uas/oauth/accessToken
    | Error 2012-03-30 10:12:13,242 [http-bio-8080-exec-7] ERROR errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [GET] /trunk/oauth/callback - parameters:
    oauth_token: 21ce3626-6323-4145-a707-c3fb8a002688
    oauth_verifier: 86389
    Stacktrace follows:
    Message: null
    Line | Method
    ->> 75 | getAccessToken in org.scribe.oauth.OAuth10aServiceImpl

    | 118 | getAccessToken in uk.co.desirableobjects.oauth.scribe.OauthService
    | 25 | doCall . . . . in uk.co.desirableobjects.oauth.scribe.OauthControlle r$_closure1
    | 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
    | 908 | run . . . . . in ''
    ^ 662 | run in java.lang.Thread

    As you can see, the requestToken stored in the session map disappears because the session id in the authenticate action is no longer in use when the callback action is called. Note that I print all of the session attributes in both actions, and the only attributeBy switching the session map call to servletContext, I get successful authentications, but aside from being bad practice, it suggests very strongly that the user's session is expiring, even with the browser open, as soon as a page that the application itself sent the user to is visited. Since the code works exactly as expected when the session is taken out of play, the only remaining question is what is causing the session to expire. I appreciate any help you all can offer.

  • #2
    Demo app up to illustrate problem in more detail

    I have added source code for a demo application that illustrates the above behaviors at the following URL:

    https://github.com/jeliotb/oauth-scribe-test

    Since the plugin installs into a directory that is not part of the path under source control on my local machine, I have copied the modifications I made to the plugin's OauthController file to a file inside the application called MyOauthController.

    Interestingly, by redirecting from the controller used in the oauth process to the original controller, the original session ID shows up again, and anything placed in the flash and session scopes in the second session thus becomes unavailable. Here is an example of the output produced by the demo:

    //inside OauthController in plugin
    session.id is 0EC29A4C722DF5C2CE65BDC284337BCF in authenticate
    attribute names for session in authenticate:
    oasRequestToken
    attribute is a Token? true
    url is https://api.linkedin.com/uas/oauth/a...0-cfb72437de11
    //inside OauthController in plugin AFTER redirect to LinkedIn
    session.id is 9FE7FD8E15BC41C2F7F7100FD383A826 in callback
    attribute names for session in callback:
    //inside DemoController in main Grails app after request token is found to be null in oauth/callback
    flash message is now null
    session message is now null
    session id is now 0EC29A4C722DF5C2CE65BDC284337BCF in /demo/failure

    I am very surprised to see that the original session continues to exist, and that it is somehow automatically recovered by Grails on the redirect to a controller that is never invoked until after the first switch occurs. But as you can see, that is exactly what happens.

    Comment


    • #3
      Not sure if this is still an issue for you - but I came across this post, which resolved the session issue for me.

      Comment

      Working...
      X