diff --git a/simple/src/main/java/com/example/AadAccessTokenProvider.java b/simple/src/main/java/com/example/AadAccessTokenProvider.java new file mode 100644 index 0000000..e7545a8 --- /dev/null +++ b/simple/src/main/java/com/example/AadAccessTokenProvider.java @@ -0,0 +1,22 @@ +package com.example; + +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException; +import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; +import org.springframework.security.oauth2.client.token.AccessTokenRequest; +import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider; +import org.springframework.security.oauth2.common.OAuth2AccessToken; + +/** + * Created by bmill on 3/22/2016. + */ +public class AadAccessTokenProvider extends AuthorizationCodeAccessTokenProvider + +{ + @Override + public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request) throws UserRedirectRequiredException, UserApprovalRequiredException, AccessDeniedException, OAuth2AccessDeniedException { + return super.obtainAccessToken(details, request); + } +} diff --git a/simple/src/main/java/com/example/AadOauth2RequestAuthenticator.java b/simple/src/main/java/com/example/AadOauth2RequestAuthenticator.java new file mode 100644 index 0000000..e67624c --- /dev/null +++ b/simple/src/main/java/com/example/AadOauth2RequestAuthenticator.java @@ -0,0 +1,67 @@ +package com.example; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.security.oauth2.client.DefaultOAuth2RequestAuthenticator; +import org.springframework.security.oauth2.client.OAuth2ClientContext; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.web.client.RestTemplate; + +public class AadOauth2RequestAuthenticator extends DefaultOAuth2RequestAuthenticator { + + @Autowired + private RestTemplate restTemplate; + + @Override + public void authenticate(OAuth2ProtectedResourceDetails resource, + OAuth2ClientContext clientContext, + ClientHttpRequest request) + { + // this call is too late. the token call was already made + super.authenticate(resource, clientContext, request); + } + + class AccessRequest { + private final String client_id; + private final String client_secret; + private final String code; + private final String grant_type; + private final String redirect_uri; + private final String resource; + + public AccessRequest(String client_id, String client_secret, String code, String grant_type, String redirect_uri, String resource) { + this.client_id = client_id; + this.client_secret = client_secret; + this.code = code; + this.grant_type = grant_type; + this.redirect_uri = redirect_uri; + this.resource = resource; + } + + + public String getClient_id() { + return client_id; + } + + public String getClient_secret() { + return client_secret; + } + + public String getCode() { + return code; + } + + public String getGrant_type() { + return grant_type; + } + + public String getRedirect_uri() { + return redirect_uri; + } + + public String getResource() { + return resource; + } + } + +} diff --git a/simple/src/main/java/com/example/AadUserInfoRestTemplateCustomizer.java b/simple/src/main/java/com/example/AadUserInfoRestTemplateCustomizer.java new file mode 100644 index 0000000..2189ada --- /dev/null +++ b/simple/src/main/java/com/example/AadUserInfoRestTemplateCustomizer.java @@ -0,0 +1,39 @@ +package com.example; + +import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; + +import java.io.IOException; +import java.util.Arrays; + +public class AadUserInfoRestTemplateCustomizer implements UserInfoRestTemplateCustomizer { + @Override + public void customize(OAuth2RestTemplate oAuth2RestTemplate) { + + // no help here + // by the time the authenticator is called, the token has already been retrieved + oAuth2RestTemplate.setAuthenticator(new AadOauth2RequestAuthenticator()); + + // Attempt 1: Use my own token provider, but it never gets called... + oAuth2RestTemplate.setAccessTokenProvider(new AadAccessTokenProvider()); + + // Even better, if only OAuth2RestTemplate provided a getter for AccessTokenProvider, I could add interceptors and or enhancers + //AuthorizationCodeAccessTokenProvider provider = oAuth2RestTemplate.getAccessTokenProvider(); + + ClientHttpRequestInterceptor myInterceptor = new ClientHttpRequestInterceptor() { + @Override + public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + + ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes); + return response; + + } + }; + + oAuth2RestTemplate.setInterceptors(Arrays.asList(myInterceptor)); + } +} diff --git a/simple/src/main/java/com/example/AzureRequestEnhancer.java b/simple/src/main/java/com/example/AzureRequestEnhancer.java new file mode 100644 index 0000000..df01ba1 --- /dev/null +++ b/simple/src/main/java/com/example/AzureRequestEnhancer.java @@ -0,0 +1,23 @@ +package com.example; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.client.token.AccessTokenRequest; +import org.springframework.security.oauth2.client.token.RequestEnhancer; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; + +@Component +public class AzureRequestEnhancer implements RequestEnhancer { + @Value("${aad.resource:null}") + private String aadResource; + + @Override + public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource, MultiValueMap form, HttpHeaders headers) { + if (!StringUtils.isEmpty(resource)) { + form.set("resource", aadResource); + } + } +} \ No newline at end of file diff --git a/simple/src/main/java/com/example/AzureRequestEnhancerCustomizer.java b/simple/src/main/java/com/example/AzureRequestEnhancerCustomizer.java new file mode 100644 index 0000000..bef3204 --- /dev/null +++ b/simple/src/main/java/com/example/AzureRequestEnhancerCustomizer.java @@ -0,0 +1,33 @@ +package com.example; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.client.token.AccessTokenRequest; +import org.springframework.security.oauth2.client.token.RequestEnhancer; +import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider; +import org.springframework.stereotype.Component; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; + +@Component +public class AzureRequestEnhancerCustomizer { + @Autowired + private OAuth2RestTemplate userInfoRestTemplate; + + @Autowired + private AzureRequestEnhancer azureRequestEnhancer; + + @PostConstruct + public void testWiring() { + AuthorizationCodeAccessTokenProvider authorizationCodeAccessTokenProvider = new AuthorizationCodeAccessTokenProvider(); + authorizationCodeAccessTokenProvider.setTokenRequestEnhancer(azureRequestEnhancer); + userInfoRestTemplate.setAccessTokenProvider(authorizationCodeAccessTokenProvider); + } +} + + diff --git a/simple/src/main/java/com/example/SocialApplication.java b/simple/src/main/java/com/example/SocialApplication.java index 695c6e0..276a5b5 100644 --- a/simple/src/main/java/com/example/SocialApplication.java +++ b/simple/src/main/java/com/example/SocialApplication.java @@ -18,6 +18,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoRestTemplateCustomizer; +import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableOAuth2Sso @@ -27,4 +29,8 @@ public static void main(String[] args) { SpringApplication.run(SocialApplication.class, args); } + @Bean + public UserInfoRestTemplateCustomizer aadUserInfoRestTemplate() { + return new AadUserInfoRestTemplateCustomizer(); + } } diff --git a/simple/src/main/resources/application.yml b/simple/src/main/resources/application.yml index bbbf439..92c2a50 100644 --- a/simple/src/main/resources/application.yml +++ b/simple/src/main/resources/application.yml @@ -1,17 +1,22 @@ +aad: + resource: https://graph.windows.net + security: oauth2: client: - clientId: 233668646673605 - clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d - accessTokenUri: https://graph.facebook.com/oauth/access_token - userAuthorizationUri: https://www.facebook.com/dialog/oauth - tokenName: oauth_token - authenticationScheme: query + clientId: [clientid] + clientSecret: [clientsecret] + accessTokenUri: https://login.microsoftonline.com/[tenant-id]/oauth2/token + userAuthorizationUri: https://login.microsoftonline.com/[tenant-id]/oauth2/authorize clientAuthenticationScheme: form + scope: openid resource: - userInfoUri: https://graph.facebook.com/me + userInfoUri: https://graph.windows.net/me?api-version=1.6 spring: resources: chain: enabled: true - \ No newline at end of file + +logging: + level: + org.springframework.security: DEBUG \ No newline at end of file