kakawait / uaa-behind-zuul-sample

Spring AuthorizationServer load balanced behind Zuul
322 stars 156 forks source link

Add data to JWT token #4

Closed menostos closed 7 years ago

menostos commented 8 years ago

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?

kakawait commented 8 years ago

Sorry I never tried... do you have more information about error ?

menostos commented 8 years ago

First I tried to extend the JwtAccessTokenConvert and add some additional information. I use a dummy-service method to return the OAuth2Authentication as JSON to debug the information.

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            OAuth2AccessToken token = super.enhance(accessToken, authentication);
            token.getAdditionalInformation().put("additional", "some-information");
            return token;
        }
    };
    KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray())
            .getKeyPair("test");
    converter.setKeyPair(keyPair);
    return converter;
}

This does nothing, it doesn't show up in the authentication object.

The i tried adding a JwtTokenStore, a TokenEnhancerChain (with a Custom Enhancer and the default JwtAccessTokenConverter) and DefaultTokenServices.

Authenticating doesn't seem to be an issue, but the dummy-service gives the following error:

java.lang.IllegalArgumentException: URI is not absolute
    at java.net.URI.toURL(URI.java:1088) ~[na:1.8.0_60]
    at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:137) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:77) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:616) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:589) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAuthorizationCode(AuthorizationCodeAccessTokenProvider.java:156) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:207) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at com.kakawait.security.SecurityConfiguration$2.doFilterInternal(SecurityConfiguration.java:90) ~[classes/:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:107) ~[spring-boot-actuator-1.4.0.M3.jar:1.4.0.M3]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.0.BUILD-20160606.171235-430.jar:4.3.0.BUILD-SNAPSHOT]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) ~[tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.33.jar:8.0.33]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
kakawait commented 8 years ago

I will try to check asap because I need such customization. But I will be on vacancies soon, so maybe need more time that you can expect.

menostos commented 8 years ago

Thank you very much. I think this is a great way to spare some backend requests, if it's already contained withing the jwt token.

kakawait commented 8 years ago

@menostos I draft a working implementation (on my side)

{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ1c2VyIiwic2NvcGUiOlsib3BlbmlkIl0sImFkZGl0aW9uYWwiOiJzb21lLWluZm9ybWF0aW9uIiwiZXhwIjoxNDY1Njk1Mjk2LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIiwiUk9MRV9VU0VSIl0sImp0aSI6ImE2NjNiNjlmLWQzNDAtNGQ4MS05MWNkLTdhNWZhODEyM2QyZSIsImNsaWVudF9pZCI6ImFjbWUifQ.hxQ1iGeJc_sXnHXTAjgHnrx3XD8XZPRSYppLGDQavLn5leqwZvG_pUC3YgLdZGZOy2qOiUGkFRy5JPrdKUjCjYoMJSfaJnmhSYROx3Li2x4kmUQHHWVxPVJkEHk6rv-C140G6zqSWRa4ow5wroTq5myfiwMokzsh6jvcWSPBUxVBJrVrRuC0zrAtB7rHapjHeIlcYtwU83AOCE-6zAl9nMj6iIC2TJ3YQcEjjZCGj5TZwJIqti-eKXKNGRZBSCrR6DB_HY0ehh_5HOKV8Jj83HhOd1_ecDzGz_y5Rj8gooKrOEL8qHnsgslTcIjHWV-Fb0qHnFdGf0hchDI4D9ZrtQ","token_type":"bearer","expires_in":43199,"scope":"openid","user_name":"user","additional":"some-information","authorities":["ROLE_ADMIN","ROLE_USER"],"jti":"a663b69f-d340-4d81-91cd-7a5fa8123d2e"}

Check https://github.com/kakawait/uaa-behind-zuul-sample/commit/865d2c4adfdad5ef9fa941bf7d0343235167ffd8

I have to polish it before merging

menostos commented 8 years ago

Works for me, i was successfully able to extract the information passed in from the uua-service.

kakawait commented 8 years ago

@menostos glad to hear that is working for you.

kakawait commented 7 years ago

I will not merge back in master but you can checkout feature/custom-jwt branch.