diff --git a/spring-credhub/pom.xml b/spring-credhub/pom.xml
new file mode 100644
index 0000000000..57fbe5c9d6
--- /dev/null
+++ b/spring-credhub/pom.xml
@@ -0,0 +1,44 @@
+
+
+ 4.0.0
+
+ com.baeldung.spring-credhub
+ spring-credhub
+ 1.0-SNAPSHOT
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+
+
+ org.springframework.credhub
+ spring-credhub-starter
+ 2.2.0
+
+
+ com.google.code.gson
+ gson
+
+
+
+
+ 8
+ 8
+ UTF-8
+
+
+
\ No newline at end of file
diff --git a/spring-credhub/src/main/java/com/baeldung/OrderApplication.java b/spring-credhub/src/main/java/com/baeldung/OrderApplication.java
new file mode 100644
index 0000000000..94d34c18bb
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/OrderApplication.java
@@ -0,0 +1,7 @@
+package com.baeldung;
+
+public class OrderApplication {
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
\ No newline at end of file
diff --git a/spring-credhub/src/main/java/com/baeldung/controller/CredentialController.java b/spring-credhub/src/main/java/com/baeldung/controller/CredentialController.java
new file mode 100644
index 0000000000..8da2b98dfd
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/controller/CredentialController.java
@@ -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 generatePassword(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.generatePassword(credentialName), HttpStatus.OK);
+ }
+
+ @PutMapping("/credentials")
+ public ResponseEntity writeJSONCredential(@RequestBody Credential secret) {
+ return new ResponseEntity<>(credentialService.writeCredential(secret), HttpStatus.OK);
+ }
+
+ @PostMapping("/credentials/rotate")
+ public ResponseEntity rotatePassword(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.rotatePassword(credentialName), HttpStatus.OK);
+ }
+
+ @DeleteMapping("/credentials")
+ public ResponseEntity deletePassword(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.deletePassword(credentialName), HttpStatus.OK);
+ }
+
+ @GetMapping("/credentials")
+ public ResponseEntity getPassword(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.getPassword(credentialName), HttpStatus.OK);
+ }
+
+ @PostMapping("/permissions")
+ public ResponseEntity addPermission(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.addCredentialPermission(credentialName), HttpStatus.OK);
+ }
+
+ @GetMapping("/permissions")
+ public ResponseEntity getPermission(@RequestBody String credentialName) {
+ return new ResponseEntity<>(credentialService.getCredentialPermission(credentialName), HttpStatus.OK);
+ }
+}
diff --git a/spring-credhub/src/main/java/com/baeldung/controller/OrderController.java b/spring-credhub/src/main/java/com/baeldung/controller/OrderController.java
new file mode 100644
index 0000000000..d839cd291b
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/controller/OrderController.java
@@ -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> 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 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 orderList = new ArrayList<>();
+ orderList.add(order);
+ return orderList;
+ }
+
+ private boolean credentialMatch(String credValue) {
+ //logic to check credValue
+ return true;
+ }
+}
+
diff --git a/spring-credhub/src/main/java/com/baeldung/model/Credential.java b/spring-credhub/src/main/java/com/baeldung/model/Credential.java
new file mode 100644
index 0000000000..c7fa25b261
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/model/Credential.java
@@ -0,0 +1,14 @@
+package com.baeldung.model;
+
+import java.util.Map;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class Credential {
+ Map value;
+ String type;
+ String name;
+}
diff --git a/spring-credhub/src/main/java/com/baeldung/model/Order.java b/spring-credhub/src/main/java/com/baeldung/model/Order.java
new file mode 100644
index 0000000000..31f40956ca
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/model/Order.java
@@ -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;
+}
diff --git a/spring-credhub/src/main/java/com/baeldung/service/CredentialService.java b/spring-credhub/src/main/java/com/baeldung/service/CredentialService.java
new file mode 100644
index 0000000000..75a11cdb9a
--- /dev/null
+++ b/spring-credhub/src/main/java/com/baeldung/service/CredentialService.java
@@ -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 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 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 oldPassword = credentialOperations.getByName(credentialName, PasswordCredential.class);
+ CredentialDetails 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;
+ }
+ }
+}
+
diff --git a/spring-credhub/src/main/resources/application.yml b/spring-credhub/src/main/resources/application.yml
new file mode 100644
index 0000000000..cd2519e4c5
--- /dev/null
+++ b/spring-credhub/src/main/resources/application.yml
@@ -0,0 +1,9 @@
+management:
+ endpoints:
+ web:
+ exposure:
+ include: "*"
+
+spring:
+ credhub:
+ url:
\ No newline at end of file
diff --git a/spring-credhub/src/test/java/com/baeldung/controller/CredentialServiceUnitTest.java b/spring-credhub/src/test/java/com/baeldung/controller/CredentialServiceUnitTest.java
new file mode 100644
index 0000000000..cc785cabda
--- /dev/null
+++ b/spring-credhub/src/test/java/com/baeldung/controller/CredentialServiceUnitTest.java
@@ -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 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 operations = orderConfig.getPermission()
+ .getOperations();
+ String identity = orderConfig.getPermission()
+ .getActor()
+ .getIdentity();
+
+ CredentialPermission newOrderConfig = credentialService.getCredentialPermission("order_config_json");
+ List 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);
+ }
+}