Announcement Announcement Module
Collapse
No announcement yet.
oath 2 legged rest web service security Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • oath 2 legged rest web service security

    Hi,

    I have a mvc website and a rest webservice. the website has been secured so that the users have to log in with username password. To perform some functions the website needs to make calls on a webservice which accesses some of the users data.

    The webservice invocation does not require the oauth dance where the user is prompted to authorise access - hence why i believe i need the 2 legged oauth implementation.

    Before calling the webservice i need to get some sort of oauth token from the webservice passing required user details, i then need to sign the request with this token when making the webservice invocation.

    I am very confused as to how to achieve this using spring security. I have read lots of stuff on the internet all with varying info. I would really appreciate if some of you learned ppl can help particularly with:

    1. how to secure the webservice so that it only accepts requests with valid oauth tokens
    2. how to configure the webservice so that it is a 2 legged oauth provider
    3. how the webapp can get a oauth token on behalf of the user and sign subsequent web service requests with that token.


    I am using spring 3.1.

    I would really appreciate your help with this as this has left me very confused.

    Samuel

  • #2
    It is a bit of a steep learning curve to start with, but luckily the OAuth2 spec is quite readable, and hopefully the samples and tests in the Spring projects help too.

    In answer to your #1: if you use Spring OAuth then you need to add a filter to your Spring Security chain. See the sparklr sample and the use of the <oauth:resource-server/> DSL.

    To your #3: you can also use Spring OAuth (OAuth2RestTemplate), but you can also use Spring Social if you prefer, or Scribe. Or something else if you are not using Java on the client (plenty of libraries around on the client side).

    As far as #2 goes, I'm not sure exactly what you need. The "2-legged" terminology is not used by the OAuth2 spec, so it is better to talk in terms of grant types. If you need your webservice calls to be on behalf of a user then you need to have a grant type that includes user authentication (client_credentials is no good). Since you have user authentication already in your client app you are starting from an unusual place, and will need to think hard about how to adpat one of the existing common patterns.

    The grant type that most obviously applies is the authorization code grant. If you don't need your users to be prompted for approval you can add a UserApprovalHandler (in Spring Security OAuth). To authenticate users you would need to establish a trusted channel between your web app and the auth server. Since authentication is out of the scope of the spec it's really up to you how to do that, so probably something simple like a shared sceret would be fine. You would have to add additional request parameters to identify the user, so you would need an extra filter to extract those. In Spring terms it's just adding an authentication filter to the <http/> element protecting the authorization endpoint.

    You could also use the password grant if you bend it a little (since you don't need to send a password, just the username). On reflection I think that would be the easiest implementation. You would just need to be careful to only expose it to your trusted client.

    If your system grew to having multiple web front end components then you would need a more conventional authentication approach with a shared identity manager (probably in the auth server). At that point you would be better off with authorization code for sure.

    Comment


    • #3
      Hi Dave, many thanks for the reply. Just to clarify I am using java and the explicit reference to 2 legged in #2 is only because this is what I thought best described the oauth journey I need.

      In my website I already have autheticated user using spring security. I now need to obtain a token from the webservice and sign subsequent requests when invoking methods on thr webservice.

      I am after the simplest solution in terms of grant types and use of filters. Would you be able to elaborate and describe what the context will like with the configuration you believe is best?

      Many thanks Dave

      Comment


      • #4
        Hi Dave,

        I have begun implementing the resource owner password grant solution. The client website will provide the necessary credentials it has obtained from the user login, and attempt to get an access token from my web service.
        I have taken the sparklr context and stripped out bits that I dont think are needed.

        My webservice (oauth provider) spring context contains the configuration shown below. At present I have a few of questions:-
        1. How does the webservice validate the token request? Is this the job of clientCredentialsTokenEndpointFilter? I have seen from your documentation advising against its use, so im confused as to how to perform the validation whereby the webservice
        would look at the credentials passed in the request, verify they belong to a real user by accessing user database before granting the access token.
        2. Having described by usage scenario, does the context configuration look right to you?
        3. what is the significance of the realmName in clientAuthenticationEntryPoint below? Can this be any string or does this need to correllate with something?
        4. When a request subsequently comes back into the webservice accompanied by a valid access token, how can i verify that it hasnt been hijacked and someone is now impersonating as that user?


        <!================================================ ========================TOKEN VENDING ================================================== ====================== -->
        <authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
        <authentication-provider user-service-ref="clientDetailsUserService" />
        </authentication-manager>

        <bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provide r.client.ClientDetailsUserDetailsService">
        <constructor-arg ref="clientDetails" />
        </bean>

        <!-- Defines just the single password grant type client -->
        <oauth:client-details-service id="clientDetails">
        <oauth:client client-id="webservice-client" authorized-grant-types="password" authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT" scope="read,write,trust" access-token-validity="60" />
        </oauth:client-details-service>

        <!-- If authentication fails and the caller has asked for a specific content type response, this entry point can send one, along with a standard 401 status-->
        <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provide r.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="myclient.com" />
        <property name="typeName" value="Basic" />
        </bean>

        <!-- If authorization fails and the caller has asked for a specific content type response, this entry point can send one, along with a standard 403 status -->
        <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provide r.error.OAuth2AccessDeniedHandler" />

        <!-- A filter and authentication endpoint for the OAuth2 Token Endpoint. Allows clients to authenticate using request parameters if included as a security filter, as permitted by the specification (but not recommended).
        It is recommended by the specification that you permit HTTP basic authentication for clients, and not use this filter at all.
        POSSIBLY NEED TO OVERRIDE THIS FILTER AND IMPLEMENT OWN AUTHENTICATION CODE
        -->
        <bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provide r.client.ClientCredentialsTokenEndpointFilter">
        <property name="authenticationManager" ref="clientAuthenticationManager" />
        </bean>

        <!--TOKEN REQUEST -->
        <http pattern="/oauth/token" create-session="stateless" entry-point-ref="clientAuthenticationEntryPoint" authentication-manager-ref="clientAuthenticationManager"
        xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" /> <!--what should the access role be?-->
        <anonymous enabled="false" />
        <!-- include this only if you need to authenticate clients via request parameters -->
        <custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
        </http>

        Sam

        Comment


        • #5
          Originally posted by samuel_coutinho View Post
          1. How does the webservice validate the token request? Is this the job of clientCredentialsTokenEndpointFilter? I have seen from your documentation advising against its use, so im confused as to how to perform the validation whereby the webservice
          would look at the credentials passed in the request, verify they belong to a real user by accessing user database before granting the access token.
          No, that's the wrong filter (it's for the auth server). See my previous response and look at the usage of <resource-server/> im sparklr.

          2. Having described by usage scenario, does the context configuration look right to you?
          * I guess in the light of your comment on #1, you should probably remove the clientCredentialsTokenEndpointFilter and replace it with a normal <basic/> filter.

          * There is no <resource-server/> filter or <http/> config for your protected resource. My understanding was that this would be in the same app (like in sparklr).

          3. what is the significance of the realmName in clientAuthenticationEntryPoint below? Can this be any string or does this need to correllate with something?
          It's just a hint to the client if it gets a 401 response. You can put anything you like in there if you control the client as well.

          4. When a request subsequently comes back into the webservice accompanied by a valid access token, how can i verify that it hasnt been hijacked and someone is now impersonating as that user?
          You can't, it's a bearer token. The definition of a bearer token is that if you have it, you can use it. Since the token is only held by your trusted client I don't see that as an issue, but you could consider limiting the validity period of the tokens if you are worried about it.

          P.S. Please use [QUOTE][/QUOTE] tags to post code and logs.

          Comment


          • #6
            Awesome Dave! Thank you so much. I know you are very busy and respond to many queries so you taking the time out to do this is very much appreciated.

            Comment


            • #7
              Hi Dave,

              I have had a look at the sparklr configuration and done a search on the internet. I cant find much info on the resource-server and it's use.

              The sparklr app simply has the following in the context with much information as to its purpose and how it functions:
              <oauth:resource-server id="resourceServerFilter" resource-id="sparklr" token-services-ref="tokenServices" />. Are you able to elaborate further or do you know where I can get more details on this?

              I'm still confused as to why you suggest using this filter. Having looked at sparklr this filter is defined in the <http/> config of the protected resource, but my question was how to I validate a access token request? I want to verify that the credentials passed when requesting an access token belongs to a real user in my system.

              Thanks

              Comment


              • #8
                Originally posted by samuel_coutinho View Post
                I want to verify that the credentials passed when requesting an access token belongs to a real user in my system.
                Ah, sorry, I didn't understand that. Please see my earlier responses on clientCredentialsTokenEndpointFilter. The normal way to authenticate a token request is with <basic/> auth, but it's entirely up to you. What I suggested was that you simply trust the webapp to send you valid user data. If you want to you could add a check in a filter downstream of the auth filter that pulls data out of your user store based on the username.
                Last edited by Dave Syer; Feb 18th, 2013, 08:13 AM. Reason: More details.

                Comment


                • #9
                  Hi Dave,

                  The normal way to authenticate a token request is with <basic/> auth
                  Do you mean I need to define my own custom filter instead of ClientCredentialsTokenEndpointFilter and declare it as follows:-

                  Code:
                  <!--TOKEN REQUEST -->
                      <http pattern="/api/oauth/token"   use-expressions="true" create-session="stateless"  entry-point-ref="clientAuthenticationEntryPoint"  authentication-manager-ref="clientAuthenticationManager">
                          <intercept-url pattern="/api/oauth/token" access="hasRole('USER')" /> 
                          <anonymous enabled="false" />
                          
                          <http-basic entry-point-ref="clientAuthenticationEntryPoint" />
                          <custom-filter ref="myCustomFilter" after="BASIC_AUTH_FILTER" />
                          <access-denied-handler ref="oauthAccessDeniedHandler" />
                      </http>
                  What I suggested was that you simply trust the webapp to send you valid user data. If you want to you could add a check in a filter downstream of the auth filter that pulls data out of your user store based on the username.
                  Surely the token request has to be validated and the credentials have to be checked? if not how do you differentiate between a valid access token request and a rogue one? A rogue client can simply invoke the /oath/token endpoint with any user credentials and get a valid token. Surely that cant be allowed?
                  Last edited by samuel_coutinho; Feb 18th, 2013, 08:55 AM.

                  Comment


                  • #10
                    That's not the usual way you would authenticate the token endpoint. The primary authentication is of the client, not the user, so <basic/> is fine if you set the right authnetication manager on it (as per the sparklr sample). The user credentials are checked by the token granter, so cancel what I said earlier about a custom filter: what I would do is just inject an authentication manager into the <password/> token granter that can ensure the username is valid but doesn't care about the password.

                    Comment


                    • #11
                      what I would do is just inject an authentication manager into the <password/> token granter
                      What is the password token granter Dave? Is it this:
                      <oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
                      user-approval-handler-ref="userApprovalHandler">
                      ...
                      <oauthassword/>
                      ...
                      </oauth:authorization-server>
                      How do I inject a an authentication manager into there to authenticate the access token request?

                      Another question for you: The oauth2 spec requires the username and password to be passed in as part of the access token request for the password grant. If these credentials are not verified by the oauth server when providng the token then what is the point of it? I can just pass in any username and password?

                      Comment


                      • #12
                        If you use a decent XML editor you can ask it to autocomplete for you, and you will quickly find that <password/> has an authentication-manager-ref attribute (hopefully with obvious meaning, but also with some documentation in the XSD). It defaults to the normal Spring Security value of "authenticationManager".

                        Comment

                        Working...
                        X