Spring Framework
  1. Spring Framework
  2. SPR-8367

3.1.0.M2 update of the RestTemplate for Apache HTTP Components will default to sending 2 requests on authentication and doesn't support HttpContext parameters without significant extention/rewrite

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1 M2
    • Fix Version/s: 3.1 GA
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      true

      Description

      Reference JIRA: https://jira.springsource.org/browse/SPR-6180?focusedCommentId=66682#comment-66682

      Any use cases which require an HttpContext attribute to be set aren't covered in this implementation, and the extensions required make the whole thing so messy as to make using the Rest Template more of a burden than a benefit. Here is the particular case that I've been fussing with today to little avail, setting preemptive authentication (i.e. send basic authentication headers by default rather than performing 2 requests to authenticate):

      http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html#d4e1023

      The problem being that the RestTemplate implementation as it is has no support for setting HttpContext parameters (the template calls the Http.execute(HttpUriRequest) which uses only the non-accessible default HttpContext), there aren't any good ways to set the default context parameters on the HttpClient in 4.x Apache HTTP Components. You end up needing to extend HttpClient to provide for default HttpContext params on the HttpClient object and the whole thing just becomes a spaghetti mess from there making the template more pain than pleasure.

        Activity

        Hide
        David Parks added a comment -

        Incidentally, I just realized how simple this is with 3.x:

        HttpClient client = new HttpClient();
        client.getParams().setAuthenticationPreemptive(true);
        Credentials defaultcreds = new UsernamePasswordCredentials("username", "password");
        client.getState().setCredentials(new AuthScope("www.host.com", 443, AuthScope.ANY_REALM), defaultcreds);
        RestTemplate restTemplate = new RestTemplate(new CommonsClientHttpRequestFactory(client));

        It seems like Commons HTTP 4 went just a tad bit abstraction happy and made things a bit more difficult because of it.

        Anyway, I just want to emphasize that the main use case I'm concerned with here is enabling preemptive authentication. I don't see much sense in not presenting credentials on the first request in context of a REST service.

        Show
        David Parks added a comment - Incidentally, I just realized how simple this is with 3.x: HttpClient client = new HttpClient(); client.getParams().setAuthenticationPreemptive(true); Credentials defaultcreds = new UsernamePasswordCredentials("username", "password"); client.getState().setCredentials(new AuthScope("www.host.com", 443, AuthScope.ANY_REALM), defaultcreds); RestTemplate restTemplate = new RestTemplate(new CommonsClientHttpRequestFactory(client)); It seems like Commons HTTP 4 went just a tad bit abstraction happy and made things a bit more difficult because of it. Anyway, I just want to emphasize that the main use case I'm concerned with here is enabling preemptive authentication. I don't see much sense in not presenting credentials on the first request in context of a REST service.
        Hide
        Arjen Poutsma added a comment -

        @David,

        I feel your pain, but it is a bit unclear to me what exactly do you want us to do?

        Do you want to be able to set a HttpContext as a property of the HttpComponentsClientHttpRequestFactory?

        Show
        Arjen Poutsma added a comment - @David, I feel your pain, but it is a bit unclear to me what exactly do you want us to do? Do you want to be able to set a HttpContext as a property of the HttpComponentsClientHttpRequestFactory?
        Hide
        David Parks added a comment -

        That's a fine question indeed Arjen.

        Let's see, there's a few things at issue here. One, HttpContext params are more of a runtime thing in the new HTTP Components, it's designed so that you can have different context params per request. Not something that's really logical in the RestTemplate context.

        But the meat of this issue is that pre-emptive authentication isn't easily configured (as it was in commons-http-3.0).

        One quick-fix solution that I think is reasonable in the case of the RestTemplate would be to just enabled pre-emptive authentication for us in the RestTemplate's usage of http components. It's a natural default in the context of REST services, and I can't see many other likely use cases for the ContextParams.

        A bigger, harrier but all encompassing solution: Provide methods within the RestTemplate4CommonsHttp (sorry, forgot the new name) for properly configuring HttpContext params that will be used at request execution time.

        A middle of the road solution might be to simply give us access to the HttpContext params that you will ultimately use in the request. This way we can configure pre-emptive authentication (or other context param features) at creation time similar to how we might in 3.0. This solution is slightly muddied because there are some hard coded default params in the default context that need to be duplicated in an odd sort of way (sorry for the fuzzy description, it's been some weeks since I did this and it was about that point that I threw up my hands and went back to 3.0)

        Show
        David Parks added a comment - That's a fine question indeed Arjen. Let's see, there's a few things at issue here. One, HttpContext params are more of a runtime thing in the new HTTP Components, it's designed so that you can have different context params per request. Not something that's really logical in the RestTemplate context. But the meat of this issue is that pre-emptive authentication isn't easily configured (as it was in commons-http-3.0). One quick-fix solution that I think is reasonable in the case of the RestTemplate would be to just enabled pre-emptive authentication for us in the RestTemplate's usage of http components. It's a natural default in the context of REST services, and I can't see many other likely use cases for the ContextParams. A bigger, harrier but all encompassing solution: Provide methods within the RestTemplate4CommonsHttp (sorry, forgot the new name) for properly configuring HttpContext params that will be used at request execution time. A middle of the road solution might be to simply give us access to the HttpContext params that you will ultimately use in the request. This way we can configure pre-emptive authentication (or other context param features) at creation time similar to how we might in 3.0. This solution is slightly muddied because there are some hard coded default params in the default context that need to be duplicated in an odd sort of way (sorry for the fuzzy description, it's been some weeks since I did this and it was about that point that I threw up my hands and went back to 3.0)
        Hide
        Oleg Kalnichevski added a comment -

        @David,

        > It seems like Commons HTTP 4 went just a tad bit abstraction happy and made things a bit more difficult because of it.

        As far pre-emptive authentication is concerned it used to be a major source of security related issues prior to HttpClient 4.x. People used to turn it on blindly and often ended up sending their corporate credentials to external sites by mistake without fully realising the implications of their action. HttpClient 4.x forces people to do more work, but at the same time it makes them configure pre-emptive selectively and also enables the use of more secure schemes such as DIGEST, not just inherently insecure BASIC.

        @Arjen

        > Do you want to be able to set a HttpContext as a property of the HttpComponentsClientHttpRequestFactory?

        A setter for AuthCache should be sufficient as long as HttpComponentsClientHttpRequestFactory sticks it into the local HTTP context prior to execution of the request.

        Oleg

        Show
        Oleg Kalnichevski added a comment - @David, > It seems like Commons HTTP 4 went just a tad bit abstraction happy and made things a bit more difficult because of it. As far pre-emptive authentication is concerned it used to be a major source of security related issues prior to HttpClient 4.x. People used to turn it on blindly and often ended up sending their corporate credentials to external sites by mistake without fully realising the implications of their action. HttpClient 4.x forces people to do more work, but at the same time it makes them configure pre-emptive selectively and also enables the use of more secure schemes such as DIGEST, not just inherently insecure BASIC. @Arjen > Do you want to be able to set a HttpContext as a property of the HttpComponentsClientHttpRequestFactory? A setter for AuthCache should be sufficient as long as HttpComponentsClientHttpRequestFactory sticks it into the local HTTP context prior to execution of the request. Oleg
        Hide
        Arjen Poutsma added a comment -

        I've opted to add a createHttpContext method to HttpComponentsClientHttpRequestFactory, and passing on the created HttpContext (if any) to the request. This seemed more flexible than having just a AuthCache setter, as the context can contain more than just a authentication cache.

        Show
        Arjen Poutsma added a comment - I've opted to add a createHttpContext method to HttpComponentsClientHttpRequestFactory, and passing on the created HttpContext (if any) to the request. This seemed more flexible than having just a AuthCache setter, as the context can contain more than just a authentication cache.
        Hide
        Eugen Paraschiv added a comment -

        Hi,
        I'm trying to figure out how to use the new infrastructure (with most examples I could find targeting the old one). I'm doing something along the lines of:
        DefaultHttpClient newHttpClient = new DefaultHttpClient();
        Credentials creds = new UsernamePasswordCredentials( username, password );
        newHttpClient.getCredentialsProvider().setCredentials( new AuthScope( host, port, AuthScope.ANY_REALM ), creds );
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory( newHttpClient );
        restTemplate.setRequestFactory( requestFactory );

        but the Authentication headers do not seem to be in the request. Is there a working example of configuring RestTemplate with HttpClient (4.x) and Digest Auth?
        Thanks.

        Show
        Eugen Paraschiv added a comment - Hi, I'm trying to figure out how to use the new infrastructure (with most examples I could find targeting the old one). I'm doing something along the lines of: DefaultHttpClient newHttpClient = new DefaultHttpClient(); Credentials creds = new UsernamePasswordCredentials( username, password ); newHttpClient.getCredentialsProvider().setCredentials( new AuthScope( host, port, AuthScope.ANY_REALM ), creds ); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory( newHttpClient ); restTemplate.setRequestFactory( requestFactory ); but the Authentication headers do not seem to be in the request. Is there a working example of configuring RestTemplate with HttpClient (4.x) and Digest Auth? Thanks.

          People

          • Assignee:
            Arjen Poutsma
            Reporter:
            David Parks
            Last updater:
            Trevor Marshall
          • Votes:
            3 Vote for this issue
            Watchers:
            7 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 8 weeks, 4 days ago

              Time Tracking

              Estimated:
              Original Estimate - Not Specified
              Not Specified
              Remaining:
              Remaining Estimate - Not Specified
              Not Specified
              Logged:
              Time Spent - 19m
              19m