[XAPID-1037] apid verify apikey - enterprise gateway integration
fix structs and add enrichment logic
[XAPID-1037] remove hardcoded tenant_id
[XAPID-1037] refactor verify apikey
[XAPID-1037] refactor verify apikey api impl
refactor verify api key
refactor verify api key
[XAPID-1037] fix some minor bugs
[XAPID-1037] refactor | make object based methods
[XAPID-1037] refactor | make object based methods
[XAPID-1037] refactor and add tests
[XAPID-1037] refactor and add tests
[XAPID-1037] move sql queries to different file
[XAPID-1037] add more tests and fix test suite
[XAPID-1037] add more tests and fix test suite
[XAPID-1037] add more tests and increase coverage
diff --git a/api.go b/api.go
index 9a09920..4da5b50 100644
--- a/api.go
+++ b/api.go
@@ -15,236 +15,285 @@
package apidVerifyApiKey
import (
- "database/sql"
"encoding/json"
- "fmt"
+ "errors"
+ "io"
+ "io/ioutil"
"net/http"
- "net/url"
+ "strings"
)
-type sucResponseDetail struct {
- Key string `json:"key"`
- ExpiresAt int64 `json:"expiresAt"`
- IssuedAt string `json:"issuedAt"`
- Status string `json:"status"`
- Type string `json:"cType"`
- RedirectionURIs string `json:"redirectionURIs"`
- AppId string `json:"appId"`
- AppName string `json:"appName"`
+type apiManagerInterface interface {
+ InitAPI()
+ handleRequest(w http.ResponseWriter, r *http.Request)
+ verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *ErrorResponse)
}
-type errResultDetail struct {
- ErrorCode string `json:"errorCode"`
- Reason string `json:"reason"`
+type apiManager struct {
+ dbMan dbManagerInterface
+ verifiersEndpoint string
+ apiInitialized bool
}
-type kmsResponseSuccess struct {
- RspInfo sucResponseDetail `json:"result"`
- Type string `json:"type"`
-}
-
-type kmsResponseFail struct {
- ErrInfo errResultDetail `json:"result"`
- Type string `json:"type"`
+func (a *apiManager) InitAPI() {
+ if a.apiInitialized {
+ return
+ }
+ services.API().HandleFunc(a.verifiersEndpoint, a.handleRequest).Methods("POST")
+ a.apiInitialized = true
+ log.Debug("API endpoints initialized")
}
// handle client API
-func handleRequest(w http.ResponseWriter, r *http.Request) {
-
- db := getDB()
- if db == nil {
- w.WriteHeader(http.StatusServiceUnavailable)
- w.Write([]byte("initializing"))
- return
- }
-
- err := r.ParseForm()
- if err != nil {
- w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte("Unable to parse form"))
- return
- }
-
- f := r.Form
- elems := []string{"action", "key", "uriPath", "scopeuuid"}
- for _, elem := range elems {
- if f.Get(elem) == "" {
- w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(fmt.Sprintf("Missing element: %s", elem)))
- return
- }
- }
+func (a *apiManager) handleRequest(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
- b, err := verifyAPIKey(f)
- if err != nil {
- log.Errorf("error: %s", err)
- w.WriteHeader(http.StatusInternalServerError)
- w.Write([]byte(err.Error()))
- return
- }
- log.Debugf("handleVerifyAPIKey result %s", b)
- w.Write(b)
+ var returnValue interface{}
+
+ if verifyApiKeyReq, err := validateRequest(r.Body, w); err == nil {
+ verifyApiKeyResponse, errorResponse := a.verifyAPIKey(verifyApiKeyReq)
+
+ if errorResponse != nil {
+ setResponseHeader(errorResponse, w)
+ returnValue = errorResponse
+ } else {
+ returnValue = verifyApiKeyResponse
+ }
+ b, _ := json.Marshal(returnValue)
+ log.Debugf("handleVerifyAPIKey result %s", b)
+ w.Write(b)
+ }
+}
+
+func setResponseHeader(errorResponse *ErrorResponse, w http.ResponseWriter) {
+ if errorResponse.StatusCode != 0 {
+ w.WriteHeader(errorResponse.StatusCode)
+ } else {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
+}
+
+func validateRequest(requestBody io.ReadCloser, w http.ResponseWriter) (VerifyApiKeyRequest, error) {
+ // 1. read request boby
+ var verifyApiKeyReq VerifyApiKeyRequest
+ body, err := ioutil.ReadAll(requestBody)
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte(err.Error()))
+ return verifyApiKeyReq, errors.New("Bad_REQUEST")
+ }
+ log.Debug(string(body))
+ // 2. umarshall json to struct
+ err = json.Unmarshal(body, &verifyApiKeyReq)
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write([]byte(err.Error()))
+ return verifyApiKeyReq, errors.New("Bad_REQUEST")
+ }
+ log.Debug(verifyApiKeyReq)
+
+ // 2. verify params
+ if isValid, err := verifyApiKeyReq.validate(); !isValid {
+ errorResponse, _ := json.Marshal(errorResponse("Bad_REQUEST", err.Error(), http.StatusBadRequest))
+ w.WriteHeader(http.StatusBadRequest)
+ w.Write(errorResponse)
+ return verifyApiKeyReq, errors.New("Bad_REQUEST")
+ }
+ return verifyApiKeyReq, nil
}
// returns []byte to be written to client
-func verifyAPIKey(f url.Values) ([]byte, error) {
+func (apiM apiManager) verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *ErrorResponse) {
- key := f.Get("key")
- scopeuuid := f.Get("scopeuuid")
- path := f.Get("uriPath")
- action := f.Get("action")
-
- if key == "" || scopeuuid == "" || path == "" || action != "verify" {
- log.Debug("Input params Invalid/Incomplete")
- reason := "Input Params Incomplete or Invalid"
- errorCode := "INCORRECT_USER_INPUT"
- return errorResponse(reason, errorCode)
+ dataWrapper := VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: verifyApiKeyReq,
}
+ dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientId = verifyApiKeyReq.Key
+ dataWrapper.verifyApiKeySuccessResponse.Environment = verifyApiKeyReq.EnvironmentName
- db := getDB()
+ err := apiM.dbMan.getApiKeyDetails(&dataWrapper)
- // DANGER: This relies on an external TABLE - EDGEX_DATA_SCOPE is maintained by apidApigeeSync
- var env, tenantId string
- err := db.QueryRow("SELECT env, scope FROM EDGEX_DATA_SCOPE WHERE id = ?;", scopeuuid).Scan(&env, &tenantId)
-
- switch err {
- case sql.ErrNoRows:
- log.Error("verifyAPIKey: sql.ErrNoRows")
- reason := "ENV Validation Failed"
- errorCode := "ENV_VALIDATION_FAILED"
- return errorResponse(reason, errorCode)
- case nil:
-
- default:
- reason := err.Error()
- errorCode := "SEARCH_INTERNAL_ERROR"
- return errorResponse(reason, errorCode)
- }
-
- log.Debug("Found tenant_id='", tenantId, "' with env='", env, "' for scopeuuid='", scopeuuid, "'")
-
- sSql := `
- SELECT
- ap.api_resources,
- ap.environments,
- c.issued_at,
- c.status,
- a.callback_url,
- ad.email,
- ad.id,
- "developer" as ctype
- FROM
- KMS_APP_CREDENTIAL AS c
- INNER JOIN KMS_APP AS a ON c.app_id = a.id
- INNER JOIN KMS_DEVELOPER AS ad
- ON ad.id = a.developer_id
- INNER JOIN KMS_APP_CREDENTIAL_APIPRODUCT_MAPPER as mp
- ON mp.appcred_id = c.id
- INNER JOIN KMS_API_PRODUCT as ap ON ap.id = mp.apiprdt_id
- WHERE (UPPER(ad.status) = 'ACTIVE'
- AND mp.apiprdt_id = ap.id
- AND mp.app_id = a.id
- AND mp.appcred_id = c.id
- AND UPPER(mp.status) = 'APPROVED'
- AND UPPER(a.status) = 'APPROVED'
- AND c.id = $1
- AND c.tenant_id = $2)
- UNION ALL
- SELECT
- ap.api_resources,
- ap.environments,
- c.issued_at,
- c.status,
- a.callback_url,
- ad.name,
- ad.id,
- "company" as ctype
- FROM
- KMS_APP_CREDENTIAL AS c
- INNER JOIN KMS_APP AS a ON c.app_id = a.id
- INNER JOIN KMS_COMPANY AS ad
- ON ad.id = a.company_id
- INNER JOIN KMS_APP_CREDENTIAL_APIPRODUCT_MAPPER as mp
- ON mp.appcred_id = c.id
- INNER JOIN KMS_API_PRODUCT as ap ON ap.id = mp.apiprdt_id
- WHERE (UPPER(ad.status) = 'ACTIVE'
- AND mp.apiprdt_id = ap.id
- AND mp.app_id = a.id
- AND mp.appcred_id = c.id
- AND UPPER(mp.status) = 'APPROVED'
- AND UPPER(a.status) = 'APPROVED'
- AND c.id = $1
- AND c.tenant_id = $2)
- ;`
-
- /* these fields need to be nullable types for scanning. This is because when using json snapshots,
- and therefore being responsible for inserts, we were able to default everything to be not null. With
- sqlite snapshots, we are not necessarily guaranteed that
- */
- var status, redirectionURIs, appName, appId, resName, resEnv, issuedAt, cType sql.NullString
- err = db.QueryRow(sSql, key, tenantId).Scan(&resName, &resEnv, &issuedAt, &status,
- &redirectionURIs, &appName, &appId, &cType)
switch {
- case err == sql.ErrNoRows:
- reason := "API Key verify failed for (" + key + ", " + scopeuuid + ", " + path + ")"
- errorCode := "REQ_ENTRY_NOT_FOUND"
- return errorResponse(reason, errorCode)
+ case err != nil && err.Error() == "InvalidApiKey":
+ reason := "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode := "oauth.v2.InvalidApiKey"
+ errResponse := errorResponse(reason, errorCode, http.StatusOK)
+ return nil, &errResponse
case err != nil:
reason := err.Error()
errorCode := "SEARCH_INTERNAL_ERROR"
- return errorResponse(reason, errorCode)
+ errResponse := errorResponse(reason, errorCode, http.StatusInternalServerError)
+ return nil, &errResponse
}
+ dataWrapper.verifyApiKeySuccessResponse.ApiProduct = shortListApiProduct(dataWrapper.apiProducts, verifyApiKeyReq)
/*
- * Perform all validations related to the Query made with the data
- * we just retrieved
+ * Perform all validations
*/
- result := validatePath(resName.String, path)
- if result == false {
- reason := "Path Validation Failed (" + resName.String + " vs " + path + ")"
- errorCode := "PATH_VALIDATION_FAILED"
- return errorResponse(reason, errorCode)
-
+ errResponse := apiM.performValidations(dataWrapper)
+ if errResponse != nil {
+ return nil, errResponse
}
- /* Verify if the ENV matches */
- result = validateEnv(resEnv.String, env)
- if result == false {
- reason := "ENV Validation Failed (" + resEnv.String + " vs " + env + ")"
- errorCode := "ENV_VALIDATION_FAILED"
- return errorResponse(reason, errorCode)
- }
+ apiM.enrichAttributes(&dataWrapper)
- var expiresAt int64 = -1
- resp := kmsResponseSuccess{
- Type: "APIKeyContext",
- RspInfo: sucResponseDetail{
- Key: key,
- ExpiresAt: expiresAt,
- IssuedAt: issuedAt.String,
- Status: status.String,
- RedirectionURIs: redirectionURIs.String,
- Type: cType.String,
- AppId: appId.String,
- AppName: appName.String},
- }
- return json.Marshal(resp)
+ setDevOrCompanyInResponseBasedOnCtype(dataWrapper.ctype, dataWrapper.tempDeveloperDetails, &dataWrapper.verifyApiKeySuccessResponse)
+
+ return &dataWrapper.verifyApiKeySuccessResponse, nil
}
-func errorResponse(reason, errorCode string) ([]byte, error) {
+func setDevOrCompanyInResponseBasedOnCtype(ctype string, tempDeveloperDetails DeveloperDetails, response *VerifyApiKeySuccessResponse) {
+ if ctype == "developer" {
+ response.Developer = tempDeveloperDetails
+ } else {
+ response.Company = CompanyDetails{
+ Id: tempDeveloperDetails.Id,
+ Name: tempDeveloperDetails.FirstName,
+ DisplayName: tempDeveloperDetails.UserName,
+ Status: tempDeveloperDetails.Status,
+ CreatedAt: tempDeveloperDetails.CreatedAt,
+ CreatedBy: tempDeveloperDetails.CreatedBy,
+ LastmodifiedAt: tempDeveloperDetails.LastmodifiedAt,
+ LastmodifiedBy: tempDeveloperDetails.LastmodifiedBy,
+ Attributes: tempDeveloperDetails.Attributes,
+ }
+ }
+}
+
+func shortListApiProduct(details []ApiProductDetails, verifyApiKeyReq VerifyApiKeyRequest) ApiProductDetails {
+ var bestMathcedProduct ApiProductDetails
+ rankedProducts := make(map[int][]ApiProductDetails)
+ rankedProducts[2] = []ApiProductDetails{}
+ rankedProducts[3] = []ApiProductDetails{}
+
+ for _, apiProd := range details {
+ if len(apiProd.Resources) == 0 || validatePath(apiProd.Resources, verifyApiKeyReq.UriPath) {
+ if len(apiProd.Apiproxies) == 0 || contains(apiProd.Apiproxies, verifyApiKeyReq.ApiProxyName) {
+ if len(apiProd.Environments) == 0 || contains(apiProd.Environments, verifyApiKeyReq.EnvironmentName) {
+ bestMathcedProduct = apiProd
+ return bestMathcedProduct
+ // set rank 1 or just return
+ } else {
+ // set rank to 2
+ rankedProducts[2] = append(rankedProducts[2], apiProd)
+ }
+ } else {
+ // set rank to 3,
+ rankedProducts[3] = append(rankedProducts[3], apiProd)
+ }
+ }
+ }
+
+ 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) *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"
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ if !strings.EqualFold("APPROVED", appDetails.Status) {
+ reason = "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode = "keymanagement.service.invalid_client-app_not_approved"
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ if !strings.EqualFold("ACTIVE", tempDeveloperDetails.Status) {
+ reason = "API Key verify failed for (" + verifyApiKeyReq.Key + ", " + verifyApiKeyReq.OrganizationName + ")"
+ errorCode = "keymanagement.service.DeveloperStatusNotActive"
+ if cType == "company" {
+ errorCode = "keymanagement.service.CompanyStatusNotActive"
+ }
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ if dataWrapper.verifyApiKeySuccessResponse.ApiProduct.Id == "" {
+ reason = "Path Validation Failed. Product not resolved"
+ errorCode = "oauth.v2.InvalidApiKeyForGivenResource"
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ 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"
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+
+ 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"
+ log.Debug("Validation error occoured ", errorCode, " ", reason)
+ ee := errorResponse(reason, errorCode, http.StatusOK)
+ return &ee
+ }
+ /* Verify if the ENV matches */
+ 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"
+ 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]
+ developerAttributes := attributeMap[dataWrapper.tempDeveloperDetails.Id]
+ appAttributes := attributeMap[dataWrapper.verifyApiKeySuccessResponse.App.Id]
+ apiProductAttributes := attributeMap[dataWrapper.verifyApiKeySuccessResponse.ApiProduct.Id]
+
+ dataWrapper.verifyApiKeySuccessResponse.ClientId.Attributes = clientIdAttributes
+ dataWrapper.verifyApiKeySuccessResponse.App.Attributes = appAttributes
+ dataWrapper.verifyApiKeySuccessResponse.ApiProduct.Attributes = apiProductAttributes
+ dataWrapper.tempDeveloperDetails.Attributes = developerAttributes
+}
+
+func errorResponse(reason, errorCode string, statusCode int) ErrorResponse {
if errorCode == "SEARCH_INTERNAL_ERROR" {
log.Error(reason)
} else {
log.Debug(reason)
}
- resp := kmsResponseFail{
- Type: "ErrorResult",
- ErrInfo: errResultDetail{
- Reason: reason,
- ErrorCode: errorCode},
+ resp := ErrorResponse{
+ ResponseCode: errorCode,
+ ResponseMessage: reason,
+ StatusCode: statusCode,
}
- return json.Marshal(resp)
+ return resp
}
diff --git a/api_ShortListApiProduct_test.go b/api_ShortListApiProduct_test.go
new file mode 100644
index 0000000..72c999e
--- /dev/null
+++ b/api_ShortListApiProduct_test.go
@@ -0,0 +1,166 @@
+// 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"
+)
+
+var _ = Describe("verifyApiKey_shortListApiProduct", func() {
+
+ Context("shortListApiProduct tests", func() {
+ It("single-product-happy-path", func() {
+ td := shortListApiProductTestDataStruct{
+ req: VerifyApiKeyRequest{EnvironmentName: "test", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}}},
+ expectedResult: "api-product-1",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-custom-resource-happy-path", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "test", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+ expectedResult: "api-product-2",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-only-one-matches-env", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{"test", "prod", "stage"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+ expectedResult: "api-product-3",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-match-with-no-env", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+ expectedResult: "api-product-3",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-match-env", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod", "stage"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/this-is-my-path"}},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+
+ expectedResult: "api-product-2",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+
+ It("multi-product-match-empty-res-env-proxy", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1"},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod", "stage"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/this-is-my-path"}},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+
+ expectedResult: "api-product-1",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+
+ It("multi-product-match-empty-res-env-proxy-second-indexed", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2"},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ },
+ expectedResult: "api-product-2",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-with-no-resource-match", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2"},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/b/**"}},
+ },
+ expectedResult: "api-product-2",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ It("multi-product-non-existent-proxy", func() {
+ td := shortListApiProductTestDataStruct{
+
+ req: VerifyApiKeyRequest{EnvironmentName: "stage", ApiProxyName: "test-non-exisitent-proxy", UriPath: "/this-is-my-path"},
+ dbData: []ApiProductDetails{
+ ApiProductDetails{Id: "api-product-1", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/a/**"}},
+ ApiProductDetails{Id: "api-product-2", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/**"}},
+ ApiProductDetails{Id: "api-product-3", Environments: []string{"test", "prod"}, Apiproxies: []string{"test-proxy"}, Resources: []string{"/b/**"}},
+ },
+ expectedResult: "api-product-2",
+ }
+
+ actual := shortListApiProduct(td.dbData, td.req)
+ Expect(actual.Id).Should(Equal(td.expectedResult))
+ })
+ })
+
+})
+
+type shortListApiProductTestDataStruct struct {
+ req VerifyApiKeyRequest
+ dbData []ApiProductDetails
+ expectedResult string
+}
diff --git a/api_performValidations_test.go b/api_performValidations_test.go
new file mode 100644
index 0000000..cb97eb0
--- /dev/null
+++ b/api_performValidations_test.go
@@ -0,0 +1,504 @@
+// 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 (
+ "encoding/json"
+ "github.com/30x/apid-core"
+ "github.com/30x/apid-core/factory"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+type performValidationsTestDataStruct struct {
+ testDesc string
+ dataWrapper VerifyApiKeyRequestResponseDataWrapper
+ expectedResult string
+ expectedWhenValidateProxyEnvIsTrue string
+}
+
+var _ = Describe("performValidationsTest", func() {
+
+ apid.Initialize(factory.DefaultServicesFactory())
+ log = factory.DefaultServicesFactory().Log()
+ a := apiManager{}
+
+ Context("performValidationsTest tests", func() {
+ It("happy-path", func() {
+ td := performValidationsTestDataStruct{
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("Inactive Developer", func() {
+ td := performValidationsTestDataStruct{
+ expectedResult: "{\"response_code\":\"keymanagement.service.DeveloperStatusNotActive\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ expectedWhenValidateProxyEnvIsTrue: "{\"response_code\":\"keymanagement.service.DeveloperStatusNotActive\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ dataWrapper: VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ Key: "test-key",
+ OrganizationName: "test-org",
+ UriPath: "/test",
+ ApiProxyName: "test-proxy-name",
+ EnvironmentName: "test-env-name",
+ },
+ tempDeveloperDetails: DeveloperDetails{
+ Status: "INACTIVE",
+ },
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("Revoked Client Id", func() {
+ td := performValidationsTestDataStruct{
+ expectedResult: "{\"response_code\":\"oauth.v2.ApiKeyNotApproved\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ expectedWhenValidateProxyEnvIsTrue: "{\"response_code\":\"oauth.v2.ApiKeyNotApproved\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ 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: "REVOKED",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("Revoked App", func() {
+ td := performValidationsTestDataStruct{
+ expectedResult: "{\"response_code\":\"keymanagement.service.invalid_client-app_not_approved\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ expectedWhenValidateProxyEnvIsTrue: "{\"response_code\":\"keymanagement.service.invalid_client-app_not_approved\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ 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: "REVOKED",
+ },
+ ClientId: ClientIdDetails{
+ Status: "APPROVED",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("Company Inactive", func() {
+ td := performValidationsTestDataStruct{
+ expectedResult: "{\"response_code\":\"keymanagement.service.CompanyStatusNotActive\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ expectedWhenValidateProxyEnvIsTrue: "{\"response_code\":\"keymanagement.service.CompanyStatusNotActive\",\"response_message\":\"API Key verify failed for (test-key, test-org)\"}",
+ dataWrapper: VerifyApiKeyRequestResponseDataWrapper{
+ ctype: "company",
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ Key: "test-key",
+ OrganizationName: "test-org",
+ UriPath: "/test",
+ ApiProxyName: "test-proxy-name",
+ EnvironmentName: "test-env-name",
+ },
+ tempDeveloperDetails: DeveloperDetails{
+ Status: "INACTIVE",
+ },
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("Product not resolved", func() {
+ td := performValidationsTestDataStruct{
+ expectedResult: "{\"response_code\":\"oauth.v2.InvalidApiKeyForGivenResource\",\"response_message\":\"Path Validation Failed. Product not resolved\"}",
+ expectedWhenValidateProxyEnvIsTrue: "{\"response_code\":\"oauth.v2.InvalidApiKeyForGivenResource\",\"response_message\":\"Path Validation Failed. Product not resolved\"}",
+ 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{},
+ App: AppDetails{
+ Status: "APPROVED",
+ },
+ ClientId: ClientIdDetails{
+ Status: "APPROVED",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("resources not configured in db", func() {
+ td := performValidationsTestDataStruct{
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("proxies not configured in db", func() {
+ td := performValidationsTestDataStruct{
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+ It("environments not configured in db", func() {
+ td := performValidationsTestDataStruct{
+ 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",
+ },
+ },
+ },
+ }
+ actualObject := a.performValidations(td.dataWrapper)
+ var actual string
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+
+ td.dataWrapper.verifyApiKeyRequest.ValidateAgainstApiProxiesAndEnvs = true
+ actualObject = a.performValidations(td.dataWrapper)
+ if actualObject != nil {
+ a, _ := json.Marshal(&actualObject)
+ actual = string(a)
+ } else {
+ actual = ""
+ }
+ Expect(actual).Should(Equal(td.expectedResult))
+ })
+
+ })
+})
diff --git a/api_test.go b/api_test.go
index f9b611c..8ba4ebc 100644
--- a/api_test.go
+++ b/api_test.go
@@ -11,157 +11,290 @@
// 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
+// TODO: end to end IT tests
+// 1. happy path for developer
+// 2. happy path for company
+// 3. error case for developer / company
+// 4. input request validation error case
+// 5. key not found case
+
import (
"encoding/json"
+ "errors"
"github.com/30x/apid-core"
+ "github.com/30x/apid-core/factory"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"io/ioutil"
"net/http"
+ "net/http/httptest"
"net/url"
"strconv"
"strings"
+ "sync"
)
-var _ = Describe("api", func() {
+var (
+ testServer *httptest.Server
+)
- Context("DB Inserts/Deletes verification", func() {
+var _ = Describe("end to end tests", func() {
+ var dataTestTempDir string
+ var dbMan *dbManager
- It("should reject a bad key", func() {
- v := url.Values{
- "key": []string{"credential_x"},
- "uriPath": []string{"/test"},
- "scopeuuid": []string{"ABCDE"},
- "action": []string{"verify"},
+ var _ = BeforeEach(func() {
+ var err error
+ dataTestTempDir, err = ioutil.TempDir(testTempDirBase, "api_test_sqlite3")
+ serviceFactoryForTest := factory.DefaultServicesFactory()
+ apid.Initialize(serviceFactoryForTest)
+ config := apid.Config()
+ config.Set("data_path", testTempDir)
+ config.Set("log_level", "DEBUG")
+ serviceFactoryForTest.Config().Set("local_storage_path", dataTestTempDir)
+
+ Expect(err).NotTo(HaveOccurred())
+
+ dbMan = &dbManager{
+ data: serviceFactoryForTest.Data(),
+ dbMux: sync.RWMutex{},
+ }
+ dbMan.setDbVersion(dataTestTempDir)
+ dbMan.initDb()
+
+ apiMan := apiManager{
+ dbMan: dbMan,
+ verifiersEndpoint: apiPath,
+ }
+
+ testServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ if req.URL.Path == apiPath {
+ apiMan.handleRequest(w, req)
}
- rsp, err := verifyAPIKey(v)
+ }))
+
+ })
+
+ Context("veriifyApiKey Api test ", func() {
+ It("should return validation error for missing input fields", func() {
+ var respObj ErrorResponse
+ reqInput := VerifyApiKeyRequest{
+ Key: "test",
+ }
+ jsonBody, _ := json.Marshal(reqInput)
+
+ responseBody, err := performTestOperation(string(jsonBody), 400)
Expect(err).ShouldNot(HaveOccurred())
- var respj kmsResponseFail
- json.Unmarshal(rsp, &respj)
- Expect(respj.Type).Should(Equal("ErrorResult"))
- Expect(respj.ErrInfo.ErrorCode).Should(Equal("REQ_ENTRY_NOT_FOUND"))
-
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.ResponseMessage).Should(Equal("Bad_REQUEST"))
+ Expect(respObj.ResponseCode).Should(Equal("Missing mandatory fields in the request : action organizationName uriPath"))
})
+ It("should return validation error for inavlid key", func() {
+ var respObj ErrorResponse
+ reqInput := VerifyApiKeyRequest{
+ Key: "invalid-key",
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ EnvironmentName: "test",
+ ApiProxyName: "DevApplication",
+ UriPath: "/zoho",
- It("should successfully verify good Developer keys", func() {
- for i := 1; i < 10; i++ {
- resulti := strconv.FormatInt(int64(i), 10)
- v := url.Values{
- "key": []string{"app_credential_" + resulti},
- "uriPath": []string{"/test"},
- "scopeuuid": []string{"ABCDE"},
- "action": []string{"verify"},
- }
- rsp, err := verifyAPIKey(v)
- Expect(err).ShouldNot(HaveOccurred())
-
- var respj kmsResponseSuccess
- json.Unmarshal(rsp, &respj)
- Expect(respj.Type).Should(Equal("APIKeyContext"))
- Expect(respj.RspInfo.Type).Should(Equal("developer"))
- Expect(respj.RspInfo.Key).Should(Equal("app_credential_" + resulti))
+ ValidateAgainstApiProxiesAndEnvs: true,
}
- })
+ jsonBody, _ := json.Marshal(reqInput)
- It("should successfully verify good Company keys", func() {
- for i := 100; i < 110; i++ {
- resulti := strconv.FormatInt(int64(i), 10)
- v := url.Values{
- "key": []string{"app_credential_" + resulti},
- "uriPath": []string{"/test"},
- "scopeuuid": []string{"ABCDE"},
- "action": []string{"verify"},
- }
- rsp, err := verifyAPIKey(v)
- Expect(err).ShouldNot(HaveOccurred())
-
- var respj kmsResponseSuccess
- json.Unmarshal(rsp, &respj)
- Expect(respj.Type).Should(Equal("APIKeyContext"))
- Expect(respj.RspInfo.Type).Should(Equal("company"))
- Expect(respj.RspInfo.Key).Should(Equal("app_credential_" + resulti))
- }
- })
-
- It("should reject a bad key", func() {
-
- uri, err := url.Parse(testServer.URL)
- uri.Path = apiPath
-
- v := url.Values{}
- v.Add("key", "credential_x")
- v.Add("scopeuuid", "ABCDE")
- v.Add("uriPath", "/test")
- v.Add("action", "verify")
-
- client := &http.Client{}
- req, err := http.NewRequest("POST", uri.String(), strings.NewReader(v.Encode()))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
-
- res, err := client.Do(req)
- defer res.Body.Close()
+ responseBody, err := performTestOperation(string(jsonBody), 200)
Expect(err).ShouldNot(HaveOccurred())
- var respj kmsResponseFail
- body, err := ioutil.ReadAll(res.Body)
- Expect(err).ShouldNot(HaveOccurred())
- json.Unmarshal(body, &respj)
- Expect(respj.Type).Should(Equal("ErrorResult"))
- Expect(respj.ErrInfo.ErrorCode).Should(Equal("REQ_ENTRY_NOT_FOUND"))
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.ResponseMessage).Should(Equal("API Key verify failed for (invalid-key, apigee-mcrosrvc-client0001)"))
+ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKey"))
})
+ It("should return validation error for inavlid env", func() {
+ setupApikeyDeveloperTestDb(dbMan.db)
+ var respObj ErrorResponse
+ reqInput := VerifyApiKeyRequest{
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ EnvironmentName: "prod",
+ ApiProxyName: "DevApplication",
+ UriPath: "/zoho",
- It("should report error for no scopes", func() {
- v := url.Values{
- "key": []string{"credential_x"},
- "uriPath": []string{"/test"},
- "scopeuuid": []string{"ABCDE"},
- "action": []string{"verify"},
+ ValidateAgainstApiProxiesAndEnvs: true,
}
+ jsonBody, _ := json.Marshal(reqInput)
- clearDataScopeTable(getDB())
- rsp, err := verifyAPIKey(v)
+ responseBody, err := performTestOperation(string(jsonBody), 200)
Expect(err).ShouldNot(HaveOccurred())
- var respj kmsResponseFail
- json.Unmarshal(rsp, &respj)
- Expect(respj.Type).Should(Equal("ErrorResult"))
- Expect(respj.ErrInfo.ErrorCode).Should(Equal("ENV_VALIDATION_FAILED"))
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.ResponseMessage).Should(Equal("ENV Validation Failed (test vs prod)"))
+ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource"))
+ })
+ It("should return validation error for inavlid resource", func() {
+ setupApikeyDeveloperTestDb(dbMan.db)
+ var respObj ErrorResponse
+ reqInput := VerifyApiKeyRequest{
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ EnvironmentName: "test",
+ ApiProxyName: "DevApplication",
+ UriPath: "/google",
+
+ ValidateAgainstApiProxiesAndEnvs: true,
+ }
+ jsonBody, _ := json.Marshal(reqInput)
+
+ responseBody, err := performTestOperation(string(jsonBody), 200)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.ResponseMessage).Should(Equal("Path Validation Failed. Product not resolved"))
+ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource"))
+ })
+ It("should return validation error for inavlid proxies", func() {
+ setupApikeyDeveloperTestDb(dbMan.db)
+ var respObj ErrorResponse
+ reqInput := VerifyApiKeyRequest{
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ EnvironmentName: "test",
+ ApiProxyName: "Invalid-proxy",
+ UriPath: "/zoho",
+
+ ValidateAgainstApiProxiesAndEnvs: true,
+ }
+ jsonBody, _ := json.Marshal(reqInput)
+
+ responseBody, err := performTestOperation(string(jsonBody), 200)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.ResponseMessage).Should(Equal("Proxy Validation Failed (DevApplication, KeysApplication vs Invalid-proxy)"))
+ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource"))
+ })
+ It("should peform verify api key for developer happy path", func() {
+ setupApikeyDeveloperTestDb(dbMan.db)
+ var respObj VerifyApiKeySuccessResponse
+
+ reqInput := VerifyApiKeyRequest{
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ EnvironmentName: "test",
+ ApiProxyName: "DevApplication",
+ UriPath: "/zoho",
+
+ ValidateAgainstApiProxiesAndEnvs: true,
+ }
+ jsonBody, _ := json.Marshal(reqInput)
+
+ responseBody, err := performTestOperation(string(jsonBody), 200)
+ Expect(err).ShouldNot(HaveOccurred())
+
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.Developer.Id).Should(Equal("209ffd18-37e9-4a67-9e30-a5c40a534b6c"))
+ Expect(respObj.Developer.FirstName).Should(Equal("Woodre"))
+ Expect(respObj.Developer.CreatedAt).Should(Equal("2017-08-08 17:24:09.008+00:00"))
+ Expect(respObj.Developer.LastmodifiedAt).Should(Equal("2017-08-08 17:24:09.008+00:00"))
+ Expect(respObj.Developer.CreatedBy).Should(Equal("defaultUser"))
+ Expect(respObj.Developer.LastmodifiedBy).Should(Equal("defaultUser"))
+ Expect(len(respObj.Developer.Attributes)).Should(Equal(0))
+ Expect(respObj.Developer.Company).Should(Equal(""))
+ Expect(respObj.Developer.Status).Should(Equal("ACTIVE"))
+ Expect(respObj.Developer.UserName).Should(Equal("wilson"))
+ Expect(respObj.Developer.Email).Should(Equal("developer@apigee.com"))
+ Expect(respObj.Developer.LastName).Should(Equal("Wilson"))
+ Expect(len(respObj.Developer.Apps)).Should(Equal(0))
+
+ Expect(respObj.ClientId.ClientId).Should(Equal("63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0"))
+ Expect(respObj.ClientId.Status).Should(Equal("APPROVED"))
+ Expect(respObj.ClientId.Attributes[0].Name).Should(Equal("Device"))
+ Expect(respObj.ClientId.Attributes[0].Value).Should(Equal("ios"))
+ Expect(respObj.ClientId.ClientSecret).Should(Equal("Ui8dcyGW3lA04YdX"))
+ Expect(respObj.ClientId.RedirectURIs[0]).Should(Equal("www.apple.com"))
+
+ Expect(respObj.Company.Id).Should(Equal(""))
+
+ Expect(respObj.App.Id).Should(Equal("d371f05a-7c04-430c-b12d-26cf4e4d5d65"))
+
+ Expect(respObj.ApiProduct.Id).Should(Equal("24987a63-edb9-4d6b-9334-87e1d70df8e3"))
+
+ Expect(respObj.Environment).Should(Equal("test"))
})
- It("should report error for invalid requests", func() {
- v := url.Values{
- "key": []string{"credential_x"},
- "uriPath": []string{"/test"},
- "scopeuuid": []string{"ABCDE"},
- "action": []string{"verify"},
+ It("should peform verify api key for company happy path", func() {
+ setupApikeyCompanyTestDb(dbMan.db)
+ var respObj VerifyApiKeySuccessResponse
+
+ reqInput := VerifyApiKeyRequest{
+ Action: "verify",
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ EnvironmentName: "test",
+ ApiProxyName: "DevApplication",
+ UriPath: "/zoho",
+
+ ValidateAgainstApiProxiesAndEnvs: true,
}
+ jsonBody, _ := json.Marshal(reqInput)
- fields := []string{"key", "uriPath", "scopeuuid", "action"}
- for _, field := range fields {
- tmp := v.Get(field)
- v.Del(field)
+ responseBody, err := performTestOperation(string(jsonBody), 200)
+ Expect(err).ShouldNot(HaveOccurred())
- rsp, err := verifyAPIKey(v)
- Expect(err).ShouldNot(HaveOccurred())
- var respj kmsResponseFail
- json.Unmarshal(rsp, &respj)
- Expect(respj.Type).Should(Equal("ErrorResult"))
- Expect(respj.ErrInfo.ErrorCode).Should(Equal("INCORRECT_USER_INPUT"))
+ json.Unmarshal(responseBody, &respObj)
+ Expect(respObj.Developer.Id).Should(Equal(""))
- v.Set(field, tmp)
- }
+ Expect(respObj.Company.Id).Should(Equal("7834c683-9453-4389-b816-34ca24dfccd9"))
+ Expect(respObj.Company.Name).Should(Equal("DevCompany"))
+ Expect(respObj.Company.CreatedAt).Should(Equal("2017-08-05 19:54:12.359+00:00"))
+ Expect(respObj.Company.LastmodifiedAt).Should(Equal("2017-08-05 19:54:12.359+00:00"))
+ Expect(respObj.Company.CreatedBy).Should(Equal("defaultUser"))
+ Expect(respObj.Company.LastmodifiedBy).Should(Equal("defaultUser"))
+ Expect(len(respObj.Company.Attributes)).Should(Equal(1))
+ Expect(respObj.Company.Attributes[0].Name).Should(Equal("country"))
+ Expect(respObj.Company.Attributes[0].Value).Should(Equal("england"))
+ Expect(respObj.Company.DisplayName).Should(Equal("East India Company"))
+ Expect(respObj.Company.Status).Should(Equal("ACTIVE"))
+ Expect(len(respObj.Developer.Apps)).Should(Equal(0))
+
+ Expect(respObj.ClientId.ClientId).Should(Equal("63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0"))
+ Expect(respObj.ClientId.Status).Should(Equal("APPROVED"))
+ Expect(len(respObj.ClientId.Attributes)).Should(Equal(0))
+ Expect(respObj.ClientId.ClientSecret).Should(Equal("Ui8dcyGW3lA04YdX"))
+ Expect(respObj.ClientId.RedirectURIs[0]).Should(Equal("www.apple.com"))
+
+ Expect(respObj.Company.Id).Should(Equal("7834c683-9453-4389-b816-34ca24dfccd9"))
+
+ Expect(respObj.App.Id).Should(Equal("d371f05a-7c04-430c-b12d-26cf4e4d5d65"))
+
+ Expect(respObj.ApiProduct.Id).Should(Equal("24987a63-edb9-4d6b-9334-87e1d70df8e3"))
+
+ Expect(respObj.Environment).Should(Equal("test"))
})
+
})
})
-func clearDataScopeTable(db apid.DB) {
- txn, _ := db.Begin()
- txn.Exec("DELETE FROM EDGEX_DATA_SCOPE")
- log.Info("clear EDGEX_DATA_SCOPE for test")
- txn.Commit()
+func performTestOperation(jsonBody string, expectedResponseCode int) ([]byte, error) {
+ uri, err := url.Parse(testServer.URL)
+ uri.Path = apiPath
+ client := &http.Client{}
+ httpReq, err := http.NewRequest("POST", uri.String(), strings.NewReader(string(jsonBody)))
+ httpReq.Header.Set("Content-Type", "application/json")
+ res, err := client.Do(httpReq)
+ defer res.Body.Close()
+ responseBody, err := ioutil.ReadAll(res.Body)
+
+ if res.StatusCode != expectedResponseCode {
+ err = errors.New("expected response status code does not match. Expected : " + strconv.Itoa(expectedResponseCode) + " ,actual : " + strconv.Itoa(res.StatusCode))
+ }
+
+ return responseBody, err
}
diff --git a/apidVerifyAPIKey-api.yaml b/apidVerifyAPIKey-api.yaml
index 853330c..7ad84ce 100644
--- a/apidVerifyAPIKey-api.yaml
+++ b/apidVerifyAPIKey-api.yaml
@@ -13,46 +13,39 @@
# limitations under the License.
host: playground.apistudio.io
-swagger: '2.0'
+swagger: "2.0"
info:
- version: 0.0.1
- title: Edge X Verify API Key
- contact:
- name: Apigee, Inc.
- url: http://www.apigee.com/
- email: sales@apigee.com
- license:
- name: Apache 2.0
- url: https://www.apache.org/licenses/LICENSE-2.0
-basePath: /verifiers
+ version: "0.0.1"
+ title: Swagger API
+host: playground.apistudio.io
+basePath: /try/35cd6835-f2ed-4582-a1ae-d10ed29d062b
schemes:
- http
+ - https
consumes:
- application/json
produces:
- application/json
paths:
- /:
- get:
- description: List verifiers
- responses:
- '200':
- description: OK
- schema:
- type: array
- items:
- type: string
- enum:
- - "apikey"
/apikey:
post:
- description: Verify API key valid and return message context
+ tags:
+ - VerifyApiKey
+ summary: Validates the consumer key and returns the attributes associated with apikey,developer,app and apiproduct. Http method is POST but it doesnt mutates any data. POST is used for sending content in the http request.
+ description: 'Verify api key '
+ produces:
+ - application/json
+ consumes:
+ - application/json
parameters:
- name: Authorization
+ description: credentials to authenticate with apid
in: header
required: true
type: string
- description: authCode from /deployments/current
+ - name: gateway
+ in: header
+ type: string
- name: _
in: body
required: true
@@ -60,133 +53,279 @@
$ref: '#/definitions/VerifyAPIKeyRequest'
responses:
'200':
- description: The result of the request
+ description: Success. ApiKey was verified successfully.
schema:
- type: object
- enum:
- - $ref: '#/definitions/VerifyAPIKeyResponseSuccess'
- - $ref: '#/definitions/VerifyAPIKeyResponseFailed'
- examples:
- application/json:
- responseType: APIKeyContext
- resultCode: "SUCCESS"
- result:
- key: abc123
- expiresAt: 1234567890
- issuedAt: 1234567890
- status: abc123
- redirectionURIs: abc123
- appName: abc123
- appId: abc123
- cType: "developer"
+ $ref: '#/definitions/VerifyApiKeySuccessResponse'
+ '401':
+ description: Either clientId,app or developer or company is not valid or status is not approved or entity is not found
+ schema:
+ $ref: '#/definitions/ErrorResponse'
+ '403':
+ description: ClientId is not authorized to access the resourceUri,environment or proxy.
+ schema:
+ $ref: '#/definitions/ErrorResponse'
default:
- description: 4xx or 5xx errors
+ description: Unexpected error.
schema:
$ref: '#/definitions/ErrorResponse'
definitions:
-
- ErrorResult:
- type: object
- required:
- - errorCode
- - reason
- properties:
- errorCode:
- type: number
- reason:
- type: string
-
VerifyAPIKeyRequest:
type: object
required:
- action
- key
- uriPath
- - scopeuuid
+ - organizationName
+ - environmentName
+ - apiProxyName
properties:
action:
- enum:
- - "verify"
+ type: string
key:
type: string
uriPath:
type: string
- scopeuuid:
+ organizationName:
type: string
-
- VerifyAPIKeyResponse:
+ environmentName:
+ type: string
+ apiProxyName:
+ type: string
+ validateAgainstApiProxiesAndEnvs:
+ type: boolean
+ description: when this flag is false, authentication of key and authorization for uripath is done and authorization for apiproxies and environments is skipped. Default is true.
+ VerifyApiKeySuccessResponse:
type: object
- required:
- - type
+ description: 'Response object for the verification of apikey. Verification of apikey response contains details such as developer-id,developer-email-id, other fields and attributes ; app-id,app-name, other fields and attributes; apiproduct-name, fields and attributes ; '
properties:
- type:
+ self:
type: string
- result:
- description: present if type is NOT ErrorResult, override me
+ organization:
+ description: Organization Identifier/Name
+ type: string
+ environment:
+ description: Environment Identifier/Name
+ type: string
+ clientId:
+ description: fields and attributes related to clientId
type: object
- error:
- description: present if type is ErrorResult, override me
+ $ref: '#/definitions/ClientIdDetails'
+ developer:
+ description: fields and attributes related to developer
type: object
+ $ref: '#/definitions/DeveloperDetails'
+ company:
+ description: fields and attributes related to company
+ type: object
+ $ref: '#/definitions/CompanyDetails'
+ app:
+ description: fields and attributes related to app
+ type: object
+ $ref: '#/definitions/AppDetails'
+ apiProduct:
+ description: fields and attributes related to apiProduct
+ type: object
+ $ref: '#/definitions/ApiProductDetails'
- VerifyAPIKeyResponseSuccess:
- allOf:
- - $ref: '#/definitions/VerifyAPIKeyResponse'
- - type: object
- properties:
- result:
- type: object
- properties:
- key:
- type: string
- expiresAt:
- type: integer
- issuedAt:
- type: integer
- status:
- type: string
- redirectionURIs:
- type: string
- appName:
- type: string
- appId:
- type: string
- cType:
- type: string
- example:
- type: "APIKeyContext"
- result:
- key: "abc123"
- expiresAt: 1234567890
- issuedAt: 1234567890
- status: "abc123"
- redirectionURIs: "abc123"
- appName: "abc123"
- appId: "abc123"
- cType: "company OR developer"
-
- VerifyAPIKeyResponseFailed:
- allOf:
- - $ref: '#/definitions/VerifyAPIKeyResponse'
- - type: object
- properties:
- error:
- $ref: '#/definitions/ErrorResult'
- example:
- type: "ErrorResult"
- error:
- errorCode: 606
- reason: "APIKey expired"
-
+ identifier:
+ description: Identifier of the authorization code. This will be unique for each request.
+ type: string
+ kind:
+ type: string
ErrorResponse:
- required:
- - errorCode
- - reason
+ type: object
+ description: Error response returned
properties:
- errorCode:
- type: number
- reason:
+ response_code:
+ type: integer
+ format: int32
+ response_message:
type: string
- example:
- errorCode: 607
- reason: "Something wrong!"
+ kind:
+ type: string
+ Attribute:
+ type: object
+ description: Attribute details
+ properties:
+ Name:
+ type: string
+ Value:
+ type: string
+ kind:
+ type: string
+ ClientIdDetails:
+ type: object
+ description: Fields related to consumer key
+ properties:
+ clientId:
+ type: string
+ clientSecret:
+ type: string
+ redirectURIs:
+ type: array
+ items:
+ type: string
+ status:
+ type: string
+ attributes:
+ description: Attributes associated with the client Id.
+ type: array
+ items:
+ $ref: '#/definitions/Attribute'
+ DeveloperDetails:
+ type: object
+ description: Fields related to developer
+ properties:
+ id:
+ type: string
+ userName:
+ type: string
+ firstName:
+ type: string
+ lastName:
+ type: string
+ email:
+ type: string
+ status:
+ type: string
+ apps:
+ type: array
+ items:
+ type: string
+ created_at:
+ type: integer
+ format: int64
+ created_by:
+ type: string
+ lastmodified_at:
+ type: integer
+ format: int64
+ lastmodified_by:
+ type: string
+ company:
+ type: string
+ attributes:
+ description: Attributes associated with the developer.
+ type: array
+ items:
+ $ref: '#/definitions/Attribute'
+ CompanyDetails:
+ type: object
+ description: Fields related to company
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ displayName:
+ type: string
+ status:
+ type: string
+ apps:
+ type: array
+ items:
+ type: string
+ created_at:
+ type: integer
+ format: int64
+ created_by:
+ type: string
+ lastmodified_at:
+ type: integer
+ format: int64
+ lastmodified_by:
+ type: string
+ attributes:
+ description: Attributes associated with the company.
+ type: array
+ items:
+ $ref: '#/definitions/Attribute'
+ AppDetails:
+ type: object
+ description: Fields related to app
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ accessType:
+ type: string
+ callbackUrl:
+ type: string
+ displayName:
+ type: string
+ status:
+ type: string
+ apiproducts:
+ type: array
+ items:
+ type: string
+ appFamily:
+ type: string
+ created_at:
+ type: integer
+ format: int64
+ created_by:
+ type: string
+ lastmodified_at:
+ type: integer
+ format: int64
+ lastmodified_by:
+ type: string
+ company:
+ type: string
+ attributes:
+ description: Attributes associated with the app.
+ type: array
+ items:
+ $ref: '#/definitions/Attribute'
+ ApiProductDetails:
+ type: object
+ description: Fields related to app
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ displayName:
+ type: string
+ quota.limit:
+ type: integer
+ format: int64
+ quota.interval:
+ type: integer
+ format: int64
+ quota.timeunit:
+ type: integer
+ format: int64
+ status:
+ type: string
+ created_at:
+ type: integer
+ format: int64
+ created_by:
+ type: string
+ lastmodified_at:
+ type: integer
+ format: int64
+ lastmodified_by:
+ type: string
+ company:
+ type: string
+ environments:
+ type: array
+ items:
+ type: string
+ apiproxies:
+ type: array
+ items:
+ type: string
+ attributes:
+ description: Attributes associated with the apiproduct.
+ type: array
+ items:
+ $ref: '#/definitions/Attribute'
+
+
+
diff --git a/data.go b/data.go
new file mode 100644
index 0000000..65583b7
--- /dev/null
+++ b/data.go
@@ -0,0 +1,193 @@
+// 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 (
+ "database/sql"
+ "errors"
+ "github.com/30x/apid-core"
+ "strings"
+ "sync"
+)
+
+type dbManager struct {
+ data apid.DataService
+ db apid.DB
+ dbMux sync.RWMutex
+ dbVersion string
+}
+
+func (dbc *dbManager) setDbVersion(version string) {
+ db, err := dbc.data.DBVersion(version)
+ if err != nil {
+ log.Panicf("Unable to access database: %v", err)
+ }
+ dbc.dbMux.Lock()
+ dbc.db = db
+ dbc.dbMux.Unlock()
+ dbc.dbVersion = version
+ // TODO : check if we need to release old db here...
+}
+
+func (dbc *dbManager) getDb() apid.DB {
+ dbc.dbMux.RLock()
+ defer dbc.dbMux.RUnlock()
+ return dbc.db
+}
+
+func (dbc *dbManager) initDb() error {
+ db := dbc.getDb()
+ if db == nil {
+ return errors.New("DB not initialized")
+ }
+ return nil
+}
+
+func (dbc *dbManager) getDbVersion() string {
+ return dbc.dbVersion
+}
+
+type dbManagerInterface interface {
+ setDbVersion(string)
+ initDb() error
+ getDb() apid.DB
+ getDbVersion() string
+ getKmsAttributes(tenantId string, entities ...string) map[string][]Attribute
+ getApiKeyDetails(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) error
+}
+
+func (dbc *dbManager) getKmsAttributes(tenantId string, entities ...string) map[string][]Attribute {
+
+ db := dbc.db
+ var attName, attValue sql.NullString
+ var entity_id string
+ // TODO : is there no other better way to do in caluse???
+ sql := sql_GET_KMS_ATTRIBUTES_FOR_TENANT + ` and entity_id in ('` + strings.Join(entities, `','`) + `')`
+ mapOfAttributes := make(map[string][]Attribute)
+ attributes, err := db.Query(sql, tenantId)
+ if err != nil {
+ log.Error("Error while fetching attributes for tenant id : %s and entityId : %s", tenantId, err)
+ return mapOfAttributes
+ }
+ for attributes.Next() {
+ err := attributes.Scan(
+ &entity_id,
+ &attName,
+ &attValue,
+ )
+ if err != nil {
+ log.Error("error fetching attributes for entityid ", entities, err)
+ }
+ if attName.String != "" {
+ att := Attribute{Name: attName.String, Value: attValue.String}
+ mapOfAttributes[entity_id] = append(mapOfAttributes[entity_id], att)
+ }
+ }
+ log.Debug("attributes returned for query ", sql, " are ", mapOfAttributes)
+ return mapOfAttributes
+}
+
+func (dbc dbManager) getApiKeyDetails(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) error {
+
+ db := dbc.db
+
+ err := db.QueryRow(sql_GET_API_KEY_DETAILS_SQL, dataWrapper.verifyApiKeyRequest.Key, dataWrapper.verifyApiKeyRequest.OrganizationName).
+ Scan(
+ &dataWrapper.ctype,
+ &dataWrapper.tenant_id,
+ &dataWrapper.verifyApiKeySuccessResponse.ClientId.Status,
+ &dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientSecret,
+
+ &dataWrapper.tempDeveloperDetails.Id,
+ &dataWrapper.tempDeveloperDetails.UserName,
+ &dataWrapper.tempDeveloperDetails.FirstName,
+ &dataWrapper.tempDeveloperDetails.LastName,
+ &dataWrapper.tempDeveloperDetails.Email,
+ &dataWrapper.tempDeveloperDetails.Status,
+ &dataWrapper.tempDeveloperDetails.CreatedAt,
+ &dataWrapper.tempDeveloperDetails.CreatedBy,
+ &dataWrapper.tempDeveloperDetails.LastmodifiedAt,
+ &dataWrapper.tempDeveloperDetails.LastmodifiedBy,
+
+ &dataWrapper.verifyApiKeySuccessResponse.App.Id,
+ &dataWrapper.verifyApiKeySuccessResponse.App.Name,
+ &dataWrapper.verifyApiKeySuccessResponse.App.AccessType,
+ &dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl,
+ &dataWrapper.verifyApiKeySuccessResponse.App.DisplayName,
+ &dataWrapper.verifyApiKeySuccessResponse.App.Status,
+ &dataWrapper.verifyApiKeySuccessResponse.App.AppFamily,
+ &dataWrapper.verifyApiKeySuccessResponse.App.Company,
+ &dataWrapper.verifyApiKeySuccessResponse.App.CreatedAt,
+ &dataWrapper.verifyApiKeySuccessResponse.App.CreatedBy,
+ &dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedAt,
+ &dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedBy,
+ )
+
+ if err != nil {
+ log.Debug("error fetching verify apikey details ", err)
+ return errors.New("InvalidApiKey")
+ }
+
+ if dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl != "" {
+ dataWrapper.verifyApiKeySuccessResponse.ClientId.RedirectURIs = []string{dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl}
+ }
+
+ dataWrapper.apiProducts = dbc.getApiProductsForApiKey(dataWrapper.verifyApiKeyRequest.Key, dataWrapper.tenant_id)
+
+ log.Debug("dataWrapper : ", dataWrapper)
+
+ return err
+}
+
+func (dbc dbManager) getApiProductsForApiKey(key, tenantId string) []ApiProductDetails {
+
+ db := dbc.db
+ allProducts := []ApiProductDetails{}
+ var proxies, environments, resources string
+
+ rows, err := db.Query(sql_GET_API_PRODUCTS_FOR_KEY_SQL, key, tenantId)
+
+ if err != nil {
+ log.Error("error fetching apiProduct details", err)
+ return allProducts
+ }
+
+ for rows.Next() {
+ apiProductDetais := ApiProductDetails{}
+ rows.Scan(
+ &apiProductDetais.Id,
+ &apiProductDetais.Name,
+ &apiProductDetais.DisplayName,
+ &apiProductDetais.QuotaLimit,
+ &apiProductDetais.QuotaInterval,
+ &apiProductDetais.QuotaTimeunit,
+ &apiProductDetais.CreatedAt,
+ &apiProductDetais.CreatedBy,
+ &apiProductDetais.LastmodifiedAt,
+ &apiProductDetais.LastmodifiedBy,
+ &proxies,
+ &environments,
+ &resources,
+ )
+ apiProductDetais.Apiproxies = jsonToStringArray(proxies)
+ apiProductDetais.Environments = jsonToStringArray(environments)
+ apiProductDetais.Resources = jsonToStringArray(resources)
+
+ allProducts = append(allProducts, apiProductDetais)
+ }
+
+ log.Debug("Api products retrieved for key : [%s] , tenantId : [%s] is ", key, tenantId, allProducts)
+
+ return allProducts
+}
diff --git a/data_helper_test.go b/data_helper_test.go
new file mode 100644
index 0000000..0b3f746
--- /dev/null
+++ b/data_helper_test.go
@@ -0,0 +1,155 @@
+// 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/30x/apid-core"
+ . "github.com/onsi/gomega"
+)
+
+//initialize DB for tests
+func setupApikeyDeveloperTestDb(db apid.DB) {
+ _, err := db.Exec(`CREATE TABLE IF NOT EXISTS kms_organization (id text,name text,display_name text,type text,tenant_id text,customer_id text,description text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_organization" VALUES('85629786-37c5-4e8c-bb45-208f3360d005','apigee-mcrosrvc-client0001','apigee-mcrosrvc-client0001','trial','bc811169','2277ba6c-8991-4a38-a5fc-12d8d36e5812','','2017-07-03 19:21:09.388+00:00','defaultUser','2017-07-05 16:24:35.413+00:00','rajanish@apigee.com','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE kms_developer (id text,tenant_id text,username text,first_name text,last_name text,password text,email text,status text,encrypted_password text,salt text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_developer" VALUES('209ffd18-37e9-4a67-9e30-a5c40a534b6c','bc811169','wilson','Woodre','Wilson','','developer@apigee.com','ACTIVE','','','2017-08-08 17:24:09.008+00:00','defaultUser','2017-08-08 17:24:09.008+00:00','defaultUser','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_company (id text,tenant_id text,name text,display_name text,status text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_company" VALUES('7834c683-9453-4389-b816-34ca24dfccd9','bc811169','DevCompany','East India Company','ACTIVE','2017-08-05 19:54:12.359+00:00','defaultUser','2017-08-05 19:54:12.359+00:00','defaultUser','bc811169');`)
+
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app (id text,tenant_id text,name text,display_name text,access_type text,callback_url text,status text,app_family text,company_id text,developer_id text,parent_id text,type text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_app" VALUES('d371f05a-7c04-430c-b12d-26cf4e4d5d65','bc811169','DeveloperApp','','READ','www.apple.com','APPROVED','default','','209ffd18-37e9-4a67-9e30-a5c40a534b6c','209ffd18-37e9-4a67-9e30-a5c40a534b6c','DEVELOPER','2017-08-07 17:00:54.25+00:00','defaultUser','2017-08-07 17:09:08.259+00:00','defaultUser','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE kms_api_product (id text,tenant_id text,name text,display_name text,description text,api_resources text,approval_type text,scopes text,proxies text,environments text,quota text,quota_time_unit text,quota_interval integer,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_api_product" VALUES('24987a63-edb9-4d6b-9334-87e1d70df8e3','bc811169','KeyProduct4','Sandbox Diamond','','{/zoho,/twitter,/nike}','AUTO','{READ,WRITE}','{DevApplication,KeysApplication}','{test}','','',NULL,'2017-08-08 02:53:32.726+00:00','defaultUser','2017-08-08 02:53:32.726+00:00','defaultUser','bc811169')`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app_credential (id text,tenant_id text,consumer_secret text,app_id text,method_type text,status text,issued_at blob,expires_at blob,app_status text,scopes text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO kms_app_credential VALUES('63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','bc811169','Ui8dcyGW3lA04YdX','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','APPROVED','2017-08-07 17:00:54.258+00:00','','','{DELETE}','2017-08-07 17:00:54.258+00:00','-NA-','2017-08-07 17:06:06.242+00:00','-NA-','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app_credential_apiproduct_mapper (tenant_id text,appcred_id text,app_id text,apiprdt_id text,status text,_change_selector text, primary key (tenant_id,appcred_id,app_id,apiprdt_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_app_credential_apiproduct_mapper" VALUES('bc811169','63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','d371f05a-7c04-430c-b12d-26cf4e4d5d65','24987a63-edb9-4d6b-9334-87e1d70df8e3','APPROVED','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_attributes (tenant_id text,entity_id text,cust_id text,org_id text,dev_id text,comp_id text,apiprdt_id text,app_id text,appcred_id text,name text,type text,value text,_change_selector text, primary key (tenant_id,entity_id,name,type));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','','','','','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','Company','APP','Apple','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','7834c683-9453-4389-b816-34ca24dfccd9','','','','7834c683-9453-4389-b816-34ca24dfccd9','','','','country','COMPANY','england','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','','','','','','','63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','Device','APP_CREDENTIAL','ios','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+}
+
+//initialize DB for tests
+func setupApikeyCompanyTestDb(db apid.DB) {
+ _, err := db.Exec(`CREATE TABLE IF NOT EXISTS kms_organization (id text,name text,display_name text,type text,tenant_id text,customer_id text,description text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_organization" VALUES('85629786-37c5-4e8c-bb45-208f3360d005','apigee-mcrosrvc-client0001','apigee-mcrosrvc-client0001','trial','bc811169','2277ba6c-8991-4a38-a5fc-12d8d36e5812','','2017-07-03 19:21:09.388+00:00','defaultUser','2017-07-05 16:24:35.413+00:00','rajanish@apigee.com','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE kms_developer (id text,tenant_id text,username text,first_name text,last_name text,password text,email text,status text,encrypted_password text,salt text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_company (id text,tenant_id text,name text,display_name text,status text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_company" VALUES('7834c683-9453-4389-b816-34ca24dfccd9','bc811169','DevCompany','East India Company','ACTIVE','2017-08-05 19:54:12.359+00:00','defaultUser','2017-08-05 19:54:12.359+00:00','defaultUser','bc811169');`)
+
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app (id text,tenant_id text,name text,display_name text,access_type text,callback_url text,status text,app_family text,company_id text,developer_id text,parent_id text,type text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_app" VALUES('d371f05a-7c04-430c-b12d-26cf4e4d5d65','bc811169','CompApp2','','READ','www.apple.com','APPROVED','default','7834c683-9453-4389-b816-34ca24dfccd9','','7834c683-9453-4389-b816-34ca24dfccd9','COMPANY','2017-08-07 17:00:54.25+00:00','defaultUser','2017-08-07 17:09:08.259+00:00','defaultUser','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE kms_api_product (id text,tenant_id text,name text,display_name text,description text,api_resources text,approval_type text,scopes text,proxies text,environments text,quota text,quota_time_unit text,quota_interval integer,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_api_product" VALUES('24987a63-edb9-4d6b-9334-87e1d70df8e3','bc811169','KeyProduct4','Sandbox Diamond','','{/zoho,/twitter,/nike}','AUTO','{READ,WRITE}','{DevApplication,KeysApplication}','{test}','','',NULL,'2017-08-08 02:53:32.726+00:00','defaultUser','2017-08-08 02:53:32.726+00:00','defaultUser','bc811169')`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app_credential (id text,tenant_id text,consumer_secret text,app_id text,method_type text,status text,issued_at blob,expires_at blob,app_status text,scopes text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (id,tenant_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO kms_app_credential VALUES('63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','bc811169','Ui8dcyGW3lA04YdX','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','APPROVED','2017-08-07 17:00:54.258+00:00','','','{DELETE}','2017-08-07 17:00:54.258+00:00','-NA-','2017-08-07 17:06:06.242+00:00','-NA-','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_app_credential_apiproduct_mapper (tenant_id text,appcred_id text,app_id text,apiprdt_id text,status text,_change_selector text, primary key (tenant_id,appcred_id,app_id,apiprdt_id));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_app_credential_apiproduct_mapper" VALUES('bc811169','63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0','d371f05a-7c04-430c-b12d-26cf4e4d5d65','24987a63-edb9-4d6b-9334-87e1d70df8e3','APPROVED','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+ _, err = db.Exec(`CREATE TABLE IF NOT EXISTS kms_attributes (tenant_id text,entity_id text,cust_id text,org_id text,dev_id text,comp_id text,apiprdt_id text,app_id text,appcred_id text,name text,type text,value text,_change_selector text, primary key (tenant_id,entity_id,name,type));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','','','','','d371f05a-7c04-430c-b12d-26cf4e4d5d65','','Company','APP','Apple','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','7834c683-9453-4389-b816-34ca24dfccd9','','','','7834c683-9453-4389-b816-34ca24dfccd9','','','','country','COMPANY','england','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+
+}
+
+func setupKmsAttributesdata(db apid.DB) {
+
+ _, err := db.Exec(`CREATE TABLE kms_attributes (tenant_id text,entity_id text,cust_id text,org_id text,dev_id text,comp_id text,apiprdt_id text,app_id text,appcred_id text,name text,type text,value text,_change_selector text, primary key (tenant_id,entity_id,name,type));`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','RateLimit','APIPRODUCT','RX100','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','85629786-37c5-4e8c-bb45-208f3360d005','','85629786-37c5-4e8c-bb45-208f3360d005','','','','','','features.isEdgexEnabled','ORGANIZATION','true','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','85629786-37c5-4e8c-bb45-208f3360d005','','85629786-37c5-4e8c-bb45-208f3360d005','','','','','','features.isCpsEnabled','ORGANIZATION','true','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','developer.quota.limit','APIPRODUCT','100','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','developer.quota.interval','APIPRODUCT','10','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','developer.quota.timeunit','APIPRODUCT','minute','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','Threshold','APIPRODUCT','TX100','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','40753e12-a50a-429d-9121-e571eb4e43a9','','','','','40753e12-a50a-429d-9121-e571eb4e43a9','','','access','APIPRODUCT','public','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(``)
+ Expect(err).NotTo(HaveOccurred())
+ _, err = db.Exec(`INSERT INTO "kms_attributes" VALUES('bc811169','2d373ed6-e38f-453b-bb34-6d731d9c4815','','','','','','2d373ed6-e38f-453b-bb34-6d731d9c4815','','DisplayName','APP','demo-app','bc811169');`)
+ Expect(err).NotTo(HaveOccurred())
+}
diff --git a/data_test.go b/data_test.go
new file mode 100644
index 0000000..4d4e8e9
--- /dev/null
+++ b/data_test.go
@@ -0,0 +1,199 @@
+// 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/30x/apid-core"
+ "github.com/30x/apid-core/factory"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "io/ioutil"
+ "sync"
+)
+
+var _ = Describe("DataTest", func() {
+
+ Context("query db to get api key details", func() {
+ var dataTestTempDir string
+ var dbMan *dbManager
+ var _ = BeforeEach(func() {
+ var err error
+ dataTestTempDir, err = ioutil.TempDir(testTempDirBase, "sqlite3")
+
+ s := factory.DefaultServicesFactory()
+ apid.Initialize(s)
+ config := apid.Config()
+ config.Set("local_storage_path", dataTestTempDir)
+
+ Expect(err).NotTo(HaveOccurred())
+
+ dbMan = &dbManager{
+ data: s.Data(),
+ dbMux: sync.RWMutex{},
+ }
+ dbMan.setDbVersion(dataTestTempDir)
+ dbMan.initDb()
+
+ })
+
+ It("should get compnay getApiKeyDetails for happy path", func() {
+ setupApikeyCompanyTestDb(dbMan.db)
+
+ dataWrapper := VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ },
+ }
+ err := dbMan.getApiKeyDetails(&dataWrapper)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(dataWrapper.ctype).Should(BeEquivalentTo("company"))
+ Expect(dataWrapper.tenant_id).Should(BeEquivalentTo("bc811169"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.ClientId.Status).Should(BeEquivalentTo("APPROVED"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientSecret).Should(BeEquivalentTo("Ui8dcyGW3lA04YdX"))
+
+ Expect(dataWrapper.tempDeveloperDetails.Id).Should(BeEquivalentTo("7834c683-9453-4389-b816-34ca24dfccd9"))
+ Expect(dataWrapper.tempDeveloperDetails.UserName).Should(BeEquivalentTo("East India Company"))
+ Expect(dataWrapper.tempDeveloperDetails.FirstName).Should(BeEquivalentTo("DevCompany"))
+ Expect(dataWrapper.tempDeveloperDetails.LastName).Should(BeEquivalentTo(""))
+ Expect(dataWrapper.tempDeveloperDetails.Email).Should(BeEquivalentTo(""))
+ Expect(dataWrapper.tempDeveloperDetails.Status).Should(BeEquivalentTo("ACTIVE"))
+ Expect(dataWrapper.tempDeveloperDetails.CreatedAt).Should(BeEquivalentTo("2017-08-05 19:54:12.359+00:00"))
+ Expect(dataWrapper.tempDeveloperDetails.CreatedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(dataWrapper.tempDeveloperDetails.LastmodifiedAt).Should(BeEquivalentTo("2017-08-05 19:54:12.359+00:00"))
+ Expect(dataWrapper.tempDeveloperDetails.LastmodifiedBy).Should(BeEquivalentTo("defaultUser"))
+
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Id).Should(BeEquivalentTo("d371f05a-7c04-430c-b12d-26cf4e4d5d65"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Name).Should(BeEquivalentTo("CompApp2"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.AccessType).Should(BeEquivalentTo("READ"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl).Should(BeEquivalentTo("www.apple.com"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.DisplayName).Should(BeEquivalentTo(""))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Status).Should(BeEquivalentTo("APPROVED"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.AppFamily).Should(BeEquivalentTo("default"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Company).Should(BeEquivalentTo("7834c683-9453-4389-b816-34ca24dfccd9"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CreatedAt).Should(BeEquivalentTo("2017-08-07 17:00:54.25+00:00"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CreatedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedAt).Should(BeEquivalentTo("2017-08-07 17:09:08.259+00:00"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedBy).Should(BeEquivalentTo("defaultUser"))
+
+ })
+
+ It("should get developer ApiKeyDetails - happy path", func() {
+ setupApikeyDeveloperTestDb(dbMan.db)
+
+ dataWrapper := VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0",
+ },
+ }
+ err := dbMan.getApiKeyDetails(&dataWrapper)
+ Expect(err).NotTo(HaveOccurred())
+
+ Expect(dataWrapper.ctype).Should(BeEquivalentTo("developer"))
+ Expect(dataWrapper.tenant_id).Should(BeEquivalentTo("bc811169"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.ClientId.Status).Should(BeEquivalentTo("APPROVED"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientSecret).Should(BeEquivalentTo("Ui8dcyGW3lA04YdX"))
+
+ Expect(dataWrapper.tempDeveloperDetails.Id).Should(BeEquivalentTo("209ffd18-37e9-4a67-9e30-a5c40a534b6c"))
+ Expect(dataWrapper.tempDeveloperDetails.UserName).Should(BeEquivalentTo("wilson"))
+ Expect(dataWrapper.tempDeveloperDetails.FirstName).Should(BeEquivalentTo("Woodre"))
+ Expect(dataWrapper.tempDeveloperDetails.LastName).Should(BeEquivalentTo("Wilson"))
+ Expect(dataWrapper.tempDeveloperDetails.Email).Should(BeEquivalentTo("developer@apigee.com"))
+ Expect(dataWrapper.tempDeveloperDetails.Status).Should(BeEquivalentTo("ACTIVE"))
+ Expect(dataWrapper.tempDeveloperDetails.CreatedAt).Should(BeEquivalentTo("2017-08-08 17:24:09.008+00:00"))
+ Expect(dataWrapper.tempDeveloperDetails.CreatedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(dataWrapper.tempDeveloperDetails.LastmodifiedAt).Should(BeEquivalentTo("2017-08-08 17:24:09.008+00:00"))
+ Expect(dataWrapper.tempDeveloperDetails.LastmodifiedBy).Should(BeEquivalentTo("defaultUser"))
+
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Id).Should(BeEquivalentTo("d371f05a-7c04-430c-b12d-26cf4e4d5d65"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Name).Should(BeEquivalentTo("DeveloperApp"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.AccessType).Should(BeEquivalentTo("READ"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CallbackUrl).Should(BeEquivalentTo("www.apple.com"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.DisplayName).Should(BeEquivalentTo(""))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Status).Should(BeEquivalentTo("APPROVED"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.AppFamily).Should(BeEquivalentTo("default"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.Company).Should(BeEquivalentTo(""))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CreatedAt).Should(BeEquivalentTo("2017-08-07 17:00:54.25+00:00"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.CreatedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedAt).Should(BeEquivalentTo("2017-08-07 17:09:08.259+00:00"))
+ Expect(dataWrapper.verifyApiKeySuccessResponse.App.LastmodifiedBy).Should(BeEquivalentTo("defaultUser"))
+
+ })
+
+ It("should throw error when apikey not found", func() {
+
+ setupApikeyCompanyTestDb(dbMan.db)
+ dataWrapper := VerifyApiKeyRequestResponseDataWrapper{
+ verifyApiKeyRequest: VerifyApiKeyRequest{
+ OrganizationName: "apigee-mcrosrvc-client0001",
+ Key: "invalid-Jkcc6GENVWGT1Zw5gek7kVJ0",
+ },
+ }
+ err := dbMan.getApiKeyDetails(&dataWrapper)
+ Expect(err).ShouldNot(BeNil())
+ Expect(err.Error()).Should(BeEquivalentTo("InvalidApiKey"))
+ })
+
+ It("should get api products ", func() {
+
+ setupApikeyCompanyTestDb(dbMan.db)
+
+ apiProducts := dbMan.getApiProductsForApiKey("63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0", "bc811169")
+ Expect(len(apiProducts)).Should(BeEquivalentTo(1))
+
+ Expect(apiProducts[0].Id).Should(BeEquivalentTo("24987a63-edb9-4d6b-9334-87e1d70df8e3"))
+ Expect(apiProducts[0].Name).Should(BeEquivalentTo("KeyProduct4"))
+ Expect(apiProducts[0].DisplayName).Should(BeEquivalentTo("Sandbox Diamond"))
+ Expect(apiProducts[0].Status).Should(BeEquivalentTo(""))
+ Expect(apiProducts[0].QuotaTimeunit).Should(BeEquivalentTo(""))
+ Expect(apiProducts[0].QuotaInterval).Should(BeEquivalentTo(0))
+ Expect(apiProducts[0].QuotaLimit).Should(BeEquivalentTo(""))
+
+ Expect(apiProducts[0].Resources).Should(BeEquivalentTo([]string{"/zoho", "/twitter", "/nike"}))
+ Expect(apiProducts[0].Apiproxies).Should(BeEquivalentTo([]string{"DevApplication", "KeysApplication"}))
+ Expect(apiProducts[0].Environments).Should(BeEquivalentTo([]string{"test"}))
+ Expect(apiProducts[0].Company).Should(BeEquivalentTo(""))
+ Expect(len(apiProducts[0].Attributes)).Should(BeEquivalentTo(0))
+
+ Expect(apiProducts[0].CreatedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(apiProducts[0].CreatedAt).Should(BeEquivalentTo("2017-08-08 02:53:32.726+00:00"))
+ Expect(apiProducts[0].LastmodifiedBy).Should(BeEquivalentTo("defaultUser"))
+ Expect(apiProducts[0].LastmodifiedAt).Should(BeEquivalentTo("2017-08-08 02:53:32.726+00:00"))
+
+ })
+
+ It("should return empty array when no api products found", func() {
+
+ setupApikeyCompanyTestDb(dbMan.db)
+ apiProducts := dbMan.getApiProductsForApiKey("invalid-LKJkcc6GENVWGT1Zw5gek7kVJ0", "bc811169")
+ Expect(len(apiProducts)).Should(BeEquivalentTo(0))
+
+ })
+
+ It("should get kms attributes", func() {
+
+ setupKmsAttributesdata(dbMan.db)
+ attributes := dbMan.getKmsAttributes("bc811169", "40753e12-a50a-429d-9121-e571eb4e43a9", "85629786-37c5-4e8c-bb45-208f3360d005", "50321842-d6ee-4e92-91b9-37234a7920c1", "test-invalid")
+ Expect(len(attributes)).Should(BeEquivalentTo(3))
+ Expect(len(attributes["40753e12-a50a-429d-9121-e571eb4e43a9"])).Should(BeEquivalentTo(1))
+ Expect(len(attributes["85629786-37c5-4e8c-bb45-208f3360d005"])).Should(BeEquivalentTo(2))
+ Expect(len(attributes["50321842-d6ee-4e92-91b9-37234a7920c1"])).Should(BeEquivalentTo(5))
+ Expect(len(attributes["test-invalid"])).Should(BeEquivalentTo(0))
+
+ })
+
+ })
+})
diff --git a/init.go b/init.go
index 03d1f0c..a60b40e 100644
--- a/init.go
+++ b/init.go
@@ -25,193 +25,39 @@
)
var (
+ services apid.Services
log apid.LogService
- data apid.DataService
- events apid.EventsService
- unsafeDB apid.DB
- dbMux sync.RWMutex
)
-func getDB() apid.DB {
- dbMux.RLock()
- db := unsafeDB
- dbMux.RUnlock()
- return db
-}
-
-func setDB(db apid.DB) {
- dbMux.Lock()
- unsafeDB = db
- dbMux.Unlock()
-}
-
func init() {
apid.RegisterPlugin(initPlugin)
}
-func initPlugin(services apid.Services) (apid.PluginData, error) {
+func initPlugin(s apid.Services) (apid.PluginData, error) {
+ services = s
+
log = services.Log().ForModule("apidVerifyAPIKey")
log.Debug("start init")
- data = services.Data()
- events = services.Events()
+ log = services.Log()
+ dbMan := &dbManager{
+ data: services.Data(),
+ dbMux: sync.RWMutex{},
+ }
+ dbMan.initDb()
+ apiMan := apiManager{
+ dbMan: dbMan,
+ verifiersEndpoint: apiPath,
+ }
- services.API().HandleFunc(apiPath, handleRequest).Methods("POST")
+ syncHandler := apigeeSyncHandler{
+ dbMan: dbMan,
+ apiMan: apiMan,
+ }
- events.Listen("ApigeeSync", &handler{})
+ syncHandler.initListener(services)
+
log.Debug("end init")
return pluginData, nil
}
-
-func createTables(db apid.DB) {
- _, err := db.Exec(`
-CREATE TABLE IF NOT EXISTS kms_api_product (
- id text,
- tenant_id text,
- name text,
- display_name text,
- description text,
- api_resources text[],
- approval_type text,
- _change_selector text,
- proxies text[],
- environments text[],
- quota text,
- quota_time_unit text,
- quota_interval int,
- created_at int64,
- created_by text,
- updated_at int64,
- updated_by text,
- PRIMARY KEY (tenant_id, id));
-CREATE TABLE IF NOT EXISTS kms_developer (
- id text,
- tenant_id text,
- username text,
- first_name text,
- last_name text,
- password text,
- email text,
- status text,
- encrypted_password text,
- salt text,
- _change_selector text,
- created_at int64,
- created_by text,
- updated_at int64,
- updated_by text,
- PRIMARY KEY (tenant_id, id)
-);
-CREATE TABLE IF NOT EXISTS kms_company (
- id text,
- tenant_id text,
- name text,
- display_name text,
- status text,
- created_at int64,
- created_by text,
- updated_at int64,
- updated_by text,
- _change_selector text,
- PRIMARY KEY (tenant_id, id)
-);
-CREATE TABLE IF NOT EXISTS kms_company_developer (
- tenant_id text,
- company_id text,
- developer_id text,
- roles text[],
- created_at int64,
- created_by text,
- updated_at int64,
- updated_by text,
- _change_selector text,
- PRIMARY KEY (tenant_id, company_id,developer_id)
-);
-CREATE TABLE IF NOT EXISTS kms_app (
- id text,
- tenant_id text,
- name text,
- display_name text,
- access_type text,
- callback_url text,
- status text,
- app_family text,
- company_id text,
- parent_id text,
- developer_id text,
- type int,
- created_at int64,
- created_by text,
- updated_at int64,
- updated_by text,
- _change_selector text,
- PRIMARY KEY (tenant_id, id)
-);
-CREATE TABLE IF NOT EXISTS kms_app_credential (
- id text,
- tenant_id text,
- consumer_secret text,
- app_id text,
- method_type text,
- status text,
- issued_at int64,
- expires_at int64,
- app_status text,
- _change_selector text,
- PRIMARY KEY (tenant_id, id)
-);
-CREATE TABLE IF NOT EXISTS kms_app_credential_apiproduct_mapper (
- tenant_id text,
- appcred_id text,
- app_id text,
- apiprdt_id text,
- _change_selector text,
- status text,
- PRIMARY KEY (appcred_id, app_id, apiprdt_id,tenant_id)
-);
-CREATE INDEX IF NOT EXISTS company_id ON kms_company (id);
-CREATE INDEX IF NOT EXISTS developer_id ON kms_developer (id);
-CREATE INDEX IF NOT EXISTS api_product_id ON kms_api_product (id);
-CREATE INDEX IF NOT EXISTS app_id ON kms_app (id);
-`)
- if err != nil {
- log.Panic("Unable to initialize DB", err)
- }
-}
-
-func createApidClusterTables(db apid.DB) {
- _, err := db.Exec(`
-CREATE TABLE edgex_apid_cluster (
- id text,
- instance_id text,
- name text,
- description text,
- umbrella_org_app_name text,
- created int64,
- created_by text,
- updated int64,
- updated_by text,
- _change_selector text,
- snapshotInfo text,
- lastSequence text,
- PRIMARY KEY (id)
-);
-CREATE TABLE edgex_data_scope (
- id text,
- apid_cluster_id text,
- scope text,
- org text,
- env text,
- created int64,
- created_by text,
- updated int64,
- updated_by text,
- _change_selector text,
- PRIMARY KEY (id)
-);
-`)
- if err != nil {
- log.Panic("Unable to initialize DB", err)
- }
-}
diff --git a/listener.go b/listener.go
index 1acc299..2d2077e 100644
--- a/listener.go
+++ b/listener.go
@@ -19,31 +19,35 @@
"github.com/apigee-labs/transicator/common"
)
-type handler struct {
+const (
+ APIGEE_SYNC_EVENT = "ApigeeSync"
+)
+
+type apigeeSyncHandler struct {
+ dbMan dbManagerInterface
+ apiMan apiManager
}
-func (h *handler) String() string {
+func (h *apigeeSyncHandler) initListener(services apid.Services) {
+ services.Events().Listen(APIGEE_SYNC_EVENT, h)
+}
+
+func (h *apigeeSyncHandler) String() string {
return "verifyAPIKey"
}
-func (h *handler) Handle(e apid.Event) {
-
- snapData, ok := e.(*common.Snapshot)
- if ok {
- processSnapshot(snapData)
- }
- return
+func (h *apigeeSyncHandler) processSnapshot(snapshot *common.Snapshot) {
+ log.Debugf("Snapshot received. Switching to DB version: %s", snapshot.SnapshotInfo)
+ h.dbMan.setDbVersion(snapshot.SnapshotInfo)
+ h.apiMan.InitAPI()
+ log.Debug("Snapshot processed")
}
-func processSnapshot(snapshot *common.Snapshot) {
+func (h *apigeeSyncHandler) Handle(e apid.Event) {
- log.Debugf("Snapshot received. Switching to DB version: %s", snapshot.SnapshotInfo)
-
- db, err := data.DBVersion(snapshot.SnapshotInfo)
- if err != nil {
- log.Panicf("Unable to access database: %v", err)
+ if snapData, ok := e.(*common.Snapshot); ok {
+ h.processSnapshot(snapData)
+ } else {
+ log.Debugf("Received event. No action required for verifyApiKey plugin. Ignoring. %v", e)
}
-
- setDB(db)
- return
}
diff --git a/listener_test.go b/listener_test.go
index 0645677..78ea736 100644
--- a/listener_test.go
+++ b/listener_test.go
@@ -16,62 +16,75 @@
import (
"github.com/30x/apid-core"
+ "github.com/30x/apid-core/factory"
"github.com/apigee-labs/transicator/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ "io/ioutil"
+ "os"
+ "sync"
)
var _ = Describe("listener", func() {
- Context("KMS create/updates verification via changes for Developer", func() {
+ var listnerTestSyncHandler apigeeSyncHandler
+ var listnerTestTempDir string
+ var _ = BeforeEach(func() {
+ var err error
+ listnerTestTempDir, err = ioutil.TempDir("", "listner_test")
+ s := factory.DefaultServicesFactory()
+ apid.Initialize(s)
+ config := apid.Config()
+ config.Set("data_path", listnerTestTempDir)
+ Expect(err).NotTo(HaveOccurred())
- handler := handler{}
+ apid.InitializePlugins("")
+
+ db, err := apid.Data().DB()
+ Expect(err).NotTo(HaveOccurred())
+
+ dbMan := &dbManager{
+ data: s.Data(),
+ dbMux: sync.RWMutex{},
+ db: db,
+ }
+ dbMan.initDb()
+
+ listnerTestSyncHandler = apigeeSyncHandler{
+ dbMan: dbMan,
+ apiMan: apiManager{},
+ }
+
+ listnerTestSyncHandler.initListener(s)
+ })
+
+ var _ = AfterEach(func() {
+ os.RemoveAll(listnerTestTempDir)
+ })
+
+ Context("Apigee Sync Event Processing", func() {
It("should set DB to appropriate version", func() {
-
- saveDb := getDB()
-
s := &common.Snapshot{
SnapshotInfo: "test_snapshot",
Tables: []common.Table{},
}
+ listnerTestSyncHandler.Handle(s)
+ Expect(listnerTestSyncHandler.dbMan.getDbVersion()).Should(BeEquivalentTo(s.SnapshotInfo))
- handler.Handle(s)
+ })
- expectedDB, err := data.DBVersion(s.SnapshotInfo)
- Expect(err).NotTo(HaveOccurred())
+ It("should not change version for chang event", func() {
- Expect(getDB() == expectedDB).Should(BeTrue())
+ version := listnerTestSyncHandler.dbMan.getDbVersion()
+ s := &common.Change{
+ ChangeSequence: 12321,
+ Table: "",
+ }
+ testSyncHandler.Handle(s)
+ Expect(listnerTestSyncHandler.dbMan.getDbVersion() == version).Should(BeTrue())
- //restore the db to the valid one
- setDB(saveDb)
})
})
})
-
-func addScopes(db apid.DB) {
- txn, _ := db.Begin()
- txn.Exec("INSERT INTO EDGEX_DATA_SCOPE (id, _change_selector, apid_cluster_id, scope, org, env) "+
- "VALUES"+
- "($1,$2,$3,$4,$5,$6)",
- "ABCDE",
- "some_cluster_id",
- "some_cluster_id",
- "tenant_id_xxxx",
- "test_org0",
- "Env_0",
- )
- txn.Exec("INSERT INTO EDGEX_DATA_SCOPE (id, _change_selector, apid_cluster_id, scope, org, env) "+
- "VALUES"+
- "($1,$2,$3,$4,$5,$6)",
- "XYZ",
- "test_org0",
- "somecluster_id",
- "tenant_id_0",
- "test_org0",
- "Env_0",
- )
- log.Info("Inserted EDGEX_DATA_SCOPE for test")
- txn.Commit()
-}
diff --git a/pluginData.go b/pluginData.go
index 2c90a87..a48b83c 100644
--- a/pluginData.go
+++ b/pluginData.go
@@ -18,8 +18,8 @@
var pluginData = apid.PluginData{
Name: "apidVerifyAPIKey",
- Version: "0.0.2",
+ Version: "0.0.3",
ExtraData: map[string]interface{}{
- "schemaVersion": "0.0.2",
+ "schemaVersion": "0.0.3",
},
}
diff --git a/sqlQueries.go b/sqlQueries.go
new file mode 100644
index 0000000..504af9a
--- /dev/null
+++ b/sqlQueries.go
@@ -0,0 +1,142 @@
+// 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
+
+const sql_GET_API_KEY_DETAILS_SQL = `
+ SELECT
+ COALESCE("developer","") as ctype,
+ COALESCE(c.tenant_id,""),
+
+ COALESCE(c.status,""),
+ COALESCE(c.consumer_secret,""),
+
+ COALESCE(ad.id,"") as dev_id,
+ COALESCE(ad.username,"") as dev_username,
+ COALESCE(ad.first_name,"") as dev_first_name,
+ COALESCE(ad.last_name,"") as dev_last_name,
+ COALESCE(ad.email,"") as dev_email,
+ COALESCE(ad.status,"") as dev_status,
+ COALESCE(ad.created_at,"") as dev_created_at,
+ COALESCE(ad.created_by,"") as dev_created_by,
+ COALESCE(ad.updated_at,"") as dev_updated_at,
+ COALESCE(ad.updated_by,"") as dev_updated_by,
+
+ COALESCE(a.id,"") as app_id,
+ COALESCE(a.name,"") as app_name,
+ COALESCE(a.access_type,"") as app_access_type,
+ COALESCE(a.callback_url,"") as app_callback_url,
+ COALESCE(a.display_name,"") as app_display_name,
+ COALESCE(a.status,"") as app_status,
+ COALESCE(a.app_family,"") as app_app_family,
+ COALESCE(a.company_id,"") as app_company_id,
+ COALESCE(a.created_at,"") as app_created_at,
+ COALESCE(a.created_by,"") as app_created_by,
+ COALESCE(a.updated_at,"") as app_updated_at,
+ COALESCE(a.updated_by,"") as app_updated_by
+
+ FROM
+ KMS_APP_CREDENTIAL AS c
+ INNER JOIN KMS_APP AS a
+ ON c.app_id = a.id
+ INNER JOIN KMS_DEVELOPER AS ad
+ ON ad.id = a.developer_id
+ INNER JOIN KMS_APP_CREDENTIAL_APIPRODUCT_MAPPER as mp
+ ON mp.appcred_id = c.id
+ INNER JOIN KMS_ORGANIZATION AS o
+ ON o.tenant_id = c.tenant_id
+ WHERE (
+ mp.app_id = a.id
+ AND mp.appcred_id = c.id
+ AND c.id = $1
+ AND o.name = $2)
+ UNION ALL
+ SELECT
+ COALESCE("company","") as ctype,
+ COALESCE(c.tenant_id,""),
+
+ COALESCE(c.status,""),
+ COALESCE(c.consumer_secret,""),
+
+ COALESCE(ad.id,"") as dev_id,
+ COALESCE(ad.display_name,"") as dev_username,
+ COALESCE(ad.name,"") as dev_first_name,
+ COALESCE("","") as dev_last_name,
+ COALESCE("","") as dev_email,
+ COALESCE(ad.status,"") as dev_status,
+ COALESCE(ad.created_at,"") as dev_created_at,
+ COALESCE(ad.created_by,"") as dev_created_by,
+ COALESCE(ad.updated_at,"") as dev_updated_at,
+ COALESCE(ad.updated_by,"") as dev_updated_by,
+
+ COALESCE(a.id,"") as app_id,
+ COALESCE(a.name,"") as app_name,
+ COALESCE(a.access_type,"") as app_access_type,
+ COALESCE(a.callback_url,"") as app_callback_url,
+ COALESCE(a.display_name,"") as app_display_name,
+ COALESCE(a.status,"") as app_status,
+ COALESCE(a.app_family,"") as app_app_family,
+ COALESCE(a.company_id,"") as app_company_id,
+ COALESCE(a.created_at,"") as app_created_at,
+ COALESCE(a.created_by,"") as app_created_by,
+ COALESCE(a.updated_at,"") as app_updated_at,
+ COALESCE(a.updated_by,"") as app_updated_by
+
+ FROM
+ KMS_APP_CREDENTIAL AS c
+ INNER JOIN KMS_APP AS a
+ ON c.app_id = a.id
+ INNER JOIN KMS_COMPANY AS ad
+ ON ad.id = a.company_id
+ INNER JOIN KMS_APP_CREDENTIAL_APIPRODUCT_MAPPER as mp
+ ON mp.appcred_id = c.id
+ INNER JOIN KMS_ORGANIZATION AS o
+ ON o.tenant_id = c.tenant_id
+ WHERE (
+ mp.app_id = a.id
+ AND mp.appcred_id = c.id
+ AND c.id = $1
+ AND o.name = $2)
+ ;`
+
+const sql_GET_API_PRODUCTS_FOR_KEY_SQL = `
+ SELECT
+ COALESCE(ap.id,"") as prod_id,
+ COALESCE(ap.name,"") as prod_name,
+ COALESCE(ap.display_name,"") as prod_display_name,
+ COALESCE(ap.quota,"") as prod_quota,
+ COALESCE(ap.quota_interval, 0) as prod_quota_interval,
+ COALESCE(ap.quota_time_unit,"") as prod_quota_time_unit,
+ COALESCE(ap.created_at,"") as prod_created_at,
+ COALESCE(ap.created_by,"") as prod_created_by,
+ COALESCE(ap.updated_at,"") as prod_updated_at,
+ COALESCE(ap.updated_by,"") as prod_updated_by,
+ COALESCE(ap.proxies,"") as prod_proxies,
+ COALESCE(ap.environments,"") as prod_environments,
+ COALESCE(ap.api_resources,"") as prod_resources
+ FROM
+ KMS_APP_CREDENTIAL AS c
+ INNER JOIN KMS_APP_CREDENTIAL_APIPRODUCT_MAPPER as mp
+ ON mp.appcred_id = c.id
+ INNER JOIN KMS_API_PRODUCT as ap
+ ON ap.id = mp.apiprdt_id
+ WHERE (
+ mp.apiprdt_id = ap.id
+ AND mp.appcred_id = c.id
+ AND mp.status = 'APPROVED'
+ AND c.id = $1
+ AND ap.tenant_id = $2
+ )
+ ;`
+
+const sql_GET_KMS_ATTRIBUTES_FOR_TENANT = "select entity_id, name, value from kms_attributes where tenant_id = $1"
diff --git a/test_helper.go b/test_helper.go
deleted file mode 100644
index 12e135b..0000000
--- a/test_helper.go
+++ /dev/null
@@ -1,101 +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 (
- "database/sql"
- "strconv"
-)
-
-func convertSuffix(i int) string {
- return strconv.FormatInt(int64(i), 10)
-}
-
-func generateTestApiProduct(suffix int, txn *sql.Tx) {
-
- s, err := txn.Prepare("INSERT INTO kms_api_product (id, api_resources, environments, tenant_id, _change_selector) VALUES(?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug : " + err.Error())
- }
- s.Exec("api_product_"+convertSuffix(suffix), "{/**, /test}", "{Env_0, Env_1}",
- "tenant_id_xxxx", "Org_0")
-}
-
-func generateTestDeveloper(suffix int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_developer (id, status, email, first_name, last_name, tenant_id, _change_selector)" +
- "VALUES (?, ?, ?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug : " + err.Error())
- }
- s.Exec("developer_id_"+convertSuffix(suffix), "Active", "test@apigee.com", "Apigee", "Google", "tenant_id_xxxx", "Org_0")
-}
-
-func generateTestCompany(suffix int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_company (id, status, name, display_name, tenant_id, _change_selector)" +
- "VALUES (?, ?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("company_id_"+convertSuffix(suffix), "Active", "Apigee Corporation", "Apigee", "tenant_id_xxxx", "Org_0")
-}
-
-func generateTestCompanyDeveloper(suffix int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_company_developer (developer_id, tenant_id, _change_selector, company_id)" +
- "VALUES (?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("developer_id_"+convertSuffix(suffix), "tenant_id_0", "test_org0", "company_id_"+convertSuffix(suffix))
-}
-
-func generateTestApp(suffix1, suffix2 int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_app (id, developer_id, status, tenant_id, callback_url, _change_selector, parent_id)" +
- " VALUES(?, ?, ?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("application_id_"+convertSuffix(suffix1), "developer_id_"+convertSuffix(suffix2), "Approved", "tenant_id_xxxx",
- "http://apigee.com", "Org_0", "developer_id_"+convertSuffix(suffix2))
-
-}
-
-func generateTestAppCompany(suffix1, suffix2 int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_app (id, company_id, status, tenant_id, callback_url, _change_selector, parent_id)" +
- " VALUES(?, ?, ?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("application_id_"+convertSuffix(suffix1), "company_id_"+convertSuffix(suffix2), "Approved", "tenant_id_xxxx",
- "http://apigee.com", "Org_0", "company_id_"+convertSuffix(suffix2))
-
-}
-
-func generateTestAppCreds(suffix int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_app_credential (id, app_id, status, tenant_id, _change_selector) VALUES(?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("app_credential_"+convertSuffix(suffix), "application_id_"+convertSuffix(suffix), "Approved",
- "tenant_id_xxxx", "Org_0")
-}
-
-func generateTestApiProductMapper(suffix int, txn *sql.Tx) {
- s, err := txn.Prepare("INSERT INTO kms_app_credential_apiproduct_mapper (apiprdt_id, status, app_id, appcred_id, tenant_id, _change_selector) VALUES(?, ?, ?, ?, ?, ?)")
- if err != nil {
- log.Panicf("This is a bug: " + err.Error())
- }
- s.Exec("api_product_"+convertSuffix(suffix), "Approved", "application_id_"+convertSuffix(suffix),
- "app_credential_"+convertSuffix(suffix), "tenant_id_xxxx", "Org_0")
-}
diff --git a/validate_env.go b/validate_env.go
deleted file mode 100644
index 5b1dc4c..0000000
--- a/validate_env.go
+++ /dev/null
@@ -1,35 +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 "strings"
-
-/*
- * Ensure the ENV matches.
- */
-func validateEnv(envLocal string, envInPath string) bool {
- if envInPath == "" {
- return false
- }
- s := strings.TrimPrefix(envLocal, "{")
- s = strings.TrimSuffix(s, "}")
- fs := strings.Split(s, ",")
- for _, a := range fs {
- if a == envInPath {
- return true
- }
- }
- return false
-}
diff --git a/validate_env_test.go b/validate_env_test.go
deleted file mode 100644
index e07e240..0000000
--- a/validate_env_test.go
+++ /dev/null
@@ -1,40 +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"
-)
-
-var _ = Describe("Validate Env", func() {
-
- It("validation1", func() {
- s := validateEnv("{foo,bar}", "foo")
- Expect(s).Should(BeTrue())
- })
- It("validation2", func() {
- s := validateEnv("{foo,bar}", "bar")
- Expect(s).Should(BeTrue())
- })
- It("validation3", func() {
- s := validateEnv("{foo,bar}", "xxx")
- Expect(s).Should(BeFalse())
- })
- It("validation4", func() {
- s := validateEnv("{}", "xxx")
- Expect(s).Should(BeFalse())
- })
-})
diff --git a/verifyAPIKey_suite_test.go b/verifyAPIKey_suite_test.go
index 7a62357..fdf728b 100644
--- a/verifyAPIKey_suite_test.go
+++ b/verifyAPIKey_suite_test.go
@@ -19,45 +19,19 @@
. "github.com/onsi/gomega"
"github.com/30x/apid-core"
- "github.com/30x/apid-core/factory"
- "io/ioutil"
- "net/http"
- "net/http/httptest"
"os"
"testing"
)
+const testTempDirBase = "./tmp/"
+
var (
- testTempDir string
- testServer *httptest.Server
+ testTempDir string
+ testSyncHandler apigeeSyncHandler
)
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)
+ _ = os.MkdirAll(testTempDirBase, os.ModePerm)
})
var _ = AfterSuite(func() {
@@ -65,78 +39,11 @@
if testServer != nil {
testServer.Close()
}
- os.RemoveAll(testTempDir)
+ os.RemoveAll(testTempDirBase)
+
})
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
new file mode 100644
index 0000000..e791c6a
--- /dev/null
+++ b/verifyApiKeyStructs.go
@@ -0,0 +1,162 @@
+package apidVerifyApiKey
+
+import "errors"
+
+type ClientIdDetails struct {
+ ClientId string `json:"clientId,omitempty"`
+ ClientSecret string `json:"clientSecret,omitempty"`
+ RedirectURIs []string `json:"redirectURIs,omitempty"`
+ Status string `json:"status,omitempty"`
+ // Attributes associated with the client Id.
+ Attributes []Attribute `json:"attributes,omitempty"`
+}
+
+type ApiProductDetails struct {
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ DisplayName string `json:"displayName,omitempty"`
+ QuotaLimit string `json:"quota.limit,omitempty"`
+ QuotaInterval int64 `json:"quota.interval,omitempty"`
+ QuotaTimeunit string `json:"quota.timeunit,omitempty"`
+ Status string `json:"status,omitempty"`
+ CreatedAt string `json:"created_at,omitempty"`
+ CreatedBy string `json:"created_by,omitempty"`
+ LastmodifiedAt string `json:"lastmodified_at,omitempty"`
+ LastmodifiedBy string `json:"lastmodified_by,omitempty"`
+ Company string `json:"company,omitempty"`
+ Environments []string `json:"environments,omitempty"`
+ Apiproxies []string `json:"apiproxies,omitempty"`
+ // Attributes associated with the apiproduct.
+ Attributes []Attribute `json:"attributes,omitempty"`
+ Resources []string `json:"-"`
+}
+
+type AppDetails struct {
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ AccessType string `json:"accessType,omitempty"`
+ CallbackUrl string `json:"callbackUrl,omitempty"`
+ DisplayName string `json:"displayName,omitempty"`
+ Status string `json:"status,omitempty"`
+ Apiproducts []string `json:"apiproducts,omitempty"`
+ AppFamily string `json:"appFamily,omitempty"`
+ CreatedAt string `json:"created_at,omitempty"`
+ CreatedBy string `json:"created_by,omitempty"`
+ LastmodifiedAt string `json:"lastmodified_at,omitempty"`
+ LastmodifiedBy string `json:"lastmodified_by,omitempty"`
+ Company string `json:"company,omitempty"`
+ // Attributes associated with the app.
+ Attributes []Attribute `json:"attributes,omitempty"`
+}
+
+type Attribute struct {
+ Name string `json:"name,omitempty"`
+ Value string `json:"value,omitempty"`
+ Kind string `json:"kind,omitempty"`
+}
+
+type CompanyDetails struct {
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ DisplayName string `json:"displayName,omitempty"`
+ Status string `json:"status,omitempty"`
+ Apps []string `json:"apps,omitempty"`
+ CreatedAt string `json:"created_at,omitempty"`
+ CreatedBy string `json:"created_by,omitempty"`
+ LastmodifiedAt string `json:"lastmodified_at,omitempty"`
+ LastmodifiedBy string `json:"lastmodified_by,omitempty"`
+ // Attributes associated with the company.
+ Attributes []Attribute `json:"attributes,omitempty"`
+}
+
+type DeveloperDetails struct {
+ Id string `json:"id,omitempty"`
+ UserName string `json:"userName,omitempty"`
+ FirstName string `json:"firstName,omitempty"`
+ LastName string `json:"lastName,omitempty"`
+ Email string `json:"email,omitempty"`
+ Status string `json:"status,omitempty"`
+ Apps []string `json:"apps,omitempty"`
+ CreatedAt string `json:"created_at,omitempty"`
+ CreatedBy string `json:"created_by,omitempty"`
+ LastmodifiedAt string `json:"lastmodified_at,omitempty"`
+ LastmodifiedBy string `json:"lastmodified_by,omitempty"`
+ Company string `json:"company,omitempty"`
+ // Attributes associated with the developer.
+ Attributes []Attribute `json:"attributes,omitempty"`
+}
+
+type ErrorResponse struct {
+ ResponseCode string `json:"response_code,omitempty"`
+ ResponseMessage string `json:"response_message,omitempty"`
+ StatusCode int `json:"-"`
+ Kind string `json:"kind,omitempty"`
+}
+
+type VerifyApiKeyRequest struct {
+ Action string `json:"action"`
+ Key string `json:"key"`
+ UriPath string `json:"uriPath"`
+ OrganizationName string `json:"organizationName"`
+ EnvironmentName string `json:"environmentName"`
+ ApiProxyName string `json:"apiProxyName"`
+ // when this flag is false, authentication of key and authorization for uripath is done and authorization for apiproxies and environments is skipped. Default is true.
+ ValidateAgainstApiProxiesAndEnvs bool `json:"validateAgainstApiProxiesAndEnvs,omitempty"`
+}
+
+func (v *VerifyApiKeyRequest) validate() (bool, error) {
+ var validationMsg string
+
+ if v.Action == "" {
+ validationMsg += " action"
+ }
+
+ if v.Key == "" {
+ validationMsg += " key"
+ }
+ if v.OrganizationName == "" {
+ validationMsg += " organizationName"
+ }
+ if v.UriPath == "" {
+ validationMsg += " uriPath"
+ }
+ if v.ValidateAgainstApiProxiesAndEnvs {
+ if v.ApiProxyName == "" {
+ validationMsg += " apiProxyName"
+ }
+ if v.EnvironmentName == "" {
+ validationMsg += " environmentName"
+ }
+ }
+
+ if validationMsg != "" {
+ validationMsg = "Missing mandatory fields in the request :" + validationMsg
+ return false, errors.New(validationMsg)
+ }
+ return true, nil
+}
+
+type VerifyApiKeySuccessResponse struct {
+ Self string `json:"self,omitempty"`
+ // Organization Identifier/Name
+ Organization string `json:"organization,omitempty"`
+ // Environment Identifier/Name
+ Environment string `json:"environment,omitempty"`
+ ClientId ClientIdDetails `json:"clientId,omitempty"`
+ Developer DeveloperDetails `json:"developer,omitempty"`
+ Company CompanyDetails `json:"company,omitempty"`
+ App AppDetails `json:"app,omitempty"`
+ ApiProduct ApiProductDetails `json:"apiProduct,omitempty"`
+ // Identifier of the authorization code. This will be unique for each request.
+ Identifier string `json:"identifier,omitempty"`
+ Kind string `json:"kind,omitempty"`
+}
+
+type VerifyApiKeyRequestResponseDataWrapper struct {
+ verifyApiKeyRequest VerifyApiKeyRequest
+ verifyApiKeySuccessResponse VerifyApiKeySuccessResponse
+ tempDeveloperDetails DeveloperDetails
+ apiProducts []ApiProductDetails
+ ctype string
+ tenant_id string
+}
diff --git a/validate_path.go b/verifyApiKeyUtil.go
similarity index 68%
rename from validate_path.go
rename to verifyApiKeyUtil.go
index f170c51..a7d2451 100644
--- a/validate_path.go
+++ b/verifyApiKeyUtil.go
@@ -15,8 +15,10 @@
package apidVerifyApiKey
import (
+ "encoding/json"
"regexp"
"strings"
+ "unicode/utf8"
)
/*
@@ -25,11 +27,8 @@
* "**" gets de-normalized as ".*" and "*" as everything till
* the next "/".
*/
-func validatePath(basePath, requestBase string) bool {
+func validatePath(fs []string, requestBase string) bool {
- s := strings.TrimPrefix(basePath, "{")
- s = strings.TrimSuffix(s, "}")
- fs := strings.Split(s, ",")
for _, a := range fs {
str1 := strings.Replace(a, "**", "(.*)", -1)
str2 := strings.Replace(a, "*", "([^/]+)", -1)
@@ -54,5 +53,28 @@
*/
}
/* if the i/p resource is empty, no checks need to be made */
- return s == ""
+ return len(fs) == 0
+}
+
+func jsonToStringArray(fjson string) []string {
+ var array []string
+ if err := json.Unmarshal([]byte(fjson), &array); err == nil {
+ return array
+ }
+ s := strings.TrimPrefix(fjson, "{")
+ s = strings.TrimSuffix(s, "}")
+ if utf8.RuneCountInString(s) > 0 {
+ array = strings.Split(s, ",")
+ }
+ log.Debug("unmarshall error for string, performing custom unmarshal ", fjson, " and result is : ", array)
+ return array
+}
+
+func contains(givenArray []string, searchString string) bool {
+ for _, element := range givenArray {
+ if element == searchString {
+ return true
+ }
+ }
+ return false
}
diff --git a/verifyApiKeyUtil_test.go b/verifyApiKeyUtil_test.go
new file mode 100644
index 0000000..4e17289
--- /dev/null
+++ b/verifyApiKeyUtil_test.go
@@ -0,0 +1,70 @@
+// 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"
+ "reflect"
+)
+
+var _ = Describe("Validate Env", func() {
+
+ It("validation1", func() {
+ s := contains([]string{"foo", "bar"}, "foo")
+ Expect(s).Should(BeTrue())
+ })
+ It("validation2", func() {
+ s := contains([]string{"foo", "bar"}, "bar")
+ Expect(s).Should(BeTrue())
+ })
+ It("validation3", func() {
+ s := contains([]string{"foo", "bar"}, "xxx")
+ Expect(s).Should(BeFalse())
+ })
+ It("validation4", func() {
+ s := contains([]string{}, "xxx")
+ Expect(s).Should(BeFalse())
+ })
+})
+
+var _ = Describe("Validate jsonToStringArray", func() {
+
+ It("should tranform simple valid json", func() {
+ array := jsonToStringArray("[\"test-1\", \"test-2\"]")
+ Expect(reflect.DeepEqual(array, []string{"test-1", "test-2"})).Should(BeTrue())
+ })
+ It("should tranform simple single valid json", func() {
+ array := jsonToStringArray("[\"test-1\"]")
+ Expect(reflect.DeepEqual(array, []string{"test-1"})).Should(BeTrue())
+ })
+ It("should tranform simple fake json", func() {
+ s := jsonToStringArray("{test-1,test-2}")
+ Expect(reflect.DeepEqual(s, []string{"test-1", "test-2"})).Should(BeTrue())
+ })
+ It("should tranform simple single valued fake json", func() {
+ s := jsonToStringArray("{test-1}")
+ Expect(reflect.DeepEqual(s, []string{"test-1"})).Should(BeTrue())
+ })
+ It("space between fields considered as valid char", func() {
+ s := jsonToStringArray("{test-1, test-2}")
+ Expect(reflect.DeepEqual(s, []string{"test-1", " test-2"})).Should(BeTrue())
+ })
+ It("remove only last braces", func() {
+ s := jsonToStringArray("{test-1,test-2}}")
+ Expect(reflect.DeepEqual(s, []string{"test-1", "test-2}"})).Should(BeTrue())
+ })
+
+})
diff --git a/validate_path_test.go b/verifyApiKeyUtil_validate_path_test.go
similarity index 63%
rename from validate_path_test.go
rename to verifyApiKeyUtil_validate_path_test.go
index 02fc0eb..eb91d8f 100644
--- a/validate_path_test.go
+++ b/verifyApiKeyUtil_validate_path_test.go
@@ -22,87 +22,87 @@
var _ = Describe("Validate Path", func() {
It("validation1", func() {
- s := validatePath("", "/foo")
+ s := validatePath([]string{}, "/foo")
Expect(s).Should(BeTrue())
})
It("validation2", func() {
- s := validatePath("", "foo")
+ s := validatePath([]string{}, "foo")
Expect(s).Should(BeTrue())
})
It("validation3", func() {
- s := validatePath("{}", "foo")
+ s := validatePath([]string{}, "foo")
Expect(s).Should(BeTrue())
})
It("validation4", func() {
- s := validatePath("{/**}", "/foo")
+ s := validatePath([]string{"/**"}, "/foo")
Expect(s).Should(BeTrue())
})
It("validation5", func() {
- s := validatePath("{/**}", "foo")
+ s := validatePath([]string{"/**"}, "foo")
Expect(s).Should(BeFalse())
})
It("validation6", func() {
- s := validatePath("{/**}", "/")
+ s := validatePath([]string{"/**"}, "/")
Expect(s).Should(BeTrue())
})
It("validation7", func() {
- s := validatePath("{/foo/**}", "/")
+ s := validatePath([]string{"/foo/**"}, "/")
Expect(s).Should(BeFalse())
})
It("validation8", func() {
- s := validatePath("{/foo/**}", "/foo/")
+ s := validatePath([]string{"/foo/**"}, "/foo/")
Expect(s).Should(BeTrue())
})
It("validation9", func() {
- s := validatePath("{/foo/**}", "/foo/bar")
+ s := validatePath([]string{"/foo/**"}, "/foo/bar")
Expect(s).Should(BeTrue())
})
It("validation10", func() {
- s := validatePath("{/foo/**}", "foo")
+ s := validatePath([]string{"/foo/**"}, "foo")
Expect(s).Should(BeFalse())
})
It("validation11", func() {
- s := validatePath("{/foo/bar/**}", "/foo/bar/xx/yy")
+ s := validatePath([]string{"/foo/bar/**"}, "/foo/bar/xx/yy")
Expect(s).Should(BeTrue())
})
It("validation12", func() {
- s := validatePath("/foo/bar/*}", "/foo/bar/xxx")
+ s := validatePath([]string{"/foo/bar/*"}, "/foo/bar/xxx")
Expect(s).Should(BeTrue())
})
It("validation13", func() {
- s := validatePath("{/foo/bar/*/}", "/foo/bar/xxx")
+ s := validatePath([]string{"/foo/bar/*/"}, "/foo/bar/xxx")
Expect(s).Should(BeFalse())
})
It("validation14", func() {
- s := validatePath("{/foo/bar/**}", "/foo/bar/xx/yy")
+ s := validatePath([]string{"/foo/bar/**"}, "/foo/bar/xx/yy")
Expect(s).Should(BeTrue())
})
It("validation15", func() {
- s := validatePath("{/foo/*/**/}", "/foo/bar")
+ s := validatePath([]string{"/foo/*/**/"}, "/foo/bar")
Expect(s).Should(BeFalse())
})
It("validation16", func() {
- s := validatePath("{/foo/bar/*/xxx}", "/foo/bar/yyy/xxx")
+ s := validatePath([]string{"/foo/bar/*/xxx"}, "/foo/bar/yyy/xxx")
Expect(s).Should(BeTrue())
})
It("validation17", func() {
- s := validatePath("{/foo/bar/*/xxx/}", "/foo/bar/yyy/xxx")
+ s := validatePath([]string{"/foo/bar/*/xxx/"}, "/foo/bar/yyy/xxx")
Expect(s).Should(BeFalse())
})
It("validation18", func() {
- s := validatePath("{/foo/bar/**/xxx/}", "/foo/bar/aaa/bbb/xxx/")
+ s := validatePath([]string{"/foo/bar/**/xxx/"}, "/foo/bar/aaa/bbb/xxx/")
Expect(s).Should(BeTrue())
})
It("validation19", func() {
- s := validatePath("{/foo/bar/***/xxx/}", "/foo/bar/aaa/bbb/xxx/")
+ s := validatePath([]string{"/foo/bar/***/xxx/"}, "/foo/bar/aaa/bbb/xxx/")
Expect(s).Should(BeTrue())
})
It("validation20", func() {
- s := validatePath("{/foo/, /bar/}", "/foo/")
+ s := validatePath([]string{"/foo/", "/bar/"}, "/foo/")
Expect(s).Should(BeTrue())
})
It("validation21", func() {
- s := validatePath("{/foo/bar/yy*/xxx}", "/foo/bar/yyy/xxx")
+ s := validatePath([]string{"/foo/bar/yy*/xxx"}, "/foo/bar/yyy/xxx")
Expect(s).Should(BeTrue())
})
})