Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: Defining response formats, response fields and HTTP methods?

  1. #1

    Question Defining response formats, response fields and HTTP methods?

    Hi, I am evaluating the brand new 1.0.0.RELEASE without previous experience from the module. Couple of questions:

    I registered Auhtorization Server as one web application and Resource Server as another one. Both are deployed to the same container. Configuration is in the bottom of this post.

    1) How to force library to use only JSON? Out of box, the responses are in the format set in Accept-header. For application/json I get JSON but for application/xml I get XML (error messages, at least). The OAuth spec doesn't even define/allow XML format.

    For example, requesting for oauth/token without Authorization-header I get:

    Code:
    <oauth><error_description>An Authentication object was not found in the SecurityContext</error_description><error>unauthorized</error></oauth>
    When I want:

    Code:
    {"error": "unauthorized", "error_description": "An Authentication object was not found in the SecurityContext" }
    Also, if you invoke oauth/token with invalid credentials in Authorization-header from browser, I get browser asking for proper username/password. If you click cancel, the response is a HTML page.

    I haven't enabled the OAuth2AccessDeniedHandler.

    2) Successful access token query always returns "scope" field in JSON. "scope" field is specified as "OPTIONAL, if identical to the scope requested by the client, otherwise REQUIRED". Looks like the implementation always returns scope (it's ok) but how can I configure to omit that? By specifying a custom TokenGranter?

    3) How can I add extra fields to the error response? By specifying a custom TokenGranter?

    4) Token endpoint (oauth/token) answers succesfully to GET, POST, DELETE and PUT. I didn't test Authroize endpoint. OAuth2 spec (v31) defines:

    "The authorization server MUST support the use of the HTTP "GET" method [RFC2616] for the authorization endpoint, and MAY support the use of the "POST" method as well."

    "The client MUST use the HTTP "POST" method when making access token requests."

    How can I limit the endpoints to only respond to GET/POST (authorize) and just GET (token)? Do I need to deny all PUT/DELETE/(GET) via http intercept entries in XML? If so, why doesn't library automatically block the invalid

    X) Core confs for refrence:

    Authorization server:

    Code:
        <!-- Secure Token Endpoint behind HTTP Basic -->
        <sec:http
                pattern="/oauth/token"
                create-session="stateless"
                authentication-manager-ref="clientAuthenticationManager">
            <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
            <sec:anonymous enabled="false" />
            <!-- Enable HTTP Basic authentication -->
            <sec:http-basic />
            <sec:access-denied-handler/>
        </sec:http>
    
        <!-- Authentication manager for Clients -->
        <sec:authentication-manager id="clientAuthenticationManager">
            <sec:authentication-provider user-service-ref="clientDetailsUserService" />
        </sec:authentication-manager>
    
        <!-- Authentication manager for Users -->
        <sec:authentication-manager alias="authenticationManager">
            <sec:authentication-provider>
                <sec:user-service>
                    <sec:user name="marissa" password="koala" authorities="ROLE_USER" />
                    <sec:user name="paul" password="emu" authorities="ROLE_USER" />
                </sec:user-service>
            </sec:authentication-provider>
        </sec:authentication-manager>
    
        <!-- Base configuration -->
        <oauth:authorization-server
                client-details-service-ref="clientDetails"
                token-services-ref="tokenServices"
                token-endpoint-url="/oauth/token">
            <oauth:authorization-code disabled="true" />
            <oauth:implicit disabled="true" />
            <oauth:refresh-token />
            <oauth:client-credentials />
            <oauth:password />
        </oauth:authorization-server>
    
        <!-- Client details service -->
        <bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
            <constructor-arg ref="clientDetails" />
        </bean>
    
        <!-- Token services -->
        <jee:jndi-lookup id="dataSource" jndi-name="jdbc/oneidDs"/>
        <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
            <constructor-arg ref="dataSource"/>
        </bean>
        <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
            <property name="tokenStore" ref="tokenStore" />
            <property name="supportRefreshToken" value="true" />
            <property name="clientDetailsService" ref="clientDetails"/>
        </bean>
    
        <oauth:client-details-service id="clientDetails">
            <oauth:client client-id="client" secret="client" authorized-grant-types="client_credentials"
                authorities="ROLE_USER" scope="read,write" access-token-validity="600"/>
        </oauth:client-details-service>
    Resource Server:

    Code:
        <!-- Defines OAuth2 Resource Server -->
        <oauth:resource-server id="resourceServerFilter" resource-id="resourceServer" token-services-ref="tokenServices" />
    
        <sec:http
                pattern="/**"
                create-session="never"
                entry-point-ref="oauthAuthenticationEntryPoint"
                use-expressions="true">
            <sec:anonymous enabled="false" />
            <sec:intercept-url pattern="/formula/teams/**"
                    access="#oauth2.clientHasRole('ROLE_USER') and #oauth2.hasScope('read')" />
            <sec:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
            <sec:expression-handler ref="oauthWebExpressionHandler" />
        </sec:http>
    
        <!-- Adds WWW-Authenticate header to response suggesting location of where to authenticate -->
        <bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="sparklr2" />
        </bean>
    
        <!-- Token services -->
        <jee:jndi-lookup id="dataSource" jndi-name="jdbc/oneidDs"/>
        <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
            <constructor-arg ref="dataSource"/>
        </bean>
        <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
            <property name="tokenStore" ref="tokenStore" />
        </bean>
    
        <!-- Dummy authentication manager. Not really needed/used for Resource Server, but required by Spring Security -->
        <sec:authentication-manager />

  2. #2
    Join Date
    Jun 2005
    Posts
    4,232

    Default

    Quote Originally Posted by tuukka.mustonen View Post
    1) How to force library to use only JSON? Out of box, the responses are in the format set in Accept-header. For application/json I get JSON but for application/xml I get XML (error messages, at least). The OAuth spec doesn't even define/allow XML format.
    The spec used to mention alternative response formats. I guess they dropped it. Anyway XML output is standard with Spring MVC so we aim to meet normal Spring REST client assumptions. If you want to switch it off you have to remove the XML HttpMessageConverters, from the <mvc:message-converters/> or define your own HandlerAdapter (see standard references and seek help on Spring MVC generally for that) and also from the OAuth2 specific error renderers (the access denied handler and auth entry point that you aren't using but maybe want to later).

    Also, if you invoke oauth/token with invalid credentials in Authorization-header from browser, I get browser asking for proper username/password. If you click cancel, the response is a HTML page.
    That's probably normal Spring Security behaviour for HTTP basic if you don't provide any custom handlers. The OAuth2AuthenticationEntryPoint is provided as a basic handler for this use case essentially. Browser clients won't get much in the way of UX by default, but you can change it if you don't like it.

    2) Successful access token query always returns "scope" field in JSON. "scope" field is specified as "OPTIONAL, if identical to the scope requested by the client, otherwise REQUIRED". Looks like the implementation always returns scope (it's ok) but how can I configure to omit that? By specifying a custom TokenGranter?
    The scope in the token response is only for information for the client, so I can't really understand why you wouldn't include it. But if you don't want to it would be the renderer that I would change, not the token itself (otherwise resource servers won't know what scope has been granted). The renderer in this case is the HttpMessageConverter.

    3) How can I add extra fields to the error response? By specifying a custom TokenGranter?
    Again, I would change the renderer not the generator if I were you. But if you need to change the generator it would be the *Endpoint not the TokenGranter (which doesn't generate error responses only exceptions).

    4) Token endpoint (oauth/token) answers succesfully to GET, POST, DELETE and PUT. I didn't test Authroize endpoint.
    I don't really want to restrict HTTP method access explicitly in Spring OAuth when it is trivial to do it in Spring Security. If I were you I would add specific <intercept-url/> declarations in your security configuration.
    Last edited by Dave Syer; Nov 20th, 2012 at 07:59 AM. Reason: missing response in original

  3. #3

    Default

    Quote Originally Posted by Dave Syer View Post
    The spec used to mention alternative response formats. I guess they dropped it. Anyway XML output is standard with Spring MVC so we aim to meet normal Spring REST client assumptions. If you want to switch it off you have to remove the XML HttpMessageConverters, from the <mvc:message-converters/> or define your own HandlerAdapter (see standard references and seek help on Spring MVC generally for that) and also from the OAuth2 specific error renderers (the access denied handler and auth entry point that you aren't using but maybe want to later).
    I found AbstractJaxbMessageConverter and its' children JaxbOAuth2AccessTokenMessageConverter and JaxbOAuth2ExceptionMessageConverter. I tried resetting the converters by something like:

    Code:
        <mvc:annotation-driven>
            <mvc:message-converters register-defaults="false">
                <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
            </mvc:message-converters>
        </mvc:annotation-driven>
    But no matter what I put there, it doesn't seem to have effect. Apparently it's not possible to define an empty list of converters. Tips?

    Quote Originally Posted by Dave Syer View Post
    That's probably normal Spring Security behaviour for HTTP basic if you don't provide any custom handlers. The OAuth2AuthenticationEntryPoint is provided as a basic handler for this use case essentially. Browser clients won't get much in the way of UX by default, but you can change it if you don't like it.
    I think I was mixing couple of separate items here. First, Spring responds with WWW-Authenticate: Basic header by default and it's browser behavior to popup for username/password when that happens. If I want to remove the browser popup I should remove the WWW-Authenticate header.

    Then there is the response type. In the original response (with WWW-Authenticate: Basic) there is also a HTML body. To remove that I need to do something like what's described in http://stackoverflow.com/questions/4...pring-security

    What is responded after passing invalid credentials as Authorization header actually comes from OAuth module (OAuth2AccessDeniedHandler?).

    Isn't OAuth2AuthenticationEntryPoint supposed to be specified only for resources in Resource Server (because it adds WWW-Authenticate: Bearer) and not for Token endpoint in Authorization Server?

    Quote Originally Posted by Dave Syer View Post
    The scope in the token response is only for information for the client, so I can't really understand why you wouldn't include it. But if you don't want to it would be the renderer that I would change, not the token itself (otherwise resource servers won't know what scope has been granted). The renderer in this case is the HttpMessageConverter.
    Quote Originally Posted by Dave Syer View Post
    Again, I would change the renderer not the generator if I were you. But if you need to change the generator it would be the *Endpoint not the TokenGranter (which doesn't generate error responses only exceptions).
    As you say, we probably don't want to remove the scope so it's not that important. Anyway, I'm a bit lost here - would you elaborate on how to add custom fields as HttpMessageConverters seem to just convert entities into one form from another. What do you mean by "you need to change the generator it would be the *Endpoint not the TokenGranter" ?

    Then there is OAuth2AccessTokenSerializer that actually serializes the entity into JSON - shouldn't I need to override that?

    Quote Originally Posted by Dave Syer View Post
    I don't really want to restrict HTTP method access explicitly in Spring OAuth when it is trivial to do it in Spring Security. If I were you I would add specific <intercept-url/> declarations in your security configuration.
    Understandable. Might be sensible to add a note in documentation about that, though, as oauth2 specification is strict about HTTP methods.
    Last edited by tuukka.mustonen; Nov 20th, 2012 at 11:07 AM.

  4. #4
    Join Date
    Jun 2005
    Posts
    4,232

    Default

    Quote Originally Posted by tuukka.mustonen View Post
    But no matter what I put there, it doesn't seem to have effect. Apparently it's not possible to define an empty list of converters. Tips?
    I would ask that question on the MVC forum or on stackoverflow. The converters in <mvc:/> elements only apply to the results of the endpoint executions though - if you are looking at an error response that doesn't come from an endpoint directly (e.g. it comes from a Spring Security filter), then the mechanism is different.

    If I want to remove the browser popup I should remove the WWW-Authenticate header.
    Why would you want to remove the header? Your clients should be expecting it.

    What is responded after passing invalid credentials as Authorization header actually comes from OAuth module (OAuth2AccessDeniedHandler?).
    Only if you configure an OAuth2AccessDeniedHandler specifically in your filter chain. It doesn't get used in the configuration you provided, for instance. Invalid credentials is not an access denied exception though, so it wouldn't be that handler that got the exception anyway. It should be an AuthenticationEntryPoint.

    Isn't OAuth2AuthenticationEntryPoint supposed to be specified only for resources in Resource Server (because it adds WWW-Authenticate: Bearer) and not for Token endpoint in Authorization Server?
    Correct. I guess that's not accurately reflected in the sample apps. It might be better to use a normal BasicAuthenticationEntryPoint.

    Anyway, would you elaborate on how to add custom fields as HttpMessageConverters seem to just convert entities into one form from another. Then there is OAuth2AccessTokenSerializer that actually serializes the entity into JSON - shouldn't I need to override that?
    I thought you said you wanted to add extra fields to the error responses (i.e. not an access token)? You can see the error responses from the endpoints being generated in @ExceptionHandler methods. You might be able to override those I suppose, but I'm not really sure what you want to add so I don't know if you can do it in the renderer or not (or maybe just a WebResponseExceptionTranslator injected into the endpoint). There are also error responses that are generated by Spring Security filters (e.g. access denied), and for those you need to plug in handlers in teh standard Spring Security places.

    If you do want to add extra fields to an access token then the default implementation has an additionalInformation map for precisely that purpose (e.g. through a custom TokenEnhancer). There are also opportunities to modify the token and authentication outputs in UserApprovalHandler and AuthorizationRequestManager.

    Understandable. Might be sensible to add a note in documentation about that, though, as oauth2 specification is strict about HTTP methods.
    The docs are in the github wiki and it is open for editing. Feel free to add your contribution. Please fill out the contributor's agreement first (link in README).

  5. #5

    Default

    Quote Originally Posted by Dave Syer View Post
    I would ask that question on the MVC forum or on stackoverflow. The converters in <mvc:/> elements only apply to the results of the endpoint executions though - if you are looking at an error response that doesn't come from an endpoint directly (e.g. it comes from a Spring Security filter), then the mechanism is different.
    Ok, I need to ask around then. Couldn't find anything on that in searches so far.

    Quote Originally Posted by Dave Syer View Post
    Why would you want to remove the header? Your clients should be expecting it.
    It's just to make behavior in web browser similar to as requests through curl etc. We want to experience immediate errors in browser as would client code requesting the endpoint. It may confuse people if they try the URL in browser and it asks for things. It's just a minor annoyance.

    Quote Originally Posted by Dave Syer View Post
    Only if you configure an OAuth2AccessDeniedHandler specifically in your filter chain. It doesn't get used in the configuration you provided, for instance. Invalid credentials is not an access denied exception though, so it wouldn't be that handler that got the exception anyway. It should be an AuthenticationEntryPoint.
    Quote Originally Posted by Dave Syer View Post
    Correct. I guess that's not accurately reflected in the sample apps. It might be better to use a normal BasicAuthenticationEntryPoint.
    Right, so I would need to override BasicAuthenticationEntryPoint if I wanted to remove that. Ok.

    Quote Originally Posted by Dave Syer View Post
    I thought you said you wanted to add extra fields to the error responses (i.e. not an access token)? You can see the error responses from the endpoints being generated in @ExceptionHandler methods. You might be able to override those I suppose, but I'm not really sure what you want to add so I don't know if you can do it in the renderer or not (or maybe just a WebResponseExceptionTranslator injected into the endpoint). There are also error responses that are generated by Spring Security filters (e.g. access denied), and for those you need to plug in handlers in teh standard Spring Security places.
    As it's valid for oauth2 spec to include extra fields to responses, I just want to know how to do it. I have no real use case for that at the moment.

    Luckily, I don't see need for customizing error responses as the lib already comes with a decent exception hierarchy/mapping. But yeah, good pointers.

    Quote Originally Posted by Dave Syer View Post
    If you do want to add extra fields to an access token then the default implementation has an additionalInformation map for precisely that purpose (e.g. through a custom TokenEnhancer). There are also opportunities to modify the token and authentication outputs in UserApprovalHandler and AuthorizationRequestManager.
    Ok, found OAuth2AccessToken#getAdditionalInformation() and indeed that looks suitable for adding extra fields to response. Looks convenient.

    Quote Originally Posted by Dave Syer View Post
    The docs are in the github wiki and it is open for editing. Feel free to add your contribution. Please fill out the contributor's agreement first (link in README).
    Sure thing, let's see if I can get a good grasp on the lib first

  6. #6

    Default

    Also, to ensure I got it right:

    1. If you omit credentials (no Authorization header) OAuth2 response should be JSON message with error of "invalid_request" or "invalid_client" (don't know which one). Now I get Spring Security's standard HTML page reporting 401 "An Authentication object was not found in the SecurityContext". I can fix this by overriding BasicAuthenticationEntryPoint.

    2. If you provide invalid credentials (as Authorization header) OAuth2 response should be JSON message with error of "unauthorized_client". Now I get Spring Security's standard HTML page reporting 401 "No client with requested id: asfasf". I can fix this by overriding BasicAuthenticationEntryPoint.

    3. If you authenticate successfully (correct Authorize header) but omit the required grant_type parameter, OAuth2 response should be JSON message with error of "invalid_request". Now I get is 400 "The request sent by the client was syntactically incorrect". I can fix this by overriding TokenEndpoint (and add ExceptionHandler for this exception, whatever it might be)? How should I register it in XML then?
    Last edited by tuukka.mustonen; Nov 21st, 2012 at 07:41 AM.

  7. #7
    Join Date
    Jun 2005
    Posts
    4,232

    Default

    Are these all scenarios on the TokenEndpoint? If so then "yes" to (1) and (2) but "override" is probably the wrong word - you need to supply an authentication entry point instance, it doesn't have to override (in the Java language sense) BasicAuthenticationEntryPoint. Actually I think the framework should provide one, and OAuth2AuthenticationEntryPoint probably was supposed to be usable, but as your pointed out it sends the wrong prefix in the WWW-Authenticate header. Please open a JIRA ticket if you want to track the progress on that.

    There is an integration test for (3) which is passing so I assume it is already working (i.e. you should not need to change the TokenEndpoint). The response you describe might be expected if the client didn't send the correct Accept header, I suppose. What exactly did it send?

  8. #8

    Default

    Quote Originally Posted by Dave Syer View Post
    Are these all scenarios on the TokenEndpoint? If so then "yes" to (1) and (2) but "override" is probably the wrong word - you need to supply an authentication entry point instance, it doesn't have to override (in the Java language sense) BasicAuthenticationEntryPoint. Actually I think the framework should provide one, and OAuth2AuthenticationEntryPoint probably was supposed to be usable, but as your pointed out it sends the wrong prefix in the WWW-Authenticate header. Please open a JIRA ticket if you want to track the progress on that.
    Yeah these occur in TokenEndpoint. Guess I was bad with terminology because I wasn't really sure if providing new EntryPoint is the answer. But I had a look at AbstractOAuth2SecurityExceptionHandler and OAuth2AuthenticationEntryPoint and I guess I should do something like that.

    Quote Originally Posted by Dave Syer View Post
    There is an integration test for (3) which is passing so I assume it is already working (i.e. you should not need to change the TokenEndpoint). The response you describe might be expected if the client didn't send the correct Accept header, I suppose. What exactly did it send?
    It simply doesn't matter what I put in Accept header. No effect.

  9. #9
    Join Date
    Jun 2005
    Posts
    4,232

    Default

    You are correct (the integration test was for something else). If there is no grant_type (as opposed to the wrong grant_type) then Spring MVC sends a 400 with no content type, so your servlet container will choose to render it in some random way. Raise a JIRA ticket if you want to track progress and submit a pull request if you like (but it's trivial, so I'll probably do it soon anyway).

    If you care so much about this that you must work around it before 1.0.1 is out you can replace the token endpoint by providing a bean definition with id="oauth2TokenEndpoint" (see user guide on bean overriding).

  10. #10
    Join Date
    Jun 2005
    Posts
    4,232

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •