7

I adapted the following OAauth2 Spring Cloud samples:

Authserver / SSO

The only change I made, was using JPA on the Authserver side to check the credentials from a database. Everything works well, except deploying it behind an nginx proxy. As used in the sample apps above, Spring Boot and embedded Tomcat is used. I also properly configured proxy headers:

server.tomcat.protocol-header=X-Forwarded-Proto
server.tomcat.remote-ip-header=X-Real-IP

Proxying HTTP is working:

accessTokenUri: http://uaa.sample.com/oauth/token
userAuthorizationUri: http://uaa.sample.com/oauth/authorize

So far so good, but I need to use SSL (obviously):

accessTokenUri: https://uaa.sample.com/oauth/token
userAuthorizationUri: https://uaa.sample.com/oauth/authorize

If I switch to SSL, I get a 401 from my client application after the auth server is redirecting back from authorize. I captured the HTTP traffic and everything seems to work:

The HTTP traffic for HTTP and HTTPS is exactly the same, except that for HTTP a proper referer is set for the last request (AFAIK, the referer isn't checked during OAuth authentication, right?):

HTTP:

GET /login?code=212eRK&state=9prwi2 HTTP/1.1
Host: test.sample.com
...
Referer: http://uaa.sample.com/login
Cookie: JSESSIONID=401EB8D1D1F4297160D518EC253A0CB5; XSRF-TOKEN=95a00a0d-3362-4e9b-b7eb-45addf2d10b4
...

---
HTTP/1.1 302 Found

HTTPS:

GET /login?code=212eRK&state=9prwi2 HTTP/1.1
Host: test.sample.com
...
Cookie: JSESSIONID=401EB8D1D1F4297160D518EC253A0CB5; XSRF-TOKEN=95a00a0d-3362-4e9b-b7eb-45addf2d10b4
...

---
HTTP/1.1 401 Unauthorized

Corresponding log message from client application:

Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token.

Any ideas why using a proxy and SSL isn't working? I'm happy to share more code and/or log output!

Thanks!!!

Thilo
  • 81
  • 1
  • 6
  • The logs will tell you probably (DEBUG logging for `org.springframework.security`). – Dave Syer May 14 '15 at 07:55
  • @DaveSyer Im having the same issue. adjusting the log level did not reveal anymore information about a possible root cause – Tucker Jun 22 '15 at 14:21
  • I can't tell any more from this level of detail. A sample app would help a lot. – Dave Syer Jun 22 '15 at 18:48
  • Just spent some time running what appears to be a similar situation though my debugger. In my case, at the point where the BadCredentialsException is thrown the underlying chained Exception is an InvalidRequestException with message: Possible CSRF detected: state parameter was required but could not be found. The BadCredentialsException is somewhat misleading to my naive (csrf matters) mind. – Nico de Wet Dec 11 '15 at 07:22
  • I am getting the sample error while trying to get the oauth(uaa/oauth/token) token behind network proxy. – Karthikeyan Jun 15 '16 at 10:09
  • I found the below things on debug
    1. OAuth2ClientAuthenticationProcessingFilter - attemptAuthentication() method's log hiding the actual error's cause(407 error) & displaying error "BadCredentialsException: Could not obtain access token"
    from the msg it's very difficult to under stand the cause(issue with basic auth or proxy or some other issue)
    2. DefaultClientAuthenticationHandler - authenticateTokenRequest() method is only setting the basic authentication header & not setting any proxy header
    – Karthikeyan Jun 15 '16 at 10:46
  • It seems we need to set it manually. From the above understanding, I think we need to override OAuth2ClientContext's AccessTokenRequest and set the proxy header. Is there any other way to set/override the network proxy setting? I tried to set the vm variables in the following ways also, but it's not working 1. -Djava.net.useSystemProxies=true 2. -Dhttp.proxy.host=127.0.0.1 -Dhttp.proxyPort=8080 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=8080 -Dhttp.proxyUser=user -Dhttp.proxyPassword=password -Dhttps.proxyUser=user -Dhttps.proxyPassword=password – Karthikeyan Jun 15 '16 at 10:49
  • please refer my previous 3 comments and Kindly help me if any one knows the solution. thanks – Karthikeyan Jun 15 '16 at 10:50
  • Managed with the below solution. http://stackoverflow.com/questions/37854133/how-to-set-proxy-on-spring-oauth2-oauth2accesstoken-request-or-how-to-override-o – Karthikeyan Jun 22 '16 at 02:24

3 Answers3

2

It looks to be failing where the SSO app tries to swap the auth code for a token. All the steps prior to this were browser redirects, this is code on the SSO server trying to call the auth server. What are you using for SSL certificates on the auth server? Are they signed by a trusted party with a CA in the Java trust store? If not, that is probably why it's failing as the BadCredentialsException is the end result of the underlying HTTP request failing.

The other option is that there is no route directly from the SSO server to the Auth server address.

I believe it's ultimately the Apache Commons HttpClient code that will be handling the request, so you should try upping the debug for those classes (org.apache.http) and see what it reported.

Jim.R
  • 743
  • 1
  • 5
  • 11
  • For me updating the JDK to latest version solved the issue because root cause was SSL Handshake. When i turned on Security DEBUG logging, i started seeing this exception- Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target – Munish Chandel Jan 04 '18 at 15:43
1

It may be a little late but I ran into the exact same thing.

My Setup is a NGINX doing SSL proxying through to a running Spring Boot Application using Spring oAuth2.

To solve this in nginx config

 proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;  
 proxy_set_header X-Forwarded-Proto  $scheme;  

And this in your spring application.yml

 server.tomcat.remote_ip_header: X-Forwarded-For
 server.tomcat.protocol_header: X-Forwarded-Proto
 security.require_ssl: true

Source: http://docs.spring.io/spring-boot/docs/current/reference/html/howto-security.html#howto-enable-https

And now Spring detects the right URL and also request.getRequestURL returns the right URL now including https://

 @Controller
 public class HomeController {
     @RequestMapping("/")
     @ResponseBody
     public String rootLandingPage(HttpServletRequest request) throws Exception {
         return "url: " + request.getRequestURL();
     }
 }
Foo Barino
  • 31
  • 1
  • after doing this, I get `The redirect URI in the request, https://localhost/login/google, does not match the ones authorized for the OAuth client. Visit https://console.developers.google.com/apis/credentials/oauthclient/477999739807-d0t4443rdep6jfnmjr4aufuh389tn2sk.apps.googleusercontent.com?project=477999739807 to update the authorized redirect URIs.` – Anand Rockzz Oct 18 '17 at 06:22
0

It may be worth taking a closer look at why the BadCredentialsException is bubbling up, and by this I mean stepping through the Spring Security OAuth2 code with your debugger.

The reason why I say this is because in my experience the BadCredentialsException may be due to an underlying InvalidRequestException with the following being the offending line:

throw new InvalidRequestException(
                "Possible CSRF detected - state parameter was required but no state could be found"); 

I have raised a separate question related to the above here:

Why is AccessTokenRequest's PreservedState perpetually null with a resultant CSRF related InvalidRequestException?

So, in terms of your situation, with the newly introduced nginx proxy, I'm just wondering whether you might not be seeing a misleading exception. That is, misleading to the untrained in terms of oauth2 and spring security oauth 2 with CSRF as an additional complexity to deal with.

Nico de Wet
  • 319
  • 2
  • 12