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

  • OAuth2 as AuthenticationProvider?

    Hi,

    I wonder whether it is possible to use the client side of Spring Security OAuth (2) as a Spring Security AuthenticationProvider. At the moment I'm working on a spring based web app which will serve as a client for a proprietary API that uses OAuth 2 Authentication. This web app is acting as a sort of trusted client that is allowed to do resource owner password authentication. I did a few test cases with Spring Security OAuth and basically the Resource Owner Password Authentication does work as expected. Now I wonder how to set up my web app to do form login against the ProtectedResourceDetails for the API.

    I guess I need to write an authentication provider for this to work. This provider would basically use the OAuth2RestTemplate to call the API for user details. If this call would succeed then the provider would generate a simple spring security UsernamePasswordAuthenticationToken and the user would be "logged in". Is this workflow correct and/or doable?

    What I'm failing to figure out is how do I set the resource owners credentials on the ProtectedResourceDetails? The Class ResourceOwnerPasswordResourceDetails does sport setters for username and password but is it correct to set them in the authentication provider code? What about threat safety? Is there a way to bind the OAuth2ProtectedResouceDetails bean to a single web request?
    Last edited by a.e; Apr 13th, 2012, 08:38 AM.

  • #2
    Have a look at https://github.com/cloudfoundry/uaa/...entFilter.java. You need to provide a resource on your auth server ("/userinfo" in this case) to serve up some sort of identifier for the user so you can tie the authentication to some local data in your app (see UserInfoEndpoint from the same project). Apart from that it's pretty easy - there's a sample /app there as well.

    Comment


    • #3
      Thanks for the pointer. So instead of an AuthenticationProvider all I need to have is a custom filter bean that works in a similar way? Does that approach work with my setup where my client is using resource owner password authentication i.e I need to take user supplied username and password and somehow set them in the OAuth2ProtectedResourceDetails?

      I tried to replicate the sample app you mentioned with my setup but I'm ending up getting a 401 even before my actual login page can be displayed:

      HTTP ERROR 401

      Problem accessing /login.html. Reason:

      Authentication Failed: Unable to obtain a new access token for resource 'myResource'. The provider manager is not configured to support it.
      What is this provider manager and how can I configure it?

      -Edit:

      Ok I'm a little step further. It seems like the namespace configuration via <oauth:resource> does not create a bean of type org.springframework.security.oauth2.client.token.g rant.password.ResourceOwnerPasswordResourceDetails even if the type is set to "password". The resulting instance of BaseOAuth2ProtectedResourceDetails ends up with the grantType of "unsupported" which no provider supports.

      So what I did was to create the resource details bean directly. No the final challange remains to setup spring security so that I'm able to display login.html again...

      -Edit2:

      I changed my spring security configuration to allow the login page to be displayed without any filters. I think this is correct. Now when the form gets submitted I see the following debug message in the logs and login is unsuccessful:

      Authentication request failed: org.springframework.security.authentication.Provid erNotFoundException: No AuthenticationProvider found for org.springframework.security.authentication.Userna mePasswordAuthenticationToken
      Is there a way to tell spring security that it's ok that there is no explicit authentication provider configured as authentication will be done through the filters?
      Last edited by a.e; Apr 13th, 2012, 11:10 AM.

      Comment


      • #4
        You lost me. You need authentication to a client webapp right? But grant_type=password would be inappropriate in that case (regular webapps in browsers with redirects use authorization_code). I can look into supporting grant-type="password" in an <oauth:resource/> but there's no way to use it from a webapp, so I might be making the wrong assumptions about your app.

        Look at the sample app and you will see that it defines an empty authentication manager (it's a validation requirement of the Security config namepsace but does nothing at runtime). Is that what you mean by telling "spring security that it's ok that there is no explicit authentication provider configured"?

        Comment


        • #5
          Let me explain what I'm trying to achieve.

          I have an application that consists of two parts. The first one is an restful webservice and the second one is a "client" to this webservice which is done as a classical web application (a small java/spring backend and a lot of html5 stuff on the frontend side).

          When the both parts were initially developed basic authentication was chosen to secure the api side. This was very simple but problems arose when it came to the implemenation of the "client backend". The original developers went with a custom implementation that stored client credentials in thread locals. This implementation did never work correctly. To get rid of it we agreed on using spring security on the client backend too. In the meantime the api side was upgraded to use oauth2 instead of basic authentication as the api will be used by different kinds of clients in the future not all developed in house.

          So now my requirement is to authenticate users using the "resource owner password" scheme from spring security on the client backend to the api. I know this is not the classical use case but there is no way the users of the client application will want to be forwarded to a seperate authentication page as the usage of oauth should be kept hidden (at least for this client).

          This is why I initially tried to write an AuthenticationProvider implementation that handles UsernamePasswordAuthenticationToken but I'm not sure whether it's possible to take the credentials that I get from spring security and somehow put them into the whole OAuth2 context so that subsequent token requests will use them. And from what I understand for this to work in a web context some beans should probably be bound to request scope instead of singleton scope.

          Comment


          • #6
            OK, I see. If I were you I would go with the flow, as it were, and stick to authorization_code for webapp clients. If you control the auth server there's no strict requirement to show the approval page (although it is highly recommended, and only needs to be shown once to get the approval if you can cache the result). If your auth server is s2-oauth then you can add a UserApprovalHandler that (for example) automatically approves requests from a certain client id.

            If you really want to use password grant that means your client app has to collect the credentials, which is exactly the pitfall that OAuth is designed to avoid. You can still do it, but there's no point trying to use the <oauth:rest-template/> or <oauth:resource/> namespace shortcuts. Just create a ResourceOwnerPasswordResourceDetails and use that to create an OAuth2RestTemplate when you want to authenticate (or if you already have an access token use that and the client details will be ignored, I guess).
            Last edited by Dave Syer; Apr 16th, 2012, 06:31 AM. Reason: spelling

            Comment


            • #7
              Hi,

              thank you for the additional info. I just wanted to present my final solution.

              I did finally implement a custom authentication provider for spring security that creates the necessary protected resource details and the rest template when authenticating. The provider saves the resource details and the client context (retrieved from the rest template) in a custom "AuthenticationContext" class and adds this to the authentication bean via its "setDetails()" method. All code paths that lie in secured contexts now have the ability to retrieve these beans via the security context and therefore generate a rest template for themselves.

              As far as the security concerns go I view this client application as "trusted" in a way that it runs in a controlled environment and only the clients web frontend is exposed to the public (via ssl). All oauth2 calls are made from the backend to the api endpoint. The frontend does simple http requests and doesn't even know about oauth. The case would be a different one I think if the frontend code (javascript) would make direct use of oauth2 i.e. call the api directly. In that case the resource owner password scheme would not sport any benefit over plain http basic authentication.

              Comment


              • #8
                Hi a.e.

                Can you post some code of your solution? I've got the same setup as you in one of my cases. I also need to add there a silent oauth authorization from a trusted frontend.

                Kind regards,
                Adrian

                Comment


                • #9
                  Hi,

                  I also have the same problem. Can you post some code of you solution?

                  I look into OpenIdClientFilter, but I had no success iimplementing Oauth2 version.

                  Best regards,
                  Marko

                  Comment


                  • #10
                    OpenIdClientFilter is an OAuth2 solution. What exactly are you trying to do?

                    Comment


                    • #11
                      Originally posted by adrian.hoehn View Post
                      Hi a.e.

                      Can you post some code of your solution? I've got the same setup as you in one of my cases. I also need to add there a silent oauth authorization from a trusted frontend.

                      Kind regards,
                      Adrian
                      I prepared a gist with the main code I'm talking about. The rest should be easily adaptable to your use case.

                      https://gist.github.com/2845397

                      Comment


                      • #12
                        Thanks for your gist. When I try to adapt your solution I allways get a "Authentication is required to store an access token (anonymous not allowed)" (AccessTokenProviderChain L78, spring-security-oauth 1.0.0.M6c).

                        This occures because my user is of course still anonymous in the AuthenticationProvider Code, but I allready need to call the backend for getting the user details for creating the Authentication object. How did you managed this?

                        Comment


                        • #13
                          This error message probably originates from the oauth provider side (the server). Be sure to set up your oauth authentication entry point accordingly. In my case I have a spring security interceptor on the url I use to retrieve the user details that requires authentication. Something like this:

                          Code:
                              <security:http create-session="stateless"
                                             entry-point-ref="oauthAuthenticationEntryPoint"
                                             access-decision-manager-ref="accessDecisionManager">
                                  <security:anonymous enabled="false"/>
                                  <security:intercept-url pattern="/me" access="ROLE_USER,SCOPE_READ-RESOURCES"/>
                                  <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER"/>
                                  <security:access-denied-handler ref="oauthAccessDeniedHandler"/>
                              </security:http>
                          When I call this url (/me) with my custom client (that uses the oauth 2 rest template) the whole oauth 2 authentication dance is done implicitly.

                          Comment


                          • #14
                            my setup looks similar. Outside of the AuthenticationProvider (e.g. after user is authenticated) the oauth-handshake is functioning without any problems.

                            At the moment I'm running with a hack depending on that Anonymous Error (just inside of the AuthenticationProvider, outside I'm able to use the ResourceOwnerPasswordResourceDetails with OAuthRestTemplate):
                            Code:
                            RestTemplate restTemplate = new RestTemplate();
                            OAuth2AccessToken token = restTemplate
                            					.getForObject(
                            							baseURL
                            									+ "/oauth/token?response_type=code&client_id=my-client&grant_type=password&scope=trust&username={username}&password={password}",
                            									OAuth2AccessToken.class, auth.getName(), (String) auth.getCredentials());
                            User user = rest.getForObject(baseURL + "/rest/user?username={username}&access_token={token}", User.class, auth.getName(), token.getValue());
                            Maybe someone can explain me a better solution or where I've to search for my mistake.

                            Comment


                            • #15
                              Hi,
                              I have two applications. One is Oauth2 provder app (based on Sparklr sample). In provider application I definied protected resource (/oauth/me) to server account details. Second application is simple MVC. I'm trying to implement AuthenticationFilter or AuthenticationProvider in second application to use first aplication protected resource for user authentication. When I try to use Oauth2Rest template from my custom AuthenticationFilter I allways get a "Authentication is required to store an access token (anonymous not allowed)". That is expected because user is still anonymous, but I'm stuck here.

                              What I trying to achieve is:

                              User go to http://localhost:8080/second-app -> redirect to Oauth2 provider login page

                              After user login into provider app -> redirect to http://localhost:8080/second-app and implicit create Authentication

                              Best regards,
                              Marko
                              Last edited by markoradinovic; Jun 1st, 2012, 09:28 AM.

                              Comment

                              Working...
                              X