From b958cf40140236a9f1e09ba87450bffe24bfa4ad Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Wed, 2 Apr 2025 15:28:12 +0530 Subject: [PATCH 01/12] feat(OAuth2): Migrated OAuth2 configuration to align with Spring Security 5 Java DSL standards - Replaced the legacy `security.authn.oauth2` structure with the new `spring.security.oauth2.client` configuration. - Updated property mappings to conform to Spring Security 5's expectations. - Ensured compatibility with existing `hal config security authn oauth2 edit` commands. **Old Configuration that used get populated gate.yml:** ``` security: authn: oauth2: enabled: true client: clientId: clientSecret: accessTokenUri: https://www.googleapis.com/oauth2/v4/token userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth scope: profile email userInfoRequirements: hd: resource: userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo userInfoMapping: email: email firstName: given_name lastName: family_name provider: GOOGLE ``` **New Configuration that gets populated in gate.yml (Aligned with Spring Security 5):** ``` spring: security: oauth2: client: registration: google: client-id: client-secret: scope: profile,email 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 ``` Commands remain unchanged: ``` hal config security authn oauth2 edit --provider google --client-id some_id --client-secret some_secret --user-info-requirements hd=company.io ``` --- .../config/model/v1/security/OAuth2.java | 6 +- .../v1/profile/GateBoot154ProfileFactory.java | 2 +- .../spinnaker/v1/profile/SpringConfig.java | 95 +++++++++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java index 8183835fdc..570078da72 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java @@ -69,7 +69,7 @@ public void setProvider(Provider provider) { case GOOGLE: newClient.setAccessTokenUri("https://www.googleapis.com/oauth2/v4/token"); newClient.setUserAuthorizationUri("https://accounts.google.com/o/oauth2/v2/auth"); - newClient.setScope("profile email"); + newClient.setScope("profile,email"); newResource.setUserInfoUri("https://www.googleapis.com/oauth2/v3/userinfo"); @@ -80,7 +80,7 @@ public void setProvider(Provider provider) { case GITHUB: newClient.setAccessTokenUri("https://github.com/login/oauth/access_token"); newClient.setUserAuthorizationUri("https://github.com/login/oauth/authorize"); - newClient.setScope("user:email"); + newClient.setScope("user,email"); newResource.setUserInfoUri("https://api.github.com/user"); @@ -93,7 +93,7 @@ public void setProvider(Provider provider) { final String idcsBaseUrl = "https://idcs-${idcsTenantId}.identity.oraclecloud.com"; newClient.setAccessTokenUri(idcsBaseUrl + "/oauth2/v1/token"); newClient.setUserAuthorizationUri(idcsBaseUrl + "/oauth2/v1/authorize"); - newClient.setScope("openid urn:opc:idm:__myscopes__"); + newClient.setScope("openid,urn:opc:idm:__myscopes__"); newResource.setUserInfoUri(idcsBaseUrl + "/oauth2/v1/userinfo"); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java index d04f888ac8..cf6647856c 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java @@ -28,7 +28,7 @@ protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); if (security.getAuthn().getOauth2().isEnabled()) { - config.security.oauth2 = security.getAuthn().getOauth2(); + config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); } else if (security.getAuthn().getSaml().isEnabled()) { config.saml = new SamlConfig(security); } else if (security.getAuthn().getLdap().isEnabled()) { diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java index 3a7a4f2f94..b7ed0eeee8 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java @@ -18,7 +18,10 @@ package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile; import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2; +import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2.UserInfoMapping; import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import java.util.HashMap; +import java.util.Map; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,10 +30,102 @@ class SpringConfig { OAuth2 oauth2; + OAuth2Security security; + SpringConfig(Security security) { OAuth2 oauth2 = security.getAuthn().getOauth2(); if (oauth2.isEnabled()) { this.oauth2 = oauth2; } } + + SpringConfig(OAuth2 oauth2) { + if (oauth2.isEnabled()) { + this.security = populateOAuth2Security(oauth2); + } + } + + private OAuth2Security populateOAuth2Security(OAuth2 oauth2) { + OAuth2.Provider provider = oauth2.getProvider(); + OAuth2Security.OAuth2.Client client = new OAuth2Security.OAuth2.Client(); + + Map registration = new HashMap<>(); + Map prvdr = new HashMap<>(); + + switch (provider) { + case GOOGLE: + client.getProvider().setGoogle(prvdr); + client.getRegistration().setGoogle(registration); + break; + case GITHUB: + client.getProvider().setGithub(prvdr); + client.getRegistration().setGithub(registration); + break; + case ORACLE: + client.getProvider().setOracle(prvdr); + client.getRegistration().setOracle(registration); + break; + case AZURE: + client.getProvider().setAzure(prvdr); + client.getRegistration().setAzure(registration); + break; + case OTHER: + client.getProvider().setOther(prvdr); + client.getRegistration().setOther(registration); + break; + default: + throw new RuntimeException("Unknown provider type " + provider); + } + + registration.put("client-id", oauth2.getClient().getClientId()); + registration.put("client-secret", oauth2.getClient().getClientSecret()); + registration.put("scope", oauth2.getClient().getScope()); + registration.put( + "clientAuthenticationScheme", oauth2.getClient().getClientAuthenticationScheme()); + prvdr.put("token-uri", oauth2.getClient().getAccessTokenUri()); + prvdr.put("authorization-uri", oauth2.getClient().getUserAuthorizationUri()); + prvdr.put("user-info-uri", oauth2.getResource().getUserInfoUri()); + client.getRegistration().setUserInfoMapping(oauth2.getUserInfoMapping()); + client.getRegistration().setUserInfoRequirements(oauth2.getUserInfoRequirements()); + + OAuth2Security security = new OAuth2Security(); + security.getOauth2().setClient(client); + return security; + } + + @Data + private class OAuth2Security { + private OAuth2 oauth2 = new OAuth2(); + + @Data + private class OAuth2 { + private Client client = new Client(); + + @Data + public static class Client { + private Registration registration = new Registration(); + private Provider provider = new Provider(); + } + + @Data + public static class Registration { + private UserInfoMapping userInfoMapping; + private Map userInfoRequirements; + private Map google; + private Map github; + private Map azure; + private Map oracle; + private Map other; + } + + @Data + public static class Provider { + private Map google; + private Map github; + private Map azure; + private Map oracle; + private Map other; + } + } + } } From 2063e0d81b10857914e185f008c7194d86ddc28c Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Wed, 2 Apr 2025 21:01:23 +0530 Subject: [PATCH 02/12] feat(OAuth2): Add new GateBoot667ProfileFactory that emits the new gate config. --- .../v1/profile/GateBoot154ProfileFactory.java | 2 +- .../v1/profile/GateBoot667ProfileFactory.java | 46 +++++++++++++++++++ .../spinnaker/v1/service/GateService.java | 10 +++- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java index cf6647856c..d04f888ac8 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java @@ -28,7 +28,7 @@ protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); if (security.getAuthn().getOauth2().isEnabled()) { - config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); + config.security.oauth2 = security.getAuthn().getOauth2(); } else if (security.getAuthn().getSaml().isEnabled()) { config.saml = new SamlConfig(security); } else if (security.getAuthn().getLdap().isEnabled()) { diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java new file mode 100644 index 0000000000..3c27af9f43 --- /dev/null +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 OpsMx, 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.halyard.deploy.spinnaker.v1.profile; + +import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; +import org.springframework.stereotype.Component; + +@Component +public class GateBoot667ProfileFactory extends GateProfileFactory { + + @Override + protected GateConfig getGateConfig(ServiceSettings gate, Security security) { + GateConfig config = new GateConfig(gate, security); + + if (security.getAuthn().getOauth2().isEnabled()) { + config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); + } else if (security.getAuthn().getSaml().isEnabled()) { + config.saml = new SamlConfig(security); + } else if (security.getAuthn().getLdap().isEnabled()) { + config.ldap = new LdapConfig(security); + } else if (security.getAuthn().getIap().isEnabled()) { + config.google.iap = new IAPConfig(security); + } + + if (security.getAuthn().getX509().isEnabled()) { + config.x509 = new X509Config(security); + } + + return config; + } +} diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index 68804a514d..2bd1d6bc77 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -24,6 +24,7 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import java.nio.file.Paths; @@ -49,6 +50,8 @@ public abstract class GateService extends SpringService { @Autowired private GateBoot128ProfileFactory boot128ProfileFactory; + @Autowired private GateBoot667ProfileFactory boot667ProfileFactory; + @Override public SpinnakerArtifact getArtifact() { return SpinnakerArtifact.GATE; @@ -90,14 +93,19 @@ public List getProfiles( private GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); + log.info("the current spinnaker version is: " + version); try { if (Versions.lessThan(version, BOOT_UPGRADED_VERSION)) { return boot128ProfileFactory; } + + if (Versions.lessThan(version, "6.67.0")) { + return boot154ProfileFactory; + } } catch (IllegalArgumentException iae) { log.warn("Could not resolve Gate version, using `boot154ProfileFactory`."); } - return boot154ProfileFactory; + return boot667ProfileFactory; } public GateService() { From 29d76dd14068623ecea289d1f8e095447ff3b6ed Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 14:05:27 +0530 Subject: [PATCH 03/12] Tests: Add GateServiceTest and GateBoot667ProfileFactoryTest. Also add redirect-uri to the new config. --- halyard-deploy/halyard-deploy.gradle | 3 + .../spinnaker/v1/profile/SpringConfig.java | 2 + .../spinnaker/v1/service/GateService.java | 2 +- .../spinnaker/v1/service/GateServiceTest.java | 74 +++++++++++++++++++ .../GateBoot667ProfileFactoryTest.java | 55 ++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java create mode 100644 halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java diff --git a/halyard-deploy/halyard-deploy.gradle b/halyard-deploy/halyard-deploy.gradle index 3368309c22..1ec8885a74 100644 --- a/halyard-deploy/halyard-deploy.gradle +++ b/halyard-deploy/halyard-deploy.gradle @@ -30,6 +30,9 @@ dependencies { testImplementation 'org.spockframework:spock-core' testImplementation 'org.springframework:spring-test' + testImplementation 'org.mockito:mockito-core' + testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'net.bytebuddy:byte-buddy' testRuntimeOnly 'org.objenesis:objenesis' } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java index b7ed0eeee8..0a2463f99d 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java @@ -82,6 +82,8 @@ private OAuth2Security populateOAuth2Security(OAuth2 oauth2) { registration.put("scope", oauth2.getClient().getScope()); registration.put( "clientAuthenticationScheme", oauth2.getClient().getClientAuthenticationScheme()); + registration.put( + "redirect-uri", "\"" + oauth2.getClient().getPreEstablishedRedirectUri() + "\""); prvdr.put("token-uri", oauth2.getClient().getAccessTokenUri()); prvdr.put("authorization-uri", oauth2.getClient().getUserAuthorizationUri()); prvdr.put("user-info-uri", oauth2.getResource().getUserInfoUri()); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index 2bd1d6bc77..a11d6cd496 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -90,7 +90,7 @@ public List getProfiles( return profiles; } - private GateProfileFactory getGateProfileFactory(String deploymentName) { + GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); log.info("the current spinnaker version is: " + version); diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java new file mode 100644 index 0000000000..b21583000d --- /dev/null +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java @@ -0,0 +1,74 @@ +package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.netflix.spinnaker.halyard.deploy.services.v1.ArtifactService; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class GateServiceTest { + + private GateService gateService; + private GateBoot128ProfileFactory mockBoot128ProfileFactory; + private GateBoot154ProfileFactory mockBoot154ProfileFactory; + private GateBoot667ProfileFactory mockBoot667ProfileFactory; + private ArtifactService mockArtifactService; + + @BeforeEach + void setUp() { + gateService = mock(GateService.class, CALLS_REAL_METHODS); + mockBoot128ProfileFactory = mock(GateBoot128ProfileFactory.class); + mockBoot154ProfileFactory = mock(GateBoot154ProfileFactory.class); + mockBoot667ProfileFactory = mock(GateBoot667ProfileFactory.class); + mockArtifactService = mock(ArtifactService.class); + + gateService.setBoot128ProfileFactory(mockBoot128ProfileFactory); + gateService.setBoot154ProfileFactory(mockBoot154ProfileFactory); + gateService.setBoot667ProfileFactory(mockBoot667ProfileFactory); + when(gateService.getArtifactService()).thenReturn(mockArtifactService); + } + + @Test + void testGetGateProfileFactoryVersionLessThan070() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("0.6.9"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot128ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryVersionBetween070And667() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("6.66.0"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot154ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryVersionGreaterThan667() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("6.67.1"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot667ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryInvalidVersionUsesDefault() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("invalid-version"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot667ProfileFactory, result); + } +} diff --git a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java new file mode 100644 index 0000000000..9d961061ca --- /dev/null +++ b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java @@ -0,0 +1,55 @@ +package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.netflix.spinnaker.halyard.config.model.v1.security.ApiSecurity; +import com.netflix.spinnaker.halyard.config.model.v1.security.Authn; +import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2; +import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import com.netflix.spinnaker.halyard.config.model.v1.security.SpringSsl; +import com.netflix.spinnaker.halyard.config.model.v1.security.X509; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class GateBoot667ProfileFactoryTest { + + private GateBoot667ProfileFactory factory; + private ServiceSettings mockServiceSettings; + private Security mockSecurity; + private Authn mockAuthn; + private OAuth2 oAuth2; + + @BeforeEach + void setUp() { + factory = new GateBoot667ProfileFactory(); + oAuth2 = new OAuth2(); + oAuth2.setEnabled(true); + oAuth2.setProvider(OAuth2.Provider.GOOGLE); + mockServiceSettings = mock(ServiceSettings.class); + mockSecurity = mock(Security.class); + mockAuthn = mock(Authn.class); + ApiSecurity mockApiSecurity = mock(ApiSecurity.class); + when(mockSecurity.getAuthn()).thenReturn(mockAuthn); + when(mockAuthn.getOauth2()).thenReturn(oAuth2); + X509 x509 = new X509(); + when(mockAuthn.getX509()).thenReturn(x509); + + when(mockSecurity.getApiSecurity()).thenReturn(mockApiSecurity); + SpringSsl springSsl = mock(SpringSsl.class); + when(mockApiSecurity.getSsl()).thenReturn(springSsl); + } + + @Test + void testGetGateConfigWithOAuth2Enabled() { + GateProfileFactory.GateConfig config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull(config); + assertNotNull(config.getSpring()); + assertNotNull(config.getSpring().getSecurity()); + } +} From 47ec3c88164d1bd537a1a0483d30244289cb874e Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 14:45:15 +0530 Subject: [PATCH 04/12] feat(OAuth2): Add javadocs and comments. --- .../v1/profile/GateBoot667ProfileFactory.java | 23 +++++++++++++++++++ .../spinnaker/v1/service/GateService.java | 13 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java index 3c27af9f43..be149235b1 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java @@ -20,9 +20,32 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; import org.springframework.stereotype.Component; +/** + * Factory class for creating Gate configuration profiles for versions 6.67.0 and above. + * + *

