Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main-2.x' into main-2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
liga-oz committed Jan 16, 2024
2 parents ba7c424 + 77a335d commit fdabc30
Show file tree
Hide file tree
Showing 19 changed files with 215 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.sap.cloud.environment.servicebinding.api.ServiceBinding;
import com.sap.cloud.environment.servicebinding.api.TypedMapView;
import com.sap.cloud.security.config.k8s.K8sConstants;
import com.sap.cloud.security.config.cf.CFConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -13,6 +13,7 @@
import static com.sap.cloud.security.config.Service.IAS;
import static com.sap.cloud.security.config.cf.CFConstants.IAS.DOMAIN;
import static com.sap.cloud.security.config.cf.CFConstants.IAS.DOMAINS;
import static com.sap.cloud.security.config.cf.CFConstants.NAME;
import static com.sap.cloud.security.config.cf.CFConstants.SERVICE_PLAN;

public class ServiceBindingMapper {
Expand All @@ -29,7 +30,7 @@ public class ServiceBindingMapper {
public static OAuth2ServiceConfigurationBuilder mapToOAuth2ServiceConfigurationBuilder(ServiceBinding b) {
if (!b.getServiceName().isPresent()) {
LOGGER.error("Ignores Service Binding with name {} as service name is not provided.", b.getName());
return null; // as of now, method is never called when service name isn't given
return null;
}

final Service service = Service.from(b.getServiceName().get());
Expand All @@ -43,7 +44,8 @@ public static OAuth2ServiceConfigurationBuilder mapToOAuth2ServiceConfigurationB
TypedMapView credentials = TypedMapView.ofCredentials(b);
OAuth2ServiceConfigurationBuilder builder = OAuth2ServiceConfigurationBuilder.forService(service)
.withProperties(credentials.getEntries(String.class))
.withProperty(SERVICE_PLAN, b.getServicePlan().orElse(K8sConstants.Plan.APPLICATION.name()).toUpperCase());
.withProperty(NAME, b.getName().orElse(""))
.withProperty(SERVICE_PLAN, b.getServicePlan().orElse(CFConstants.Plan.APPLICATION.toString()));

if (IAS.equals(service)) {
parseDomains(builder, credentials);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.sap.cloud.security.config.cf.CFConstants.SERVICE_PLAN;
Expand All @@ -30,7 +29,7 @@ public class K8sEnvironment implements Environment {
private static final Logger LOGGER = LoggerFactory.getLogger(K8sEnvironment.class);

static K8sEnvironment instance;
private final Map<Service, Map<String, OAuth2ServiceConfiguration>> serviceConfigurations;
private final Map<Service, EnumMap<K8sConstants.Plan, OAuth2ServiceConfiguration>> serviceConfigurations;

private K8sEnvironment() {
serviceConfigurations = new EnumMap<>(Service.class);
Expand All @@ -53,20 +52,32 @@ public Type getType() {
private void loadAll() {
List<ServiceBinding> serviceBindings = DefaultServiceBindingAccessor.getInstance().getServiceBindings();

Map<String, OAuth2ServiceConfiguration> xsuaaPlans = serviceBindings.stream()
EnumMap<Plan, OAuth2ServiceConfiguration> xsuaaPlans = serviceBindings.stream()
.filter(b -> Service.XSUAA.equals(Service.from(b.getServiceName().orElse(null))))
.map(ServiceBindingMapper::mapToOAuth2ServiceConfigurationBuilder)
.filter(Objects::nonNull)
.map(OAuth2ServiceConfigurationBuilder::build)
.collect(Collectors.toMap(config -> config.getProperty(SERVICE_PLAN),
Function.identity()));
Map<String, OAuth2ServiceConfiguration> identityPlans = serviceBindings.stream()
.collect(Collectors.toMap(config -> Plan.from(config.getProperty(SERVICE_PLAN)),
config -> config,
(l, r) -> {
LOGGER.info("Found 2 service configurations of '{}' plan, taking the last one",
r.getProperty(SERVICE_PLAN));
return r;
},
() -> new EnumMap<>(Plan.class)));
EnumMap<Plan, OAuth2ServiceConfiguration> identityPlans = serviceBindings.stream()
.filter(b -> Service.IAS.equals(Service.from(b.getServiceName().orElse(null))))
.map(ServiceBindingMapper::mapToOAuth2ServiceConfigurationBuilder)
.filter(Objects::nonNull)
.map(OAuth2ServiceConfigurationBuilder::build)
.collect(Collectors.toMap(config -> config.getProperty(SERVICE_PLAN),
Function.identity()));
.collect(Collectors.toMap(config -> Plan.from(config.getProperty(SERVICE_PLAN)),
config -> config,
(l, r) -> {
LOGGER.info("Found 2 service configurations of '{}' plan, taking the last one",
r.getProperty(SERVICE_PLAN));
return r;
},
() -> new EnumMap<>(Plan.class)));
serviceConfigurations.put(Service.XSUAA, xsuaaPlans);
serviceConfigurations.put(Service.IAS, identityPlans);
}
Expand All @@ -79,27 +90,25 @@ private void loadAll() {
* @return the map of all found configurations or empty map, in case there are
* no service bindings.
*/
Map<String, OAuth2ServiceConfiguration> getServiceConfigurationsOf(Service service) {
return serviceConfigurations.getOrDefault(service, Collections.emptyMap());
EnumMap<Plan, OAuth2ServiceConfiguration> getServiceConfigurationsOf(Service service) {
return serviceConfigurations.getOrDefault(service, new EnumMap<>(Plan.class));
}

@Nullable
@Override
public OAuth2ServiceConfiguration getXsuaaConfiguration() {
return Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.APPLICATION.name()))
.orElse(Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.BROKER.name()))
.orElse(Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.SPACE.name()))
.orElse(Optional
.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.DEFAULT.name()))
.orElse(null))));
return Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.APPLICATION))
.orElse(Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.BROKER))
.orElse(Optional.ofNullable(getServiceConfigurationsOf(Service.XSUAA).get(Plan.SPACE))
.orElse(getServiceConfigurationsOf(Service.XSUAA).get(Plan.DEFAULT))));

}

