From 55cef7e7ee8be904fc63307df816b7b18322be5d Mon Sep 17 00:00:00 2001 From: John Blum Date: Tue, 10 Sep 2019 12:29:32 -0700 Subject: [PATCH] Add capability to find an optional user by name. Resolves gh-44. --- .../geode/core/env/VcapPropertySource.java | 82 +++++++++-- .../core/env/VcapPropertySourceUnitTests.java | 131 ++++++++++++++++-- 2 files changed, 189 insertions(+), 24 deletions(-) diff --git a/spring-geode/src/main/java/org/springframework/geode/core/env/VcapPropertySource.java b/spring-geode/src/main/java/org/springframework/geode/core/env/VcapPropertySource.java index 944d5832..2223bc1d 100644 --- a/spring-geode/src/main/java/org/springframework/geode/core/env/VcapPropertySource.java +++ b/spring-geode/src/main/java/org/springframework/geode/core/env/VcapPropertySource.java @@ -34,6 +34,7 @@ import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.geode.core.env.support.CloudCacheService; import org.springframework.geode.core.env.support.Service; import org.springframework.geode.core.env.support.User; @@ -52,6 +53,7 @@ import org.springframework.util.StringUtils; * @see java.net.URL * @see java.util.Properties * @see java.util.function.Predicate + * @see org.springframework.core.env.ConfigurableEnvironment * @see org.springframework.core.env.EnumerablePropertySource * @see org.springframework.core.env.Environment * @see org.springframework.core.env.PropertiesPropertySource @@ -72,9 +74,11 @@ public class VcapPropertySource extends PropertySource CLOUD_CACHE_SERVICE_PREDICATE = propertyValue -> String.valueOf(propertyValue).toLowerCase().contains(CLOUD_CACHE_TAG_NAME); @@ -152,7 +156,7 @@ public class VcapPropertySource extends PropertySource findAllPropertiesByNameMatching(Iterable properties, Predicate predicate) { - return StreamSupport.stream(properties.spliterator(), false) + return StreamSupport.stream(CollectionUtils.nullSafeIterable(properties).spliterator(), false) .filter(predicate) .collect(Collectors.toSet()); } @@ -163,7 +167,7 @@ public class VcapPropertySource extends PropertySource findAllPropertiesByValueMatching(Iterable properties, Predicate predicate) { - return StreamSupport.stream(properties.spliterator(), false) + return StreamSupport.stream(CollectionUtils.nullSafeIterable(properties).spliterator(), false) .filter(propertyName -> predicate.test(getProperty(propertyName))) .collect(Collectors.toSet()); } @@ -207,7 +211,7 @@ public class VcapPropertySource extends PropertySource newIllegalStateException("No service with tags [%s] was found", tags)); } - public Optional findFirstUserByRoleClusterOperator(Service service) { + public Optional findUserByName(Service service, String targetUsername) { + + Assert.hasText(targetUsername, String.format("Target username [%s] is required", targetUsername)); + + Optional optionalUser = Optional.empty(); String serviceName = service.getName(); - String userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_PROPERTY, serviceName, 0); + String userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_INDEX_PROPERTY, serviceName, 0); - for (int index = 1; containsProperty(userPropertyName+".roles"); index++) { + for (int index = 1; containsProperty(asUserUsernameProperty(userPropertyName)); index++) { - String roles = String.valueOf(getProperty(userPropertyName+".roles")); + String username = String.valueOf(getProperty(asUserUsernameProperty(userPropertyName))); + + if (username.equals(targetUsername)) { + break; + } + + userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_INDEX_PROPERTY, serviceName, index); + } + + if (containsProperty(asUserUsernameProperty(userPropertyName))) { + + String username = String.valueOf(getProperty(asUserUsernameProperty(userPropertyName))); + String password = String.valueOf(getProperty(asUserPasswordProperty(userPropertyName))); + + User user = User.with(username) + .withPassword(password); + + optionalUser = Optional.of(user); + } + + return optionalUser; + } + + public Optional findFirstUserByRoleClusterOperator(Service service) { + + Optional optionalUser = Optional.empty(); + + String serviceName = service.getName(); + String userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_INDEX_PROPERTY, serviceName, 0); + + for (int index = 1; containsProperty(asUserRolesProperty(userPropertyName)); index++) { + + String roles = String.valueOf(getProperty(asUserRolesProperty(userPropertyName))); if (roles.contains(User.Role.CLUSTER_OPERATOR.name().toLowerCase())) { break; } - userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_PROPERTY, serviceName, index); + userPropertyName = String.format(VCAP_SERVICES_SERVICE_NAME_USERS_INDEX_PROPERTY, serviceName, index); } - if (containsProperty(userPropertyName+".username")) { + if (containsProperty(asUserUsernameProperty(userPropertyName))) { - String username = String.valueOf(getProperty(userPropertyName+".username")); - String password = String.valueOf(getProperty(userPropertyName+".password")); + String username = String.valueOf(getProperty(asUserUsernameProperty(userPropertyName))); + String password = String.valueOf(getProperty(asUserPasswordProperty(userPropertyName))); User user = User.with(username) .withPassword(password) .withRole(User.Role.CLUSTER_OPERATOR); - return Optional.of(user); + optionalUser = Optional.of(user); } - return Optional.empty(); + return optionalUser; + } + + private String asUserPasswordProperty(String userProperty) { + return String.format("%s.password", userProperty); + } + + private String asUserRolesProperty(String userProperty) { + return String.format("%s.roles", userProperty); + } + + private String asUserUsernameProperty(String userProperty) { + return String.format("%s.username", userProperty); } @Nullable diff --git a/spring-geode/src/test/java/org/springframework/geode/core/env/VcapPropertySourceUnitTests.java b/spring-geode/src/test/java/org/springframework/geode/core/env/VcapPropertySourceUnitTests.java index 2d41647c..a56da58f 100644 --- a/spring-geode/src/test/java/org/springframework/geode/core/env/VcapPropertySourceUnitTests.java +++ b/spring-geode/src/test/java/org/springframework/geode/core/env/VcapPropertySourceUnitTests.java @@ -51,13 +51,20 @@ import org.springframework.geode.core.env.support.User; * Unit tests for {@link VcapPropertySource}. * * @author John Blum + * @see java.net.URL * @see java.util.Properties + * @see java.util.function.Predicate * @see org.junit.Test * @see org.mockito.Mockito + * @see org.springframework.core.env.ConfigurableEnvironment + * @see org.springframework.core.env.EnumerablePropertySource * @see org.springframework.core.env.Environment * @see org.springframework.core.env.PropertiesPropertySource * @see org.springframework.core.env.PropertySource * @see org.springframework.geode.core.env.VcapPropertySource + * @see org.springframework.geode.core.env.support.CloudCacheService + * @see org.springframework.geode.core.env.support.Service + * @see org.springframework.geode.core.env.support.User * @since 1.0.0 */ public class VcapPropertySourceUnitTests { @@ -355,7 +362,7 @@ public class VcapPropertySourceUnitTests { } @Test - public void findTargetVcapApplicationPropertiesIsSuccessful() { + public void findTargetVcapServicePropertiesIsSuccessful() { EnumerablePropertySource mockPropertySource = mock(EnumerablePropertySource.class); @@ -609,29 +616,134 @@ public class VcapPropertySourceUnitTests { } @Test - public void findFirstUserByRoleClusterOperatorReturnsUser() { + public void findUserByNameReturnsOptionalOfUser() { Properties vcap = new Properties(); vcap.setProperty("vcap.application.name", "boot-example"); + vcap.setProperty("vcap.application.uris", "boot-example.boot-apps.apps.cloud.net"); + vcap.setProperty("vcap.services.jblum-pcc.name", "jblum-pcc"); + vcap.setProperty("vcap.services.jblum-pcc.tags", "pivotal,cloudcache,database,gemfire"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users", "admin, root, majorTom, jimbo, buster"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].username", "admin"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].roles", "cluster_admin"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].password", "p@55w0rd"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[1].username", "root"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[1].roles", "cluster_operator"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[1].password", "p@55w0rd"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].username", "majorTom"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].roles", "cluster_operator,ground_controller"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].password", "s3cUr3"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[3].username", "jimbo"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[3].roles", "cluster_fuck"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[3].password", "p@55!t"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[4].username", "buster"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[4].roles", "cluster_operator"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[4].password", "p@55!t"); + + VcapPropertySource propertySource = VcapPropertySource.from(vcap); + + assertThat(propertySource).isNotNull(); + + Service jblumPcc = Service.with("jblum-pcc"); + Service nonExistingService = Service.with("non-existing-service"); + + Optional user = propertySource.findUserByName(jblumPcc, "majorTom"); + + assertThat(user).isNotNull(); + assertThat(user.map(User::getName).orElse(null)).isEqualTo("majorTom"); + assertThat(user.flatMap(User::getPassword).orElse(null)).isEqualTo("s3cUr3"); + + user = propertySource.findUserByName(jblumPcc, "admin"); + + assertThat(user).isNotNull(); + assertThat(user.map(User::getName).orElse(null)).isEqualTo("admin"); + assertThat(user.flatMap(User::getPassword).orElse(null)).isEqualTo("p@55w0rd"); + + user = propertySource.findUserByName(jblumPcc, "nonExistingUser"); + + assertThat(user).isNotNull(); + assertThat(user.isPresent()).isFalse(); + + user = propertySource.findUserByName(nonExistingService, "root"); + + assertThat(user).isNotNull(); + assertThat(user.isPresent()).isFalse(); + + + user = propertySource.findUserByName(jblumPcc, "buster"); + + assertThat(user).isNotNull(); + assertThat(user.map(User::getName).orElse(null)).isEqualTo("buster"); + assertThat(user.flatMap(User::getPassword).orElse(null)).isEqualTo("p@55!t"); + } + + private void testFindUserByInvalidNameThrowsIllegalArgumentException(String targetUsername) { + + Properties vcap = new Properties(); + + vcap.setProperty("vcap.application.name", "boot-example"); + vcap.setProperty("vcap.application.uris", "boot-example.boot-apps.apps.cloud.net"); + + VcapPropertySource propertySource = VcapPropertySource.from(vcap); + + assertThat(propertySource).isNotNull(); + + try { + propertySource.findUserByName(Service.with("test-service"), targetUsername); + } + catch (IllegalArgumentException expected) { + + assertThat(expected).hasMessage("Target username [%s] is required", targetUsername); + assertThat(expected).hasNoCause(); + + throw expected; + } + } + + @Test(expected = IllegalArgumentException.class) + public void findUserByBlankName() { + testFindUserByInvalidNameThrowsIllegalArgumentException(" "); + } + + @Test(expected = IllegalArgumentException.class) + public void findUserByEmptyName() { + testFindUserByInvalidNameThrowsIllegalArgumentException(""); + } + + @Test(expected = IllegalArgumentException.class) + public void findUserByNullName() { + testFindUserByInvalidNameThrowsIllegalArgumentException(null); + } + + @Test + public void findFirstUserByRoleClusterOperatorReturnsOptionalOfUser() { + + Properties vcap = new Properties(); + + vcap.setProperty("vcap.application.name", "boot-example"); + vcap.setProperty("vcap.application.space_name", "outerspace"); + vcap.setProperty("vcap.application.uris", "boot-example.boot-apps.apps.cloud.net"); vcap.setProperty("vcap.services.test-pcc.name", "test-pcc"); + vcap.setProperty("vcap.services.test-pcc.tags", "pivotal,cloudcache , database, gemfire "); + vcap.setProperty("vcap.services.test-pcc.credentials.users", "jdoe"); vcap.setProperty("vcap.services.test-pcc.credentials.users[0].username", "jdoe"); vcap.setProperty("vcap.services.test-pcc.credentials.users[0].roles", "developer,poweruser,seaswab"); vcap.setProperty("vcap.services.test-pcc.credentials.users[0].password", "test"); - vcap.setProperty("vcap.services.test-pcc.tags", "pivotal,cloudcache , database, gemfire "); - vcap.setProperty("vcap.application.space_name", "outerspace"); vcap.setProperty("vcap.services.a-pcc.name", "a-pcc"); + vcap.setProperty("vcap.services.a-pcc.tags", "pivotal,cloudcache,database"); + vcap.setProperty("vcap.services.a-pcc.credentials.users", "admin, root"); vcap.setProperty("vcap.services.a-pcc.credentials.users[0].username", "admin"); vcap.setProperty("vcap.services.a-pcc.credentials.users[0].roles", "cluster_admin"); vcap.setProperty("vcap.services.a-pcc.credentials.users[0].password", "p@55w0rd"); vcap.setProperty("vcap.services.a-pcc.credentials.users[1].username", "root"); vcap.setProperty("vcap.services.a-pcc.credentials.users[1].roles", "cluster_operator"); vcap.setProperty("vcap.services.a-pcc.credentials.users[1].password", "p@55w0rd"); - vcap.setProperty("vcap.services.a-pcc.tags", "pivotal,cloudcache,database"); - vcap.setProperty("vcap.application.uris", "boot-example.boot-apps.apps.cloud.net"); vcap.setProperty("vcap.services.jblum-pcc.name", "jblum-pcc"); + vcap.setProperty("vcap.services.jblum-pcc.tags", "pivotal,gemfire,database"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users", "majorTom, jimbo, buster"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].username", "majorTom"); - vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].roles", "cluster_operator,ground_contoller"); + vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].roles", "cluster_operator,ground_controller"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[0].password", "s3cUr3"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[1].username", "jimbo"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[1].roles", "cluster_fuck"); @@ -639,12 +751,13 @@ public class VcapPropertySourceUnitTests { vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].username", "buster"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].roles", "cluster_operator"); vcap.setProperty("vcap.services.jblum-pcc.credentials.users[2].password", "p@55!t"); - vcap.setProperty("vcap.services.jblum-pcc.tags", "pivotal,gemfire,database"); VcapPropertySource propertySource = VcapPropertySource.from(vcap); assertThat(propertySource).isNotNull(); assertThat(propertySource.findFirstUserByRoleClusterOperator(Service.with("test-pcc")).isPresent()).isFalse(); + assertThat(propertySource.findFirstUserByRoleClusterOperator(Service.with("non-existing-service")).isPresent()) + .isFalse(); User root = propertySource.findFirstUserByRoleClusterOperator(Service.with("a-pcc")).orElse(null); @@ -667,7 +780,7 @@ public class VcapPropertySourceUnitTests { Properties properties = new Properties(); - properties.setProperty("vcap.application.name", "withVcapServicePredicateConfiguresVcapServicePredicateReturnsThis"); + properties.setProperty("vcap.application.name", "withMockVcapServicePredicateConfiguresVcapServicePredicateReturnsThis"); properties.setProperty("vcap.application.uris", "{}"); Predicate mockVcapServicePredicate = mock(Predicate.class);