[XAPID-1037] refactor and add tests
diff --git a/api.go b/api.go
index d8cbe34..220da6e 100644
--- a/api.go
+++ b/api.go
@@ -15,7 +15,6 @@
package apidVerifyApiKey
import (
- "database/sql"
"encoding/json"
"errors"
"io"
@@ -47,14 +46,14 @@
}
// handle client API
-func (apiManager *apiManager) handleRequest(w http.ResponseWriter, r *http.Request) {
+func (a *apiManager) handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
verifyApiKeyReq, err := validateRequest(r.Body, w)
if err != nil {
return
}
- b, err := apiManager.verifyAPIKey(verifyApiKeyReq)
+ b, err := a.verifyAPIKey(verifyApiKeyReq)
if err != nil {
respStatusCode, atoierr := strconv.Atoi(err.Error())
@@ -91,9 +90,10 @@
log.Debug(verifyApiKeyReq)
// 2. verify params
+ // TODO : make this method of verifyApiKeyReq struct
if verifyApiKeyReq.Action == "" || verifyApiKeyReq.ApiProxyName == "" || verifyApiKeyReq.OrganizationName == "" || verifyApiKeyReq.EnvironmentName == "" || verifyApiKeyReq.Key == "" {
- // TODO : set correct fields in error response
- errorResponse := errorResponse("Bad_REQUEST", "Missing element")
+ // TODO : set correct missing fields in error response
+ errorResponse, _ := json.Marshal(errorResponse("Bad_REQUEST", "Missing element", http.StatusBadRequest))
w.WriteHeader(http.StatusBadRequest)
w.Write(errorResponse)
return verifyApiKeyReq, errors.New("Bad_REQUEST")
@@ -112,25 +112,26 @@
err := apiM.dbMan.getApiKeyDetails(&dataWrapper)
switch {
- case err == sql.ErrNoRows:
+ case err != nil && err.Error() == "InvalidApiKey":
reason := "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
errorCode := "oauth.v2.InvalidApiKey"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ errResponse := errorResponse(reason, errorCode, http.StatusOK)
+ return json.Marshal(errResponse)
case err != nil:
reason := err.Error()
errorCode := "SEARCH_INTERNAL_ERROR"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusInternalServerError))
+ errResponse := errorResponse(reason, errorCode, http.StatusInternalServerError)
+ return json.Marshal(errResponse)
}
- apiProduct := shortListApiProduct(dataWrapper.apiProducts, verifyApiKeyReq)
- dataWrapper.verifyApiKeySuccessResponse.ApiProduct = apiProduct
+ dataWrapper.verifyApiKeySuccessResponse.ApiProduct = shortListApiProduct(dataWrapper.apiProducts, verifyApiKeyReq)
/*
* Perform all validations
*/
- errResponse, err := apiM.performValidations(dataWrapper)
+ errResponse := apiM.performValidations(dataWrapper)
if errResponse != nil {
- return errResponse, err
+ return json.Marshal(&errResponse)
}
apiM.enrichAttributes(&dataWrapper)
@@ -183,79 +184,78 @@
}
}
- // TODO : remove this check from here and let performValidations take care of checking this
- if !verifyApiKeyReq.ValidateAgainstApiProxiesAndEnvs {
- if len(rankedProducts[2]) > 0 {
- return rankedProducts[2][0]
- } else if len(rankedProducts[3]) > 0 {
- return rankedProducts[3][0]
- }
+ if len(rankedProducts[2]) > 0 {
+ return rankedProducts[2][0]
+ } else if len(rankedProducts[3]) > 0 {
+ return rankedProducts[3][0]
}
return bestMathcedProduct
}
-func (apiM apiManager) performValidations(dataWrapper VerifyApiKeyRequestResponseDataWrapper) ([]byte, error) {
+func (apiM apiManager) performValidations(dataWrapper VerifyApiKeyRequestResponseDataWrapper) *ErrorResponse {
clientIdDetails := dataWrapper.verifyApiKeySuccessResponse.ClientId
verifyApiKeyReq := dataWrapper.verifyApiKeyRequest
appDetails := dataWrapper.verifyApiKeySuccessResponse.App
tempDeveloperDetails := dataWrapper.tempDeveloperDetails
cType := dataWrapper.ctype
apiProductDetails := dataWrapper.verifyApiKeySuccessResponse.ApiProduct
+ var reason, errorCode string
if !strings.EqualFold("APPROVED", clientIdDetails.Status) {
- reason := "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
- errorCode := "oauth.v2.ApiKeyNotApproved"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ reason = "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode = "oauth.v2.ApiKeyNotApproved"
}
if !strings.EqualFold("APPROVED", appDetails.Status) {
- reason := "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
- errorCode := "keymanagement.service.invalid_client-app_not_approved"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ reason = "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode = "keymanagement.service.invalid_client-app_not_approved"
}
if !strings.EqualFold("ACTIVE", tempDeveloperDetails.Status) {
- reason := "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
- errorCode := "keymanagement.service.DeveloperStatusNotActive"
+ reason = "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode = "keymanagement.service.DeveloperStatusNotActive"
if cType == "company" {
errorCode = "keymanagement.service.CompanyStatusNotActive"
}
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
}
if dataWrapper.verifyApiKeySuccessResponse.ApiProduct.Id == "" {
- reason := "Path Validation Failed. Product not resolved"
- errorCode := "oauth.v2.InvalidApiKeyForGivenResource"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ reason = "Path Validation Failed. Product not resolved"
+ errorCode = "oauth.v2.InvalidApiKeyForGivenResource"
}
- result := validatePath(apiProductDetails.Resources, verifyApiKeyReq.UriPath)
- if result == false {
- reason := "Path Validation Failed (" + strings.Join(apiProductDetails.Resources, ", ") + " vs " + verifyApiKeyReq.UriPath + ")"
- errorCode := "oauth.v2.InvalidApiKeyForGivenResource"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ result := len(apiProductDetails.Resources) == 0 || validatePath(apiProductDetails.Resources, verifyApiKeyReq.UriPath)
+ if !result {
+ reason = "Path Validation Failed (" + strings.Join(apiProductDetails.Resources, ", ") + " vs " + verifyApiKeyReq.UriPath + ")"
+ errorCode = "oauth.v2.InvalidApiKeyForGivenResource"
}
// TODO : empty check
- if verifyApiKeyReq.ValidateAgainstApiProxiesAndEnvs && !contains(apiProductDetails.Apiproxies, verifyApiKeyReq.ApiProxyName) {
- reason := "Proxy Validation Failed (" + strings.Join(apiProductDetails.Apiproxies, ", ") + " vs " + verifyApiKeyReq.ApiProxyName + ")"
- errorCode := "oauth.v2.InvalidApiKeyForGivenResource"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ if verifyApiKeyReq.ValidateAgainstApiProxiesAndEnvs && (len(apiProductDetails.Apiproxies) > 0 && !contains(apiProductDetails.Apiproxies, verifyApiKeyReq.ApiProxyName)) {
+ reason = "Proxy Validation Failed (" + strings.Join(apiProductDetails.Apiproxies, ", ") + " vs " + verifyApiKeyReq.ApiProxyName + ")"
+ errorCode = "oauth.v2.InvalidApiKeyForGivenResource"
}
/* Verify if the ENV matches */
- if verifyApiKeyReq.ValidateAgainstApiProxiesAndEnvs && !contains(apiProductDetails.Environments, verifyApiKeyReq.EnvironmentName) {
- reason := "ENV Validation Failed (" + strings.Join(apiProductDetails.Environments, ", ") + " vs " + verifyApiKeyReq.EnvironmentName + ")"
- errorCode := "oauth.v2.InvalidApiKeyForGivenResource"
- return errorResponse(reason, errorCode), errors.New(strconv.Itoa(http.StatusOK))
+ if verifyApiKeyReq.ValidateAgainstApiProxiesAndEnvs && (len(apiProductDetails.Environments) > 0 && !contains(apiProductDetails.Environments, verifyApiKeyReq.EnvironmentName)) {
+ reason = "ENV Validation Failed (" + strings.Join(apiProductDetails.Environments, ", ") + " vs " + verifyApiKeyReq.EnvironmentName + ")"
+ errorCode = "oauth.v2.InvalidApiKeyForGivenResource"
+
}
- return nil, nil
+ if errorCode != "" {
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ return nil
}
func (a *apiManager) enrichAttributes(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) {
+
attributeMap := a.dbMan.getKmsAttributes(dataWrapper.tenant_id, dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientId, dataWrapper.tempDeveloperDetails.Id, dataWrapper.verifyApiKeySuccessResponse.ApiProduct.Id, dataWrapper.verifyApiKeySuccessResponse.App.Id)
clientIdAttributes := attributeMap[dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientId]
@@ -269,7 +269,7 @@
dataWrapper.tempDeveloperDetails.Attributes = developerAttributes
}
-func errorResponse(reason, errorCode string) []byte {
+func errorResponse(reason, errorCode string, statusCode int) ErrorResponse {
if errorCode == "SEARCH_INTERNAL_ERROR" {
log.Error(reason)
} else {
@@ -278,7 +278,7 @@
resp := ErrorResponse{
ResponseCode: errorCode,
ResponseMessage: reason,
+ StatusCode: statusCode,
}
- ret, _ := json.Marshal(resp)
- return ret
+ return resp
}
diff --git a/api_ShortListApiProduct_test.go b/api_ShortListApiProduct_test.go
index f604b83..f41e118 100644
--- a/api_ShortListApiProduct_test.go
+++ b/api_ShortListApiProduct_test.go
@@ -130,13 +130,3 @@
}
}
}
-
-func TestShortListApiProductValidateProxyEnv(t *testing.T) {
- for _, td := range shortListApiProductTestData {
- td.req.ValidateAgainstApiProxiesAndEnvs = true
- actual := shortListApiProduct(td.dbData, td.req)
- if actual.Id != td.expectedWhenValidateProxyEnvIsTrue {
- t.Errorf("TestData (%s) ValidateProxyEnv (%t) : expected (%s), actual (%s)", td.testDesc, td.req.ValidateAgainstApiProxiesAndEnvs, td.expectedResult, actual.Id)
- }
- }
-}
diff --git a/api_performValidations_test.go b/api_performValidations_test.go
index 1054308..c6e015d 100644
--- a/api_performValidations_test.go
+++ b/api_performValidations_test.go
@@ -15,6 +15,7 @@
package apidVerifyApiKey
import (
+ "encoding/json"
"github.com/30x/apid-core"
"github.com/30x/apid-core/factory"
"testing"
@@ -212,6 +213,102 @@
},
},
},
+ {
+ testDesc: "resources not configured in db",
+ expectedResult: "",
+ expectedWhenValidateProxyEnvIsTrue: "",
+ dataWrapper: VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ Key: "test-key",
+ OrganizationName: "test-org",
+ UriPath: "/test",
+ ApiProxyName: "test-proxy-name",
+ EnvironmentName: "test-env-name",
+ },
+ tempDeveloperDetails: DeveloperDetails{
+ Status: "ACTIVE",
+ },
+ verifyApiKeySuccessResponse: VerifyApiKeySuccessResponse{
+ ApiProduct: ApiProductDetails{
+ Id: "test-api-product",
+ Resources: []string{},
+ Apiproxies: []string{"test-proxy-name"},
+ Environments: []string{"test-env-name"},
+ Status: "APPROVED",
+ },
+ App: AppDetails{
+ Status: "APPROVED",
+ },
+ ClientId: ClientIdDetails{
+ Status: "APPROVED",
+ },
+ },
+ },
+ },
+ {
+ testDesc: "proxies not configured in db",
+ expectedResult: "",
+ expectedWhenValidateProxyEnvIsTrue: "",
+ dataWrapper: VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ Key: "test-key",
+ OrganizationName: "test-org",
+ UriPath: "/test",
+ ApiProxyName: "test-proxy-name",
+ EnvironmentName: "test-env-name",
+ },
+ tempDeveloperDetails: DeveloperDetails{
+ Status: "ACTIVE",
+ },
+ verifyApiKeySuccessResponse: VerifyApiKeySuccessResponse{
+ ApiProduct: ApiProductDetails{
+ Id: "test-api-product",
+ Resources: []string{"/test"},
+ Apiproxies: []string{},
+ Environments: []string{"test-env-name"},
+ Status: "APPROVED",
+ },
+ App: AppDetails{
+ Status: "APPROVED",
+ },
+ ClientId: ClientIdDetails{
+ Status: "APPROVED",
+ },
+ },
+ },
+ },
+ {
+ testDesc: "environments not configured in db",
+ expectedResult: "",
+ expectedWhenValidateProxyEnvIsTrue: "",
+ dataWrapper: VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ Key: "test-key",
+ OrganizationName: "test-org",
+ UriPath: "/test",
+ ApiProxyName: "test-proxy-name",
+ EnvironmentName: "test-env-name",
+ },
+ tempDeveloperDetails: DeveloperDetails{
+ Status: "ACTIVE",
+ },
+ verifyApiKeySuccessResponse: VerifyApiKeySuccessResponse{
+ ApiProduct: ApiProductDetails{
+ Id: "test-api-product",
+ Resources: []string{"/test"},
+ Apiproxies: []string{"test-proxy-name"},
+ Environments: []string{},
+ Status: "APPROVED",
+ },
+ App: AppDetails{
+ Status: "APPROVED",
+ },
+ ClientId: ClientIdDetails{
+ Status: "APPROVED",
+ },
+ },
+ },
+ },
}
func TestPerformValidation(t *testing.T) {
@@ -221,12 +318,16 @@
log = factory.DefaultServicesFactory().Log()
a := apiManager{}
for _, td := range performValidationsTestData {
- actual, err := a.performValidations(td.dataWrapper)
- if string(actual) != td.expectedResult {
- t.Errorf("TestData (%s) ValidateProxyEnv (%t) : expected (%s), actual (%s)", td.testDesc, td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs, td.expectedResult, string(actual))
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
}
- if err != nil && err.Error() != "200" {
- t.Error("Expected to return 200 status code")
+ if string(actual) != td.expectedResult {
+ t.Errorf("TestData (%s) ValidateProxyEnv (%t) : expected (%s), actual (%s)", td.testDesc, td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs, td.expectedResult, actual)
}
}
}
@@ -239,12 +340,17 @@
a := apiManager{}
for _, td := range performValidationsTestData {
td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
- actual, err := a.performValidations(td.dataWrapper)
- if string(actual) != td.expectedWhenValidateProxyEnvIsTrue {
- t.Errorf("TestData (%s) ValidateProxyEnv (%t) : expected (%s), actual (%s)", td.testDesc, td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs, td.expectedWhenValidateProxyEnvIsTrue, string(actual))
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
}
- if err != nil && err.Error() != "200" {
- t.Error("Expected to return 200 status code")
+ if string(actual) != td.expectedWhenValidateProxyEnvIsTrue {
+
+ t.Errorf("TestData (%s) ValidateProxyEnv (%t) : expected (%s), actual (%s)", td.testDesc, td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs, td.expectedWhenValidateProxyEnvIsTrue, actual)
}
}
}
diff --git a/data.go b/data.go
index 2674a92..695ef8e 100644
--- a/data.go
+++ b/data.go
@@ -254,7 +254,7 @@
if err != nil {
log.Error("error fetching verify apikey details ", err)
- return err
+ return errors.New("InvalidApiKey")
}
if dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl != "" {
diff --git a/verifyAPIKey_suite_test_old.go.bak b/verifyAPIKey_suite_test_old.go.bak
deleted file mode 100644
index ff656a3..0000000
--- a/verifyAPIKey_suite_test_old.go.bak
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2017 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package apidVerifyApiKey
-
-import (
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-
- "github.com/30x/apid-core"
- "github.com/30x/apid-core/factory"
- "io/ioutil"
- //"net/http"
- "net/http/httptest"
- "os"
- "testing"
-)
-
-var (
- testTempDir string
- testServer *httptest.Server
-)
-
-var _ = BeforeSuite(func() {
- apid.Initialize(factory.DefaultServicesFactory())
-
- config := apid.Config()
-
- var err error
- testTempDir, err = ioutil.TempDir("", "api_test")
- Expect(err).NotTo(HaveOccurred())
-
- config.Set("data_path", testTempDir)
-
- apid.InitializePlugins("")
-
- db, err := apid.Data().DB()
- Expect(err).NotTo(HaveOccurred())
- //setDB(db)
- //createTables(db)
- //createApidClusterTables(db)
- //addScopes(db)
- //testServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
- // if req.URL.Path == apiPath {
- // handleRequest(w, req)
- // }
- //}))
-
- createTestData(db)
-})
-
-var _ = AfterSuite(func() {
- apid.Events().Close()
- if testServer != nil {
- testServer.Close()
- }
- os.RemoveAll(testTempDir)
-})
-
-func TestVerifyAPIKey(t *testing.T) {
- RegisterFailHandler(Fail)
- RunSpecs(t, "VerifyAPIKey Suite")
-}
-
-func createTestData(db apid.DB) {
- txn, err := db.Begin()
- Expect(err).ShouldNot(HaveOccurred())
- // api products
- for i := 0; i < 10; i++ {
- generateTestApiProduct(i, txn)
- }
- // developers
- for i := 0; i < 10; i++ {
- generateTestDeveloper(i, txn)
- }
-
- // application
- var j, k int
- for i := 0; i < 10; i++ {
- for j = k; j < 10+k; j++ {
- generateTestApp(j, i, txn)
- }
- k = j
- }
- // app credentials
- for i := 0; i < 10; i++ {
- generateTestAppCreds(i, txn)
- }
- // api product mapper
- for i := 0; i < 10; i++ {
- generateTestApiProductMapper(i, txn)
- }
-
- // Following are data for company
- // api products
- for i := 100; i < 110; i++ {
- generateTestApiProduct(i, txn)
- }
-
- // companies
- for i := 100; i < 110; i++ {
- generateTestCompany(i, txn)
- }
-
- // company developers
- for i := 100; i < 110; i++ {
- generateTestCompanyDeveloper(i, txn)
- }
-
- // application
- k = 100
- for i := 100; i < 110; i++ {
- for j = k; j < 100+k; j++ {
- generateTestAppCompany(j, i, txn)
- }
- k = j
- }
- // app credentials
- for i := 100; i < 110; i++ {
- generateTestAppCreds(i, txn)
- }
- // api product mapper
- for i := 100; i < 110; i++ {
- generateTestApiProductMapper(i, txn)
- }
-
- txn.Commit()
- var count int64
- db.QueryRow("select count(*) from EDGEX_DATA_SCOPE").Scan(&count)
- log.Info("Found ", count)
-}
diff --git a/verifyApiKeyStructs.go b/verifyApiKeyStructs.go
index 49a4b15..8c15778 100644
--- a/verifyApiKeyStructs.go
+++ b/verifyApiKeyStructs.go
@@ -87,6 +87,7 @@
type ErrorResponse struct {
ResponseCode string `json:"response_code,omitempty"`
ResponseMessage string `json:"response_message,omitempty"`
+ StatusCode int `json:"-"`
Kind string `json:"kind,omitempty"`
}