Skip to content
This repository was archived by the owner on Dec 20, 2025. It is now read-only.

Commit fe51eda

Browse files
committed
feature(OAuth2): Remove deprecated OAuth2 annotation. Instead Use Java DSL way of OAuth2
Oauth configuration properties are changed for new java way of dsl. Old Config Properties: security: authn: oauth2: enabled: true client: clientId: <client-id> clientSecret: <client-secret> accessTokenUri: https://www.googleapis.com/oauth2/v4/token userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth scope: profile email userInfoRequirements: hd: <domain> resource: userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo userInfoMapping: email: email firstName: given_name lastName: family_name provider: GOOGLE New Config Properties: Google: spring: security: oauth2: client: registration: google: client-id: <client-id> client-secret: <client-secret> authorization-grant-type: authorization_code redirect-uri: "https://<your-domain>/login/oauth2/code/google" scope: profile,email,openid client-name: google provider: google: authorization-uri: https://accounts.google.com/o/oauth2/auth token-uri: https://oauth2.googleapis.com/token user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo user-name-attribute: sub Github: spring: security: oauth2: client: registration: userInfoMapping: email: email firstName: '' lastName: name username: login github: client-id: <client-id> client-secret: <client-secret> authorization-grant-type: authorization_code redirect-uri: "https://<your-domain>/login/oauth2/code/github" scope: user,email client-name: github provider: github: authorization-uri: https://github.com/login/oauth/authorize token-uri: https://github.com/login/oauth/access_token user-info-uri: https://api.github.com/user user-name-attribute: login
1 parent ed77027 commit fe51eda

15 files changed

Lines changed: 678 additions & 665 deletions

