GithubHelp home page GithubHelp logo

uaa-behind-zuul-sample's Introduction

UAA (AuthorizationServer) load balanced behind API-GATEWAY (Edge service Zuul)

Twitter Follow

Disclamer

This project is Proof of concept (aka PoC) (and code quality is not perfect), please before using in production review security concerns among other things. (See #6)

Change Log

see CHANGELOG.md

Overview

Quick&dirty sample to expose how to configure AuthorizationServer (UAA) behind Zuul

This way to do may not work for all kind of configuration (I do not test without JWT and prefer-token-info: true)

Usage

Please deploy every services using docker way or maven way, then simply load http://localhost:8765/dummy on your favorite browser.

Default user/password is user/password

Docker

Start building docker images for every services, simply run following command on root directory

mvn clean package -Pdocker

Launch services using docker-compose

docker-compose up -d

Maven

On each service folder run following command:

mvn spring-boot:run

Run

Open http://localhost:8765/dummy and connect with:

  • user: user
  • password: password

Goals

  1. Avoid any absolute/hardcoded urls for security.oauth2.client.accessTokenUri & security.oauth2.client.userAuthorizationUri in order to improve portability!
  2. AuthorizationServer distribution for HA
  3. Do not expose AuthorizationServer, like other service AuthorizationServer will be behind Zuul

network

Where localhost:8765 is Zuul, as you can see AuthorizationServer is not leaked outside! Only Zuul is targeted.

ATTENTION for 2. you should manage yourself shared storage backend (unlike following sample)! Using database or something els.

Keys points of the sample

[Zuul] Custom OAuth2ClientContextFilter

I had to override OAuth2ClientContextFilter to support URI and not only URL (see DynamicOauth2ClientContextFilter). Indeed URL does not support path like /uaa/oauth/authorize.

Why adding path support on OAuth2ClientContextFilter?

Because I want to use path on security.oauth2.client.userAuthorizationUri in order to redirect user to Zuul itself.

On this case I can't use http://localhost:${server.port}/uaa/oauth/authorize because security.oauth2.client.userAuthorizationUri is use on web redirection (header Location: ).

Flow will look like following

Browser                             Zuul                               UAA
   │        /dummy                   │                                  │
   ├────────────────────────────────>│                                  │
   │  Location:http://ZUUL/login     │                                  │
   │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤                                  │
   │        /login                   │                                  │
   ├────────────────────────────────>│                                  │
   │  Location:/uaa/oauth/authorize  │                                  │
   │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤                                  │
   │     /uaa/oauth/authorize        │                                  │
   ├────────────────────────────────>│                                  │
   │                                 │      /uaa/oauth/authorize        │
   │                                 ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄>│
   │                                 │                                  ├──┐
   │                                 │                                  │  │ Not authorize
   │                                 │                                  │<─┘
   │                                 │  Location:http://ZUUL/uaa/login  │
   │                                 │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
   │                                 │                                  │
   │ Location:http://ZUUL/uaa/login  │                                  │
   │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤                                  │
   │       /uaa/login                │                                  │
   ├────────────────────────────────>│                                  │
   │                                 │            /uaa/login            │
   │                                 ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄>│
   │                                 │           LOGIN FORM             │
   │                                 │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┤
   │           LOGIN FORM            │                                  │
   │<────────────────────────────────┤                                  │

Take attention on second redirection, location is using path (not at browser level).

[Zuul] localhost trick for security.oauth2.client.accessTokenUri

Unlike security.oauth2.client.userAuthorizationUri, security.oauth2.client.accessTokenUri is not used a browser level for redirection but used by RestTemplate. However default RestTemplate used for accessTokenUri is not load balanced thus we can't use url like http://service-name/oauth/token.

We can simply add load balanced feature by adding such Bean

@Bean
UserInfoRestTemplateCustomizer userInfoRestTemplateCustomizer(SpringClientFactory springClientFactory) {
    return template -> {
        AccessTokenProviderChain accessTokenProviderChain = Stream
                .of(new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(),
                        new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider())
                .peek(tp -> tp.setRequestFactory(new RibbonClientHttpRequestFactory(springClientFactory)))
                .collect(Collectors.collectingAndThen(Collectors.toList(), AccessTokenProviderChain::new));
        template.setAccessTokenProvider(accessTokenProviderChain);
    };
}

An opened isse exists spring-attic/spring-security-oauth#671

[Zuul] Clear sensitiveHeaders lists for AuthorizationServer route

Since Brixton.RC1, Zuul filters some headers (http://cloud.spring.io/spring-cloud-static/spring-cloud.html#_cookies_and_sensitive_headers).

By default it filters:

  • Cookie
  • Set-Cookie
  • Authorization

But we need that AuthorizationServer could create cookies so we must clear list

zuul:
  routes:
    uaa-service:
      sensitiveHeaders:
      path: /uaa/**
      stripPrefix: false

TODO Check if zuul.routes.uaa-service.sensitiveHeaders: Authorization could work?

[Zuul] Disable XSRF at gateway level for AuthorizationServer

AuthorizationServer has it own XSRF protection so we must disable at Zuul level

private RequestMatcher csrfRequestMatcher() {
    return new RequestMatcher() {
        // Always allow the HTTP GET method
        private final Pattern allowedMethods = Pattern.compile("^(GET|HEAD|OPTIONS|TRACE)$");

        // Disable CSFR protection on the following urls:
        private final AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/uaa/**") };

        @Override
        public boolean matches(HttpServletRequest request) {
            if (allowedMethods.matcher(request.getMethod()).matches()) {
                return false;
            }

            for (AntPathRequestMatcher matcher : requestMatchers) {
                if (matcher.matches(request)) {
                    return false;
                }
            }
            return true;
        }
    };
}

[Zuul] Authorize request to AuthorizationServer

Ok should I really need to explain why?

http.authorizeRequests().antMatchers("/uaa/**", "/login").permitAll()

ATTENTION do not use "/uaa/**" authorize only necessary API (I was to lazy)

[UAA] Deploy AuthorizationServer on isolated context-path

Zuul and AuthorizationServer have to manage their own session! So both have to write two JSESSIONID cookies.

You must isolate AuthorizationServer on other context-path server.context-path = /uaa to avoid any cookies collision.

ALTERNATIVE we can check if server.session.cookie.path or server.session.cookie.name is not sufficient, I did not test it.

[UAA] Enable server.use-forward-headers

Does not work without. I will not explain why, please look about X-Forwarded-* headers for more information.

uaa-behind-zuul-sample's People

Contributors

bilak avatar kakawait avatar kentoj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uaa-behind-zuul-sample's Issues

Some questions.

Hi, first off, thaks for this wondrefull repo and your contribution.

I have some questions for you and i hope that you can help me.

a) How does Token expire? Did you configure as sign once or something like that?

b) You have 2 files like 'login.ftl' and 'authorize.ftl'. Do i need these 2? How can i configure for custom login like using Angular, React, etc. ?

c) How can I configure for a Token Store and User store?

d) About the user roles, do i need to handle this in code way?

Thanks to advance!

Needed help understand project more

Could you please help understand this project better to me? Is it like a proxy app in front of an existing UUA? Or the app has UAA embedded in it?

I was looking for an app that acts like some sort of proxy in front of my existing UAA thats running on say http://localhost:8080/uaa (to start with)

Does this app talk to that external UAA for authentication etc?

[Question] Spring Boot 2 and Spring Security 5

Hi,

Very interesting project and POC, and would like to know if you intend to migrate in Spring Security 5 and/or Spring boot 2.

I saw lot of projects exemple for Spring boot 2 / Spring Security 5 with "direct" integration in the App (with Oauth2 new formLogin), but not with a front zuul and Microservices behind.

This would be great :)

dear kakawait,special thanks

dear kakawait,special thanks
from your post ,i benefit more,but now i have two problem to resolve
first ,i use ui gateway to offer one point endpoint services ,at the same time ,the backends service machine can't be access by the Internet, when users open the browser the ui server route to the sso system,when login success,the sso server redirect to the ui gateway ,the ui gateway according to the session id get user info from redis ,now the requirements is according to the userID, the ui gateway route to different pc get ui pages.
the first problem is how i get zuul route config info from database
the second is how ui gateway according to userid to route to diff pc,(because some service such as http://192.168.1.22, there not the context, at the same time can't use http Re-direct 302, ) ,dynamic add the zuul route and bypass to the diff pc get ui page

Error when get refresh token .(when token is expired)

Dear Sir:
I am trying to practice spring cloud and oauth2 by your code.
And I found a problem :
When token is expired and go to refresh token, it failed.
After trace code, i found the final http request is still htttp://service-name:port?parameter.
So it's get faild at :
OAuth2TokenRelayFilter.getAccessToken().
Can you help me to find the reason why the service name not change to real http address to
execute
Very thank you and appreciate.

Couple of small questions (or maybe suggestions)

Hi,

I am new to spring boot and spring security, and trying to build an app protected with oauth2 + zuul. I am using your wonderful sample code for learning how to build my own. So first of all, thanks a lot for putting this up!

My questions:

a) In resource server app (dummy-service), you've used EnableResourceServer. The documentation for this states

In order to use this filter you must EnableWebSecurity somewhere in your application, either in the same place as you use this annotation, or somewhere else.

So is this required in your app, and if so how does it work fine without this?

b) The controller method secret, which is protected by PreAuthorize, seems to be accessible for user without admin role, at least on my box. After doing some digging, it looks like we need to add the below to DummyServiceApplication to make it work:

@EnableGlobalMethodSecurity(prePostEnabled = true)

Is this correct?

c) As I understand, the decoding/validation of the auth token happens locally in the resource server. This would mean that resource server is not aware of any changes in user details (for eg: password), since it doesn't contact auth server after receiving token. Is this correct? I am not pointing this out as an issue (I understand it is a demo app), but just thought I'd validate my understanding.

Add data to JWT token

I like the example very much, it really helps getting startet.
One thing I was wondering is, how to add more data to the JWT token, so that it'll be available on the dummy-service Authentication Object (or anywhere there).

I tried using a TokenEnhancer and a TokenEnhancerChain, but it always gives me errors about token uris or other strange things.

Do you have an example on how to achieve this, or could you extend the code to get this goeing?

hostname different to localhost

Hi friend,

I have been using your solution and I would like to say that works perfect while it's tested over localhost. But if I move the uaa-server and the gateway-server to a different host, the /uaa/oauth/authorize changes the "location" header to "uaa-host:gateway-port/uaa/login"

Ej:
eureka-server: 192.168.0.10:8761
gateway-server: 192.168.0.11:8080
uaa-server: 192.168.0.12:9999

When gateway redirects to 192.168.0.11:8080/uaa/oauth/authorize, the "location" header of this response is change to: 192.168.0.12:8080/login

Could you tell me what I'm doing wrong?

failower + gui

Hi,
Thanks for this nice project, It gave me a lot to setup my applications. Now I'm thinking about adding next module and it should be GUI (based on angular2).

I have some questions and would like to discuss it.

  1. How to work with csrf while angular application will also need csrf token and I bet that the token generated by gateway wont work unless I somehow hack to GUI application.
  2. What about failower in this situation (with GUI). What if gateway goes down and I wold like to redirect user to second node/cluster? Is there a simple way how to do that? I was thinking about spring session support to store session to redis/jdbc, but I'm not sure if this is right direction.

Thanks in advance

Authentication Failed: Could not obtain access token

Hi @kakawait ,

I have gone through your code. It is working as expected when I run it locally.

Using spring-boot 1.5.7.RELEASE

I want to achieve a similar thing.

  • Uaa Service is stateless,so it can scale out.
    -ApiGateway is stateless.then it can scale out too.

So I add spring session and redis surport to Uaa Service and Uaa Server ,there are dependencies as fowlling.

org.springframework.boot spring-boot-starter-data-redis
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>

when I run Uaa Service greater than one.I get "Authentication failed could not obtain access token".
"InvalidGrantException: Invalid authorization code: FDHOsW"

debug logs from zuul gateway.
apigateway.txt.txt

Security concern with passed credentials

First of all, I like your example a lot. It creates nice illusion for browser users that they always interact with one single application. However, doesn't it neglect one of the key benefits (IMO) of the OAuth - avoidance of the credentials sharing? In case when the AS is fully behind proxy and all the login requests are passing the actual credentials though the proxy, won't it be a security concern? Especially when personnel access to AS and proxy is managed in a different way (i.e. proxy is treated less seriously). In case of external AS such as Facebook it becomes even more dangerous.

Am I missing something or this is known limitation? If it is limitation then probably mentioning it in README would help a lot.

Thank you!

Authentication Failed: Could not obtain access token

Hi @kakawait ,

I have gone through your code. It is working as expected when I clone your repository and deploy them in a docker container.

Using spring-boot 1.5.7.RELEASE

I want to achieve a similar thing. I have few doubts.

  1. when I hit http://localhost:8080/resource on my ZUUL gateway.
    -- it sends redirect_uri as redirect_uri=http://localhost:8080/login.
  2. I have made some changes in Authorization server for fetching user/client authentication from mongodb datastore.

grant_type=password/client_credentials are working good.
But as far as form login is concerned passes up to authorization grant approval screen. but when I approve it shows me white label error showing

"Authentication failed could not obtain access token".

and forward me to URL "http://localhost:8080/login"

which means that it is asking for /login resource from zuul gateway. which is not available in zuul gateway.

I tried to debug the cause but not able to crack it. I hereby attach my debug logs. Can u please help me out.

debug logs from zuul gateway.

gateway.txt

Try to reduce number of redirection

Today there are

api-gateway/                   302 Location: /login
api-gateway/login              302 Location: /uaa/authorize
api-gateway/uaa/authorize      302 Location: /uaa/login
api-gateway/uaa/login          FORM

3 redirects to get login form

Could not obtain access token

After upgrading it to spring boot version 1.5.9.RELEASE and spring cloud Edgware.RELEASE.
It's started failing:

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Jan 06 15:40:12 GMT 2018
There was an unexpected error (type=Unauthorized, status=401).
Authentication Failed: Could not obtain access token
2018-01-06 15:40:12.243 DEBUG 1 --- [nio-8765-exec-2] g.c.AuthorizationCodeAccessTokenProvider : Encoding and sending form: {grant_type=[authorization_code], code=[78X0xZ], redirect_uri=[http://localhost:8765/login]}
2018-01-06 15:40:12.287 DEBUG 1 --- [nio-8765-exec-2] uth2ClientAuthenticationProcessingFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
2018-01-06T15:40:12.290924600Z 
org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:107) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at com.kakawait.security.SecurityConfiguration$2.doFilterInternal(SecurityConfiguration.java:94) [classes!/:0.0.4-SNAPSHOT]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) [spring-security-web-4.2.3.RELEASE.jar!/:4.2.3.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60) [spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) [spring-boot-actuator-1.5.9.RELEASE.jar!/:1.5.9.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111-internal]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111-internal]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.23.jar!/:8.5.23]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111-internal]
Caused by: org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException: Error requesting access token.
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:145) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:209) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
... 63 common frames omitted
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://uaa-service/uaa/oauth/token": com.netflix.client.ClientException; nested exception is java.io.IOException: com.netflix.client.ClientException
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:673) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:628) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137) ~[spring-security-oauth2-2.0.14.RELEASE.jar!/:na]
... 69 common frames omitted
Caused by: java.io.IOException: com.netflix.client.ClientException
at org.springframework.cloud.netflix.ribbon.RibbonHttpRequest.executeInternal(RibbonHttpRequest.java:88) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar!/:1.4.0.RELEASE]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:659) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
... 71 common frames omitted
Caused by: com.netflix.client.ClientException: null
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:118) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at org.springframework.cloud.netflix.ribbon.RibbonHttpRequest.executeInternal(RibbonHttpRequest.java:85) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar!/:1.4.0.RELEASE]
... 73 common frames omitted
Caused by: com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused (Connection refused)
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar!/:1.19.1]
at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar!/:1.19.1]
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar!/:1.19.1]
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar!/:1.19.1]
at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570) ~[jersey-client-1.19.1.jar!/:1.19.1]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:621) ~[ribbon-httpclient-2.2.4.jar!/:2.2.4]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:527) ~[ribbon-httpclient-2.2.4.jar!/:2.2.4]
at com.netflix.niws.client.http.RestClient.execute(RestClient.java:92) ~[ribbon-httpclient-2.2.4.jar!/:2.2.4]
at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:104) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.Observable.unsafeSubscribe(Observable.java:10151) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) ~[rxjava-1.2.0.jar!/:1.2.0]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
at rx.Observable.unsafeSubscribe(Observable.java:10151) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.Observable.unsafeSubscribe(Observable.java:10151) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.Observable.subscribe(Observable.java:10247) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.Observable.subscribe(Observable.java:10214) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:444) ~[rxjava-1.2.0.jar!/:1.2.0]
at rx.observables.BlockingObservable.single(BlockingObservable.java:341) ~[rxjava-1.2.0.jar!/:1.2.0]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112) ~[ribbon-loadbalancer-2.2.4.jar!/:2.2.4]
... 74 common frames omitted
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_111-internal]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_111-internal]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_111-internal]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_111-internal]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_111-internal]
at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_111-internal]
at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:121) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) ~[httpclient-4.5.3.jar!/:4.5.3]
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.3.jar!/:4.5.3]
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173) ~[jersey-apache-client4-1.19.1.jar!/:1.19.1]
... 115 common frames omitted

Logout doesn't work

I tried to use your project. I run this application. After that I move to localhost:8765/dummy authorized and got hello world but after I logout and went to localhost:8765/dummy and I got hello world page. Is it expect?

Plans about this project?

Hi @kakawait, first of all congrats on this poc, I think it's a very useful example. I'd like to know how much more you are planning to add to this project? And what do you want to add?

If you are looking for ideas, I can suggest looking into;

  • Make it completely stateless, so each service can scale out. (Or if you're not going to abandon sessions, use session by adding Spring Session?)
  • Externalize token store (e.g. Redis)
  • Maybe federated logins? E.g. Facebook logins, I'm not necessarily suggesting Spring Social, this might be a stretch but may be more like a social auth server explained in this article

Migrating to Spring Boot 2 (2.0.0.M5)

Hi,

I'm trying to build a system with services discovery Eureka, UAA server (spring oauth2) and a Zuul as gateway. I tried to use this project as a starting points. But I'm having hard time with migrating to Spring Boot 2 as there's lots of things moved or removed. Things I'm missing so far:

  • Annotation EnableOauth2Sso
  • Intefarce UserInfoRestTemplateCustomizer
  • Bean of type ResourceServerTokenServices

// They all belongs to spring-boot-autoconfigure:1.5.7.RELEASE packages.

So I would like to ask if there's any chance you can migrate this project to Spring Boot 2.0 soon. It's also great if you can help me with those above.

Thanks in advance.

A question about using curl to access resource server?

Hi kakawait
Thanks for the awesome sample. It helps me a lot about understanding zuul with security.

Now I have one problem about the sample, could you help me? thank you very much.

a). I can get token from zuul server by using curl, that is result expected.

curl --insecure -H "Authorization: Basic $(echo -n 'acme:acmesecret' | base64)" http://localhost:8765/uaa/oauth/token -d grant_type=password -d username=user -d password=password -v
the token is
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc4NzEwMDAsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIiwiUk9MRV9VU0VSIl0sImp0aSI6IjhiODdhNTNhLWU0MmEtNDkyYS05ZWMxLTY2YWE4NmU4ZDkxOCIsImNsaWVudF9pZCI6ImFjbWUiLCJzY29wZSI6WyJvcGVuaWQiXX0.TWef-agKnnKaWDiW44ROxIseL0tVG7TXZWYTiMIV4RoKVLXXCFsFb5l24gRjxRCZAhmyB-5N6l-axLflgvKEbLrPHYJj054nEE9bi_I5mi9b2y4Z2mII6sfMkjeTAlrlyGKN-s-oU-nO2tws-vKCAYtycKmTL_xsNMH3Qmm1-4haG9SZIFq4YJkC93RvBDCGxit7jV62XrEyDj1atPWQ8QJeJmp0I8z04sVKlxulzRYpkkFMKjvWAx5lgnx5B6m-0jhXgi8g4kejUpZK9yojDTNRKMkYJuhPyTVCLsakpTl3vwOBZ5xpO-o2mgd9yn-zvjo7P1TK1rFys9xvREu2mw

b). then, when I request zuul server by the command

curl -v -H 'Content-type: application/json' -H 'Authorization: Bearer ACCESS_TOKEN' http://localhost:8765/dummy
the result always show
" X-Frame-Options: DENY
< Location: http://localhost:8765/login"

for the case, how can I access the http://localhost:8765/dummy by curl with token rather than using browser? suppose that I have a client which can send api request to zuul server.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.