This class extends {@link GateProfileFactory} and provides specific configurations required + * for Gate versions 6.67.0 and later. In these versions, a different set of properties is needed to + * enable OAuth2 authentication. + * + *

The factory determines the appropriate security configuration (OAuth2, SAML, LDAP, IAP, X509) + * based on the provided {@link Security} settings and constructs the {@link GateConfig} + * accordingly. + */ @Component public class GateBoot667ProfileFactory extends GateProfileFactory { + /** + * Creates a {@link GateConfig} instance based on the provided security settings. + * + *

If OAuth2 authentication is enabled, a {@link SpringConfig} is set up. If SAML + * authentication is enabled, a {@link SamlConfig} is set. If LDAP authentication is enabled, a + * {@link LdapConfig} is set. If IAP authentication is enabled, a {@link IAPConfig} is set under + * Google authentication. If X509 authentication is enabled, a {@link X509Config} is set. + * + * @param gate The service settings for Gate. + * @param security The security configuration settings. + * @return A configured {@link GateConfig} instance. + */ @Override protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index a11d6cd496..8ba19eae0d 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -90,6 +90,16 @@ public List getProfiles( return profiles; } + /** + * Retrieves the appropriate GateProfileFactory based on the given deployment's Gate version. + * + *

- If version is less than 0.7.0, returns {@code boot128ProfileFactory}. - If version is + * between 0.7.0 and 6.67.0, returns {@code boot154ProfileFactory}. - If version is greater than + * 6.67.0 or invalid, defaults to {@code boot667ProfileFactory}. + * + * @param deploymentName Name of the deployment. + * @return The appropriate {@link GateProfileFactory} instance. + */ GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); @@ -99,6 +109,9 @@ GateProfileFactory getGateProfileFactory(String deploymentName) { return boot128ProfileFactory; } + // For Gate versions 6.67.0 and above, a different set of properties is required to enable + // OAuth2. + // Therefore, boot154ProfileFactory is not used, and boot667ProfileFactory is chosen instead. if (Versions.lessThan(version, "6.67.0")) { return boot154ProfileFactory; } From 9796027f557999cb39deb515d2db4dd583a623a0 Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Wed, 2 Apr 2025 15:28:12 +0530 Subject: [PATCH 05/12] feat(OAuth2): Migrated OAuth2 configuration to align with Spring Security 5 Java DSL standards - Replaced the legacy `security.authn.oauth2` structure with the new `spring.security.oauth2.client` configuration. - Updated property mappings to conform to Spring Security 5's expectations. - Ensured compatibility with existing `hal config security authn oauth2 edit` commands. **Old Configuration that used get populated gate.yml:** ``` security: authn: oauth2: enabled: true client: clientId: clientSecret: accessTokenUri: https://www.googleapis.com/oauth2/v4/token userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth scope: profile email userInfoRequirements: hd: resource: userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo userInfoMapping: email: email firstName: given_name lastName: family_name provider: GOOGLE ``` **New Configuration that gets populated in gate.yml (Aligned with Spring Security 5):** ``` spring: security: oauth2: client: registration: google: client-id: client-secret: scope: profile,email 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 ``` Commands remain unchanged: ``` hal config security authn oauth2 edit --provider google --client-id some_id --client-secret some_secret --user-info-requirements hd=company.io ``` --- .../config/model/v1/security/OAuth2.java | 6 +- .../v1/profile/GateBoot154ProfileFactory.java | 2 +- .../spinnaker/v1/profile/SpringConfig.java | 95 +++++++++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java index 8183835fdc..570078da72 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/security/OAuth2.java @@ -69,7 +69,7 @@ public void setProvider(Provider provider) { case GOOGLE: newClient.setAccessTokenUri("https://www.googleapis.com/oauth2/v4/token"); newClient.setUserAuthorizationUri("https://accounts.google.com/o/oauth2/v2/auth"); - newClient.setScope("profile email"); + newClient.setScope("profile,email"); newResource.setUserInfoUri("https://www.googleapis.com/oauth2/v3/userinfo"); @@ -80,7 +80,7 @@ public void setProvider(Provider provider) { case GITHUB: newClient.setAccessTokenUri("https://github.com/login/oauth/access_token"); newClient.setUserAuthorizationUri("https://github.com/login/oauth/authorize"); - newClient.setScope("user:email"); + newClient.setScope("user,email"); newResource.setUserInfoUri("https://api.github.com/user"); @@ -93,7 +93,7 @@ public void setProvider(Provider provider) { final String idcsBaseUrl = "https://idcs-${idcsTenantId}.identity.oraclecloud.com"; newClient.setAccessTokenUri(idcsBaseUrl + "/oauth2/v1/token"); newClient.setUserAuthorizationUri(idcsBaseUrl + "/oauth2/v1/authorize"); - newClient.setScope("openid urn:opc:idm:__myscopes__"); + newClient.setScope("openid,urn:opc:idm:__myscopes__"); newResource.setUserInfoUri(idcsBaseUrl + "/oauth2/v1/userinfo"); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java index d04f888ac8..cf6647856c 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java @@ -28,7 +28,7 @@ protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); if (security.getAuthn().getOauth2().isEnabled()) { - config.security.oauth2 = security.getAuthn().getOauth2(); + config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); } else if (security.getAuthn().getSaml().isEnabled()) { config.saml = new SamlConfig(security); } else if (security.getAuthn().getLdap().isEnabled()) { diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java index 3a7a4f2f94..b7ed0eeee8 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java @@ -18,7 +18,10 @@ package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile; import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2; +import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2.UserInfoMapping; import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import java.util.HashMap; +import java.util.Map; import lombok.Data; import lombok.EqualsAndHashCode; @@ -27,10 +30,102 @@ class SpringConfig { OAuth2 oauth2; + OAuth2Security security; + SpringConfig(Security security) { OAuth2 oauth2 = security.getAuthn().getOauth2(); if (oauth2.isEnabled()) { this.oauth2 = oauth2; } } + + SpringConfig(OAuth2 oauth2) { + if (oauth2.isEnabled()) { + this.security = populateOAuth2Security(oauth2); + } + } + + private OAuth2Security populateOAuth2Security(OAuth2 oauth2) { + OAuth2.Provider provider = oauth2.getProvider(); + OAuth2Security.OAuth2.Client client = new OAuth2Security.OAuth2.Client(); + + Map registration = new HashMap<>(); + Map prvdr = new HashMap<>(); + + switch (provider) { + case GOOGLE: + client.getProvider().setGoogle(prvdr); + client.getRegistration().setGoogle(registration); + break; + case GITHUB: + client.getProvider().setGithub(prvdr); + client.getRegistration().setGithub(registration); + break; + case ORACLE: + client.getProvider().setOracle(prvdr); + client.getRegistration().setOracle(registration); + break; + case AZURE: + client.getProvider().setAzure(prvdr); + client.getRegistration().setAzure(registration); + break; + case OTHER: + client.getProvider().setOther(prvdr); + client.getRegistration().setOther(registration); + break; + default: + throw new RuntimeException("Unknown provider type " + provider); + } + + registration.put("client-id", oauth2.getClient().getClientId()); + registration.put("client-secret", oauth2.getClient().getClientSecret()); + registration.put("scope", oauth2.getClient().getScope()); + registration.put( + "clientAuthenticationScheme", oauth2.getClient().getClientAuthenticationScheme()); + prvdr.put("token-uri", oauth2.getClient().getAccessTokenUri()); + prvdr.put("authorization-uri", oauth2.getClient().getUserAuthorizationUri()); + prvdr.put("user-info-uri", oauth2.getResource().getUserInfoUri()); + client.getRegistration().setUserInfoMapping(oauth2.getUserInfoMapping()); + client.getRegistration().setUserInfoRequirements(oauth2.getUserInfoRequirements()); + + OAuth2Security security = new OAuth2Security(); + security.getOauth2().setClient(client); + return security; + } + + @Data + private class OAuth2Security { + private OAuth2 oauth2 = new OAuth2(); + + @Data + private class OAuth2 { + private Client client = new Client(); + + @Data + public static class Client { + private Registration registration = new Registration(); + private Provider provider = new Provider(); + } + + @Data + public static class Registration { + private UserInfoMapping userInfoMapping; + private Map userInfoRequirements; + private Map google; + private Map github; + private Map azure; + private Map oracle; + private Map other; + } + + @Data + public static class Provider { + private Map google; + private Map github; + private Map azure; + private Map oracle; + private Map other; + } + } + } } From b05f42e7c34493d7f83c5845d2d44aeafa02042e Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Wed, 2 Apr 2025 21:01:23 +0530 Subject: [PATCH 06/12] feat(OAuth2): Add new GateBoot667ProfileFactory that emits the new gate config. --- .../v1/profile/GateBoot154ProfileFactory.java | 2 +- .../v1/profile/GateBoot667ProfileFactory.java | 46 +++++++++++++++++++ .../spinnaker/v1/service/GateService.java | 10 +++- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java index cf6647856c..d04f888ac8 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot154ProfileFactory.java @@ -28,7 +28,7 @@ protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); if (security.getAuthn().getOauth2().isEnabled()) { - config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); + config.security.oauth2 = security.getAuthn().getOauth2(); } else if (security.getAuthn().getSaml().isEnabled()) { config.saml = new SamlConfig(security); } else if (security.getAuthn().getLdap().isEnabled()) { diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java new file mode 100644 index 0000000000..3c27af9f43 --- /dev/null +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 OpsMx, 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.halyard.deploy.spinnaker.v1.profile; + +import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; +import org.springframework.stereotype.Component; + +@Component +public class GateBoot667ProfileFactory extends GateProfileFactory { + + @Override + protected GateConfig getGateConfig(ServiceSettings gate, Security security) { + GateConfig config = new GateConfig(gate, security); + + if (security.getAuthn().getOauth2().isEnabled()) { + config.setSpring(new SpringConfig(security.getAuthn().getOauth2())); + } else if (security.getAuthn().getSaml().isEnabled()) { + config.saml = new SamlConfig(security); + } else if (security.getAuthn().getLdap().isEnabled()) { + config.ldap = new LdapConfig(security); + } else if (security.getAuthn().getIap().isEnabled()) { + config.google.iap = new IAPConfig(security); + } + + if (security.getAuthn().getX509().isEnabled()) { + config.x509 = new X509Config(security); + } + + return config; + } +} diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index 68804a514d..2bd1d6bc77 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -24,6 +24,7 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import java.nio.file.Paths; @@ -49,6 +50,8 @@ public abstract class GateService extends SpringService { @Autowired private GateBoot128ProfileFactory boot128ProfileFactory; + @Autowired private GateBoot667ProfileFactory boot667ProfileFactory; + @Override public SpinnakerArtifact getArtifact() { return SpinnakerArtifact.GATE; @@ -90,14 +93,19 @@ public List getProfiles( private GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); + log.info("the current spinnaker version is: " + version); try { if (Versions.lessThan(version, BOOT_UPGRADED_VERSION)) { return boot128ProfileFactory; } + + if (Versions.lessThan(version, "6.67.0")) { + return boot154ProfileFactory; + } } catch (IllegalArgumentException iae) { log.warn("Could not resolve Gate version, using `boot154ProfileFactory`."); } - return boot154ProfileFactory; + return boot667ProfileFactory; } public GateService() { From e04687b63514f835eda68f328b94b231bbcb15c5 Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 14:05:27 +0530 Subject: [PATCH 07/12] Tests: Add GateServiceTest and GateBoot667ProfileFactoryTest. Also add redirect-uri to the new config. --- halyard-deploy/halyard-deploy.gradle | 3 + .../spinnaker/v1/profile/SpringConfig.java | 2 + .../spinnaker/v1/service/GateService.java | 2 +- .../spinnaker/v1/service/GateServiceTest.java | 74 +++++++++++++++++++ .../GateBoot667ProfileFactoryTest.java | 55 ++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java create mode 100644 halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java diff --git a/halyard-deploy/halyard-deploy.gradle b/halyard-deploy/halyard-deploy.gradle index 3368309c22..1ec8885a74 100644 --- a/halyard-deploy/halyard-deploy.gradle +++ b/halyard-deploy/halyard-deploy.gradle @@ -30,6 +30,9 @@ dependencies { testImplementation 'org.spockframework:spock-core' testImplementation 'org.springframework:spring-test' + testImplementation 'org.mockito:mockito-core' + testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'net.bytebuddy:byte-buddy' testRuntimeOnly 'org.objenesis:objenesis' } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java index b7ed0eeee8..0a2463f99d 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java @@ -82,6 +82,8 @@ private OAuth2Security populateOAuth2Security(OAuth2 oauth2) { registration.put("scope", oauth2.getClient().getScope()); registration.put( "clientAuthenticationScheme", oauth2.getClient().getClientAuthenticationScheme()); + registration.put( + "redirect-uri", "\"" + oauth2.getClient().getPreEstablishedRedirectUri() + "\""); prvdr.put("token-uri", oauth2.getClient().getAccessTokenUri()); prvdr.put("authorization-uri", oauth2.getClient().getUserAuthorizationUri()); prvdr.put("user-info-uri", oauth2.getResource().getUserInfoUri()); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index 2bd1d6bc77..a11d6cd496 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -90,7 +90,7 @@ public List getProfiles( return profiles; } - private GateProfileFactory getGateProfileFactory(String deploymentName) { + GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); log.info("the current spinnaker version is: " + version); diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java new file mode 100644 index 0000000000..b21583000d --- /dev/null +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java @@ -0,0 +1,74 @@ +package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.netflix.spinnaker.halyard.deploy.services.v1.ArtifactService; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class GateServiceTest { + + private GateService gateService; + private GateBoot128ProfileFactory mockBoot128ProfileFactory; + private GateBoot154ProfileFactory mockBoot154ProfileFactory; + private GateBoot667ProfileFactory mockBoot667ProfileFactory; + private ArtifactService mockArtifactService; + + @BeforeEach + void setUp() { + gateService = mock(GateService.class, CALLS_REAL_METHODS); + mockBoot128ProfileFactory = mock(GateBoot128ProfileFactory.class); + mockBoot154ProfileFactory = mock(GateBoot154ProfileFactory.class); + mockBoot667ProfileFactory = mock(GateBoot667ProfileFactory.class); + mockArtifactService = mock(ArtifactService.class); + + gateService.setBoot128ProfileFactory(mockBoot128ProfileFactory); + gateService.setBoot154ProfileFactory(mockBoot154ProfileFactory); + gateService.setBoot667ProfileFactory(mockBoot667ProfileFactory); + when(gateService.getArtifactService()).thenReturn(mockArtifactService); + } + + @Test + void testGetGateProfileFactoryVersionLessThan070() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("0.6.9"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot128ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryVersionBetween070And667() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("6.66.0"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot154ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryVersionGreaterThan667() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("6.67.1"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot667ProfileFactory, result); + } + + @Test + void testGetGateProfileFactoryInvalidVersionUsesDefault() { + when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) + .thenReturn("invalid-version"); + + GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); + assertEquals(mockBoot667ProfileFactory, result); + } +} diff --git a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java new file mode 100644 index 0000000000..9d961061ca --- /dev/null +++ b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java @@ -0,0 +1,55 @@ +package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.netflix.spinnaker.halyard.config.model.v1.security.ApiSecurity; +import com.netflix.spinnaker.halyard.config.model.v1.security.Authn; +import com.netflix.spinnaker.halyard.config.model.v1.security.OAuth2; +import com.netflix.spinnaker.halyard.config.model.v1.security.Security; +import com.netflix.spinnaker.halyard.config.model.v1.security.SpringSsl; +import com.netflix.spinnaker.halyard.config.model.v1.security.X509; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class GateBoot667ProfileFactoryTest { + + private GateBoot667ProfileFactory factory; + private ServiceSettings mockServiceSettings; + private Security mockSecurity; + private Authn mockAuthn; + private OAuth2 oAuth2; + + @BeforeEach + void setUp() { + factory = new GateBoot667ProfileFactory(); + oAuth2 = new OAuth2(); + oAuth2.setEnabled(true); + oAuth2.setProvider(OAuth2.Provider.GOOGLE); + mockServiceSettings = mock(ServiceSettings.class); + mockSecurity = mock(Security.class); + mockAuthn = mock(Authn.class); + ApiSecurity mockApiSecurity = mock(ApiSecurity.class); + when(mockSecurity.getAuthn()).thenReturn(mockAuthn); + when(mockAuthn.getOauth2()).thenReturn(oAuth2); + X509 x509 = new X509(); + when(mockAuthn.getX509()).thenReturn(x509); + + when(mockSecurity.getApiSecurity()).thenReturn(mockApiSecurity); + SpringSsl springSsl = mock(SpringSsl.class); + when(mockApiSecurity.getSsl()).thenReturn(springSsl); + } + + @Test + void testGetGateConfigWithOAuth2Enabled() { + GateProfileFactory.GateConfig config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull(config); + assertNotNull(config.getSpring()); + assertNotNull(config.getSpring().getSecurity()); + } +} From 326bd1e21a85ce90168288b71300dca6689371c3 Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 14:45:15 +0530 Subject: [PATCH 08/12] feat(OAuth2): Add javadocs and comments. --- .../v1/profile/GateBoot667ProfileFactory.java | 23 +++++++++++++++++++ .../spinnaker/v1/service/GateService.java | 13 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java index 3c27af9f43..be149235b1 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java @@ -20,9 +20,32 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; import org.springframework.stereotype.Component; +/** + * Factory class for creating Gate configuration profiles for versions 6.67.0 and above. + * + *

