diff --git a/agreementbot/secrets/secrets.go b/agreementbot/secrets/secrets.go index cf98ac0d1..9a2f333d5 100644 --- a/agreementbot/secrets/secrets.go +++ b/agreementbot/secrets/secrets.go @@ -16,6 +16,23 @@ type AgbotSecrets interface { Close() IsReady() bool - ListOrgSecret(user, token, org, name string) ([]string, error) + ListOrgSecret(user, token, org, name string) (map[string]string, error) ListOrgSecrets(user, token, org string) ([]string, error) + CreateOrgSecret(user, token, org, vaultSecretName string, data CreateSecretRequest) error + DeleteOrgSecret(user, token, org, name string) error +} + +type CreateSecretRequest struct { + SecretName string `json:"name"` + SecretValue string `json:"secret"` +} + +type ErrorResponse struct { + Msg string // the error message which shall be logged and added to response body + Details string // optional log message + RespCode int // response type from the agbot API +} + +func (e ErrorResponse) Error() string { + return e.Msg } diff --git a/agreementbot/secrets/vault/http.go b/agreementbot/secrets/vault/http.go index 6569963ee..34f51b6de 100644 --- a/agreementbot/secrets/vault/http.go +++ b/agreementbot/secrets/vault/http.go @@ -67,6 +67,10 @@ type KeyData struct { Keys []string `json:"keys"` } +type ListSecretResponse struct { + Data map[string]string `json:"data"` +} + type ListSecretsResponse struct { Data KeyData `json:"data"` } @@ -120,7 +124,7 @@ func (vs *AgbotVaultSecrets) newHTTPClient(cfg *config.HorizonConfig) (*http.Cli } -// Common function to invoke the Exchange API with builtin retry logic. +// Common function to invoke the Vault API with builtin retry logic. func (vs *AgbotVaultSecrets) invokeVaultWithRetry(token string, url string, method string, body interface{}) (*http.Response, error) { var currRetry int var resp *http.Response diff --git a/agreementbot/secrets/vault/vault.go b/agreementbot/secrets/vault/vault.go index 7c3aa0a37..74e94bee6 100644 --- a/agreementbot/secrets/vault/vault.go +++ b/agreementbot/secrets/vault/vault.go @@ -28,10 +28,49 @@ func (vs *AgbotVaultSecrets) String() string { return fmt.Sprintf("Token: %v", vs.token) } -func (vs *AgbotVaultSecrets) ListOrgSecret(user, password, org, name string) ([]string, error) { - return []string{}, nil +// This utility will be available to any users within the org. +func (vs *AgbotVaultSecrets) ListOrgSecret(user, password, org, name string) (map[string]string, error) { + + glog.V(3).Infof(vaultPluginLogString(fmt.Sprintf("list secret %v for org %v", name, org))) + + // Login the user to ensure that the vault ACLs can take effect + userVaultToken, err := vs.loginUser(user, password, org) + if err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to login user %s, error: %v", user, err), Details: "", RespCode: http.StatusUnauthorized} + } + + url := fmt.Sprintf("%s/v1/openhorizon/%s/%s", vs.cfg.GetAgbotVaultURL(), org, name) + + resp, err := vs.invokeVaultWithRetry(userVaultToken, url, http.MethodGet, nil) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to list %s secret %s, error: %v", org, name, err), Details: "", RespCode: http.StatusServiceUnavailable} + } + + respBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to read secret %s from %s, error: %v", name, org, err), Details: "", RespCode: http.StatusInternalServerError} + } else if httpCode := resp.StatusCode; httpCode == http.StatusNotFound { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Secret does not exist. Vault response %s", string(respBytes)), Details: "", RespCode: http.StatusNotFound} + } else if httpCode == http.StatusForbidden { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Secret not available with the specified credentials. Vault response %s", string(respBytes)), Details: "", RespCode: http.StatusForbidden} + } else if httpCode != http.StatusOK { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to find secret %s for org %s, HTTP status code: %v", name, org, httpCode), Details: "", RespCode: httpCode} + } + + respMsg := ListSecretResponse{} + if err := json.Unmarshal(respBytes, &respMsg); err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to parse response body %v", err), Details: "", RespCode: http.StatusInternalServerError} + } + + glog.V(3).Infof(vaultPluginLogString("Done reading secret value.")) + + return respMsg.Data, nil } +// This utility will be available to only admin users within the org. func (vs *AgbotVaultSecrets) ListOrgSecrets(user, password, org string) ([]string, error) { glog.V(3).Infof(vaultPluginLogString(fmt.Sprintf("listing secrets in %v", org))) @@ -39,7 +78,7 @@ func (vs *AgbotVaultSecrets) ListOrgSecrets(user, password, org string) ([]strin // Login the user to ensure that the vault ACLs can take effect userVaultToken, err := vs.loginUser(user, password, org) if err != nil { - return nil, errors.New(fmt.Sprintf("unable to login user %s, error: %v", user, err)) + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to login user %s, error: %v", user, err), Details: "", RespCode: http.StatusUnauthorized} } // Query the vault using the user's credentials @@ -50,35 +89,88 @@ func (vs *AgbotVaultSecrets) ListOrgSecrets(user, password, org string) ([]strin defer resp.Body.Close() } if err != nil { - return nil, errors.New(fmt.Sprintf("unable to list %s secrets, error: %v", org, err)) + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to list %s secrets, error: %v", org, err), Details: "", RespCode: http.StatusServiceUnavailable} } - httpCode := resp.StatusCode - if httpCode == http.StatusNotFound { - return []string{}, nil + respBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to read list %s secrets response, error: %v", org, err), Details: "", RespCode: http.StatusInternalServerError} + } else if httpCode := resp.StatusCode; httpCode == http.StatusNotFound { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to list secrets for %s. Vault response %s ", org, string(respBytes)), Details: string(respBytes), RespCode: http.StatusNotFound} + } else if httpCode == http.StatusForbidden { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to list secrets for %s. Vault response %s ", org, string(respBytes)), Details: string(respBytes), RespCode: http.StatusForbidden} + } else if httpCode != http.StatusOK { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to list secrets for %s, HTTP status code: %v", org, httpCode), Details: "", RespCode: httpCode} + } + + glog.V(5).Infof(vaultPluginLogString(fmt.Sprintf("list %s secrets response: %v", org, string(respBytes)))) + + respMsg := ListSecretsResponse{} + if err := json.Unmarshal(respBytes, &respMsg); err != nil { + return nil, secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to parse response %v", string(respBytes)), Details: "", RespCode: http.StatusInternalServerError} } - if httpCode != http.StatusOK { - return nil, errors.New(fmt.Sprintf("unable to list %s secrets, HTTP status code: %v", org, httpCode)) + glog.V(3).Infof(vaultPluginLogString("Done listing secrets.")) + + return respMsg.Data.Keys, nil +} + +// This utility will be used to create secrets. +func (vs *AgbotVaultSecrets) CreateOrgSecret(user, password, org, vaultSecretName string, data secrets.CreateSecretRequest) error { + glog.V(3).Infof(vaultPluginLogString(fmt.Sprintf("create secret %s for org %s", vaultSecretName, org))) + + userVaultToken, err := vs.loginUser(user, password, org) + if err != nil { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to login user %s, error %v", user, err), Details: "", RespCode: http.StatusUnauthorized} + } + + url := fmt.Sprintf("%s/v1/openhorizon/%s/%s", vs.cfg.GetAgbotVaultURL(), org, vaultSecretName) + resp, err := vs.invokeVaultWithRetry(userVaultToken, url, http.MethodPost, map[string]string{data.SecretName: data.SecretValue}) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if err != nil { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to create secret, error %v", err), Details: "", RespCode: http.StatusServiceUnavailable} } respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, errors.New(fmt.Sprintf("unable to read list %s secrets response, error: %v", org, err)) + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to read response, error: %v", err), Details: "", RespCode: http.StatusInternalServerError} + } else if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to create secret for %s, error %v", org, string(respBytes)), Details: "", RespCode: resp.StatusCode} } + glog.V(3).Infof(vaultPluginLogString("Done creating secret in vault.")) - glog.V(5).Infof(vaultPluginLogString(fmt.Sprintf("list %s secrets response: %v", org, string(respBytes)))) + return nil +} - respMsg := ListSecretsResponse{} - err = json.Unmarshal(respBytes, &respMsg) +// This utility will be used to delete secrets. +func (vs *AgbotVaultSecrets) DeleteOrgSecret(user, password, org, name string) error { + glog.V(3).Infof(vaultPluginLogString(fmt.Sprintf("delete secret %s for org %s", name, org))) + + userVaultToken, err := vs.loginUser(user, password, org) if err != nil { - return nil, errors.New(fmt.Sprintf("unable to parse response %v", string(respBytes))) + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to login user %s, error %v", user, err), Details: "", RespCode: http.StatusUnauthorized} } - glog.V(3).Infof(vaultPluginLogString("done listing secrets.")) + url := fmt.Sprintf("%s/v1/openhorizon/%s/%s", vs.cfg.GetAgbotVaultURL(), org, name) + resp, err := vs.invokeVaultWithRetry(userVaultToken, url, http.MethodDelete, nil) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if err != nil { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to delete secret, error %v", err), Details: "", RespCode: http.StatusServiceUnavailable} + } - return respMsg.Data.Keys, nil + respBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to read response, error: %v", err), Details: "", RespCode: http.StatusInternalServerError} + } else if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { + return secrets.ErrorResponse{Msg: fmt.Sprintf("Unable to delete secret for %s, error %v", org, string(respBytes)), Details: "", RespCode: resp.StatusCode} + } + glog.V(3).Infof(vaultPluginLogString("Done deleting secret in vault.")) + return nil } func (vs *AgbotVaultSecrets) loginUser(user, password, org string) (string, error) { diff --git a/agreementbot/secure_api.go b/agreementbot/secure_api.go index 06e952fcc..4c72d0d42 100644 --- a/agreementbot/secure_api.go +++ b/agreementbot/secure_api.go @@ -540,9 +540,7 @@ func (a *SecureAPI) writeCompCheckResponse(w http.ResponseWriter, output interfa } } -// Handles secret fetch, updates and delete from the vault API -// org - This url sub-path dictates where the secret exists within the vault -// vault-secret-name - The actual secret name used in the secret bindings +// Handles secret fetch, updates and delete using the vault API func (a *SecureAPI) secrets(w http.ResponseWriter, r *http.Request) { ec, msgPrinter, userAuthenticated := a.processUserCred("/org/{org}/secrets/{secret}", w, r) @@ -566,6 +564,7 @@ func (a *SecureAPI) secrets(w http.ResponseWriter, r *http.Request) { // Process in the inputs and verify that they are consistent with the logged in user. pathVars := mux.Vars(r) org := pathVars["org"] + novalue := r.URL.Query().Get("novalue") vaultSecretName := pathVars["secret"] glog.V(5).Infof(APIlogString(fmt.Sprintf("%v /org/%v/secrets/%v called.", r.Method, org, vaultSecretName))) @@ -579,7 +578,7 @@ func (a *SecureAPI) secrets(w http.ResponseWriter, r *http.Request) { // The user could be authenticated but might be trying to access secrets in another org. if exchange.GetOrg(ec.GetExchangeId()) != org { glog.Errorf(APIlogString(fmt.Sprintf("user %s cannot access secrets in org %s.", exchange.GetOrg(ec.GetExchangeId()), org))) - writeResponse(w, msgPrinter.Sprintf("Unauthorized. User %s cannot access secrets in org %s.", ec.GetExchangeId(), org), http.StatusUnauthorized) + writeResponse(w, msgPrinter.Sprintf("Unauthorized. User %s cannot access secrets in org %s.", ec.GetExchangeId(), org), http.StatusForbidden) return } @@ -591,69 +590,69 @@ func (a *SecureAPI) secrets(w http.ResponseWriter, r *http.Request) { if vaultSecretName == "" { secretNames, err := a.secretProvider.ListOrgSecrets(ec.GetExchangeId(), ec.GetExchangeToken(), org) - if err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("unable to access secrets provider, error: %v.", err))) - writeResponse(w, msgPrinter.Sprintf("unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) - return + if serr, ok := err.(secrets.ErrorResponse); err != nil && ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v. %v", serr, serr.Details))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", serr), serr.RespCode) + } else if err != nil && !ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v.", err))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) + } else { + writeResponse(w, secretNames, http.StatusOK) } - writeResponse(w, secretNames, http.StatusOK) - return - } else { secretName, err := a.secretProvider.ListOrgSecret(ec.GetExchangeId(), ec.GetExchangeToken(), org, vaultSecretName) - if err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("unable to access secrets provider, error: %v.", err))) - writeResponse(w, msgPrinter.Sprintf("unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) - return + if serr, ok := err.(secrets.ErrorResponse); err != nil && ok && (novalue == "" || serr.RespCode != http.StatusNotFound) { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v. %v", serr, serr.Details))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", serr), serr.RespCode) + } else if err != nil && !ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v.", err))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) + } else if novalue == "1" { + writeResponse(w, map[string]bool{"exists" : (serr.RespCode != http.StatusNotFound)}, http.StatusOK) + } else { + writeResponse(w, secretName, http.StatusOK) } - writeResponse(w, secretName, http.StatusOK) - return } - - // if vaultToken, ok := a.processVaultUserCred(fmt.Sprintf("/org/%v/secrets/%v", org, vaultSecretName), msgPrinter, w, r); ok { - // targetURL := fmt.Sprintf("%v/org/%v/secrets/%v", a.Config.GetAgbotVaultURL(), org, vaultSecretName) - // if _, respCode, err := fmt.Sprintf("Dummy response - Token:%v, url:%v", vaultToken, targetURL), http.StatusOK, error(nil); err != nil { - // glog.Errorf(APIlogString(fmt.Sprintf("Vault invocation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err))) - // writeResponse(w, msgPrinter.Sprintf("Vault invovation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err), http.StatusServiceUnavailable) - // } else if respCode == http.StatusNotFound { - // glog.Infof(APIlogString("Secret does not exist.")) - // writeResponse(w, msgPrinter.Sprintf("Secret does not exist."), http.StatusNotFound) - // } else if respCode == http.StatusOK { - // glog.Infof(APIlogString("Secret exists.")) - // writeResponse(w, map[string]bool{"exists": true}, http.StatusOK) - // } - // } case "PUT": fallthrough case "POST": - if vaultToken, ok := a.processVaultUserCred(fmt.Sprintf("/org/%v/secrets/%v", org, vaultSecretName), msgPrinter, w, r); ok { - targetURL := fmt.Sprintf("%v/org/%v/secrets/%v", a.Config.GetAgbotVaultURL(), org, vaultSecretName) - // Replace with a call to invoke the vault API at targetURL with the vault token generated from authentication - if _, respCode, err := fmt.Sprintf("Token:%v, url:%v", vaultToken, targetURL), http.StatusCreated, error(nil); err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("Vault invocation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err))) - writeResponse(w, msgPrinter.Sprintf("Vault invovation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err), http.StatusServiceUnavailable) - } else if respCode == http.StatusCreated { - // POST application logic goes here - glog.Infof(APIlogString("Secret created/updated.")) - writeResponse(w, map[string]string{"name": "secret-name", "secret": "secret"}, http.StatusCreated) - } + var input secrets.CreateSecretRequest + if body, err := ioutil.ReadAll(r.Body); err != nil { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to read request body, error: %v.", err))) + writeResponse(w, msgPrinter.Sprintf("Unable to read request body, error: %v.", err), http.StatusInternalServerError) + return + } else if len(body) == 0 { + glog.Errorf(APIlogString(fmt.Sprintf("Request body is empty."))) + writeResponse(w, msgPrinter.Sprintf("Request body is empty."), http.StatusBadRequest) + return + } else if uerr := json.Unmarshal(body, &input); uerr != nil { + glog.Errorf(APIlogString(fmt.Sprintf("Request body parse error, %v", uerr))) + writeResponse(w, msgPrinter.Sprintf("Request body parse error, %v", uerr), http.StatusBadRequest) + return + } + + err := a.secretProvider.CreateOrgSecret(ec.GetExchangeId(), ec.GetExchangeToken(), org, vaultSecretName, input) + if serr, ok := err.(secrets.ErrorResponse); err != nil && ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v. %v", serr, serr.Details))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", serr), serr.RespCode) + } else if err != nil && !ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v.", err))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) + } else { + writeResponse(w, "Secret created/updated.", http.StatusCreated) } case "DELETE": - if vaultToken, ok := a.processVaultUserCred(fmt.Sprintf("/org/%v/secrets/%v", org, vaultSecretName), msgPrinter, w, r); ok { - targetURL := fmt.Sprintf("%v/org/%v/secrets/%v", a.Config.GetAgbotVaultURL(), org, vaultSecretName) - // Replace with a call to invoke the vault API at targetURL with the vaultToken generated from authentication - if _, respCode, err := fmt.Sprintf("Token:%v, url:%v", vaultToken, targetURL), http.StatusNoContent, error(nil); err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("Vault invocation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err))) - writeResponse(w, msgPrinter.Sprintf("Vault invovation failure. The caller should retry this API call a small number of times with a short delay between calls to ensure that the vault is really not there. %v.", err), http.StatusServiceUnavailable) - } else if respCode == http.StatusNotFound { - glog.Infof(APIlogString("Secret does not exist.")) - writeResponse(w, msgPrinter.Sprintf("Secret does not exist."), http.StatusNotFound) - } else if respCode == http.StatusNoContent { - // DELETE application logic goes here - glog.Infof(APIlogString("Secret is deleted.")) - writeResponse(w, "Secret is deleted.", http.StatusNoContent) - } + err := a.secretProvider.DeleteOrgSecret(ec.GetExchangeId(), ec.GetExchangeToken(), org, vaultSecretName) + + if serr, ok := err.(secrets.ErrorResponse); err != nil && ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v. %v", serr, serr.Details))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", serr), serr.RespCode) + } else if err != nil && !ok { + glog.Errorf(APIlogString(fmt.Sprintf("Unable to access secrets provider, error: %v.", err))) + writeResponse(w, msgPrinter.Sprintf("Unable to access secrets provider, error: %v.", err), http.StatusInternalServerError) + } else { + writeResponse(w, "Secret is deleted.", http.StatusNoContent) } case "OPTIONS": w.Header().Set("Allow", "GET, PUT, POST, DELETE, OPTIONS") @@ -663,63 +662,6 @@ func (a *SecureAPI) secrets(w http.ResponseWriter, r *http.Request) { } } -func (a *SecureAPI) processVaultUserCred(resource string, msgPrinter *message.Printer, w http.ResponseWriter, r *http.Request) (string, bool) { - // check caller user credentials - userID, userPasswd, ok := r.BasicAuth() - - // extract user org and secret org from API path - userOrg, _ := cutil.SplitOrgSpecUrl(userID) - pathVars := mux.Vars(r) - secretOrg := pathVars["org"] - - if !ok { - glog.Errorf(APIlogString(fmt.Sprintf("%v is called without vault authentication.", resource))) - writeResponse(w, msgPrinter.Sprintf("Unauthorized. No vault user id is supplied."), http.StatusUnauthorized) - return "", false - } else if _, err := a.authenticateWithExchange(userID, userPasswd, msgPrinter); err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("Failed to authenticate user %v with the Exchange. %v", userID, err))) - writeResponse(w, msgPrinter.Sprintf("Failed to authenticate the user with the Exchange. %v", err), http.StatusUnauthorized) - return "", false - } else if tokenID, err := a.authenticateWithVault(userID, userPasswd, msgPrinter); err != nil && userOrg != secretOrg { - // The vault api returns same respCode for invalid credentials and forbidden access to resources - // Hence upon failed authentication unmatching user orgs and secret orgs is a possible casue for failure - glog.Errorf(APIlogString(fmt.Sprintf("Failed to authenticate user %v with the vault. User not in org specified on secret API path.", userID))) - writeResponse(w, msgPrinter.Sprintf("Failed to authenticate the user with the vault. User not in org specified on secret API path."), http.StatusForbidden) - return "", false - } else if err != nil { - glog.Errorf(APIlogString(fmt.Sprintf("Failed to authenticate user %v with the vault. %v", userID, err))) - writeResponse(w, msgPrinter.Sprintf("Failed to authenticate the user with the vault. %v", err), http.StatusUnauthorized) - return "", false - } else { - return tokenID, true - } -} - -// Possibly replace token returned as a part of a vault context -func (a *SecureAPI) authenticateWithVault(user string, userPasswd string, msgPrinter *message.Printer) (string, error) { - glog.V(5).Infof(APIlogString(fmt.Sprintf("authenticateWithVault called with user %v", user))) - - orgID, userID := cutil.SplitOrgSpecUrl(user) - if userID == "" { - return "", fmt.Errorf(msgPrinter.Sprintf("No vault user id is supplied.")) - } else if orgID == "" { - return "", fmt.Errorf(msgPrinter.Sprintf("No vault user org id is supplied.")) - } else if userPasswd == "" { - return "", fmt.Errorf(msgPrinter.Sprintf("No vault user password is supplied.")) - } - - // Make the API call to authentication plugin for vault - targetURL := fmt.Sprintf("%v/auth/openhorizon/login", a.Config.AgreementBot.Vault.VaultURL) - if _, respCode, err := fmt.Sprintf("URL:%v", targetURL), http.StatusOK, error(nil); err != nil { - return "", fmt.Errorf(msgPrinter.Sprintf("Vault invocation failure. %v"), err) - } else if respCode == http.StatusOK { - // extract token from response body - return "tokenID", nil - } else { - return "", nil - } -} - // convert the policy check error code to http status code func getHTTPStatusCode(code int) int { var httpCode int diff --git a/test/gov/agbot_apitest.sh b/test/gov/agbot_apitest.sh index a4694e8de..d57560c83 100755 --- a/test/gov/agbot_apitest.sh +++ b/test/gov/agbot_apitest.sh @@ -42,14 +42,18 @@ function results { exit 2 fi - # check if error text - if [ ! -z "$3" ]; then - res=$(echo "$1" | grep "$3") - if [ $? -ne 0 ]; then - echo -e "Error: the response should have contained \"$3\", but did not. \n" - exit 2 + # check if error text contains all of the test text snippets + for (( i=3; i<=$#; i++)) + { + eval TEST_ARG='$'$i + if [ ! -z "$TEST_ARG" ]; then + res=$(echo "$1" | grep "$TEST_ARG") + if [ $? -ne 0 ]; then + echo -e "Error: the response should have contained \"$TEST_ARG\", but did not. \n" + exit 2 + fi fi - fi + } #statements echo -e "Result expected." @@ -456,38 +460,92 @@ check_comp_results "false" "User Input Incompatible" echo "" echo -e "${PREFIX} Start testing for vault secrets API" -if [ "$HZN_VAULT" != "true" ] || [ "$NOVAULT" != "1" ]; then +if [ "$HZN_VAULT" != "true" ] || [ "$NOVAULT" == "1" ]; then echo -e "\n${PREFIX} Skipping agbot API tests for vault\n" exit 0 fi # Later export these from /root/init_vault TEST_VAULT_SECRET_ORG="userdev" -TEST_VAULT_SECRET_NAME="test_secret_name" -api="org/${TEST_VAULT_SECRET_ORG}/secrets/${TEST_VAULT_SECRET_NAME}" +TEST_VAULT_SECRET_NAME="secret" +TEST_VAULT_SECRET_VALUE="${TEST_VAULT_SECRET_NAME}" + +read -d '' create_secret <