@Nullable
@Override
public OAuth2ServiceConfiguration getXsuaaConfigurationForTokenExchange() {
if (getNumberOfXsuaaConfigurations() > 1) {
return getServiceConfigurationsOf(Service.XSUAA).get(Plan.BROKER.name());
return getServiceConfigurationsOf(Service.XSUAA).get(Plan.BROKER);
}
return getXsuaaConfiguration();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
import com.sap.cloud.security.config.OAuth2ServiceConfiguration;
import com.sap.cloud.security.config.Service;
import com.sap.cloud.security.config.cf.CFConstants;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.nio.file.Paths;
import java.util.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.sap.cloud.environment.servicebinding.SapServiceOperatorLayeredServiceBindingAccessor.DEFAULT_PARSING_STRATEGIES;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;

class K8sEnvironmentTest {

Expand All @@ -45,11 +47,11 @@ void afterEach() {
void getXsuaaConfiguration() {
cut = K8sEnvironment.getInstance();
OAuth2ServiceConfiguration config = cut.getXsuaaConfiguration();
assertEquals("xsuaaClientId", config.getClientId());
assertEquals("uaadomain.org", config.getProperty(CFConstants.XSUAA.UAA_DOMAIN));
assertEquals("xsuaa-basic", config.getProperty(CFConstants.XSUAA.APP_ID));
assertEquals("xsuaaSecret", config.getClientSecret());
assertEquals("https://auth.sap.com", config.getUrl().toString());
assertEquals("xsuaaClientId2", config.getClientId());
assertEquals("uaadomain2.org", config.getProperty(CFConstants.XSUAA.UAA_DOMAIN));
assertEquals("xsuaa-basic2", config.getProperty(CFConstants.XSUAA.APP_ID));
assertEquals("xsuaaSecret2", config.getClientSecret());
assertEquals("https://auth2.sap.com", config.getUrl().toString());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xsuaaClientId2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xsuaaSecret2
1 change: 1 addition & 0 deletions env/src/test/resources/k8s/xsuaa/xsuaa-application2/plan
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
application
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uaadomain2.org
1 change: 1 addition & 0 deletions env/src/test/resources/k8s/xsuaa/xsuaa-application2/url
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://auth2.sap.com
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
xsuaa-basic2
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class CFConstants {
public static final String VCAP_APPLICATION = "VCAP_APPLICATION";
public static final String CREDENTIALS = "credentials";
public static final String SERVICE_PLAN = "plan";
public static final String NAME = "name";
public static final String URL = "url";
public static final String CLIENT_ID = "clientid";
public static final String CLIENT_SECRET = "clientsecret";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
*/
package com.sap.cloud.security.config.k8s;

import com.sap.cloud.security.config.cf.CFConstants;

/**
* Constants that simplifies access to service configuration properties in the
* Kubernetes environment.
Expand All @@ -24,9 +22,13 @@ private K8sConstants() {
public enum Plan {
DEFAULT, BROKER, APPLICATION, SPACE, APIACCESS, SYSTEM;

public static CFConstants.Plan from(String planAsString) {
return CFConstants.Plan.valueOf(planAsString.toUpperCase());
public static K8sConstants.Plan from(String planAsString) {
if (planAsString == null) {
return APPLICATION;
}
return K8sConstants.Plan.valueOf(planAsString.toUpperCase());
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ public class IdentityServicesPropertySourceFactory implements PropertySourceFact
.asList(new String[] { "clientid", "clientsecret", "identityzoneid",
"sburl", "tenantid", "tenantmode", "uaadomain", "url", "verificationkey", "xsappname",
"certificate",
"key", "credential-type", "certurl" }));
"key", "credential-type", "certurl", "name", "plan" }));

private static final List<String> IAS_ATTRIBUTES = Collections.unmodifiableList(Arrays
.asList(new String[] { "clientid", "clientsecret", "domains", "url" }));
.asList(new String[] { "clientid", "clientsecret", "domains", "url", "name", "plan" }));

private Properties properties;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,22 @@ public Service getService() {
return getConfiguration().getService();
}

public void setName(String name) {
builder.withProperty(CFConstants.NAME, name);
}

public String getName() {
return getConfiguration().getProperty(CFConstants.NAME);
}

public void setPlan(String plan) {
builder.withProperty(CFConstants.SERVICE_PLAN, plan);
}

public String getPlan() {
return getConfiguration().getProperty(CFConstants.SERVICE_PLAN);
}

@Override
public boolean isLegacyMode() {
return getConfiguration().isLegacyMode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,66 @@
*/
package com.sap.cloud.security.spring.config;

import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Tests that the {@link IdentityServicesPropertySourceFactory} puts 2 XSUAA
* service instances with plan 'application' into the Spring properties without
* creating a hole at index 1. For backward-compatibility, the order of the
* service instance must be as follows: Index 0: Configuration accessible via
* Environment#getXsuaaConfiguration (Application) Index 1: Configuration
* accessible via Environment#getXsuaaConfigurationForTokenExchange (Broker) if
* exists, otherwise next XSUAA configuration Index 2+: Remaining XSUAA
* configurations In addition, tests that the IAS service instance from the
* environment is correctly added as well.
*/
@SpringBootTest(classes = { BrokerHoleTestConfigurationFromFile.class })
class IdentityServicesPropertySourceFactoryBrokerNoHoleTest {

@Autowired
BrokerHoleTestConfigurationFromFile configuration;

@Test
void testInjectedPropertyValues_fourXsuaaBindings() {
void testInjectedPropertyValues() {
/* Index 0 */
assertEquals("client-id2", configuration.xsuaaClientId0);
assertEquals("client-secret2", configuration.xsuaaClientSecret0);
assertEquals("http://domain.xsuaadomain", configuration.xsuaaUrl0);
assertEquals("xsuaadomain", configuration.xsuaaDomain0);
assertEquals("xsappname2", configuration.xsuaaAppName0);
assertEquals("xsuaaInstance0", configuration.xsuaaName0);
assertEquals("application", configuration.xsuaaPlan0);
assertEquals("", configuration.unknown0);

/* Index 1 */
assertEquals("client-id", configuration.xsuaaClientId1);
assertEquals("client-secret", configuration.xsuaaClientSecret1);
assertEquals("xsappname", configuration.xsuaaAppName1);
assertEquals("xsuaaInstance1", configuration.xsuaaName1);
assertEquals("application", configuration.xsuaaPlan1);

/* Index 2 */
assertEquals("none", configuration.xsuaaClientId2);
assertEquals("none", configuration.xsuaaClientSecret2);

/* IAS */
assertEquals("client-id-ias", configuration.identityClientId);
assertEquals("client-secret-ias", configuration.identityClientSecret);
assertTrue(configuration.identityDomains.contains("iasdomain"));
assertTrue(configuration.identityDomains.contains("iasdomain.com"));
assertEquals(2, configuration.identityDomains.size());
assertEquals("identityInstance0", configuration.identityName0);
assertEquals("broker", configuration.identityPlan);
}
}

Expand All @@ -57,7 +74,7 @@ void testInjectedPropertyValues_fourXsuaaBindings() {
class BrokerHoleTestConfigurationFromFile {

/* Index 0 */

@Value("${sap.security.services.xsuaa[0].url:}")
public String xsuaaUrl0;

Expand All @@ -73,12 +90,17 @@ class BrokerHoleTestConfigurationFromFile {
@Value("${sap.security.services.xsuaa[0].xsappname:}")
public String xsuaaAppName0;

@Value("${sap.security.services.xsuaa[0].name:}")
public String xsuaaName0;

@Value("${sap.security.services.xsuaa[0].plan:}")
public String xsuaaPlan0;

@Value("${sap.security.services.xsuaa[0].unknown:}")
public String unknown0;


/* Index 1 */

@Value("${sap.security.services.xsuaa[1].clientid:none}")
public String xsuaaClientId1;

Expand All @@ -87,19 +109,23 @@ class BrokerHoleTestConfigurationFromFile {

@Value("${sap.security.services.xsuaa[1].xsappname}")
public String xsuaaAppName1;


@Value("${sap.security.services.xsuaa[1].name:}")
public String xsuaaName1;

@Value("${sap.security.services.xsuaa[1].plan:}")
public String xsuaaPlan1;

/* Index 2 */

@Value("${sap.security.services.xsuaa[2].clientid:none}")
public String xsuaaClientId2;

@Value("${sap.security.services.xsuaa[2].clientsecret:none}")
public String xsuaaClientSecret2;



/* IAS */

@Value("${sap.security.services.identity.clientid:}")
public String identityClientId;

Expand All @@ -108,4 +134,10 @@ class BrokerHoleTestConfigurationFromFile {

@Value("${sap.security.services.identity.domains:}")
public List<String> identityDomains;

@Value("${sap.security.services.identity.name:}")
public String identityName0;

@Value("${sap.security.services.identity.plan:}")
public String identityPlan;
}
Loading

0 comments on commit fdabc30

Please sign in to comment.