gate-oauth2/gate-oauth2.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ dependencies {
77
implementation "io.spinnaker.kork:kork-retrofit"
88
implementation "io.spinnaker.kork:kork-security"
99
implementation "org.apache.groovy:groovy-json"
10-
implementation "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure"
10+
implementation "org.springframework.boot:spring-boot-starter-oauth2-client"
1111
implementation "org.springframework.session:spring-session-core"
1212

1313
testImplementation "com.squareup.retrofit2:retrofit-mock"

gate-oauth2/src/main/java/com/netflix/spinnaker/gate/security/oauth2/ExternalAuthTokenFilter.java

Lines changed: 0 additions & 71 deletions
This file was deleted.

gate-oauth2/src/main/java/com/netflix/spinnaker/gate/security/oauth2/OAuth2SsoConfig.java

Lines changed: 20 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -15,110 +15,54 @@
1515
*/
1616
package com.netflix.spinnaker.gate.security.oauth2;
1717

18-
import com.netflix.spectator.api.Registry;
19-
import com.netflix.spinnaker.fiat.shared.FiatClientConfigurationProperties;
2018
import com.netflix.spinnaker.gate.config.AuthConfig;
21-
import com.netflix.spinnaker.gate.security.AllowedAccountsSupport;
2219
import com.netflix.spinnaker.gate.security.SpinnakerAuthConfig;
23-
import com.netflix.spinnaker.gate.security.oauth2.provider.SpinnakerProviderTokenServices;
24-
import com.netflix.spinnaker.gate.services.CredentialsService;
25-
import com.netflix.spinnaker.gate.services.PermissionService;
26-
import com.netflix.spinnaker.gate.services.internal.Front50Service;
2720
import java.util.HashMap;
28-
import java.util.Optional;
29-
import javax.servlet.http.HttpServletRequest;
30-
import javax.servlet.http.HttpServletResponse;
3121
import lombok.Data;
32-
import lombok.extern.slf4j.Slf4j;
3322
import org.springframework.beans.factory.annotation.Autowired;
34-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
35-
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
36-
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoProperties;
37-
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
38-
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
3923
import org.springframework.boot.context.properties.ConfigurationProperties;
40-
import org.springframework.boot.context.properties.EnableConfigurationProperties;
41-
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Conditional;
4225
import org.springframework.context.annotation.Configuration;
43-
import org.springframework.context.annotation.Primary;
4426
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4527
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
4628
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
47-
import org.springframework.security.core.AuthenticationException;
48-
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
49-
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
50-
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
51-
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
52-
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
53-
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
29+
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
5430
import org.springframework.session.web.http.DefaultCookieSerializer;
5531
import org.springframework.stereotype.Component;
5632

5733
@Configuration
58-
@SpinnakerAuthConfig
5934
@EnableWebSecurity
60-
@EnableOAuth2Sso
61-
@EnableConfigurationProperties
62-
@ConditionalOnProperty(name = "security.oauth2.client.clientId")
63-
@Slf4j
35+
@SpinnakerAuthConfig
36+
@Conditional(OAuthConfigEnabled.class)
6437
public class OAuth2SsoConfig extends WebSecurityConfigurerAdapter {
6538

6639
@Autowired private AuthConfig authConfig;
67-
@Autowired private ExternalAuthTokenFilter externalAuthTokenFilter;
68-
@Autowired private ExternalSslAwareEntryPoint entryPoint;
40+
@Autowired private SpinnakerOAuth2UserInfoService customOAuth2UserService;
41+
@Autowired private SpinnakerOIDCUserInfoService oidcUserInfoService;
6942
@Autowired private DefaultCookieSerializer defaultCookieSerializer;
70-
71-
@Primary
72-
@Bean
73-
@ConditionalOnProperty(
74-
prefix = "security.oauth2.resource.spinnaker-user-info-token-services",
75-
name = "enabled",
76-
havingValue = "true",
77-
matchIfMissing = true)
78-
public ResourceServerTokenServices spinnakerUserInfoTokenServices(
79-
ResourceServerProperties sso,
80-
UserInfoTokenServices userInfoTokenServices,
81-
CredentialsService credentialsService,
82-
OAuth2SsoConfig.UserInfoMapping userInfoMapping,
83-
OAuth2SsoConfig.UserInfoRequirements userInfoRequirements,
84-
PermissionService permissionService,
85-
Front50Service front50Service,
86-
Optional<SpinnakerProviderTokenServices> providerTokenServices,
87-
AllowedAccountsSupport allowedAccountsSupport,
88-
FiatClientConfigurationProperties fiatClientConfigurationProperties,
89-
Registry registry) {
90-
return new SpinnakerUserInfoTokenServices(
91-
sso,
92-
userInfoTokenServices,
93-
credentialsService,
94-
userInfoMapping,
95-
userInfoRequirements,
96-
permissionService,
97-
front50Service,
98-
providerTokenServices,
99-
allowedAccountsSupport,
100-
fiatClientConfigurationProperties,
101-
registry);
102-
}
43+
@Autowired private ClientRegistrationRepository clientRegistrationRepository;
10344

10445
@Override
105-
public void configure(HttpSecurity http) throws Exception {
46+
public void configure(HttpSecurity httpSecurity) throws Exception {
10647
defaultCookieSerializer.setSameSite(null);
107-
authConfig.configure(http);
108-
109-
http.exceptionHandling().authenticationEntryPoint(entryPoint);
110-
http.addFilterBefore(
111-
new BasicAuthenticationFilter(authenticationManager()),
112-
UsernamePasswordAuthenticationFilter.class);
113-
http.addFilterBefore(externalAuthTokenFilter, AbstractPreAuthenticatedProcessingFilter.class);
48+
authConfig.configure(httpSecurity);
49+
httpSecurity
50+
.authorizeRequests(auth -> auth.anyRequest().authenticated())
51+
.oauth2Login(
52+
oauth2 ->
53+
oauth2.userInfoEndpoint(
54+
userInfo ->
55+
userInfo
56+
.userService(customOAuth2UserService)
57+
.oidcUserService(oidcUserInfoService)));
11458
}
11559

11660
/**
11761
* Use this class to specify how to map fields from the userInfoUri response to what's expected to
11862
* be in the User.
11963
*/
12064
@Component
121-
@ConfigurationProperties("security.oauth2.user-info-mapping")
65+
@ConfigurationProperties("spring.security.oauth2.client.registration.user-info-mapping")
12266
@Data
12367
public static class UserInfoMapping {
12468
private String email = "email";
@@ -130,32 +74,6 @@ public static class UserInfoMapping {
13074
}
13175

13276
@Component
133-
@ConfigurationProperties("security.oauth2.user-info-requirements")
77+
@ConfigurationProperties("spring.security.oauth2.client.registration.user-info-requirements")
13478
public static class UserInfoRequirements extends HashMap<String, String> {}
135-
136-
/**
137-
* This class exists to change the login redirect (to /login) to the same URL as the
138-
* preEstablishedRedirectUri, if set, where the SSL is terminated outside of this server.
139-
*/
140-
@Component
141-
@ConditionalOnProperty(name = "security.oauth2.client.client-id")
142-
public static class ExternalSslAwareEntryPoint extends LoginUrlAuthenticationEntryPoint {
143-
@Autowired private AuthorizationCodeResourceDetails details;
144-
145-
@Autowired
146-
public ExternalSslAwareEntryPoint(OAuth2SsoProperties sso) {
147-
super(sso.getLoginPath());
148-
}
149-
150-
@Override
151-
protected String determineUrlToUseForThisRequest(
152-
HttpServletRequest request,
153-
HttpServletResponse response,
154-
AuthenticationException exception) {
155-
final String uri = details.getPreEstablishedRedirectUri();
156-
return uri != null
157-
? uri
158-
: super.determineUrlToUseForThisRequest(request, response, exception);
159-
}
160-
}
16179
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2025 OpsMx, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.gate.security.oauth2;
18+
19+
import java.util.regex.Pattern;
20+
import lombok.extern.slf4j.Slf4j;
21+
import org.springframework.context.annotation.Condition;
22+
import org.springframework.context.annotation.ConditionContext;
23+
import org.springframework.core.env.ConfigurableEnvironment;
24+
import org.springframework.core.env.EnumerablePropertySource;
25+
import org.springframework.core.env.PropertySource;
26+
import org.springframework.core.type.AnnotatedTypeMetadata;
27+
28+
@Slf4j
29+
public class OAuthConfigEnabled implements Condition {
30+
private static final String SPRING_SECURITY_OAUTH2_REGEX =
31+
"spring\\.security\\.oauth2\\.client\\.registration\\..*\\.client-id";
32+
private static final Pattern SPRING_SECURITY_OAUTH2_PATTERN =
33+
Pattern.compile(SPRING_SECURITY_OAUTH2_REGEX);
34+
35+
@Override
36+
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
37+
if (!(context.getEnvironment() instanceof ConfigurableEnvironment)) {
38+
return false;
39+
}
40+
41+
ConfigurableEnvironment env = (ConfigurableEnvironment) context.getEnvironment();
42+
43+
for (PropertySource<?> propertySource : env.getPropertySources()) {
44+
if (propertySource instanceof EnumerablePropertySource) {
45+
for (String propertyName :
46+
((EnumerablePropertySource<?>) propertySource).getPropertyNames()) {
47+
if (SPRING_SECURITY_OAUTH2_PATTERN.matcher(propertyName).matches()) {
48+
return true; // If any property matches, load the configuration
49+
}
50+
}
51+
}
52+
}
53+
return false; // Skip configuration if no matching properties found
54+
}
55+
}

0 commit comments

Comments
 (0)