diff --git a/.github/register_service_credential_in_primaza.sh b/.github/register_service_credential_in_primaza.sh
index 286871cb..cabde37f 100755
--- a/.github/register_service_credential_in_primaza.sh
+++ b/.github/register_service_credential_in_primaza.sh
@@ -5,6 +5,7 @@ SERVICE_NAME=$2
USERNAME=$3
PASSWORD=$4
DATABASE_NAME=$5
+CREDENTIAL_TYPE=$6
PRIMAZA_KUBERNETES_NAMESPACE=sb
POD_NAME=$(kubectl get pod -l app.kubernetes.io/name=primaza-app -n $PRIMAZA_KUBERNETES_NAMESPACE -o name)
@@ -12,7 +13,7 @@ POD_NAME=$(kubectl get pod -l app.kubernetes.io/name=primaza-app -n $PRIMAZA_KUB
SERVICE=$(kubectl exec -i $POD_NAME --container primaza-app -n $PRIMAZA_KUBERNETES_NAMESPACE -- sh -c "curl -H 'Accept: application/json' -s localhost:8080/services/name/$SERVICE_NAME")
SERVICE_ID=$(echo "$SERVICE" | jq -r '.id')
-BODY="name=$CREDENTIAL_NAME&serviceId=$SERVICE_ID&username=$USERNAME&password=$PASSWORD¶ms=database:$DATABASE_NAME"
+BODY="name=$CREDENTIAL_NAME&type=$CREDENTIAL_TYPE&serviceId=$SERVICE_ID&username=$USERNAME&password=$PASSWORD¶ms=database:$DATABASE_NAME"
echo "Sending service credential with body: $BODY"
RESULT=$(kubectl exec -i $POD_NAME --container primaza-app -n $PRIMAZA_KUBERNETES_NAMESPACE -- sh -c "curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d '$BODY' -s -i localhost:8080/credentials")
if [[ "$RESULT" = *"500 Internal Server Error"* ]]
diff --git a/.github/workflows/e2e-atomic-fruits-vault-crossplane.yml b/.github/workflows/e2e-atomic-fruits-vault-crossplane.yml
index e55b8417..ccc15b95 100644
--- a/.github/workflows/e2e-atomic-fruits-vault-crossplane.yml
+++ b/.github/workflows/e2e-atomic-fruits-vault-crossplane.yml
@@ -85,7 +85,7 @@ jobs:
./scripts/data/services.sh url=$PRIMAZA_URL service_name=activemq-artemis version=2.26 type=activemq endpoint=tcp:8161
./scripts/data/services.sh url=$PRIMAZA_URL service_name=mariadb version=10.9 type=mariadb endpoint=tcp:3306
- ./scripts/data/credentials.sh url=$PRIMAZA_URL credential_name=fruits_database-vault-creds service_name=postgresql vault_kv=primaza/fruits
+ ./scripts/data/credentials.sh url=$PRIMAZA_URL credential_type=vault credential_name=fruits_database-vault-creds service_name=postgresql vault_kv=primaza/fruits
- name: Installing Vault
run: |
diff --git a/.github/workflows/e2e-atomic-fruits-vault.yml b/.github/workflows/e2e-atomic-fruits-vault.yml
index d600e989..c8b0f118 100644
--- a/.github/workflows/e2e-atomic-fruits-vault.yml
+++ b/.github/workflows/e2e-atomic-fruits-vault.yml
@@ -84,7 +84,7 @@ jobs:
./scripts/data/services.sh url=$PRIMAZA_URL service_name=activemq-artemis version=2.26 type=activemq endpoint=tcp:8161
./scripts/data/services.sh url=$PRIMAZA_URL service_name=mariadb version=10.9 type=mariadb endpoint=tcp:3306
- ./scripts/data/credentials.sh url=$PRIMAZA_URL credential_name=fruits_database-vault-creds service_name=postgresql vault_kv=primaza/fruits
+ ./scripts/data/credentials.sh url=$PRIMAZA_URL credential_type=vault credential_name=fruits_database-vault-creds service_name=postgresql vault_kv=primaza/fruits
- name: Installing Vault
run: |
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index 541ce438..4306a31b 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -140,6 +140,7 @@ jobs:
PASSWORD=superman
TYPE=postgresql
DATABASE_NAME=database
+ CREDENTIAL_TYPE=basic
# First, we install Postgresql via Helm.
helm repo add bitnami https://charts.bitnami.com/bitnami
@@ -150,7 +151,7 @@ jobs:
.github/register_service_in_primaza.sh postgresql 11 tcp:5432 $TYPE
# We create the credentials for the PostgreSQL service recently registered
- .github/register_service_credential_in_primaza.sh postgresql-credentials postgresql $USERNAME $PASSWORD $DATABASE_NAME
+ .github/register_service_credential_in_primaza.sh postgresql-credentials postgresql $USERNAME $PASSWORD $DATABASE_NAME $CREDENTIAL_TYPE
- name: Register claim
run: .github/register_claim_in_primaza.sh heroClaimDb postgresql-11
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index e44ab76e..927b175d 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -147,6 +147,7 @@ jobs:
PASSWORD=superman
TYPE=postgresql
DATABASE_NAME=database
+ CREDENTIAL_TYPE=basic
# First, we install Postgresql via Helm.
helm repo add bitnami https://charts.bitnami.com/bitnami
@@ -157,7 +158,7 @@ jobs:
.github/register_service_in_primaza.sh postgresql 11 tcp:5432 $TYPE
# And finally the credentials
- .github/register_service_credential_in_primaza.sh postgresql-credentials postgresql $USERNAME $PASSWORD $DATABASE_NAME
+ .github/register_service_credential_in_primaza.sh postgresql-credentials postgresql $USERNAME $PASSWORD $DATABASE_NAME $CREDENTIAL_TYPE
- name: Register claim
run: .github/register_claim_in_primaza.sh heroClaimDb postgresql-11
diff --git a/app/src/main/java/io/halkyon/model/Credential.java b/app/src/main/java/io/halkyon/model/Credential.java
index f1f1b886..add7bede 100644
--- a/app/src/main/java/io/halkyon/model/Credential.java
+++ b/app/src/main/java/io/halkyon/model/Credential.java
@@ -38,6 +38,8 @@ public class Credential extends PanacheEntityBase {
@JoinColumn(name = "service_id", nullable = false)
public Service service;
+ public String type;
+
public String vaultKvPath;
public String username;
diff --git a/app/src/main/java/io/halkyon/resource/requests/CredentialRequest.java b/app/src/main/java/io/halkyon/resource/requests/CredentialRequest.java
index 3caa5f8b..6731b0ce 100644
--- a/app/src/main/java/io/halkyon/resource/requests/CredentialRequest.java
+++ b/app/src/main/java/io/halkyon/resource/requests/CredentialRequest.java
@@ -16,6 +16,10 @@ public class CredentialRequest {
@FormParam
public String name;
+ @NotBlank
+ @FormParam
+ public String type;
+
@NotNull
@FormParam
public Long serviceId;
diff --git a/app/src/main/java/io/halkyon/services/CredentialService.java b/app/src/main/java/io/halkyon/services/CredentialService.java
index 533a2f0f..375987f2 100644
--- a/app/src/main/java/io/halkyon/services/CredentialService.java
+++ b/app/src/main/java/io/halkyon/services/CredentialService.java
@@ -59,6 +59,7 @@ private Credential mergeEntities(Credential old, Credential edited) {
public Credential initializeCredential(CredentialRequest request) {
Credential credential = new Credential();
credential.name = request.name;
+ credential.type = request.type;
credential.username = request.username;
credential.password = request.password;
if (request.vaultKvPath != null) {
diff --git a/app/src/main/resources/templates/credentials/form.html b/app/src/main/resources/templates/credentials/form.html
index abc1a9b0..38a884f0 100644
--- a/app/src/main/resources/templates/credentials/form.html
+++ b/app/src/main/resources/templates/credentials/form.html
@@ -1,139 +1,202 @@
{@java.lang.Integer items}
{#include base}
- {#title}Credential{/title}
- {#body}
-
-
- {/body}
+ // Attach the event listener to the select element
+ document.getElementById("credential_type").addEventListener("change", handleSelectChange);
+
+ function addParameterRow() {
+ var nameInput = document.getElementById("new-param-name");
+ var valueInput = document.getElementById("new-param-value");
+ var table = document.getElementById("credential-params");
+
+ // hidden input for form
+ var formInput = document.createElement("input");
+ formInput.type = "hidden";
+ formInput.name = "params";
+ formInput.value = nameInput.value + ":" + valueInput.value;
+
+ // delete button
+ var button = document.createElement("button");
+ button.setAttribute("class", "btn btn-secondary");
+ button.type = "button";
+ button.innerHTML = "Delete";
+ button.setAttribute("onclick", "deleteParameterRow(this)");
+
+ var newRow = table.insertRow(-1);
+ var cell1 = newRow.insertCell(0);
+ var cell2 = newRow.insertCell(1);
+ var cell3 = newRow.insertCell(2);
+ cell1.innerHTML = nameInput.value;
+ cell2.innerHTML = valueInput.value;
+ cell3.appendChild(button);
+ cell3.appendChild(formInput);
+
+ nameInput.value = "";
+ valueInput.value = "";
+ }
+
+ function deleteParameterRow(row) {
+ var i = row.parentNode.parentNode.rowIndex;
+ document.getElementById("credential-params").deleteRow(i - 1);
+ }
+
+ {/body}
{/include}
\ No newline at end of file
diff --git a/app/src/main/resources/templates/credentials/item.html b/app/src/main/resources/templates/credentials/item.html
index 2924f637..f12e054f 100644
--- a/app/src/main/resources/templates/credentials/item.html
+++ b/app/src/main/resources/templates/credentials/item.html
@@ -4,6 +4,7 @@
{credential.name} |
{credential.username} |
{credential.password} |
+ {credential.vaultKvPath} |
-
diff --git a/app/src/main/resources/templates/credentials/table.html b/app/src/main/resources/templates/credentials/table.html
index e2923cee..95a7bfa9 100644
--- a/app/src/main/resources/templates/credentials/table.html
+++ b/app/src/main/resources/templates/credentials/table.html
@@ -8,6 +8,7 @@
Name |
Username |
Password |
+ Vault Path |
Action |
@@ -36,7 +37,7 @@
|
{#for credential in credentials}
-
+
{#include credentials/item.html credential=credential /}
{/for}
diff --git a/app/src/test/java/io/halkyon/ApplicationsPageTest.java b/app/src/test/java/io/halkyon/ApplicationsPageTest.java
index dc41c8c5..56d7ec1b 100644
--- a/app/src/test/java/io/halkyon/ApplicationsPageTest.java
+++ b/app/src/test/java/io/halkyon/ApplicationsPageTest.java
@@ -148,13 +148,14 @@ public void testBindApplication() throws ClusterConnectException {
String claimName = prefix + "claim";
String serviceName = prefix + "service";
String credentialName = prefix + "credential";
+ String credentialType = "basic";
String appName = prefix + "app";
// mock data
configureMockServiceFor(clusterName, "testbind", "1111", "ns1");
configureMockApplicationFor(clusterName, appName, "image2", "ns1");
// create data
Service service = createService(serviceName, "version", "type", "testbind:1111");
- createCredential(credentialName, service.id, "user1", "pass1", null);
+ createCredential(credentialName, credentialType, service.id, "user1", "pass1", null);
createCluster(clusterName, "host:9999");
serviceDiscoveryJob.execute(); // this action will change the service to available
Claim claim = createClaim(claimName, serviceName + "-version");
@@ -209,6 +210,7 @@ public void testBindApplicationUsingServiceFromAnotherCluster() throws ClusterCo
String claimName = prefix + "claim";
String serviceName = prefix + "service";
String credentialName = prefix + "credential";
+ String credentialType = "basic";
String appName = prefix + "app";
String externalServiceIp = serviceName + "ip";
@@ -218,7 +220,7 @@ public void testBindApplicationUsingServiceFromAnotherCluster() throws ClusterCo
// create data
Service service = createService(serviceName, "version", "type", "testbind:1111");
- createCredential(credentialName, service.id, "user1", "pass1", null);
+ createCredential(credentialName, credentialType, service.id, "user1", "pass1", null);
createCluster(clusterNameOfService, "host:9999");
createCluster(clusterNameOfApplication, "host:9999");
serviceDiscoveryJob.execute(); // this action will change the service to available
@@ -314,6 +316,7 @@ public void testBindApplicationGettingCredentialsFromVault() throws ClusterConne
String claimName = prefix + "claim";
String serviceName = prefix + "service";
String credentialName = prefix + "credential";
+ String credentialType = "vault";
String appName = prefix + "app";
String username = "user1";
String password = "pass1";
@@ -323,7 +326,7 @@ public void testBindApplicationGettingCredentialsFromVault() throws ClusterConne
configureMockApplicationFor(clusterName, appName, "image2", "ns1");
// create data
Service service = createService(serviceName, "version", "type", "testbind:1111");
- createCredential(credentialName, service.id, null, null, "myapps/app");
+ createCredential(credentialName, credentialType, service.id, null, null, "myapps/app");
createCluster(clusterName, "host:9999");
Map newsecrets = new HashMap<>();
diff --git a/app/src/test/java/io/halkyon/CredentialsPageTest.java b/app/src/test/java/io/halkyon/CredentialsPageTest.java
index f7b77d01..3ca4ed11 100644
--- a/app/src/test/java/io/halkyon/CredentialsPageTest.java
+++ b/app/src/test/java/io/halkyon/CredentialsPageTest.java
@@ -15,9 +15,10 @@
public class CredentialsPageTest extends BaseTest {
@Test
- public void testCreateNewCredential() {
- createService("postgresql-credential1", "8", "postgresql");
+ public void testCreateUserPasswordCredential() {
+ Service service = createService("postgresql-credential1", "8", "postgresql");
page.goTo("/credentials/new");
+
// add param a=1
page.type("new-param-name", "a");
page.type("new-param-value", "1");
@@ -26,12 +27,14 @@ public void testCreateNewCredential() {
page.type("new-param-name", "b");
page.type("new-param-value", "2");
page.clickById("add-param-to-credential-button");
+
// set data
- page.select("credential_service", "postgresql-credential1-8");
+ page.select("credential_service", service.name + "-" + service.version);
page.type("credential_name", "Credential1");
page.type("credential_username", "Admin");
page.type("credential_password", "Supersecret");
- page.type("credential_vault_path", "myapps/vault-quickstart/private");
+ page.select("credential_type", "basic");
+
// submit credential
page.clickById("credential-button");
@@ -42,7 +45,7 @@ public void testCreateNewCredential() {
.as(Credential.class);
assertEquals("Admin", credential.username);
assertEquals("Supersecret", credential.password);
- assertEquals("myapps/vault-quickstart/private", credential.vaultKvPath);
+
assertEquals(2, credential.params.size());
assertEquals("a", credential.params.get(0).paramName);
assertEquals("1", credential.params.get(0).paramValue);
@@ -50,18 +53,47 @@ public void testCreateNewCredential() {
assertEquals("2", credential.params.get(1).paramValue);
// and the service should have been linked to it.
- Service service = given().when().get("/services/name/postgresql-credential1").then().statusCode(200).extract()
+ service = given().when().get("/services/name/postgresql-credential1").then().statusCode(200).extract()
.as(Service.class);
assertEquals(1, service.credentials.size());
assertEquals("Credential1", service.credentials.get(0).name);
}
+ @Test
+ public void testCreateNewVaultCredential() {
+ Service service = createService("postgresql-credential2", "8", "postgresql");
+ page.goTo("/credentials/new");
+
+ page.select("credential_type", "vault");
+
+ // set data
+ page.select("credential_service", service.name + "-" + service.version);
+ page.type("credential_name", "Credential2");
+
+ page.type("credential_vault_path", "myapps/vault-quickstart/private");
+ // submit credential
+ page.clickById("credential-button");
+
+ // then, the new credential should be listed:
+ page.goTo("/credentials");
+ page.assertContentContains("Credential2");
+ Credential credential = given().when().get("/credentials/name/Credential2").then().statusCode(200).extract()
+ .as(Credential.class);
+ assertEquals("myapps/vault-quickstart/private", credential.vaultKvPath);
+
+ // and the service should have been linked to it.
+ service = given().when().get("/services/name/postgresql-credential2").then().statusCode(200).extract()
+ .as(Service.class);
+ assertEquals(1, service.credentials.size());
+ assertEquals("Credential2", service.credentials.get(0).name);
+ }
+
@Test
public void testEditCredentialFromPage() {
// Create data
String prefix = "CredentialsPageTest-testEditCredentialFromPage-";
Service service = createService(prefix + "service", "8", "type");
- Credential credential = createCredential(prefix + "credential", service.id, "user", "pass",
+ Credential credential = createCredential(prefix + "credential", "basic", service.id, "user", "pass",
"myapps/vault-quickstart/private");
// Go to the page
page.goTo("/credentials");
@@ -85,7 +117,7 @@ public void testEditCredentialFromPage() {
public void testDeleteCredential() {
String prefix = "CredentialsPageTest-testDeleteCredential-";
Service service = createService(prefix + "service", "8", "postgresql");
- Credential credential = createCredential(prefix + "credential", service.id, "user", "pass",
+ Credential credential = createCredential(prefix + "credential", "basic", service.id, "user", "pass",
"myapps/vault-quickstart/private");
// When, we go to the credentials page
diff --git a/app/src/test/java/io/halkyon/utils/TestUtils.java b/app/src/test/java/io/halkyon/utils/TestUtils.java
index 8ccd99e2..e91eda7e 100644
--- a/app/src/test/java/io/halkyon/utils/TestUtils.java
+++ b/app/src/test/java/io/halkyon/utils/TestUtils.java
@@ -48,7 +48,7 @@ public static Service createService(String serviceName, String serviceVersion, S
public static Service createServiceWithCredential(String serviceName, String serviceVersion, String serviceType,
String endpoint) {
Service service = createService(serviceName, serviceVersion, serviceType, endpoint);
- createCredential(serviceName + "-credential", service.id, "username", "password", null);
+ createCredential(serviceName + "-credential", "basic", service.id, "username", "password", null);
return service;
}
@@ -110,11 +110,12 @@ public static Application createApplication(String applicationName, String clust
return app;
}
- public static Credential createCredential(String credentialName, long serviceId, String username, String password,
- String vaultPath) {
+ public static Credential createCredential(String credentialName, String credentialType, long serviceId,
+ String username, String password, String vaultPath) {
given().contentType(MediaType.APPLICATION_FORM_URLENCODED).formParam("name", credentialName)
- .formParam("serviceId", serviceId).formParam("username", username).formParam("password", password)
- .formParam("vaultKvPath", vaultPath).when().post("/credentials").then().statusCode(201);
+ .formParam("type", credentialType).formParam("serviceId", serviceId).formParam("username", username)
+ .formParam("password", password).formParam("vaultKvPath", vaultPath).when().post("/credentials").then()
+ .statusCode(201);
return given().contentType(MediaType.APPLICATION_JSON).get("/credentials/name/" + credentialName).then()
.statusCode(200).extract().as(Credential.class);
diff --git a/scripts/data/credentials.sh b/scripts/data/credentials.sh
index fc3fc924..6cc77600 100755
--- a/scripts/data/credentials.sh
+++ b/scripts/data/credentials.sh
@@ -18,6 +18,7 @@ NO_WAIT=true
# Default parameter values
DEFAULT_PRIMAZA_URL="localhost:8080"
+DEFAULT_CREDENTIAL_TYPE="basic"
DEFAULT_CREDENTIAL_NAME=""
DEFAULT_SERVICE_NAME=""
DEFAULT_USERNAME=""
@@ -35,6 +36,9 @@ parse_parameters() {
credential_name=*)
CREDENTIAL_NAME="${arg#*=}"
;;
+ credential_type=*)
+ CREDENTIAL_TYPE="${arg#*=}"
+ ;;
service_name=*)
SERVICE_NAME="${arg#*=}"
;;
@@ -65,6 +69,7 @@ parse_parameters "$@"
# Set defaults if parameters are not provided
PRIMAZA_URL=${PRIMAZA_URL:-$DEFAULT_PRIMAZA_URL}
CREDENTIAL_NAME=${CREDENTIAL_NAME:-$DEFAULT_CREDENTIAL_NAME}
+CREDENTIAL_TYPE=${CREDENTIAL_TYPE:-$DEFAULT_CREDENTIAL_TYPE}
SERVICE_ID=${SERVICE_ID:-$DEFAULT_SERVICE_ID}
SERVICE_NAME=${SERVICE_NAME:-$DEFAULT_SERVICE_NAME}
USERNAME=${USERNAME:-$DEFAULT_USERNAME}
@@ -83,14 +88,13 @@ else
note "Service id found: $SERVICE_ID"
fi
-if [ -z "$USERNAME" ] && [ -z "$PASSWORD" ]; then
- BODY="name=$CREDENTIAL_NAME&serviceId=$SERVICE_ID&vaultKvPath=primaza/fruits"
-else
- BODY="name=$CREDENTIAL_NAME&serviceId=$SERVICE_ID&username=$USERNAME&password=$PASSWORD¶ms=database:$DATABASE_NAME"
-fi
-
-note "Creating the credential using as body: $BODY"
-note "curl -X POST -s -k -d \"${BODY}\" ${PRIMAZA_URL}/credentials" >&2
+case $CREDENTIAL_TYPE in
+ basic)
+ BODY="type=$CREDENTIAL_TYPE&name=$CREDENTIAL_NAME&serviceId=$SERVICE_ID&username=$USERNAME&password=$PASSWORD¶ms=database:$DATABASE_NAME"
+ ;;
+ vault)
+ BODY="type=$CREDENTIAL_TYPE&name=$CREDENTIAL_NAME&serviceId=$SERVICE_ID&vaultKvPath=$VAULT_KV"
+esac
RESPONSE=$(curl -s -k -o response.txt -w '%{http_code}' \
-X POST \
|