Spring CredHub code (#12929)

* Spring CredHub code

* Added test cases
This commit is contained in:
Shreya Baid 2022-10-28 11:36:50 +05:30 committed by GitHub
parent 7ab9be3c1f
commit 781300d024
9 changed files with 482 additions and 0 deletions

44
spring-credhub/pom.xml Normal file
View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring-credhub</groupId>
<artifactId>spring-credhub</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@ -0,0 +1,7 @@
package com.baeldung;
public class OrderApplication {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

View File

@ -0,0 +1,55 @@
package com.baeldung.controller;
import com.baeldung.model.Credential;
import com.baeldung.service.CredentialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.credhub.support.CredentialPermission;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CredentialController {
@Autowired
CredentialService credentialService;
@PostMapping("/credentials")
public ResponseEntity<String> generatePassword(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.generatePassword(credentialName), HttpStatus.OK);
}
@PutMapping("/credentials")
public ResponseEntity<String> writeJSONCredential(@RequestBody Credential secret) {
return new ResponseEntity<>(credentialService.writeCredential(secret), HttpStatus.OK);
}
@PostMapping("/credentials/rotate")
public ResponseEntity<String> rotatePassword(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.rotatePassword(credentialName), HttpStatus.OK);
}
@DeleteMapping("/credentials")
public ResponseEntity<String> deletePassword(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.deletePassword(credentialName), HttpStatus.OK);
}
@GetMapping("/credentials")
public ResponseEntity<String> getPassword(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.getPassword(credentialName), HttpStatus.OK);
}
@PostMapping("/permissions")
public ResponseEntity<CredentialPermission> addPermission(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.addCredentialPermission(credentialName), HttpStatus.OK);
}
@GetMapping("/permissions")
public ResponseEntity<CredentialPermission> getPermission(@RequestBody String credentialName) {
return new ResponseEntity<>(credentialService.getCredentialPermission(credentialName), HttpStatus.OK);
}
}

View File

