Announcement Announcement Module
Collapse
No announcement yet.
Spring OAuth2 vs. Jersey? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring OAuth2 vs. Jersey?

    I'm trying to use this very nice Spring OAuth2 package to secure a Jersey JAX-RS application. I'm using Spring 3.2.0 and Spring Security 3.1.3 with Spring Security OAuth2 1.0.4. My Spring XML is available here and my web.xml is available here.

    I'm running into a very confusing problem. At application start-up, Spring logs the registration of appropriate endpoints to support OAuth, e.g.

    INFO 15:37:46.991 (FrameworkEndpointHandlerMapping) Mapped "{[/oauth/token],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<org.spring framework.security.oauth2.common.OAuth2AccessToken > org.springframework.security.oauth2.provider.endpo int.TokenEndpoint.getAccessToken(java.security.Pri ncipal,java.lang.String,java.util.Map<java.lang.St ring, java.lang.String>)

    but these endpoints (e.g. /oauth/token) just return 404s from Jersey, e.g.:

    com.sun.jersey.api.NotFoundException: null for uri: http://localhost:8080/oauth/token

    Is there perhaps something I am missing about the interaction of Jersey and Spring here?

    Thanks for any advice!

  • #2
    The <authorization-server/> features are Spring MVC controllers, so you need a DispatcherServlet. I don't know what the Jersey SpringServlet does, but it isn't that.

    It would be easier probably to separate out the <authorization-server/> from the <resource-server/> (deploy them separately). If you can't do that then you are going to have to teach Jersey to play with Spring. In principle that should be easy, but all the samples have the DispatcherServlet mapped to "/" or "/*" so if you want your Jersey servlet on that mapping you will need to modify the endpoint paths either in the <authorization-server/> or your <client-details/> or both. E.g. if you map a DispatcherServlet to "/oauth/*" you could use <authorization-server token-endpoint-url="/token" authorization-endpoint-url="/authorize"/>.

    Comment


    • #3
      Thank you so much for this reply. I see now that I need to do more to make Jersey "play nicely".

      It would be very difficult for my project to deploy multiple artifacts, so I'll start by going down the road of altering the mappings to see if I can get these guys to route around each other.

      Comment


      • #4
        Thanks again-- installing a DispatcherServlet in my web.xml and adjusting the URL routing did, indeed, get the endpoints up and available. I'm finding a different and very puzzling issue now, and I wonder if it's something that's been seen.

        I can successfully retrieve a token from /oauth/token via the Password flow (which seemed easiest to use for testing) but it cannot be used to take action against a secured endpoint. When I use a retrieved token, I get a log like:

        DEBUG 16:29:34.131 (OAuth2AuthenticationProcessingFilter) Token not found in headers. Trying request parameters.
        DEBUG 16:29:34.133 (OAuth2AuthenticationProcessingFilter) Authentication request failed: error="invalid_token", error_description="Invalid access token: c91be6d8-370b-438a-8613-086b1404ed76"

        which seems to be thrown from DefaultTokenServices line 200, when it receives a null result from its TokenStore (which, in my case, is an InMemoryTokenStore). But that would seem to imply that the token was never recorded when it was issued, which makes no sense.

        My two calls to make this happen are:

        curl "[user]:[password]@localhost:8080/oauth/token?grant_type=password&username=[user]&password=[password]&client_id=[client_id]" -X POST

        which returns as expected something like:

        {"access_token":"c91be6d8-370b-438a-8613-086b1404ed76","token_type":"bearer","expires_in":4 2520}

        so I'm pretty sure the token is correctly being granted. It's when I try to get a resource:

        curl -X POST "localhost:8080/rest/objects/oauthGuarded?access_token=c91be6d8-370b-438a-8613-086b1404ed76"

        that I get:

        {"error":"invalid_token","error_description":"Inva lid access token: c91be6d8-370b-438a-8613-086b1404ed76"}

        Any thoughts? Thanks!

        Comment


        • #5
          Probably you have 2 InMemoryTokenStore instances? Maybe you have 2 application contexts (one for the filter wrapping the Jersey servlet and one for the Spring servlet)? If one is the parent of the other (which is normal, but we'd have to look in detail) you only need to define it in the parent.

          Comment


          • #6
            I've run a profiler over the app, and it looks like that there are indeed two TokenStores, coming from different contexts. One is the named context in which I've been doing this work. The other appears to be the root context of the app. I certainly have only defined these beans once. Is there perhaps something I'm missing about the relationship between these two contexts? Perhaps I need to make it explicit (it is not now)? You can see my web.xml at the links above.

            Thanks for the help so far!

            Comment


            • #7
              You only have one Spring XML file but you are instantiating it twice (once in the ContextLaderListener and once in the DispatcherServlet). If I were you I'd remove the ContextLoaderListener (see samples in oauth2 project for a template), but there are other ways of dealing with the problem (e.g. split up your beans into ones that the servlet uses directly and ones that it doesn't).

              Comment


              • #8
                Thanks very much! Indeed, that was the problem. But now I have a different problem, one that is a general Spring question (so feel free to redirect me out of this forum): I can't seem to get the Spring contexts associated with security to be loaded by the MVC Dispatcher Servlet, and at the same time get the contexts associated with the construction of our application and JAX-RS API to be loaded by the Jersey Spring servlet. Is there perhaps some standard practice for loading different sets of contexts into different servlets? I've tried every possible combination of contextConfigLocation as a context parameter in web.xml, as an init parameter for the servlets, the use (or deletion) of ContextLoaderListener with and without a dummy applicationContext.xml, all kinds of flailing.

                Thanks for any help, or a pointer to a better place to go for help!

                Comment

                Working...
                X