diff --git a/gate-core/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleResourceServerTokenServices.groovy b/gate-core/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleResourceServerTokenServices.groovy deleted file mode 100644 index a651c2d74b..0000000000 --- a/gate-core/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleResourceServerTokenServices.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2015 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.gate.security.oauth2 - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.security.core.AuthenticationException -import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails -import org.springframework.security.oauth2.common.OAuth2AccessToken -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException -import org.springframework.security.oauth2.provider.AuthorizationRequest -import org.springframework.security.oauth2.provider.OAuth2Authentication -import org.springframework.security.oauth2.provider.OAuth2Request -import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory -import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken -import org.springframework.web.client.RestTemplate - -class GoogleResourceServerTokenServices implements ResourceServerTokenServices { - - @Autowired - RestTemplate restTemplate - - @Autowired - OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails // OAuth2 config details - - @Override - OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { - def uri = 'https://www.googleapis.com/oauth2/v3/tokeninfo' + '?access_token=' + URLEncoder.encode(accessToken, 'UTF-8') // TODO(jacobkiefer): hardcoded - Map responseMap = restTemplate.getForObject(uri, Map) - if (responseMap?.error || (responseMap.aud != oAuth2ProtectedResourceDetails.clientId)) { - return null - } - def reqFactory = new DefaultOAuth2RequestFactory() - def authzReq = new AuthorizationRequest(oAuth2ProtectedResourceDetails.clientId, oAuth2ProtectedResourceDetails.scope) - authzReq.setApproved(true) - OAuth2Request oauthzReq = reqFactory.createOAuth2Request(authzReq) - def authn = new OAuth2Authentication(oauthzReq, null) - authn.setAuthenticated(true) - return authn - } - - @Override - OAuth2AccessToken readAccessToken(String accessToken) { - throw new UnsupportedOperationException("Not supported: read access token") // TODO(jacobkiefer): is this true for Google oauth2 provider - } -} diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/config/GateConfig.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/config/GateConfig.groovy index b6c48f89ca..159c1a2b04 100644 --- a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/config/GateConfig.groovy +++ b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/config/GateConfig.groovy @@ -16,13 +16,6 @@ package com.netflix.spinnaker.gate.config -import org.springframework.http.HttpHeaders - -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import javax.servlet.* -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext import com.netflix.spectator.api.Registry import com.netflix.spinnaker.config.OkHttpClientConfiguration @@ -52,6 +45,13 @@ import retrofit.Endpoint import retrofit.RequestInterceptor import retrofit.RestAdapter import retrofit.converter.JacksonConverter + +import javax.servlet.* +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors + import static retrofit.Endpoints.newFixedEndpoint @CompileStatic diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleOAuth2AuthenticationProvider.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleOAuth2AuthenticationProvider.groovy deleted file mode 100644 index a5c9d1b4f2..0000000000 --- a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/GoogleOAuth2AuthenticationProvider.groovy +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.gate.security.oauth2 - -import org.springframework.security.authentication.AuthenticationProvider -import org.springframework.security.core.Authentication -import org.springframework.security.core.AuthenticationException -import org.springframework.security.oauth2.provider.OAuth2Authentication -import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails -import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken - -class GoogleOAuth2AuthenticationProvider implements AuthenticationProvider { - - private final ResourceServerTokenServices resourceServerTokenServices - - GoogleOAuth2AuthenticationProvider(ResourceServerTokenServices resourceServerTokenServices) { - this.resourceServerTokenServices = resourceServerTokenServices - } - - - @Override - Authentication authenticate(Authentication authentication) throws AuthenticationException { - if (!(authentication.details instanceof OAuth2AuthenticationDetails)) { - return null - } - - def oauth2AuthenticationDetails = authentication.details as OAuth2AuthenticationDetails - return resourceServerTokenServices.loadAuthentication(oauth2AuthenticationDetails.tokenValue) - } - - @Override - boolean supports(Class authentication) { - return authentication.isAssignableFrom(PreAuthenticatedAuthenticationToken) - } -} diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/NetflixOAuth2SecurityConfig.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/NetflixOAuth2SecurityConfig.groovy new file mode 100644 index 0000000000..d902e42cbf --- /dev/null +++ b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/NetflixOAuth2SecurityConfig.groovy @@ -0,0 +1,120 @@ +/* + * Copyright 2015 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.gate.security.oauth2 + +import com.netflix.spinnaker.gate.security.WebSecurityAugmentor +import com.netflix.spinnaker.security.AuthenticatedRequest +import com.netflix.spinnaker.security.User +import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.AuthenticationProvider +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.core.Authentication +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter +import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter +import org.springframework.web.client.RestOperations +import org.springframework.web.client.RestTemplate + +import javax.servlet.FilterChain +import javax.servlet.ServletException +import javax.servlet.ServletRequest +import javax.servlet.ServletResponse + +@Slf4j +@CompileStatic +@Configuration +@ConditionalOnExpression('${netflixOAuth2.enabled:false}') +class NetflixOAuth2SecurityConfig implements WebSecurityAugmentor { + @Override + void configure(HttpSecurity http, UserDetailsService userDetailsService, AuthenticationManager authenticationManager) { + def filter = new OAuth2AuthenticationProcessingFilter() { + @Override + void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + if (AuthenticatedRequest.getSpinnakerUser().isPresent()) { + // No need to attempt OAuth if user is already authenticated + chain.doFilter(req, res) + return + } + super.doFilter(req, res, chain) + } + } + + filter.setAuthenticationManager(authenticationManager) + http.addFilterBefore(filter, BasicAuthenticationFilter) + + http.csrf().disable() + } + + @Override + void configure(AuthenticationManagerBuilder authenticationManagerBuilder) { + authenticationManagerBuilder.authenticationProvider( + authenticationProvider(identityResourceServerTokenServices(restTemplate())) + ) + } + + @Bean + AuthenticationProvider authenticationProvider(IdentityResourceServerTokenServices identityResourceServerTokenServices) { + return new OAuth2AuthenticationProvider(identityResourceServerTokenServices) + } + + @Bean + IdentityResourceServerTokenServices identityResourceServerTokenServices(RestOperations restOperations) { + def defaultAccessTokenConverter = new DefaultAccessTokenConverter() + defaultAccessTokenConverter.userTokenConverter = new DefaultUserAuthenticationConverter() + + return new IdentityResourceServerTokenServices( + identityServerConfiguration(), restOperations, defaultAccessTokenConverter + ) + } + + @Bean + @ConfigurationProperties('oauth2') + IdentityResourceServerTokenServices.IdentityServerConfiguration identityServerConfiguration() { + new IdentityResourceServerTokenServices.IdentityServerConfiguration() + } + + @Bean + @ConditionalOnMissingBean(RestOperations) + RestOperations restTemplate() { + new RestTemplate() + } + + static class DefaultUserAuthenticationConverter implements UserAuthenticationConverter { + @Override + Map convertUserAuthentication(Authentication userAuthentication) { + return [:] + } + + @Override + Authentication extractAuthentication(Map map) { + def allowedAccounts = (map.scope ?: []).collect { String scope -> scope.replace("spinnaker_", "")} + def user = new User(map.client_id as String, null, null, [], allowedAccounts) + return new UsernamePasswordAuthenticationToken(user, "N/A", []) + } + } +} diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityConfig.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityConfig.groovy index bec3fe0a13..f5a8e39a5d 100644 --- a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityConfig.groovy +++ b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityConfig.groovy @@ -16,59 +16,24 @@ package com.netflix.spinnaker.gate.security.oauth2 -import com.netflix.discovery.converters.Auto import com.netflix.spinnaker.gate.security.WebSecurityAugmentor -import com.netflix.spinnaker.security.AuthenticatedRequest -import com.netflix.spinnaker.security.User import groovy.transform.CompileStatic import groovy.util.logging.Slf4j -import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.HttpMethod -import org.springframework.http.client.ClientHttpResponse import org.springframework.http.converter.FormHttpMessageConverter import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.AuthenticationProvider -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.core.Authentication -import org.springframework.security.core.AuthenticationException import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.oauth2.client.OAuth2ClientContext -import org.springframework.security.oauth2.client.OAuth2RestTemplate -import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter -import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer -import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer -import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer -import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter -import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter -import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices -import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter -import org.springframework.security.web.AuthenticationEntryPoint -import org.springframework.security.web.authentication.RememberMeServices -import org.springframework.security.web.authentication.logout.LogoutFilter -import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter -import org.springframework.web.client.DefaultResponseErrorHandler -import org.springframework.web.client.ResponseErrorHandler -import org.springframework.web.client.RestOperations import org.springframework.web.client.RestTemplate -import javax.servlet.FilterChain -import javax.servlet.ServletException -import javax.servlet.ServletRequest -import javax.servlet.ServletResponse -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse - @Slf4j @CompileStatic @Configuration @@ -77,21 +42,6 @@ class OAuth2SecurityConfig implements WebSecurityAugmentor { @Override void configure(HttpSecurity http, UserDetailsService userDetailsService, AuthenticationManager authenticationManager) { - def filter = new OAuth2AuthenticationProcessingFilter() { - @Override - void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - if (AuthenticatedRequest.getSpinnakerUser().isPresent()) { - // No need to attempt OAuth if user is already authenticated - chain.doFilter(req, res) - return - } - super.doFilter(req, res, chain) - } - } - - filter.setAuthenticationManager(authenticationManager) - http.addFilterBefore(filter, BasicAuthenticationFilter) - http.csrf().disable() http.authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() @@ -102,60 +52,9 @@ class OAuth2SecurityConfig implements WebSecurityAugmentor { @Override void configure(AuthenticationManagerBuilder authenticationManagerBuilder) { - authenticationManagerBuilder.authenticationProvider( - googleAuthenticationProvider(googleResourceServerTokenServices()) - ) + // do nothing } - // Google specific stuff - @Bean - AuthenticationProvider googleAuthenticationProvider(ResourceServerTokenServices resourceServerTokenServices) { - return new GoogleOAuth2AuthenticationProvider(resourceServerTokenServices) - } - - @Bean - ResourceServerTokenServices googleResourceServerTokenServices() { - new GoogleResourceServerTokenServices() - } - // End Google specific stuff - - // Netflix specific stuff -// @Bean -// AuthenticationProvider authenticationProvider(IdentityResourceServerTokenServices identityResourceServerTokenServices) { -// return new OAuth2AuthenticationProvider(identityResourceServerTokenServices) -// } -// -// @Bean -// IdentityResourceServerTokenServices identityResourceServerTokenServices(RestOperations restOperations) { -// def defaultAccessTokenConverter = new DefaultAccessTokenConverter() -// defaultAccessTokenConverter.userTokenConverter = new DefaultUserAuthenticationConverter() -// -// return new IdentityResourceServerTokenServices( -// identityServerConfiguration(), restOperations, defaultAccessTokenConverter -// ) -// } -// -// @Bean -// @ConfigurationProperties('oauth2') -// IdentityResourceServerTokenServices.IdentityServerConfiguration identityServerConfiguration() { -// new IdentityResourceServerTokenServices.IdentityServerConfiguration() -// } -// -// static class DefaultUserAuthenticationConverter implements UserAuthenticationConverter { -// @Override -// Map convertUserAuthentication(Authentication userAuthentication) { -// return [:] -// } -// -// @Override -// Authentication extractAuthentication(Map map) { -// def allowedAccounts = (map.scope ?: []).collect { String scope -> scope.replace("spinnaker_", "") } -// def user = new User(map.client_id as String, null, null, [], allowedAccounts) -// return new UsernamePasswordAuthenticationToken(user, "N/A", []) -// } -// } - // End Netflix specific stuff - @Bean @ConditionalOnMissingBean(RestTemplate) RestTemplate restTemplate() { @@ -164,9 +63,16 @@ class OAuth2SecurityConfig implements WebSecurityAugmentor { return template } + static class OAuth2Configuration extends AuthorizationCodeResourceDetails { + @Value('${spring.oauth2.resource.userInfoUri}') + String userInfoUri + + String userAuthorizationUri + } + @Bean @ConfigurationProperties('spring.oauth2.client') - protected OAuth2ProtectedResourceDetails resource() { - new AuthorizationCodeResourceDetails() + OAuth2Configuration resource() { + new OAuth2Configuration() } } diff --git a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityController.groovy b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityController.groovy index 7a78afa306..9c906e4956 100644 --- a/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityController.groovy +++ b/gate-web/src/main/groovy/com/netflix/spinnaker/gate/security/oauth2/OAuth2SecurityController.groovy @@ -17,12 +17,16 @@ package com.netflix.spinnaker.gate.security.oauth2 import com.netflix.spinnaker.gate.config.Headers +import com.netflix.spinnaker.gate.security.AnonymousAccountsService import com.netflix.spinnaker.gate.security.anonymous.AnonymousSecurityConfig +import com.netflix.spinnaker.gate.security.oauth2.OAuth2SecurityConfig.OAuth2Configuration import com.netflix.spinnaker.security.User import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders -import org.springframework.http.HttpStatus +import org.springframework.http.HttpMethod import org.springframework.http.ResponseEntity import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails @@ -52,10 +56,17 @@ class OAuth2SecurityController { @Autowired OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails // OAuth2 config details + @Autowired + OAuth2Configuration oAuth2Configuration + @Autowired(required = false) AnonymousSecurityConfig anonymousSecurityConfig - private String oauth2TokenValue + @Autowired + AnonymousAccountsService anonymousAccountsService + + @Value('${services.deck.baseUrl:http://localhost:9000}') + String deckUrl @RequestMapping(value = "/code") void codeCallback(HttpServletRequest request, HttpServletResponse response, @@ -69,65 +80,63 @@ class OAuth2SecurityController { throw new AccessDeniedException("OAuth2 access denied") } + // get token def form = new LinkedMultiValueMap(); form.add('code', code) - form.add('client_id', oAuth2ProtectedResourceDetails.clientId) - form.add('client_secret', oAuth2ProtectedResourceDetails.clientSecret) + form.add('client_id', oAuth2Configuration.clientId) + form.add('client_secret', oAuth2Configuration.clientSecret) form.add('redirect_uri', request.scheme + '://' + request.serverName + ':' + request.serverPort + '/oauth/code') form.add('grant_type', 'authorization_code') - ResponseEntity responseEntity = restTemplate.postForEntity(oAuth2ProtectedResourceDetails.accessTokenUri, form, DefaultOAuth2AccessToken) - - PreAuthenticatedAuthenticationToken authn = new PreAuthenticatedAuthenticationToken(new User(email: 'jacobkiefer'), responseEntity.body) + ResponseEntity tokenResponse = restTemplate.postForEntity(oAuth2Configuration.accessTokenUri, form, DefaultOAuth2AccessToken) + + // get email + HttpHeaders headers = new HttpHeaders() + headers.set('Authorization', 'Bearer ' + tokenResponse.body.value) + def infoReq = new HttpEntity(headers) + ResponseEntity userInfo = restTemplate.exchange(oAuth2Configuration.userInfoUri, HttpMethod.GET, infoReq, Map) + log.info(userInfo.body.toString()) + + // populate security context + def user = new User(userInfo.body.email, null, null, ["user"], anonymousAccountsService.getAllowedAccounts()) + // TODO(jacobkiefer): service accounts? + PreAuthenticatedAuthenticationToken authn = new PreAuthenticatedAuthenticationToken(user, null) authn.setAuthenticated(true) SecurityContextHolder.context.setAuthentication(authn) - log.info('oauth token: ' + responseEntity.body.toString()) - oauth2TokenValue = responseEntity.body.value - request - response.sendRedirect('http://localhost:9000') // TODO(jacobkiefer) don't hardcode this + + response.sendRedirect(deckUrl) } @RequestMapping(value = "/info", method = RequestMethod.GET) - ResponseEntity getUser(HttpServletRequest request, HttpServletResponse response) { + User getUser(HttpServletRequest request, HttpServletResponse response) { Object whoami = SecurityContextHolder.context.authentication.principal - if (!whoami || !(whoami instanceof User) || !(hasRequiredRole(anonymousSecurityConfig, oAuth2ProtectedResourceDetails, whoami))) { + if (!whoami || !(whoami instanceof User) || !(hasRequiredRole(anonymousSecurityConfig, oAuth2Configuration, whoami))) { - UriBuilder redirectBuilder = UriBuilder.fromUri('https://accounts.google.com/o/oauth2/v2/auth') + UriBuilder redirectBuilder = UriBuilder.fromUri(oAuth2Configuration.userAuthorizationUri) // TODO(jacobkiefer): add in state qparam? redirectBuilder.queryParam('response_type', 'code') - redirectBuilder.queryParam('client_id', oAuth2ProtectedResourceDetails.clientId) + redirectBuilder.queryParam('client_id', oAuth2Configuration.clientId) redirectBuilder.queryParam('redirect_uri', URLEncoder.encode(request.scheme + '://' + request.serverName + ':' + request.serverPort + request.contextPath + '/oauth/code', 'UTF-8')) - redirectBuilder.queryParam('scope', 'profile email') // TODO(jacobkiefer): don't hardcode this? + redirectBuilder.queryParam('scope', 'profile email') response.addHeader Headers.AUTHENTICATION_REDIRECT_HEADER_NAME, redirectBuilder.build().toString() response.sendError 401 null } else { (User) whoami - HttpHeaders respHeaders = new HttpHeaders(); - respHeaders.set(Headers.OAUTH2_TOKEN_HEADER, oauth2TokenValue) - SecurityContextHolder.clearContext() // TODO(jacobkiefer): set up a filter to clear this after each request - new ResponseEntity((User) whoami, respHeaders, HttpStatus.OK) } } static boolean hasRequiredRole(AnonymousSecurityConfig anonymousSecurityConfig, - OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails, + OAuth2Configuration oAuth2Configuration, User user) { -// if (oAuth2ProtectedResourceDetails.requiredRoles) { -// // ensure the user has at least one of the required roles (and at least one allowed account) -// return user.getRoles().find { String allowedRole -> -// samlSecurityConfigProperties.requiredRoles.contains(allowedRole) -// } && user.allowedAccounts -// } - + // TODO(jacobkiefer): requiredRoles if (anonymousSecurityConfig && user.email == anonymousSecurityConfig.defaultEmail) { // force an anonymous user to login and get a proper set of roles/allowedAccounts return false } return true -// return user.allowedAccounts } }