@ -0,0 +1,56 @@
package com.baeldung.controller;
import static java.time.LocalDate.now;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.baeldung.model.Order;
import com.baeldung.service.CredentialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
CredentialService credentialService;
public OrderController(CredentialService credentialService) {
this.credentialService = credentialService;
}
@GetMapping
public ResponseEntity<Collection<Order>> getAllOrders() {
try {
String apiKey = credentialService.getPassword("api_key");
return new ResponseEntity<>(getOrderList(apiKey), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
private List<Order> getOrderList(String apiKey) throws Exception {
if (!credentialMatch(apiKey))
throw new Exception();
Order order = new Order();
order.setId(123L);
order.setCustomerName("Craig");
order.setOrderDate(now());
List<Order> orderList = new ArrayList<>();
orderList.add(order);
return orderList;
}
private boolean credentialMatch(String credValue) {
//logic to check credValue
return true;
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.model;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Credential {
Map<String, Object> value;
String type;
String name;
}

View File

@ -0,0 +1,15 @@
package com.baeldung.model;
import java.time.LocalDate;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Order {
private Long id;
private String customerName;
private LocalDate orderDate;
}

View File

@ -0,0 +1,195 @@
package com.baeldung.service;
import java.util.Map;
import java.util.UUID;
import org.springframework.credhub.core.CredHubOperations;
import org.springframework.credhub.core.credential.CredHubCredentialOperations;
import org.springframework.credhub.core.permissionV2.CredHubPermissionV2Operations;
import org.springframework.credhub.support.CredentialDetails;
import org.springframework.credhub.support.CredentialPermission;
import org.springframework.credhub.support.CredentialRequest;
import org.springframework.credhub.support.SimpleCredentialName;
import org.springframework.credhub.support.certificate.CertificateCredential;
import org.springframework.credhub.support.certificate.CertificateCredentialRequest;
import org.springframework.credhub.support.json.JsonCredentialRequest;
import org.springframework.credhub.support.password.PasswordCredential;
import org.springframework.credhub.support.password.PasswordCredentialRequest;
import org.springframework.credhub.support.password.PasswordParameters;
import org.springframework.credhub.support.password.PasswordParametersRequest;
import org.springframework.credhub.support.permissions.Operation;
import org.springframework.credhub.support.permissions.Permission;
import org.springframework.credhub.support.rsa.RsaCredential;
import org.springframework.credhub.support.rsa.RsaCredentialRequest;
import org.springframework.credhub.support.ssh.SshCredential;
import org.springframework.credhub.support.ssh.SshCredentialRequest;
import org.springframework.credhub.support.user.UserCredential;
import org.springframework.credhub.support.user.UserCredentialRequest;
import org.springframework.credhub.support.value.ValueCredential;
import org.springframework.credhub.support.value.ValueCredentialRequest;
import com.baeldung.model.Credential;
public class CredentialService {
private final CredHubCredentialOperations credentialOperations;
private final CredHubPermissionV2Operations permissionOperations;
public CredentialService(CredHubOperations credHubOperations) {
this.credentialOperations = credHubOperations.credentials();
this.permissionOperations = credHubOperations.permissionsV2();
}
public String generatePassword(String name) {
try {
SimpleCredentialName credentialName = new SimpleCredentialName(name);
PasswordParameters parameters = PasswordParameters.builder()
.length(24)
.excludeUpper(false)
.excludeLower(false)
.includeSpecial(true)
.excludeNumber(false)
.build();
CredentialDetails<PasswordCredential> generatedCred = credentialOperations.generate(PasswordParametersRequest.builder()
.name(credentialName)
.parameters(parameters)
.build());
return generatedCred.getValue()
.getPassword();
} catch (Exception e) {
return null;
}
}
public String writeCredential(Credential credential) {
try {
SimpleCredentialName credentialName = new SimpleCredentialName(credential.getName());
CredentialRequest request = null;
Map<String, Object> value = credential.getValue();
switch (credential.getType()) {
case "value":
ValueCredential valueCredential = new ValueCredential((String) value.get("value"));
request = ValueCredentialRequest.builder()
.name(credentialName)
.value(valueCredential)
.build();
break;
case "json":
request = JsonCredentialRequest.builder()
.name(credentialName)
.value(value)
.build();
break;
case "user":
UserCredential userCredential = new UserCredential((String) value.get("username"), (String) value.get("password"));
request = UserCredentialRequest.builder()
.name(credentialName)
.value(userCredential)
.build();
break;
case "password":
PasswordCredential passwordCredential = new PasswordCredential((String) value.get("password"));
request = PasswordCredentialRequest.builder()
.name(credentialName)
.value(passwordCredential)
.build();
break;
case "certificate":
CertificateCredential certificateCredential = new CertificateCredential((String) value.get("certificate"), (String) value.get("certificate_authority"), (String) value.get("private_key"));
request = CertificateCredentialRequest.builder()
.name(credentialName)
.value(certificateCredential)
.build();
break;
case "rsa":
RsaCredential rsaCredential = new RsaCredential((String) value.get("public_key"), (String) value.get("private_key"));
request = RsaCredentialRequest.builder()
.name(credentialName)
.value(rsaCredential)
.build();
break;
case "ssh":
SshCredential sshCredential = new SshCredential((String) value.get("public_key"), (String) value.get("private_key"));
request = SshCredentialRequest.builder()
.name(credentialName)
.value(sshCredential)
.build();
break;
default:
}
if (request != null) {
credentialOperations.write(request);
}
return "Credential:" + credentialName + " written successfully!";
} catch (Exception e) {
return "Error! Unable to write credential";
}
}
public String rotatePassword(String name) {
try {
SimpleCredentialName credentialName = new SimpleCredentialName(name);
CredentialDetails<PasswordCredential> oldPassword = credentialOperations.getByName(credentialName, PasswordCredential.class);
CredentialDetails<PasswordCredential> newPassword = credentialOperations.regenerate(credentialName, PasswordCredential.class);
return "Credential:" + credentialName + " re-generated successfully!";
} catch (Exception e) {
return "Error! Unable to re-generate credential";
}
}
public String deletePassword(String name) {
try {
SimpleCredentialName credentialName = new SimpleCredentialName(name);
credentialOperations.deleteByName(credentialName);
return "Credential:" + credentialName + " deleted successfully!";
} catch (Exception e) {
return "Error! Unable to delete credential";
}
}
public String getPassword(String name) {
try {
SimpleCredentialName credentialName = new SimpleCredentialName(name);
return credentialOperations.getByName(credentialName, PasswordCredential.class)
.getValue()
.getPassword();
} catch (Exception e) {
return null;
}
}
public CredentialPermission addCredentialPermission(String name) {
SimpleCredentialName credentialName = new SimpleCredentialName(name);
try {
Permission permission = Permission.builder()
.app(UUID.randomUUID()
.toString())
.operations(Operation.READ, Operation.WRITE)
.user("u101")
.build();
CredentialPermission credentialPermission = permissionOperations.addPermissions(credentialName, permission);
return credentialPermission;
} catch (Exception e) {
return null;
}
}
public CredentialPermission getCredentialPermission(String name) {
try {
return permissionOperations.getPermissions(name);
} catch (Exception e) {
return null;
}
}
}

View File

@ -0,0 +1,9 @@
management:
endpoints:
web:
exposure:
include: "*"
spring:
credhub:
url: <url>

View File

@ -0,0 +1,87 @@
package com.baeldung.controller;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.assertj.core.util.DateUtil;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.credhub.support.CredentialPermission;
import org.springframework.credhub.support.permissions.Operation;
import com.baeldung.model.Credential;
import com.baeldung.service.CredentialService;
@Ignore
@ExtendWith(MockitoExtension.class)
public class CredentialServiceUnitTest {
@InjectMocks
private CredentialService credentialService;
@Test
public void whenGeneratePassword_thenReturnNewPassword() {
String orderApiKey = credentialService.generatePassword("order_api_key");
assertFalse(orderApiKey.isEmpty());
}
@Test
public void whenWriteCredential_thenReturnSuccess() {
Map<String, Object> value = new HashMap<>();
value.put("end_date", DateUtil.now());
value.put("start_date", DateUtil.yesterday());
Credential credential = new Credential();
credential.setName("order_config_json");
credential.setType("json");
credential.setValue(value);
String result = credentialService.writeCredential(credential);
assertThat(result).isEqualTo("Credential:order_config_json written successfully!");
}
@Test
public void whenRotatePassword_thenRegenerateNewPassword() {
String orderApiKey = credentialService.rotatePassword("order_api_key");
assertThat(orderApiKey).isEqualTo("Credential:order_api_key re-generated successfully!");
}
@Test
public void whenRevokePassword_thenDeletePassword() {
String orderApiKey = credentialService.deletePassword("order_api_key");
assertThat(orderApiKey).isEqualTo("Credential:order_api_key deleted successfully!");
}
@Test
public void whenRetrieveExistingCredential_thenReturnCredentialValue() {
String orderConfigJson = credentialService.getPassword("order_config_json");
assertFalse(orderConfigJson.isEmpty());
}
@Test
public void whenCredentialPermissionCreated_thenAddToCredential() {
CredentialPermission orderConfig = credentialService.addCredentialPermission("order_config_json");
List<Operation> operations = orderConfig.getPermission()
.getOperations();
String identity = orderConfig.getPermission()
.getActor()
.getIdentity();
CredentialPermission newOrderConfig = credentialService.getCredentialPermission("order_config_json");
List<Operation> newOperations = newOrderConfig.getPermission()
.getOperations();
String newIdentity = newOrderConfig.getPermission()
.getActor()
.getIdentity();
assertThat(operations.size() == newOperations.size() && operations.containsAll(newOperations) && newOperations.containsAll(operations));
assertThat(identity).isEqualTo(newIdentity);
}
}