This class extends {@link GateProfileFactory} and provides specific configurations required + * for Gate versions 6.67.0 and later. In these versions, a different set of properties is needed to + * enable OAuth2 authentication. + * + *

The factory determines the appropriate security configuration (OAuth2, SAML, LDAP, IAP, X509) + * based on the provided {@link Security} settings and constructs the {@link GateConfig} + * accordingly. + */ @Component public class GateBoot667ProfileFactory extends GateProfileFactory { + /** + * Creates a {@link GateConfig} instance based on the provided security settings. + * + *

If OAuth2 authentication is enabled, a {@link SpringConfig} is set up. If SAML + * authentication is enabled, a {@link SamlConfig} is set. If LDAP authentication is enabled, a + * {@link LdapConfig} is set. If IAP authentication is enabled, a {@link IAPConfig} is set under + * Google authentication. If X509 authentication is enabled, a {@link X509Config} is set. + * + * @param gate The service settings for Gate. + * @param security The security configuration settings. + * @return A configured {@link GateConfig} instance. + */ @Override protected GateConfig getGateConfig(ServiceSettings gate, Security security) { GateConfig config = new GateConfig(gate, security); diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index a11d6cd496..8ba19eae0d 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -90,6 +90,16 @@ public List getProfiles( return profiles; } + /** + * Retrieves the appropriate GateProfileFactory based on the given deployment's Gate version. + * + *

- If version is less than 0.7.0, returns {@code boot128ProfileFactory}. - If version is + * between 0.7.0 and 6.67.0, returns {@code boot154ProfileFactory}. - If version is greater than + * 6.67.0 or invalid, defaults to {@code boot667ProfileFactory}. + * + * @param deploymentName Name of the deployment. + * @return The appropriate {@link GateProfileFactory} instance. + */ GateProfileFactory getGateProfileFactory(String deploymentName) { String version = getArtifactService().getArtifactVersion(deploymentName, SpinnakerArtifact.GATE); @@ -99,6 +109,9 @@ GateProfileFactory getGateProfileFactory(String deploymentName) { return boot128ProfileFactory; } + // For Gate versions 6.67.0 and above, a different set of properties is required to enable + // OAuth2. + // Therefore, boot154ProfileFactory is not used, and boot667ProfileFactory is chosen instead. if (Versions.lessThan(version, "6.67.0")) { return boot154ProfileFactory; } From 38caab9691c04360215ddb68fee91f39101a69c7 Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 17:48:56 +0530 Subject: [PATCH 09/12] tests(OAuth2): Add license and some more tests around different providers. --- .../spinnaker/v1/profile/SpringConfig.java | 8 ++-- .../spinnaker/v1/service/GateServiceTest.java | 15 ++++++ .../GateBoot667ProfileFactoryTest.java | 46 +++++++++++++++++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java index 0a2463f99d..f0560016d1 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/SpringConfig.java @@ -91,16 +91,16 @@ private OAuth2Security populateOAuth2Security(OAuth2 oauth2) { client.getRegistration().setUserInfoRequirements(oauth2.getUserInfoRequirements()); OAuth2Security security = new OAuth2Security(); - security.getOauth2().setClient(client); + security.getOAuth2().setClient(client); return security; } @Data - private class OAuth2Security { - private OAuth2 oauth2 = new OAuth2(); + public class OAuth2Security { + private OAuth2 oAuth2 = new OAuth2(); @Data - private class OAuth2 { + public class OAuth2 { private Client client = new Client(); @Data diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java index b21583000d..6781131b2c 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 OpsMx, 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.halyard.deploy.spinnaker.v1.service; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java index 9d961061ca..0f80935fb9 100644 --- a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java +++ b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025 OpsMx, 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.halyard.deploy.spinnaker.v1.profile; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -48,8 +64,32 @@ void setUp() { @Test void testGetGateConfigWithOAuth2Enabled() { GateProfileFactory.GateConfig config = factory.getGateConfig(mockServiceSettings, mockSecurity); - assertNotNull(config); - assertNotNull(config.getSpring()); - assertNotNull(config.getSpring().getSecurity()); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGoogle()); + + oAuth2.setProvider(OAuth2.Provider.GITHUB); + config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGithub()); + + oAuth2.setProvider(OAuth2.Provider.AZURE); + config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getAzure()); + + oAuth2.setProvider(OAuth2.Provider.ORACLE); + config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getOracle()); + + oAuth2.setProvider(OAuth2.Provider.OTHER); + config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getOther()); + + oAuth2.setProvider(OAuth2.Provider.GITHUB); + config = factory.getGateConfig(mockServiceSettings, mockSecurity); + assertNotNull( + config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGithub()); } } From 9c61acd34986b1c3ac1a1e4c5a9ef5754b5d7593 Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 17:51:25 +0530 Subject: [PATCH 10/12] feat(OAuth2): Update gate version. --- .../halyard/deploy/spinnaker/v1/service/GateService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index 8ba19eae0d..c5226c1cd9 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -112,7 +112,7 @@ GateProfileFactory getGateProfileFactory(String deploymentName) { // For Gate versions 6.67.0 and above, a different set of properties is required to enable // OAuth2. // Therefore, boot154ProfileFactory is not used, and boot667ProfileFactory is chosen instead. - if (Versions.lessThan(version, "6.67.0")) { + if (Versions.lessThan(version, "6.68.0")) { return boot154ProfileFactory; } } catch (IllegalArgumentException iae) { From 1bf30235912747c85e678d9a615c84a10d2fe08c Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 18:28:12 +0530 Subject: [PATCH 11/12] feat(OAuth2): Rename classes, properties. Add comments. --- ...eSpringSecurity5OAuth2ProfileFactory.java} | 2 +- .../spinnaker/v1/service/GateService.java | 11 +++++---- .../spinnaker/v1/service/GateServiceTest.java | 8 +++---- ...ingSecurity5OAuth2ProfileFactoryTest.java} | 24 ++++++++++++------- 4 files changed, 26 insertions(+), 19 deletions(-) rename halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/{GateBoot667ProfileFactory.java => GateSpringSecurity5OAuth2ProfileFactory.java} (97%) rename halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/{GateBoot667ProfileFactoryTest.java => GateSpringSecurity5OAuth2ProfileFactoryTest.java} (89%) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactory.java similarity index 97% rename from halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java rename to halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactory.java index be149235b1..8c61707a67 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactory.java @@ -32,7 +32,7 @@ * accordingly. */ @Component -public class GateBoot667ProfileFactory extends GateProfileFactory { +public class GateSpringSecurity5OAuth2ProfileFactory extends GateProfileFactory { /** * Creates a {@link GateConfig} instance based on the provided security settings. diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index c5226c1cd9..bbef5d61e7 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -24,8 +24,8 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; -import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateSpringSecurity5OAuth2ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import java.nio.file.Paths; import java.util.Collections; @@ -50,7 +50,7 @@ public abstract class GateService extends SpringService { @Autowired private GateBoot128ProfileFactory boot128ProfileFactory; - @Autowired private GateBoot667ProfileFactory boot667ProfileFactory; + @Autowired private GateSpringSecurity5OAuth2ProfileFactory springSecurity5OAuth2ProfileFactory; @Override public SpinnakerArtifact getArtifact() { @@ -95,7 +95,7 @@ public List getProfiles( * *

- If version is less than 0.7.0, returns {@code boot128ProfileFactory}. - If version is * between 0.7.0 and 6.67.0, returns {@code boot154ProfileFactory}. - If version is greater than - * 6.67.0 or invalid, defaults to {@code boot667ProfileFactory}. + * 6.67.0 or invalid, defaults to {@code springSecurity5OAuth2ProfileFactory}. * * @param deploymentName Name of the deployment. * @return The appropriate {@link GateProfileFactory} instance. @@ -111,14 +111,15 @@ GateProfileFactory getGateProfileFactory(String deploymentName) { // For Gate versions 6.67.0 and above, a different set of properties is required to enable // OAuth2. - // Therefore, boot154ProfileFactory is not used, and boot667ProfileFactory is chosen instead. + // Therefore, boot154ProfileFactory is not used, and springSecurity5OAuth2ProfileFactory is + // chosen instead. if (Versions.lessThan(version, "6.68.0")) { return boot154ProfileFactory; } } catch (IllegalArgumentException iae) { log.warn("Could not resolve Gate version, using `boot154ProfileFactory`."); } - return boot667ProfileFactory; + return springSecurity5OAuth2ProfileFactory; } public GateService() { diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java index 6781131b2c..5177725bb4 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java @@ -24,8 +24,8 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot128ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot154ProfileFactory; -import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateBoot667ProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.GateSpringSecurity5OAuth2ProfileFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,7 +34,7 @@ class GateServiceTest { private GateService gateService; private GateBoot128ProfileFactory mockBoot128ProfileFactory; private GateBoot154ProfileFactory mockBoot154ProfileFactory; - private GateBoot667ProfileFactory mockBoot667ProfileFactory; + private GateSpringSecurity5OAuth2ProfileFactory mockBoot667ProfileFactory; private ArtifactService mockArtifactService; @BeforeEach @@ -42,12 +42,12 @@ void setUp() { gateService = mock(GateService.class, CALLS_REAL_METHODS); mockBoot128ProfileFactory = mock(GateBoot128ProfileFactory.class); mockBoot154ProfileFactory = mock(GateBoot154ProfileFactory.class); - mockBoot667ProfileFactory = mock(GateBoot667ProfileFactory.class); + mockBoot667ProfileFactory = mock(GateSpringSecurity5OAuth2ProfileFactory.class); mockArtifactService = mock(ArtifactService.class); gateService.setBoot128ProfileFactory(mockBoot128ProfileFactory); gateService.setBoot154ProfileFactory(mockBoot154ProfileFactory); - gateService.setBoot667ProfileFactory(mockBoot667ProfileFactory); + gateService.setSpringSecurity5OAuth2ProfileFactory(mockBoot667ProfileFactory); when(gateService.getArtifactService()).thenReturn(mockArtifactService); } diff --git a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactoryTest.java similarity index 89% rename from halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java rename to halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactoryTest.java index 0f80935fb9..f080304e70 100644 --- a/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateBoot667ProfileFactoryTest.java +++ b/halyard-deploy/src/test/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/GateSpringSecurity5OAuth2ProfileFactoryTest.java @@ -33,20 +33,24 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class GateBoot667ProfileFactoryTest { +class GateSpringSecurity5OAuth2ProfileFactoryTest { - private GateBoot667ProfileFactory factory; + private GateSpringSecurity5OAuth2ProfileFactory factory; private ServiceSettings mockServiceSettings; private Security mockSecurity; private Authn mockAuthn; private OAuth2 oAuth2; + /** + * Sets up the test environment before each test execution. Initializes required mock objects and + * test fixture to ensure a clean test state before each test case. + */ @BeforeEach void setUp() { - factory = new GateBoot667ProfileFactory(); + factory = new GateSpringSecurity5OAuth2ProfileFactory(); oAuth2 = new OAuth2(); oAuth2.setEnabled(true); - oAuth2.setProvider(OAuth2.Provider.GOOGLE); + mockServiceSettings = mock(ServiceSettings.class); mockSecurity = mock(Security.class); mockAuthn = mock(Authn.class); @@ -63,33 +67,35 @@ void setUp() { @Test void testGetGateConfigWithOAuth2Enabled() { + + // google + oAuth2.setProvider(OAuth2.Provider.GOOGLE); GateProfileFactory.GateConfig config = factory.getGateConfig(mockServiceSettings, mockSecurity); assertNotNull( config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGoogle()); + // github oAuth2.setProvider(OAuth2.Provider.GITHUB); config = factory.getGateConfig(mockServiceSettings, mockSecurity); assertNotNull( config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGithub()); + // azure oAuth2.setProvider(OAuth2.Provider.AZURE); config = factory.getGateConfig(mockServiceSettings, mockSecurity); assertNotNull( config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getAzure()); + // oracle oAuth2.setProvider(OAuth2.Provider.ORACLE); config = factory.getGateConfig(mockServiceSettings, mockSecurity); assertNotNull( config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getOracle()); + // other oAuth2.setProvider(OAuth2.Provider.OTHER); config = factory.getGateConfig(mockServiceSettings, mockSecurity); assertNotNull( config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getOther()); - - oAuth2.setProvider(OAuth2.Provider.GITHUB); - config = factory.getGateConfig(mockServiceSettings, mockSecurity); - assertNotNull( - config.getSpring().getSecurity().getOAuth2().getClient().getRegistration().getGithub()); } } From 19944c165d67cc4033e8de36ed59d0911c2cdbde Mon Sep 17 00:00:00 2001 From: rahul-chekuri Date: Thu, 3 Apr 2025 18:35:42 +0530 Subject: [PATCH 12/12] feat(OAuth2): Update tests/comments with gate version 6.68.0 --- .../halyard/deploy/spinnaker/v1/service/GateService.java | 4 ++-- .../halyard/deploy/spinnaker/v1/service/GateServiceTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java index bbef5d61e7..183558e7df 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateService.java @@ -94,7 +94,7 @@ public List getProfiles( * Retrieves the appropriate GateProfileFactory based on the given deployment's Gate version. * *

- If version is less than 0.7.0, returns {@code boot128ProfileFactory}. - If version is - * between 0.7.0 and 6.67.0, returns {@code boot154ProfileFactory}. - If version is greater than + * between 0.7.0 and 6.68.0, returns {@code boot154ProfileFactory}. - If version is greater than * 6.67.0 or invalid, defaults to {@code springSecurity5OAuth2ProfileFactory}. * * @param deploymentName Name of the deployment. @@ -109,7 +109,7 @@ GateProfileFactory getGateProfileFactory(String deploymentName) { return boot128ProfileFactory; } - // For Gate versions 6.67.0 and above, a different set of properties is required to enable + // For Gate versions 6.68.0 and above, a different set of properties is required to enable // OAuth2. // Therefore, boot154ProfileFactory is not used, and springSecurity5OAuth2ProfileFactory is // chosen instead. diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java index 5177725bb4..71e3679b10 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/GateServiceTest.java @@ -63,7 +63,7 @@ void testGetGateProfileFactoryVersionLessThan070() { @Test void testGetGateProfileFactoryVersionBetween070And667() { when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) - .thenReturn("6.66.0"); + .thenReturn("6.67.0"); GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); assertEquals(mockBoot154ProfileFactory, result); @@ -72,7 +72,7 @@ void testGetGateProfileFactoryVersionBetween070And667() { @Test void testGetGateProfileFactoryVersionGreaterThan667() { when(mockArtifactService.getArtifactVersion("test-deployment", SpinnakerArtifact.GATE)) - .thenReturn("6.67.1"); + .thenReturn("6.68.1"); GateProfileFactory result = gateService.getGateProfileFactory("test-deployment"); assertEquals(mockBoot667ProfileFactory, result);