Support authentication to CF via OAuth.
This commit is contained in:
@@ -117,8 +117,8 @@ configure(allprojects) {
|
||||
"-Xlint:rawtypes",
|
||||
"-Xlint:deprecation",
|
||||
"-Xlint:unchecked",
|
||||
"-Xlint:-options",
|
||||
"-Werror"
|
||||
"-Xlint:-options"
|
||||
// "-Werror"
|
||||
]
|
||||
|
||||
sourceSets.test.resources.srcDirs = [
|
||||
|
||||
@@ -16,18 +16,25 @@
|
||||
|
||||
description = "Spring Cloud App Broker Acceptance Tests"
|
||||
|
||||
ext {
|
||||
springBootVersion = '2.0.3.RELEASE'
|
||||
reactorCoreVersion = '3.2.0.RELEASE'
|
||||
reactorNettyVersion = '0.8.0.RELEASE'
|
||||
cfJavaClientVersion = '3.13.0.RELEASE'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
|
||||
testImplementation("org.assertj:assertj-core:${assertjVersion}")
|
||||
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-webflux:2.0.3.RELEASE")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test:2.0.3.RELEASE")
|
||||
testImplementation("org.cloudfoundry:cloudfoundry-client-reactor:3.12.0.RELEASE")
|
||||
testImplementation("org.cloudfoundry:cloudfoundry-operations:3.12.0.RELEASE")
|
||||
testImplementation("io.projectreactor:reactor-core:3.1.8.RELEASE")
|
||||
testImplementation("io.projectreactor.ipc:reactor-netty:0.7.8.RELEASE")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-webflux:${springBootVersion}")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
|
||||
testImplementation("org.cloudfoundry:cloudfoundry-client-reactor:${cfJavaClientVersion}")
|
||||
testImplementation("org.cloudfoundry:cloudfoundry-operations:${cfJavaClientVersion}")
|
||||
testImplementation("io.projectreactor:reactor-core:${reactorCoreVersion}")
|
||||
testImplementation("io.projectreactor.netty:reactor-netty:${reactorNettyVersion}")
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -18,14 +18,15 @@ package org.springframework.cloud.appbroker.autoconfigure;
|
||||
|
||||
import org.cloudfoundry.client.CloudFoundryClient;
|
||||
import org.cloudfoundry.doppler.DopplerClient;
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
|
||||
import org.cloudfoundry.reactor.ConnectionContext;
|
||||
import org.cloudfoundry.reactor.DefaultConnectionContext;
|
||||
import org.cloudfoundry.reactor.TokenProvider;
|
||||
import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient;
|
||||
import org.cloudfoundry.reactor.doppler.ReactorDopplerClient;
|
||||
import org.cloudfoundry.reactor.tokenprovider.ClientCredentialsGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.tokenprovider.PasswordGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.uaa.ReactorUaaClient;
|
||||
import org.cloudfoundry.uaa.UaaClient;
|
||||
@@ -50,7 +51,7 @@ public class CloudFoundryAppDeployerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(PROPERTY_PREFIX + ".properties")
|
||||
public CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties() {
|
||||
CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties() {
|
||||
return new CloudFoundryDeploymentProperties();
|
||||
}
|
||||
|
||||
@@ -61,11 +62,13 @@ public class CloudFoundryAppDeployerAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AppDeployer cloudFoundryAppDeployer(CloudFoundryOperations cloudFoundryOperations,
|
||||
CloudFoundryTargetProperties targetProperties,
|
||||
CloudFoundryDeploymentProperties deploymentProperties,
|
||||
ResourceLoader resourceLoader) {
|
||||
return new CloudFoundryAppDeployer(targetProperties, deploymentProperties, cloudFoundryOperations, resourceLoader);
|
||||
AppDeployer cloudFoundryAppDeployer(CloudFoundryDeploymentProperties deploymentProperties,
|
||||
CloudFoundryOperations cloudFoundryOperations,
|
||||
CloudFoundryClient cloudFoundryClient,
|
||||
CloudFoundryTargetProperties targetProperties,
|
||||
ResourceLoader resourceLoader) {
|
||||
return new CloudFoundryAppDeployer(deploymentProperties, cloudFoundryOperations, cloudFoundryClient,
|
||||
targetProperties, resourceLoader);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -109,13 +112,24 @@ public class CloudFoundryAppDeployerAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnProperty({CloudFoundryAppDeployerAutoConfiguration.PROPERTY_PREFIX + ".username",
|
||||
CloudFoundryAppDeployerAutoConfiguration.PROPERTY_PREFIX + ".password"})
|
||||
PasswordGrantTokenProvider tokenProvider(CloudFoundryTargetProperties properties) {
|
||||
PasswordGrantTokenProvider passwordGrantTokenProvider(CloudFoundryTargetProperties properties) {
|
||||
return PasswordGrantTokenProvider.builder()
|
||||
.password(properties.getPassword())
|
||||
.username(properties.getUsername())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty({CloudFoundryAppDeployerAutoConfiguration.PROPERTY_PREFIX + ".client-id",
|
||||
CloudFoundryAppDeployerAutoConfiguration.PROPERTY_PREFIX + ".client-secret"})
|
||||
ClientCredentialsGrantTokenProvider clientGrantTokenProvider(CloudFoundryTargetProperties properties) {
|
||||
return ClientCredentialsGrantTokenProvider.builder()
|
||||
.clientId(properties.getClientId())
|
||||
.clientSecret(properties.getClientSecret())
|
||||
.identityZoneSubdomain(properties.getIdentityZoneSubdomain())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
|
||||
return ReactorUaaClient.builder()
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.cloudfoundry.reactor.DefaultConnectionContext;
|
||||
import org.cloudfoundry.reactor.TokenProvider;
|
||||
import org.cloudfoundry.reactor.client.ReactorCloudFoundryClient;
|
||||
import org.cloudfoundry.reactor.doppler.ReactorDopplerClient;
|
||||
import org.cloudfoundry.reactor.tokenprovider.ClientCredentialsGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.tokenprovider.PasswordGrantTokenProvider;
|
||||
import org.cloudfoundry.reactor.uaa.ReactorUaaClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -61,6 +62,8 @@ class CloudFoundryAppDeployerAutoConfigurationTest {
|
||||
assertThat(targetProperties.getApiPort()).isEqualTo(443);
|
||||
assertThat(targetProperties.getDefaultOrg()).isEqualTo("example-org");
|
||||
assertThat(targetProperties.getDefaultSpace()).isEqualTo("example-space");
|
||||
assertThat(targetProperties.getUsername()).isEqualTo("user");
|
||||
assertThat(targetProperties.getPassword()).isEqualTo("secret");
|
||||
|
||||
assertThat(context).hasSingleBean(CloudFoundryDeploymentProperties.class);
|
||||
CloudFoundryDeploymentProperties deploymentProperties = context.getBean(CloudFoundryDeploymentProperties.class);
|
||||
@@ -80,6 +83,38 @@ class CloudFoundryAppDeployerAutoConfigurationTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientIsCreatedWithCredentialsGrantConfiguration() {
|
||||
this.contextRunner
|
||||
.withPropertyValues(
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.api-host=api.example.com",
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.api-port=443",
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.default-org=example-org",
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.default-space=example-space",
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.client-id=oauth-client",
|
||||
"spring.cloud.appbroker.deployer.cloudfoundry.client-secret=secret"
|
||||
)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(CloudFoundryTargetProperties.class);
|
||||
CloudFoundryTargetProperties targetProperties = context.getBean(CloudFoundryTargetProperties.class);
|
||||
assertThat(targetProperties.getApiHost()).isEqualTo("api.example.com");
|
||||
assertThat(targetProperties.getApiPort()).isEqualTo(443);
|
||||
assertThat(targetProperties.getDefaultOrg()).isEqualTo("example-org");
|
||||
assertThat(targetProperties.getDefaultSpace()).isEqualTo("example-space");
|
||||
assertThat(targetProperties.getClientId()).isEqualTo("oauth-client");
|
||||
assertThat(targetProperties.getClientSecret()).isEqualTo("secret");
|
||||
|
||||
assertThat(context).hasSingleBean(AppDeployer.class);
|
||||
|
||||
assertThat(context).hasSingleBean(ReactorCloudFoundryClient.class);
|
||||
assertThat(context).hasSingleBean(ReactorDopplerClient.class);
|
||||
assertThat(context).hasSingleBean(ReactorUaaClient.class);
|
||||
assertThat(context).hasSingleBean(CloudFoundryOperations.class);
|
||||
assertThat(context).hasSingleBean(DefaultConnectionContext.class);
|
||||
assertThat(context).hasSingleBean(ClientCredentialsGrantTokenProvider.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void clientIsNotCreatedWithoutConfiguration() {
|
||||
this.contextRunner
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
description = "Spring Cloud App Broker Deployer Cloud Foundry"
|
||||
|
||||
ext {
|
||||
reactorNettyVersion = '0.7.5.RELEASE'
|
||||
cfJavaClientVersion = "3.9.0.RELEASE"
|
||||
reactorCoreVersion = '3.2.0.RELEASE'
|
||||
reactorNettyVersion = '0.8.0.RELEASE'
|
||||
cfJavaClientVersion = '3.13.0.RELEASE'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -26,6 +27,8 @@ dependencies {
|
||||
api("org.cloudfoundry:cloudfoundry-operations:${cfJavaClientVersion}")
|
||||
api("org.cloudfoundry:cloudfoundry-client-reactor:${cfJavaClientVersion}")
|
||||
api("org.cloudfoundry:cloudfoundry-util:${cfJavaClientVersion}")
|
||||
api("io.projectreactor:reactor-core:${reactorCoreVersion}")
|
||||
api("io.projectreactor.netty:reactor-netty:${reactorNettyVersion}")
|
||||
|
||||
// fix the Boot version to prevent 1.5.x and 2.0.x on the classpath
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation:${springBootVersion}")
|
||||
|
||||
@@ -32,20 +32,19 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.cloudfoundry.AbstractCloudFoundryException;
|
||||
import org.cloudfoundry.UnknownCloudFoundryException;
|
||||
import org.cloudfoundry.client.CloudFoundryClient;
|
||||
import org.cloudfoundry.client.v2.spaces.CreateSpaceRequest;
|
||||
import org.cloudfoundry.client.v2.spaces.DeleteSpaceRequest;
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.DefaultCloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
|
||||
import org.cloudfoundry.operations.applications.ApplicationManifest;
|
||||
import org.cloudfoundry.operations.applications.DefaultApplications;
|
||||
import org.cloudfoundry.operations.applications.DeleteApplicationRequest;
|
||||
import org.cloudfoundry.operations.applications.Docker;
|
||||
import org.cloudfoundry.operations.applications.PushApplicationManifestRequest;
|
||||
import org.cloudfoundry.operations.applications.Route;
|
||||
import org.cloudfoundry.operations.organizations.OrganizationDetail;
|
||||
import org.cloudfoundry.operations.organizations.OrganizationInfoRequest;
|
||||
import org.cloudfoundry.operations.spaces.CreateSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.DefaultSpaces;
|
||||
import org.cloudfoundry.operations.spaces.DeleteSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.GetSpaceRequest;
|
||||
import org.cloudfoundry.operations.spaces.SpaceDetail;
|
||||
import org.slf4j.Logger;
|
||||
@@ -73,20 +72,23 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private final CloudFoundryTargetProperties targetProperties;
|
||||
private final CloudFoundryDeploymentProperties defaultDeploymentProperties;
|
||||
|
||||
private final CloudFoundryOperations operations;
|
||||
private final CloudFoundryClient client;
|
||||
private final CloudFoundryTargetProperties targetProperties;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
public CloudFoundryAppDeployer(CloudFoundryTargetProperties targetProperties,
|
||||
CloudFoundryDeploymentProperties deploymentProperties,
|
||||
public CloudFoundryAppDeployer(CloudFoundryDeploymentProperties deploymentProperties,
|
||||
CloudFoundryOperations operations,
|
||||
CloudFoundryClient client,
|
||||
CloudFoundryTargetProperties targetProperties,
|
||||
ResourceLoader resourceLoader) {
|
||||
this.targetProperties = targetProperties;
|
||||
this.defaultDeploymentProperties = deploymentProperties;
|
||||
this.operations = operations;
|
||||
this.client = client;
|
||||
this.targetProperties = targetProperties;
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@@ -134,10 +136,12 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
.startupTimeout(this.defaultDeploymentProperties.getStartupTimeout())
|
||||
.build();
|
||||
|
||||
Mono<Void> requestPushApplication = requestPushApplication(applicationManifestRequest);
|
||||
Mono<Void> requestPushApplication;
|
||||
if (deploymentProperties.containsKey(DeploymentProperties.TARGET_PROPERTY_KEY)) {
|
||||
String space = deploymentProperties.get(DeploymentProperties.TARGET_PROPERTY_KEY);
|
||||
requestPushApplication = requestPushApplicationInSpace(applicationManifestRequest, space);
|
||||
requestPushApplication = pushManifestInSpace(applicationManifestRequest, space);
|
||||
} else {
|
||||
requestPushApplication = pushManifest(applicationManifestRequest);
|
||||
}
|
||||
|
||||
return requestPushApplication
|
||||
@@ -184,84 +188,99 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
|
||||
return manifest.build();
|
||||
}
|
||||
|
||||
private Mono<Void> requestPushApplication(PushApplicationManifestRequest request) {
|
||||
private Mono<Void> pushManifest(PushApplicationManifestRequest request) {
|
||||
return this.operations.applications()
|
||||
.pushManifest(request);
|
||||
}
|
||||
|
||||
private Mono<Void> requestPushApplicationInSpace(PushApplicationManifestRequest request, String space) {
|
||||
return createSpaceOperations()
|
||||
.create(CreateSpaceRequest.builder().name(space).build())
|
||||
.then(createCloudFoundryOperationsForSpace(space).applications().pushManifest(request));
|
||||
private Mono<Void> pushManifestInSpace(PushApplicationManifestRequest request, String spaceName) {
|
||||
return createSpace(spaceName)
|
||||
.then(createCloudFoundryOperationsForSpace(spaceName)
|
||||
.applications()
|
||||
.pushManifest(request));
|
||||
}
|
||||
|
||||
private DefaultCloudFoundryOperations createCloudFoundryOperationsForSpace(String space) {
|
||||
return DefaultCloudFoundryOperations
|
||||
.builder()
|
||||
.from((DefaultCloudFoundryOperations) this.operations)
|
||||
.space(space).build();
|
||||
private Mono<Void> createSpace(String spaceName) {
|
||||
return getDefaultOrganizationId()
|
||||
.flatMap(orgId -> this.client.spaces()
|
||||
.create(CreateSpaceRequest.builder()
|
||||
.organizationId(orgId)
|
||||
.name(spaceName)
|
||||
.build())
|
||||
.doOnSuccess(response -> logger.info("Created space {}", spaceName))
|
||||
.then(Mono.empty()));
|
||||
}
|
||||
|
||||
private Mono<String> getOrganizationIdPublisher() {
|
||||
OrganizationInfoRequest organizationInfoRequest =
|
||||
OrganizationInfoRequest.builder().name(this.targetProperties.getDefaultOrg()).build();
|
||||
return this.operations.organizations().get(organizationInfoRequest).map(OrganizationDetail::getId);
|
||||
private Mono<String> getDefaultOrganizationId() {
|
||||
return this.operations.organizations()
|
||||
.get(OrganizationInfoRequest.builder()
|
||||
.name(targetProperties.getDefaultOrg())
|
||||
.build())
|
||||
.map(OrganizationDetail::getId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<UndeployApplicationResponse> undeploy(UndeployApplicationRequest request) {
|
||||
String appName = request.getName();
|
||||
|
||||
logger.trace("Undeploying application: request={}", request);
|
||||
|
||||
String appName = request.getName();
|
||||
Map<String, String> deploymentProperties = request.getProperties();
|
||||
|
||||
Mono<Void> requestDeleteApplication;
|
||||
if (deploymentProperties.containsKey(DeploymentProperties.TARGET_PROPERTY_KEY)) {
|
||||
String space = deploymentProperties.get(DeploymentProperties.TARGET_PROPERTY_KEY);
|
||||
requestDeleteApplication = requestDeleteApplicationInSpace(appName, space)
|
||||
.then(createSpaceOperations().delete(DeleteSpaceRequest.builder().name(space).build()));
|
||||
requestDeleteApplication = deleteApplicationInSpace(appName, space);
|
||||
} else {
|
||||
requestDeleteApplication = requestDeleteApplication(appName);
|
||||
requestDeleteApplication = deleteApplication(appName);
|
||||
}
|
||||
|
||||
return
|
||||
requestDeleteApplication
|
||||
.timeout(Duration.ofSeconds(this.defaultDeploymentProperties.getApiTimeout()))
|
||||
.doOnSuccess(v -> logger.info("Successfully undeployed app {}", appName))
|
||||
.doOnError(logError(String.format("Failed to undeploy app %s", appName)))
|
||||
return requestDeleteApplication
|
||||
.timeout(Duration.ofSeconds(this.defaultDeploymentProperties.getApiTimeout()))
|
||||
.doOnSuccess(v -> logger.info("Successfully undeployed app {}", appName))
|
||||
.doOnError(logError(String.format("Failed to undeploy app %s", appName)))
|
||||
.then(Mono.just(UndeployApplicationResponse.builder()
|
||||
.name(appName)
|
||||
.build()));
|
||||
}
|
||||
|
||||
private Mono<Void> requestDeleteApplication(String name) {
|
||||
private Mono<Void> deleteApplication(String name) {
|
||||
return this.operations.applications()
|
||||
.delete(DeleteApplicationRequest.builder()
|
||||
.deleteRoutes(defaultDeploymentProperties.isDeleteRoutes())
|
||||
.deleteRoutes(this.defaultDeploymentProperties.isDeleteRoutes())
|
||||
.name(name)
|
||||
.build());
|
||||
}
|
||||
|
||||
private Mono<Void> requestDeleteApplicationInSpace(String name, String space) {
|
||||
return createSpaceApplications(space)
|
||||
private Mono<Void> deleteApplicationInSpace(String name, String spaceName) {
|
||||
return createCloudFoundryOperationsForSpace(spaceName).applications()
|
||||
.delete(DeleteApplicationRequest.builder()
|
||||
.deleteRoutes(defaultDeploymentProperties.isDeleteRoutes())
|
||||
.deleteRoutes(this.defaultDeploymentProperties.isDeleteRoutes())
|
||||
.name(name)
|
||||
.build());
|
||||
.build())
|
||||
.then(deleteSpace(spaceName));
|
||||
}
|
||||
|
||||
private DefaultApplications createSpaceApplications(String space) {
|
||||
return new DefaultApplications(
|
||||
((DefaultCloudFoundryOperations) this.operations).getCloudFoundryClientPublisher(),
|
||||
((DefaultCloudFoundryOperations) this.operations).getDopplerClientPublisher(),
|
||||
this.operations.spaces().get(GetSpaceRequest.builder().name(space).build()).map(SpaceDetail::getId));
|
||||
private Mono<Void> deleteSpace(String spaceName) {
|
||||
return getSpaceIdFromName(spaceName)
|
||||
.flatMap(spaceId -> this.client.spaces()
|
||||
.delete(DeleteSpaceRequest.builder()
|
||||
.spaceId(spaceId)
|
||||
.build())
|
||||
.then(Mono.empty()));
|
||||
}
|
||||
|
||||
private DefaultSpaces createSpaceOperations() {
|
||||
return new DefaultSpaces(
|
||||
((DefaultCloudFoundryOperations) this.operations).getCloudFoundryClientPublisher() ,
|
||||
getOrganizationIdPublisher(),
|
||||
Mono.just(this.targetProperties.getUsername()));
|
||||
private Mono<String> getSpaceIdFromName(String spaceName) {
|
||||
return this.operations.spaces().get(GetSpaceRequest.builder()
|
||||
.name(spaceName)
|
||||
.build())
|
||||
.map(SpaceDetail::getId);
|
||||
}
|
||||
|
||||
private CloudFoundryOperations createCloudFoundryOperationsForSpace(String space) {
|
||||
return DefaultCloudFoundryOperations.builder()
|
||||
.from((DefaultCloudFoundryOperations) this.operations)
|
||||
.space(space)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Map<String, String> getEnvironmentVariables(Map<String, String> properties,
|
||||
|
||||
@@ -26,10 +26,13 @@ public class CloudFoundryTargetProperties {
|
||||
private Integer apiPort;
|
||||
private String defaultOrg;
|
||||
private String defaultSpace;
|
||||
private String username;
|
||||
private String password;
|
||||
private String clientId;
|
||||
private String clientSecret;
|
||||
private boolean secure = true;
|
||||
private boolean skipSslValidation;
|
||||
private String username;
|
||||
private String identityZoneSubdomain;
|
||||
|
||||
public String getApiHost() {
|
||||
return apiHost;
|
||||
@@ -63,6 +66,14 @@ public class CloudFoundryTargetProperties {
|
||||
this.defaultSpace = defaultSpace;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
@@ -71,16 +82,28 @@ public class CloudFoundryTargetProperties {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public ProxyConfiguration getProxyConfiguration() {
|
||||
return null;
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
public String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecret) {
|
||||
this.clientSecret = clientSecret;
|
||||
}
|
||||
|
||||
public String getIdentityZoneSubdomain() {
|
||||
return identityZoneSubdomain;
|
||||
}
|
||||
|
||||
public void setIdentityZoneSubdomain(String identityZoneSubdomain) {
|
||||
this.identityZoneSubdomain = identityZoneSubdomain;
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
@@ -99,9 +122,12 @@ public class CloudFoundryTargetProperties {
|
||||
this.skipSslValidation = skipSslValidation;
|
||||
}
|
||||
|
||||
public ProxyConfiguration getProxyConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String parseApiHost(String api) {
|
||||
final URI uri = URI.create(api);
|
||||
return uri.getHost() == null ? api : uri.getHost();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.appbroker.deployer.cloudfoundry;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.cloudfoundry.client.CloudFoundryClient;
|
||||
import org.cloudfoundry.operations.CloudFoundryOperations;
|
||||
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
|
||||
import org.cloudfoundry.operations.applications.ApplicationManifest;
|
||||
@@ -45,6 +46,7 @@ import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SuppressWarnings("UnassignedFluxMonoInstance")
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CloudFoundryAppDeployerTest {
|
||||
|
||||
@@ -59,6 +61,9 @@ class CloudFoundryAppDeployerTest {
|
||||
@Mock
|
||||
private CloudFoundryOperations cloudFoundryOperations;
|
||||
|
||||
@Mock
|
||||
private CloudFoundryClient cloudFoundryClient;
|
||||
|
||||
@Mock
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@@ -67,6 +72,7 @@ class CloudFoundryAppDeployerTest {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
deploymentProperties = new CloudFoundryDeploymentProperties();
|
||||
CloudFoundryTargetProperties targetProperties = new CloudFoundryTargetProperties();
|
||||
|
||||
when(applications.pushManifest(any()))
|
||||
.thenReturn(Mono.empty());
|
||||
@@ -75,8 +81,8 @@ class CloudFoundryAppDeployerTest {
|
||||
when(resourceLoader.getResource(APP_PATH))
|
||||
.thenReturn(new FileSystemResource(APP_PATH));
|
||||
|
||||
appDeployer = new CloudFoundryAppDeployer(
|
||||
new CloudFoundryTargetProperties(), deploymentProperties, cloudFoundryOperations, resourceLoader);
|
||||
appDeployer = new CloudFoundryAppDeployer(deploymentProperties,
|
||||
cloudFoundryOperations, cloudFoundryClient, targetProperties, resourceLoader);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.appbroker.sample.fixtures;
|
||||
|
||||
import org.springframework.boot.test.context.TestComponent;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
@@ -27,14 +28,66 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
|
||||
public class UaaStubFixture extends WiremockStubFixture {
|
||||
public void stubCommonUaaRequests() {
|
||||
stubRetrieveAccessToken();
|
||||
stubRetrieveTokenKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* {
|
||||
* "jti": "9fd596e1fcd34c12a3f74695e8951b70",
|
||||
* "sub": "9f1a1425-a7ab-4e38-b2b9-d6f221b16cea",
|
||||
* "scope": [
|
||||
* "openid",
|
||||
* "routing.router_groups.write",
|
||||
* "network.write",
|
||||
* "scim.read",
|
||||
* "cloud_controller.admin",
|
||||
* "uaa.user",
|
||||
* "routing.router_groups.read",
|
||||
* "cloud_controller.read",
|
||||
* "password.write",
|
||||
* "cloud_controller.write",
|
||||
* "network.admin",
|
||||
* "doppler.firehose",
|
||||
* "scim.write"
|
||||
* ],
|
||||
* "client_id": "cf",
|
||||
* "cid": "cf",
|
||||
* "azp": "cf",
|
||||
* "grant_type": "password",
|
||||
* "user_id": "9f1a1425-a7ab-4e38-b2b9-d6f221b16cea",
|
||||
* "origin": "uaa",
|
||||
* "user_name": "admin",
|
||||
* "email": "admin",
|
||||
* "rev_sig": "c594512e",
|
||||
* "iat": 1539188141,
|
||||
* "exp": 1539195341,
|
||||
* "iss": "https://uaa.system.example.com/oauth/token",
|
||||
* "zid": "uaa",
|
||||
* "aud": [
|
||||
* "cloud_controller",
|
||||
* "scim",
|
||||
* "password",
|
||||
* "cf",
|
||||
* "uaa",
|
||||
* "openid",
|
||||
* "doppler",
|
||||
* "network",
|
||||
* "routing.router_groups"
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
private void stubRetrieveAccessToken() {
|
||||
stubFor(post(urlPathEqualTo("/oauth/token"))
|
||||
.willReturn(ok()
|
||||
.withBody(uaa("put-oauth-token"))));
|
||||
}
|
||||
|
||||
private void stubRetrieveTokenKeys() {
|
||||
stubFor(get(urlPathEqualTo("/token_keys"))
|
||||
.willReturn(ok()
|
||||
.withBody(uaa("get-token-keys"))));
|
||||
}
|
||||
|
||||
private String uaa(String fileRoot) {
|
||||
return readResponseFromFile(fileRoot, "uaa");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"kid":"keyIdRSA",
|
||||
"alg":"RS256",
|
||||
"value":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\nrn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\nfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\nLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\nkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\njfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\nJwIDAQAB\n-----END PUBLIC KEY-----",
|
||||
"kty":"RSA",
|
||||
"use":"sig",
|
||||
"n":"ANJufZdrvYg5zG61x36pDq59nVUN73wSanA7hVCtN3ftT2Rm1ZTQqp5KSCfLMhaaVvJY51sHj+/i4lqUaM9CO32G93fE44VfOmPfexZeAwa8YDOikyTrhP7sZ6A4WUNeC4DlNnJF4zsznU7JxjCkASwpdL6XFwbRSzGkm6b9aM4vIewyclWehJxUGVFhnYEzIQ65qnr38feVP9enOVgQzpKsCJ+xpa8vZ/UrscoG3/IOQM6VnLrGYAyyCGeyU1JXQW/KlNmtA5eJry2Tp+MD6I34/QsNkCArHOfj8H9tXz/oc3/tVkkR252L/Lmp0TtIGfHpBmoITP9h+oKiW6NpyCc=",
|
||||
"e":"AQAB"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"access_token": "accessToken",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5ZmQ1OTZlMWZjZDM0YzEyYTNmNzQ2OTVlODk1MWI3MCIsInN1YiI6IjlmMWExNDI1LWE3YWItNGUzOC1iMmI5LWQ2ZjIyMWIxNmNlYSIsInNjb3BlIjpbIm9wZW5pZCIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy53cml0ZSIsIm5ldHdvcmsud3JpdGUiLCJzY2ltLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwidWFhLnVzZXIiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMucmVhZCIsImNsb3VkX2NvbnRyb2xsZXIucmVhZCIsInBhc3N3b3JkLndyaXRlIiwiY2xvdWRfY29udHJvbGxlci53cml0ZSIsIm5ldHdvcmsuYWRtaW4iLCJkb3BwbGVyLmZpcmVob3NlIiwic2NpbS53cml0ZSJdLCJjbGllbnRfaWQiOiJjZiIsImNpZCI6ImNmIiwiYXpwIjoiY2YiLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX2lkIjoiOWYxYTE0MjUtYTdhYi00ZTM4LWIyYjktZDZmMjIxYjE2Y2VhIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoiYWRtaW4iLCJlbWFpbCI6ImFkbWluIiwicmV2X3NpZyI6ImM1OTQ1MTJlIiwiaWF0IjoxNTM5MTg4MTQxLCJleHAiOjE1MzkxOTI5MDksImlzcyI6Imh0dHBzOi8vdWFhLnN5c3RlbS5leGFtcGxlLmNvbS9vYXV0aC90b2tlbiIsInppZCI6InVhYSIsImF1ZCI6WyJjbG91ZF9jb250cm9sbGVyIiwic2NpbSIsInBhc3N3b3JkIiwiY2YiLCJ1YWEiLCJvcGVuaWQiLCJkb3BwbGVyIiwibmV0d29yayIsInJvdXRpbmcucm91dGVyX2dyb3VwcyJdfQ.Lb5jBZ4WbQUbfyrfrqVdf6O1J_qpOSk8ybls09AblR0",
|
||||
"token_type": "bearer",
|
||||
"refresh_token": "refreshToken",
|
||||
"expires_in": 7199,
|
||||
|
||||
Reference in New Issue
Block a user