Access Entity (#27) * [ISSUE-67901957] refactor * [ISSUE-67901957] update glide.yaml * [ISSUE-67901957] refactor dbManager * [ISSUE-67901957] add "entities/apiproducts" endpoint * [ISSUE-67901957] fix bug * [ISSUE-67901957] implement all endpoints * [ISSUE-67901957] fix bugs * [ISSUE-67901957] add org * [ISSUE-67901957] fix bugs * [ISSUE-67901957] add tests, change identifiers to outermost * [ISSUE-67901957] add db tests * [ISSUE-67901957] 404 for no resources * [ISSUE-67901957] update glide.yaml * [ISSUE-67901957] fix bug * [ISSUE-67901957] fix bug * [ISSUE-67901957] add api tests * [ISSUE-67901957] do not omit empty json fields * [ISSUE-67901957] update api specs * [ISSUE-67901957] address comments * [ISSUE-67901957] correct typos * [ISSUE-67901957] address comments, prevent SQL injection * [ISSUE-67901957] add coverage to travis
diff --git a/.travis.yml b/.travis.yml index 9a1d122..8ba8205 100644 --- a/.travis.yml +++ b/.travis.yml
@@ -12,4 +12,4 @@ - glide up --strip-vendor script: - - go test $(glide novendor) + - go test -covermode=atomic $(glide novendor)
diff --git a/accessEntity/accessEntity_suite_test.go b/accessEntity/accessEntity_suite_test.go new file mode 100644 index 0000000..7ffc503 --- /dev/null +++ b/accessEntity/accessEntity_suite_test.go
@@ -0,0 +1,56 @@ +// 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 accessEntity + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/apid/apid-core" + "github.com/apid/apid-core/factory" + "github.com/apid/apidVerifyApiKey/common" + "io/ioutil" + "os" + "testing" + "time" +) + +var testTempDirBase string + +func initSetup(s apid.Services) (apid.PluginData, error) { + SetApidServices(s, apid.Log()) + common.SetApidServices(s, s.Log()) + return common.PluginData, nil +} + +var _ = BeforeSuite(func() { + apid.RegisterPlugin(initSetup, common.PluginData) + var err error + testTempDirBase, err = ioutil.TempDir("", "verify_apikey_") + Expect(err).Should(Succeed()) + apid.Initialize(factory.DefaultServicesFactory()) + apid.InitializePlugins("0.0.0") + go services.API().Listen() + time.Sleep(time.Second) +}, 2) + +var _ = AfterSuite(func() { + apid.Events().Close() + Expect(os.RemoveAll(testTempDirBase)).Should(Succeed()) +}) + +func TestVerifyAPIKey(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AccessEntity Suite") +}
diff --git a/accessEntity/api.go b/accessEntity/api.go new file mode 100644 index 0000000..d70306d --- /dev/null +++ b/accessEntity/api.go
@@ -0,0 +1,721 @@ +// 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 accessEntity + +import ( + "encoding/json" + "fmt" + "github.com/apid/apidVerifyApiKey/common" + "net/http" + "strconv" + "strings" +) + +const ( + AccessEntityPath = "/entities" + EndpointApp = "/apps" + EndpointApiProduct = "/apiproducts" + EndpointCompany = "/companies" + EndpointCompanyDeveloper = "/companydevelopers" + EndpointDeveloper = "/developers" + EndpointAppCredentials = "/appcredentials" +) + +const ( + IdentifierAppId = "appid" + IdentifierApiProductName = "apiproductname" + IdentifierAppName = "appname" + IdentifierApiResource = "apiresource" + IdentifierDeveloperId = "developerid" + IdentifierDeveloperEmail = "developeremail" + IdentifierConsumerKey = "consumerkey" + IdentifierCompanyName = "companyname" + IdentifierOrganization = "organization" +) + +const ( + TypeDeveloper = "developer" + TypeCompany = "company" + TypeApp = "app" + TypeConsumerKey = "consumerkey" +) + +const ( + AppTypeDeveloper = "DEVELOPER" + AppTypeCompany = "COMPANY" +) + +const ( + StatusApproved = "APPROVED" + StatusRevoked = "REVOKED" + StatusExpired = "EXPIRED" +) + +var ( + Identifiers = map[string]bool{ + "appid": true, + "apiproductname": true, + "appname": true, + "apiresource": true, + "developerid": true, + "companyname": true, + "developeremail": true, + "consumerkey": true, + } + + ErrInvalidPar = &common.ErrorResponse{ + ResponseCode: strconv.Itoa(INVALID_PARAMETERS), + ResponseMessage: "Invalid Identifiers", + StatusCode: http.StatusBadRequest, + } + + ErrNotFound = &common.ErrorResponse{ + ResponseCode: strconv.Itoa(NOT_FOUND), + ResponseMessage: "Resource Not Found", + StatusCode: http.StatusNotFound, + } + + IdentifierTree = map[string]map[string][]string{ + EndpointApiProduct: { + IdentifierApiProductName: {}, + IdentifierAppId: {IdentifierApiResource}, + IdentifierAppName: {IdentifierApiResource, IdentifierDeveloperEmail, IdentifierDeveloperId, IdentifierCompanyName}, + IdentifierConsumerKey: {IdentifierApiResource}, + }, + EndpointApp: { + IdentifierAppId: {}, + IdentifierAppName: {IdentifierDeveloperEmail, IdentifierDeveloperId, IdentifierCompanyName}, + IdentifierConsumerKey: {}, + }, + EndpointCompany: { + IdentifierAppId: {}, + IdentifierCompanyName: {}, + IdentifierConsumerKey: {}, + }, + EndpointCompanyDeveloper: { + IdentifierCompanyName: {}, + }, + EndpointAppCredentials: { + IdentifierConsumerKey: {}, + }, + EndpointDeveloper: { + IdentifierDeveloperEmail: {}, + IdentifierAppId: {}, + IdentifierDeveloperId: {}, + IdentifierConsumerKey: {}, + }, + } +) + +const ( + INVALID_PARAMETERS = iota + // Server DB Error + DB_ERROR + // Invalid/Wrong Data in DB data. This probably means something wrong happened in upstream PG/Transicator. + DATA_ERROR + // 404 + NOT_FOUND +) + +type ApiManager struct { + DbMan DbManagerInterface + AccessEntityPath string + apiInitialized bool +} + +func (a *ApiManager) InitAPI() { + if a.apiInitialized { + return + } + services.API().HandleFunc(a.AccessEntityPath+EndpointApp, a.HandleApps).Methods("GET") + services.API().HandleFunc(a.AccessEntityPath+EndpointApiProduct, a.HandleApiProducts).Methods("GET") + services.API().HandleFunc(a.AccessEntityPath+EndpointCompany, a.HandleCompanies).Methods("GET") + services.API().HandleFunc(a.AccessEntityPath+EndpointCompanyDeveloper, a.HandleCompanyDevelopers).Methods("GET") + services.API().HandleFunc(a.AccessEntityPath+EndpointDeveloper, a.HandleDevelopers).Methods("GET") + services.API().HandleFunc(a.AccessEntityPath+EndpointAppCredentials, a.HandleAppCredentials).Methods("GET") + a.apiInitialized = true + log.Debug("API endpoints initialized") +} + +func (a *ApiManager) handleEndpoint(endpoint string, w http.ResponseWriter, r *http.Request) { + ids, org, err := extractIdentifiers(r.URL.Query()) + if err != nil { + common.WriteError(w, err.Error(), INVALID_PARAMETERS, http.StatusBadRequest) + } + var res interface{} + var errRes *common.ErrorResponse + switch endpoint { + case EndpointApp: + res, errRes = a.getApp(org, ids) + case EndpointApiProduct: + res, errRes = a.getApiProduct(org, ids) + case EndpointCompany: + res, errRes = a.getCompany(org, ids) + case EndpointCompanyDeveloper: + res, errRes = a.getCompanyDeveloper(org, ids) + case EndpointDeveloper: + res, errRes = a.getDeveloper(org, ids) + case EndpointAppCredentials: + res, errRes = a.getAppCredential(org, ids) + } + + if errRes != nil { + w.WriteHeader(errRes.StatusCode) + writeJson(errRes, w, r) + return + } + writeJson(res, w, r) +} + +func (a *ApiManager) HandleApps(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointApp, w, r) +} + +func (a *ApiManager) HandleApiProducts(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointApiProduct, w, r) +} + +func (a *ApiManager) HandleCompanies(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointCompany, w, r) +} + +func (a *ApiManager) HandleCompanyDevelopers(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointCompanyDeveloper, w, r) +} +func (a *ApiManager) HandleDevelopers(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointDeveloper, w, r) +} + +func (a *ApiManager) HandleAppCredentials(w http.ResponseWriter, r *http.Request) { + a.handleEndpoint(EndpointAppCredentials, w, r) +} + +func extractIdentifiers(pars map[string][]string) (map[string]string, string, error) { + m := make(map[string]string) + orgs := pars[IdentifierOrganization] + if len(orgs) == 0 { + return nil, "", fmt.Errorf("no org specified") + } + org := orgs[0] + for k, v := range pars { + k = strings.ToLower(k) + if Identifiers[k] { + if len(v) == 1 { + m[k] = v[0] + } else { + return nil, org, fmt.Errorf("each identifier must have only 1 value") + } + } + } + return m, org, nil +} + +func (a *ApiManager) getCompanyDeveloper(org string, ids map[string]string) (*CompanyDevelopersSuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointCompanyDeveloper, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal := keyVals[0], keyVals[1] + + devs, err := a.DbMan.GetCompanyDevelopers(org, priKey, priVal, "", "") + if err != nil { + log.Errorf("getCompanyDeveloper: %v", err) + return nil, newDbError(err) + } + + if len(devs) == 0 { + return nil, ErrNotFound + } + + var details []*CompanyDeveloperDetails + for _, dev := range devs { + comName, err := a.DbMan.GetComNames(dev.CompanyId, TypeCompany) + if err != nil || len(comName) == 0 { + log.Errorf("getCompanyDeveloper: %v", err) + return nil, newDbError(err) + } + email, err := a.DbMan.GetDevEmailByDevId(dev.DeveloperId) + if err != nil { + log.Errorf("getCompanyDeveloper: %v", err) + return nil, newDbError(err) + } + detail := makeComDevDetails(&dev, comName[0], email) + details = append(details, detail) + } + return &CompanyDevelopersSuccessResponse{ + CompanyDevelopers: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + }, nil +} + +func (a *ApiManager) getDeveloper(org string, ids map[string]string) (*DeveloperSuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointDeveloper, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal := keyVals[0], keyVals[1] + + devs, err := a.DbMan.GetDevelopers(org, priKey, priVal, "", "") + if err != nil { + log.Errorf("getDeveloper: %v", err) + return nil, newDbError(err) + } + + if len(devs) == 0 { + return nil, ErrNotFound + } + dev := &devs[0] + + attrs := a.DbMan.GetKmsAttributes(dev.TenantId, dev.Id)[dev.Id] + comNames, err := a.DbMan.GetComNames(dev.Id, TypeDeveloper) + if err != nil { + log.Errorf("getDeveloper: %v", err) + return nil, newDbError(err) + } + appNames, err := a.DbMan.GetAppNames(dev.Id, TypeDeveloper) + if err != nil { + log.Errorf("getDeveloper: %v", err) + return nil, newDbError(err) + } + details := makeDevDetails(dev, appNames, comNames, attrs) + return &DeveloperSuccessResponse{ + Developer: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + }, nil +} + +func (a *ApiManager) getCompany(org string, ids map[string]string) (*CompanySuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointCompany, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal := keyVals[0], keyVals[1] + + coms, err := a.DbMan.GetCompanies(org, priKey, priVal, "", "") + if err != nil { + log.Errorf("getCompany: %v", err) + return nil, newDbError(err) + } + + if len(coms) == 0 { + return nil, ErrNotFound + } + com := &coms[0] + + attrs := a.DbMan.GetKmsAttributes(com.TenantId, com.Id)[com.Id] + appNames, err := a.DbMan.GetAppNames(com.Id, TypeCompany) + if err != nil { + log.Errorf("getCompany: %v", err) + return nil, newDbError(err) + } + details := makeCompanyDetails(com, appNames, attrs) + return &CompanySuccessResponse{ + Company: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + }, nil +} + +func (a *ApiManager) getApiProduct(org string, ids map[string]string) (*ApiProductSuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointApiProduct, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal, secKey, secVal := keyVals[0], keyVals[1], "", "" + if len(keyVals) > 2 { + secKey, secVal = keyVals[2], keyVals[3] + } + prods, err := a.DbMan.GetApiProducts(org, priKey, priVal, secKey, secVal) + if err != nil { + log.Errorf("getApiProduct: %v", err) + return nil, newDbError(err) + } + + var attrs []common.Attribute + if len(prods) == 0 { + return nil, ErrNotFound + } + prod := &prods[0] + attrs = a.DbMan.GetKmsAttributes(prod.TenantId, prod.Id)[prod.Id] + details, errRes := makeApiProductDetails(prod, attrs) + if errRes != nil { + return nil, errRes + } + + return &ApiProductSuccessResponse{ + ApiProduct: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + SecondaryIdentifierType: secKey, + SecondaryIdentifierValue: secVal, + }, nil +} + +func (a *ApiManager) getAppCredential(org string, ids map[string]string) (*AppCredentialSuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointApiProduct, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal := keyVals[0], keyVals[1] + + appCreds, err := a.DbMan.GetAppCredentials(org, priKey, priVal, "", "") + if err != nil { + log.Errorf("getAppCredential: %v", err) + return nil, newDbError(err) + } + + if len(appCreds) == 0 { + return nil, ErrNotFound + } + appCred := &appCreds[0] + attrs := a.DbMan.GetKmsAttributes(appCred.TenantId, appCred.Id)[appCred.Id] + apps, err := a.DbMan.GetApps(org, IdentifierAppId, appCred.AppId, "", "") + if err != nil { + log.Errorf("getAppCredential: %v", err) + return nil, newDbError(err) + } + + if len(apps) == 0 { + log.Errorf("getAppCredential: No App with id=%v", appCred.AppId) + return &AppCredentialSuccessResponse{ + AppCredential: nil, + Organization: org, + }, nil + } + app := &apps[0] + cd, errRes := a.getCredDetails(appCred, app.Status) + if errRes != nil { + return nil, errRes + } + devStatus := "" + if app.DeveloperId != "" { + devStatus, err = a.DbMan.GetStatus(app.DeveloperId, AppTypeDeveloper) + if err != nil { + log.Errorf("getAppCredential error get status: %v", err) + return nil, newDbError(err) + } + } + cks := makeConsumerKeyStatusDetails(app, cd, devStatus) + details := makeAppCredentialDetails(appCred, cks, []string{app.CallbackUrl}, attrs) + return &AppCredentialSuccessResponse{ + AppCredential: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + }, nil +} + +func (a *ApiManager) getApp(org string, ids map[string]string) (*AppSuccessResponse, *common.ErrorResponse) { + valid, keyVals := parseIdentifiers(EndpointApp, ids) + if !valid { + return nil, ErrInvalidPar + } + priKey, priVal, secKey, secVal := keyVals[0], keyVals[1], "", "" + if len(keyVals) > 2 { + secKey, secVal = keyVals[2], keyVals[3] + } + + apps, err := a.DbMan.GetApps(org, priKey, priVal, secKey, secVal) + if err != nil { + log.Errorf("getApp: %v", err) + return nil, newDbError(err) + } + + var app *common.App + var attrs []common.Attribute + + if len(apps) == 0 { + return nil, ErrNotFound + } + + app = &apps[0] + attrs = a.DbMan.GetKmsAttributes(app.TenantId, app.Id)[app.Id] + prods, err := a.DbMan.GetApiProductNames(app.Id, TypeApp) + if err != nil { + log.Errorf("getApp error getting productNames: %v", err) + return nil, newDbError(err) + } + parStatus, err := a.DbMan.GetStatus(app.ParentId, app.Type) + if err != nil { + log.Errorf("getApp error getting parent status: %v", err) + return nil, newDbError(err) + } + creds, err := a.DbMan.GetAppCredentials(org, IdentifierAppId, app.Id, "", "") + if err != nil { + log.Errorf("getApp error getting parent status: %v", err) + return nil, newDbError(err) + } + var credDetails []*CredentialDetails + for _, cred := range creds { + detail, errRes := a.getCredDetails(&cred, app.Status) + if errRes != nil { + return nil, errRes + } + credDetails = append(credDetails, detail) + } + + parent, errRes := a.getAppParent(app.ParentId, app.Type) + if errRes != nil { + return nil, errRes + } + details, errRes := makeAppDetails(app, parent, parStatus, prods, credDetails, attrs) + if errRes != nil { + return nil, errRes + } + return &AppSuccessResponse{ + App: details, + Organization: org, + PrimaryIdentifierType: priKey, + PrimaryIdentifierValue: priVal, + SecondaryIdentifierType: secKey, + SecondaryIdentifierValue: secVal, + }, nil +} + +func (a *ApiManager) getAppParent(id string, parentType string) (string, *common.ErrorResponse) { + switch parentType { + case AppTypeDeveloper: + return id, nil + case AppTypeCompany: + names, err := a.DbMan.GetComNames(id, TypeCompany) + if err != nil { + return "", newDbError(err) + } + if len(names) == 0 { + log.Warnf("getAppParent: No company with id=%v", id) + return "", nil + } + return names[0], nil + } + return "", nil +} + +func makeConsumerKeyStatusDetails(app *common.App, c *CredentialDetails, devStatus string) *ConsumerKeyStatusDetails { + return &ConsumerKeyStatusDetails{ + AppCredential: c, + AppID: c.AppID, + AppName: app.Name, + AppStatus: app.Status, + AppType: app.Type, + DeveloperID: app.DeveloperId, + DeveloperStatus: devStatus, + IsValidKey: strings.EqualFold(c.Status, StatusApproved), + } +} + +func makeAppCredentialDetails(ac *common.AppCredential, cks *ConsumerKeyStatusDetails, redirectUrl []string, attrs []common.Attribute) *AppCredentialDetails { + return &AppCredentialDetails{ + AppID: ac.AppId, + AppName: cks.AppName, + Attributes: attrs, + ConsumerKey: ac.Id, + ConsumerKeyStatus: cks, + ConsumerSecret: ac.ConsumerSecret, + DeveloperID: cks.DeveloperID, + RedirectUris: redirectUrl, + Scopes: common.JsonToStringArray(ac.Scopes), + Status: ac.Status, + } +} + +func makeApiProductDetails(prod *common.ApiProduct, attrs []common.Attribute) (*ApiProductDetails, *common.ErrorResponse) { + var a *ApiProductDetails + if prod != nil { + var quotaLimit int + var err error + if prod.Quota != "" { + quotaLimit, err = strconv.Atoi(prod.Quota) + if err != nil { + return nil, newDataError(err) + } + } + + a = &ApiProductDetails{ + ApiProxies: common.JsonToStringArray(prod.Proxies), + ApiResources: common.JsonToStringArray(prod.ApiResources), + ApprovalType: prod.ApprovalType, + Attributes: attrs, + CreatedAt: prod.CreatedAt, + CreatedBy: prod.CreatedBy, + Description: prod.Description, + DisplayName: prod.DisplayName, + Environments: common.JsonToStringArray(prod.Environments), + ID: prod.Id, + LastModifiedAt: prod.UpdatedAt, + LastModifiedBy: prod.UpdatedBy, + Name: prod.Name, + QuotaInterval: prod.QuotaInterval, + QuotaLimit: int64(quotaLimit), + QuotaTimeUnit: prod.QuotaTimeUnit, + Scopes: common.JsonToStringArray(prod.Scopes), + } + } else { + a = new(ApiProductDetails) + } + return a, nil +} + +func makeAppDetails(app *common.App, parent string, parentStatus string, prods []string, creds []*CredentialDetails, attrs []common.Attribute) (*AppDetails, *common.ErrorResponse) { + var a *AppDetails + if app != nil { + a = &AppDetails{ + AccessType: app.AccessType, + ApiProducts: prods, + AppCredentials: creds, + AppFamily: app.AppFamily, + AppParentID: parent, + AppParentStatus: parentStatus, + AppType: app.Type, + Attributes: attrs, + CallbackUrl: app.CallbackUrl, + CreatedAt: app.CreatedAt, + CreatedBy: app.CreatedBy, + DisplayName: app.DisplayName, + Id: app.Id, + LastModifiedAt: app.UpdatedAt, + LastModifiedBy: app.UpdatedBy, + Name: app.Name, + Status: app.Status, + } + } else { + a = new(AppDetails) + } + return a, nil +} + +func makeCompanyDetails(com *common.Company, appNames []string, attrs []common.Attribute) *CompanyDetails { + return &CompanyDetails{ + Apps: appNames, + Attributes: attrs, + CreatedAt: com.CreatedAt, + CreatedBy: com.CreatedBy, + DisplayName: com.DisplayName, + ID: com.Id, + LastModifiedAt: com.UpdatedAt, + LastModifiedBy: com.UpdatedBy, + Name: com.Name, + Status: com.Status, + } +} + +func makeDevDetails(dev *common.Developer, appNames []string, comNames []string, attrs []common.Attribute) *DeveloperDetails { + return &DeveloperDetails{ + Apps: appNames, + Attributes: attrs, + Companies: comNames, + CreatedAt: dev.CreatedAt, + CreatedBy: dev.CreatedBy, + Email: dev.Email, + FirstName: dev.FirstName, + ID: dev.Id, + LastModifiedAt: dev.UpdatedAt, + LastModifiedBy: dev.UpdatedBy, + LastName: dev.LastName, + Password: dev.Password, + Status: dev.Status, + UserName: dev.UserName, + } +} + +func makeComDevDetails(comDev *common.CompanyDeveloper, comName, devEmail string) *CompanyDeveloperDetails { + return &CompanyDeveloperDetails{ + CompanyName: comName, + CreatedAt: comDev.CreatedAt, + CreatedBy: comDev.CreatedBy, + DeveloperEmail: devEmail, + LastModifiedAt: comDev.UpdatedAt, + LastModifiedBy: comDev.UpdatedBy, + Roles: common.JsonToStringArray(comDev.Roles), + } +} + +func (a *ApiManager) getCredDetails(cred *common.AppCredential, appStatus string) (*CredentialDetails, *common.ErrorResponse) { + + refs, err := a.DbMan.GetApiProductNames(cred.Id, TypeConsumerKey) + if err != nil { + log.Errorf("Error when getting product reference list") + return nil, newDbError(err) + } + return &CredentialDetails{ + ApiProductReferences: refs, + AppID: cred.AppId, + AppStatus: appStatus, + Attributes: a.DbMan.GetKmsAttributes(cred.TenantId, cred.Id)[cred.Id], + ConsumerKey: cred.Id, + ConsumerSecret: cred.ConsumerSecret, + ExpiresAt: cred.ExpiresAt, + IssuedAt: cred.IssuedAt, + MethodType: cred.MethodType, + Scopes: common.JsonToStringArray(cred.Scopes), + Status: cred.Status, + }, nil +} + +func parseIdentifiers(endpoint string, ids map[string]string) (valid bool, keyVals []string) { + if len(ids) > 2 { + return false, nil + } + if m := IdentifierTree[endpoint]; m != nil { + for key, val := range ids { + if m[key] != nil { + keyVals = append(keyVals, key, val) + for _, id := range m[key] { + if ids[id] != "" { + keyVals = append(keyVals, id, ids[id]) + return true, keyVals + } + } + if len(ids) == 2 { + return false, nil + } + return true, keyVals + } + } + } + return false, nil +} + +func newDbError(err error) *common.ErrorResponse { + return &common.ErrorResponse{ + ResponseCode: strconv.Itoa(DB_ERROR), + ResponseMessage: err.Error(), + StatusCode: http.StatusInternalServerError, + } +} + +func newDataError(err error) *common.ErrorResponse { + return &common.ErrorResponse{ + ResponseCode: strconv.Itoa(DATA_ERROR), + ResponseMessage: err.Error(), + StatusCode: http.StatusInternalServerError, + } +} + +func writeJson(obj interface{}, w http.ResponseWriter, r *http.Request) { + bytes, err := json.Marshal(obj) + if err != nil { + log.Error("unable to marshal errorResponse: " + err.Error()) + w.Write([]byte("unable to marshal errorResponse: " + err.Error())) + } else { + w.Header().Set("Content-Type", "application/json") + w.Write(bytes) + } +}
diff --git a/accessEntity/api_response.go b/accessEntity/api_response.go new file mode 100644 index 0000000..ea1e65c --- /dev/null +++ b/accessEntity/api_response.go
@@ -0,0 +1,313 @@ +// 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 accessEntity + +import "github.com/apid/apidVerifyApiKey/common" + +type ApiProductSuccessResponse struct { + // api product + ApiProduct *ApiProductDetails `json:"apiProduct"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` + // secondary identifier type + SecondaryIdentifierType string `json:"secondaryIdentifierType"` + // secondary identifier value + SecondaryIdentifierValue string `json:"secondaryIdentifierValue"` +} + +type AppCredentialSuccessResponse struct { + // app credential + AppCredential *AppCredentialDetails `json:"appCredential"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` +} + +type AppSuccessResponse struct { + // app + App *AppDetails `json:"app"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` + // secondary identifier type + SecondaryIdentifierType string `json:"secondaryIdentifierType"` + // secondary identifier value + SecondaryIdentifierValue string `json:"secondaryIdentifierValue"` +} + +type CompanyDevelopersSuccessResponse struct { + // company developers + CompanyDevelopers []*CompanyDeveloperDetails `json:"companyDevelopers"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` +} + +type CompanySuccessResponse struct { + // company + Company *CompanyDetails `json:"company"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` +} + +type DeveloperSuccessResponse struct { + // developer + Developer *DeveloperDetails `json:"developer"` + // Organization Identifier/Name + Organization string `json:"organization"` + // primary identifier type + PrimaryIdentifierType string `json:"primaryIdentifierType"` + // primary identifier value + PrimaryIdentifierValue string `json:"primaryIdentifierValue"` +} + +type ApiProductDetails struct { + // api proxies + ApiProxies []string `json:"apiProxies"` + // api resources + ApiResources []string `json:"apiResources"` + // approval type + ApprovalType string `json:"approvalType"` + // Attributes associated with the apiproduct. + Attributes []common.Attribute `json:"attributes"` + // ISO-8601 + CreatedAt string `json:"createdAt"` + // created by + CreatedBy string `json:"createdBy"` + // description + Description string `json:"description"` + // display name + DisplayName string `json:"displayName"` + // environments + Environments []string `json:"environments"` + // id + ID string `json:"id"` + // ISO-8601 + LastModifiedAt string `json:"lastModifiedAt"` + // last modified by + LastModifiedBy string `json:"lastModifiedBy"` + // name + Name string `json:"name"` + // quota interval + QuotaInterval int64 `json:"quotaInterval"` + // quota limit + QuotaLimit int64 `json:"quotaLimit"` + // quota time unit + QuotaTimeUnit string `json:"quotaTimeUnit"` + // scopes + Scopes []string `json:"scopes"` +} + +type AppDetails struct { + + // access type + AccessType string `json:"accessType"` + // api products + ApiProducts []string `json:"apiProducts"` + // app credentials + AppCredentials []*CredentialDetails `json:"appCredentials"` + // app family + AppFamily string `json:"appFamily"` + // app parent, developer's Id or company's name + AppParentID string `json:"appParentId"` + // app parent status + AppParentStatus string `json:"appParentStatus"` + // Developer or Company + AppType string `json:"appType"` + // Attributes associated with the app. + Attributes []common.Attribute `json:"attributes"` + // callback Url + CallbackUrl string `json:"callbackUrl"` + // ISO-8601 + CreatedAt string `json:"createdAt"` + // created by + CreatedBy string `json:"createdBy"` + // display name + DisplayName string `json:"displayName"` + // id + Id string `json:"id"` + // ISO-8601 + LastModifiedAt string `json:"lastModifiedAt"` + // last modified by + LastModifiedBy string `json:"lastModifiedBy"` + // name + Name string `json:"name"` + // status + Status string `json:"status"` +} + +type CredentialDetails struct { + // api product references + ApiProductReferences []string `json:"apiProductReferences"` + // app Id + AppID string `json:"appId"` + // app status + AppStatus string `json:"appStatus"` + // Attributes associated with the client Id. + Attributes []common.Attribute `json:"attributes"` + // consumer key + ConsumerKey string `json:"consumerKey"` + // consumer secret + ConsumerSecret string `json:"consumerSecret"` + // expires at + ExpiresAt string `json:"expiresAt"` + // issued at + IssuedAt string `json:"issuedAt"` + // method type + MethodType string `json:"methodType"` + // scopes + Scopes []string `json:"scopes"` + // status + Status string `json:"status"` +} + +/* +type ApiProductReferenceDetails struct { + // status of the api product + Status string `json:"status"` + // name of the api product + ApiProduct string `json:"apiProduct"` +} +*/ +type AppCredentialDetails struct { + // app Id + AppID string `json:"appId"` + // app name + AppName string `json:"appName"` + // Attributes associated with the app credential + Attributes []common.Attribute `json:"attributes"` + // consumer key + ConsumerKey string `json:"consumerKey"` + // consumer key status + ConsumerKeyStatus *ConsumerKeyStatusDetails `json:"consumerKeyStatus"` + // consumer secret + ConsumerSecret string `json:"consumerSecret"` + // developer Id + DeveloperID string `json:"developerId"` + // redirect uris + RedirectUris []string `json:"redirectURIs"` + // scopes + Scopes []string `json:"scopes"` + // status + Status string `json:"status"` +} + +type ConsumerKeyStatusDetails struct { + // app credential + AppCredential *CredentialDetails `json:"appCredential"` + // app Id + AppID string `json:"appId"` + // app name + AppName string `json:"appName"` + // app status + AppStatus string `json:"appStatus"` + // app type + AppType string `json:"appType"` + // developer Id + DeveloperID string `json:"developerId"` + // developer status + DeveloperStatus string `json:"developerStatus"` + // is valid key + IsValidKey bool `json:"isValidKey"` +} + +type CompanyDetails struct { + + // apps + Apps []string `json:"apps"` + // Attributes associated with the company. + Attributes []common.Attribute `json:"attributes"` + // ISO-8601 + CreatedAt string `json:"createdAt"` + // created by + CreatedBy string `json:"createdBy"` + // display name + DisplayName string `json:"displayName"` + // id + ID string `json:"id"` + // ISO-8601 + LastModifiedAt string `json:"lastModifiedAt"` + // last modified by + LastModifiedBy string `json:"lastModifiedBy"` + // name + Name string `json:"name"` + // status + Status string `json:"status"` +} + +type CompanyDeveloperDetails struct { + // company name + CompanyName string `json:"companyName"` + // ISO-8601 + CreatedAt string `json:"createdAt"` + // created by + CreatedBy string `json:"createdBy"` + // developer email + DeveloperEmail string `json:"developerEmail"` + // ISO-8601 + LastModifiedAt string `json:"lastModifiedAt"` + // last modified by + LastModifiedBy string `json:"lastModifiedBy"` + // roles + Roles []string `json:"roles"` +} + +type DeveloperDetails struct { + // apps + Apps []string `json:"apps"` + // Attributes associated with the developer. + Attributes []common.Attribute `json:"attributes"` + // companies + Companies []string `json:"companies"` + // ISO-8601 + CreatedAt string `json:"createdAt"` + // created by + CreatedBy string `json:"createdBy"` + // email + Email string `json:"email"` + // first name + FirstName string `json:"firstName"` + // id + ID string `json:"id"` + // ISO-8601 + LastModifiedAt string `json:"lastModifiedAt"` + // last modified by + LastModifiedBy string `json:"lastModifiedBy"` + // last name + LastName string `json:"lastName"` + // password + Password string `json:"password"` + // status + Status string `json:"status"` + // user name + UserName string `json:"userName"` +}
diff --git a/accessEntity/api_test.go b/accessEntity/api_test.go new file mode 100644 index 0000000..7f46f07 --- /dev/null +++ b/accessEntity/api_test.go
@@ -0,0 +1,776 @@ +// 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 accessEntity + +import ( + "encoding/json" + "github.com/apid/apidVerifyApiKey/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "time" +) + +const ( + apiTestUrl = "http://127.0.0.1:9000" +) + +var _ = Describe("API Tests", func() { + var apiMan *ApiManager + testCount := 0 + client := &http.Client{} + dbMan := &DummyDbMan{} + var attrs []common.Attribute + var testId string + clientGet := func(path string, pars map[string][]string) (int, []byte) { + uri, err := url.Parse(apiTestUrl + path) + Expect(err).Should(Succeed()) + query := url.Values(pars) + uri.RawQuery = query.Encode() + httpReq, err := http.NewRequest("GET", uri.String(), nil) + Expect(err).Should(Succeed()) + res, err := client.Do(httpReq) + Expect(err).Should(Succeed()) + defer res.Body.Close() + responseBody, err := ioutil.ReadAll(res.Body) + Expect(err).Should(Succeed()) + return res.StatusCode, responseBody + } + + BeforeEach(func() { + testCount++ + testId = "test-" + strconv.Itoa(testCount) + apiMan = &ApiManager{ + DbMan: dbMan, + AccessEntityPath: AccessEntityPath + strconv.Itoa(testCount), + apiInitialized: false, + } + attrs = setAttrs(dbMan, testId) + apiMan.InitAPI() + time.Sleep(100 * time.Millisecond) + }) + + It("ApiProduct", func() { + testProd := []common.ApiProduct{ + { + Id: testId, + Name: "apstest", + DisplayName: "apstest", + Description: "", + ApiResources: "{/**}", + ApprovalType: "AUTO", + Scopes: `{foo,bar}`, + Proxies: `{aps,perfBenchmark}`, + Environments: `{prod,test}`, + Quota: "10000000", + QuotaTimeUnit: "MINUTE", + QuotaInterval: 1, + CreatedAt: "2017-08-18 22:12:49.363+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:26:50.153+00:00", + UpdatedBy: "haoming@apid.git", + TenantId: "515211e9", + }, + } + + expected := ApiProductSuccessResponse{ + ApiProduct: &ApiProductDetails{ + ApiProxies: []string{"aps", "perfBenchmark"}, + ApiResources: []string{"/**"}, + ApprovalType: testProd[0].ApprovalType, + Attributes: attrs, + CreatedAt: testProd[0].CreatedAt, + CreatedBy: testProd[0].CreatedBy, + Description: testProd[0].Description, + DisplayName: testProd[0].DisplayName, + Environments: []string{"prod", "test"}, + ID: testProd[0].Id, + LastModifiedAt: testProd[0].UpdatedAt, + LastModifiedBy: testProd[0].UpdatedBy, + Name: testProd[0].Name, + QuotaInterval: testProd[0].QuotaInterval, + QuotaLimit: 10000000, + QuotaTimeUnit: testProd[0].QuotaTimeUnit, + Scopes: []string{"foo", "bar"}, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierAppName, + PrimaryIdentifierValue: "test-app", + SecondaryIdentifierType: IdentifierDeveloperId, + SecondaryIdentifierValue: "test-dev", + } + + testData := [][]common.ApiProduct{ + testProd, + nil, + testProd, + testProd, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + { + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + for i, data := range testData { + dbMan.apiProducts = data + code, body := clientGet(apiMan.AccessEntityPath+EndpointApiProduct, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res ApiProductSuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + + }) + + It("Apps", func() { + testApp := []common.App{ + { + Id: testId, + TenantId: "515211e9", + Name: "apstest", + DisplayName: "apstest", + AccessType: "READ", + CallbackUrl: "https://www.google.com", + Status: "APPROVED", + AppFamily: "default", + CompanyId: "", + DeveloperId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + ParentId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + Type: "DEVELOPER", + CreatedAt: "2017-08-18 22:13:18.325+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:13:18.325+00:00", + UpdatedBy: "haoming@apid.git", + }, + } + + testComApp := []common.App{ + { + Id: testId, + TenantId: "515211e9", + Name: "apstest", + DisplayName: "apstest", + AccessType: "READ", + CallbackUrl: "https://www.google.com", + Status: "APPROVED", + AppFamily: "default", + CompanyId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + DeveloperId: "", + ParentId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + Type: "COMPANY", + CreatedAt: "2017-08-18 22:13:18.325+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:13:18.325+00:00", + UpdatedBy: "haoming@apid.git", + }, + } + + testProductNames := []string{"foo", "bar"} + testStatus := "test-status" + testCreds := []common.AppCredential{ + { + Id: testId, + TenantId: "515211e9", + ConsumerSecret: "secret1", + AppId: testId, + MethodType: "GET", + Status: "APPROVED", + IssuedAt: "2017-08-18 22:13:18.35+00:00", + ExpiresAt: "2018-08-18 22:13:18.35+00:00", + AppStatus: "APPROVED", + Scopes: "{foo,bar}", + CreatedAt: "2017-08-18 22:13:18.35+00:00", + CreatedBy: "-NA-", + UpdatedAt: "2017-08-18 22:13:18.352+00:00", + UpdatedBy: "-NA-", + }, + } + expected := AppSuccessResponse{ + App: &AppDetails{ + AccessType: testApp[0].AccessType, + ApiProducts: testProductNames, + AppCredentials: []*CredentialDetails{ + { + ApiProductReferences: testProductNames, + AppID: testCreds[0].AppId, + AppStatus: testApp[0].Status, + Attributes: attrs, + ConsumerKey: testCreds[0].Id, + ConsumerSecret: testCreds[0].ConsumerSecret, + ExpiresAt: testCreds[0].ExpiresAt, + IssuedAt: testCreds[0].IssuedAt, + MethodType: testCreds[0].MethodType, + Scopes: []string{"foo", "bar"}, + Status: testCreds[0].Status, + }, + }, + AppFamily: testApp[0].AppFamily, + AppParentID: testApp[0].ParentId, + AppParentStatus: testStatus, + AppType: testApp[0].Type, + Attributes: attrs, + CallbackUrl: testApp[0].CallbackUrl, + CreatedAt: testApp[0].CreatedAt, + CreatedBy: testApp[0].CreatedBy, + DisplayName: testApp[0].DisplayName, + Id: testApp[0].Id, + LastModifiedAt: testApp[0].UpdatedAt, + LastModifiedBy: testApp[0].UpdatedBy, + Name: testApp[0].Name, + Status: testApp[0].Status, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierAppName, + PrimaryIdentifierValue: "test-app", + SecondaryIdentifierType: IdentifierDeveloperId, + SecondaryIdentifierValue: "test-dev", + } + + expectedComApp := AppSuccessResponse{ + App: &AppDetails{ + AccessType: testComApp[0].AccessType, + ApiProducts: testProductNames, + AppCredentials: []*CredentialDetails{ + { + ApiProductReferences: testProductNames, + AppID: testCreds[0].AppId, + AppStatus: testComApp[0].Status, + Attributes: attrs, + ConsumerKey: testCreds[0].Id, + ConsumerSecret: testCreds[0].ConsumerSecret, + ExpiresAt: testCreds[0].ExpiresAt, + IssuedAt: testCreds[0].IssuedAt, + MethodType: testCreds[0].MethodType, + Scopes: []string{"foo", "bar"}, + Status: testCreds[0].Status, + }, + }, + AppFamily: testComApp[0].AppFamily, + AppParentID: "testcompanyhflxv", + AppParentStatus: testStatus, + AppType: testComApp[0].Type, + Attributes: attrs, + CallbackUrl: testComApp[0].CallbackUrl, + CreatedAt: testComApp[0].CreatedAt, + CreatedBy: testComApp[0].CreatedBy, + DisplayName: testComApp[0].DisplayName, + Id: testComApp[0].Id, + LastModifiedAt: testComApp[0].UpdatedAt, + LastModifiedBy: testComApp[0].UpdatedBy, + Name: testComApp[0].Name, + Status: testComApp[0].Status, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierAppName, + PrimaryIdentifierValue: "test-app", + SecondaryIdentifierType: IdentifierDeveloperId, + SecondaryIdentifierValue: "test-dev", + } + + testData := [][]common.App{ + testApp, + testComApp, + nil, + testApp, + testApp, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + { + IdentifierOrganization: {"test-org"}, + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + { + IdentifierAppName: {"test-app"}, + IdentifierDeveloperId: {"test-dev"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusOK, expectedComApp}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + dbMan.apiProductNames = testProductNames + dbMan.status = testStatus + dbMan.appCredentials = testCreds + for i, data := range testData { + dbMan.apps = data + dbMan.comNames = []string{"testcompanyhflxv"} + code, body := clientGet(apiMan.AccessEntityPath+EndpointApp, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res AppSuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + + }) + + It("Company", func() { + testCom := []common.Company{ + { + Id: testId, + TenantId: "515211e9", + Name: "testcompanyhflxv", + DisplayName: "testcompanyhflxv", + Status: "ACTIVE", + CreatedAt: "2017-11-02 16:00:16.287+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:16.287+00:00", + UpdatedBy: "haoming@apid.git", + }, + } + + testAppNames := []string{"foo", "bar"} + + expected := CompanySuccessResponse{ + Company: &CompanyDetails{ + Apps: testAppNames, + Attributes: attrs, + CreatedAt: testCom[0].CreatedAt, + CreatedBy: testCom[0].CreatedBy, + DisplayName: testCom[0].DisplayName, + ID: testCom[0].Id, + LastModifiedAt: testCom[0].UpdatedAt, + LastModifiedBy: testCom[0].UpdatedBy, + Name: testCom[0].Name, + Status: testCom[0].Status, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierAppId, + PrimaryIdentifierValue: "test-app", + } + + testData := [][]common.Company{ + testCom, + nil, + testCom, + testCom, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierAppId: {"test-app"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierAppId: {"test-app"}, + }, + { + IdentifierAppId: {"test-app"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + dbMan.appNames = testAppNames + + for i, data := range testData { + dbMan.companies = data + code, body := clientGet(apiMan.AccessEntityPath+EndpointCompany, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res CompanySuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + + }) + + It("Developer", func() { + testDev := []common.Developer{ + { + Id: testId, + TenantId: "515211e9", + UserName: "haoming", + FirstName: "haoming", + LastName: "zhang", + Password: "111", + Email: "bar@google.com", + Status: "ACTIVE", + EncryptedPassword: "222", + Salt: "333", + CreatedAt: "2017-08-16 22:39:46.669+00:00", + CreatedBy: "foo@google.com", + UpdatedAt: "2017-08-16 22:39:46.669+00:00", + UpdatedBy: "foo@google.com", + }, + } + + testAppNames := []string{"foo", "bar"} + testComNames := []string{"foo", "bar"} + + expected := DeveloperSuccessResponse{ + Developer: &DeveloperDetails{ + Apps: testAppNames, + Attributes: attrs, + Companies: testComNames, + CreatedAt: testDev[0].CreatedAt, + CreatedBy: testDev[0].CreatedBy, + Email: testDev[0].Email, + FirstName: testDev[0].FirstName, + ID: testDev[0].Id, + LastModifiedAt: testDev[0].UpdatedAt, + LastModifiedBy: testDev[0].UpdatedBy, + LastName: testDev[0].LastName, + Password: testDev[0].Password, + Status: testDev[0].Status, + UserName: testDev[0].UserName, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierAppId, + PrimaryIdentifierValue: "test-app", + } + + testData := [][]common.Developer{ + testDev, + nil, + testDev, + testDev, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierAppId: {"test-app"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierAppId: {"test-app"}, + }, + { + IdentifierAppId: {"test-app"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + dbMan.appNames = testAppNames + dbMan.comNames = testComNames + + for i, data := range testData { + dbMan.developers = data + code, body := clientGet(apiMan.AccessEntityPath+EndpointDeveloper, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res DeveloperSuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + + }) + + It("AppCredential", func() { + testAppCred := []common.AppCredential{ + { + Id: testId, + TenantId: "515211e9", + ConsumerSecret: "secret1", + AppId: testId, + MethodType: "GET", + Status: "APPROVED", + IssuedAt: "2017-08-18 22:13:18.35+00:00", + ExpiresAt: "2018-08-18 22:13:18.35+00:00", + AppStatus: "APPROVED", + Scopes: "{foo,bar}", + CreatedAt: "2017-08-18 22:13:18.35+00:00", + CreatedBy: "-NA-", + UpdatedAt: "2017-08-18 22:13:18.352+00:00", + UpdatedBy: "-NA-", + }, + } + testApp := []common.App{ + { + Id: testId, + TenantId: "515211e9", + Name: "apstest", + DisplayName: "apstest", + AccessType: "READ", + CallbackUrl: "https://www.google.com", + Status: "APPROVED", + AppFamily: "default", + CompanyId: "", + DeveloperId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + ParentId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + Type: "DEVELOPER", + CreatedAt: "2017-08-18 22:13:18.325+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:13:18.325+00:00", + UpdatedBy: "haoming@apid.git", + }, + } + + testProductNames := []string{"foo", "bar"} + testStatus := "test-status" + + expected := AppCredentialSuccessResponse{ + AppCredential: &AppCredentialDetails{ + AppID: testAppCred[0].AppId, + AppName: testApp[0].Name, + Attributes: attrs, + ConsumerKey: testAppCred[0].Id, + ConsumerKeyStatus: &ConsumerKeyStatusDetails{ + AppCredential: &CredentialDetails{ + ApiProductReferences: testProductNames, + AppID: testAppCred[0].AppId, + AppStatus: testApp[0].Status, + Attributes: attrs, + ConsumerKey: testAppCred[0].Id, + ConsumerSecret: testAppCred[0].ConsumerSecret, + ExpiresAt: testAppCred[0].ExpiresAt, + IssuedAt: testAppCred[0].IssuedAt, + MethodType: testAppCred[0].MethodType, + Scopes: []string{"foo", "bar"}, + Status: testAppCred[0].Status, + }, + AppID: testAppCred[0].AppId, + AppName: testApp[0].Name, + AppStatus: testApp[0].Status, + AppType: testApp[0].Type, + DeveloperID: testApp[0].DeveloperId, + DeveloperStatus: testStatus, + IsValidKey: true, + }, + ConsumerSecret: testAppCred[0].ConsumerSecret, + DeveloperID: testApp[0].DeveloperId, + RedirectUris: []string{testApp[0].CallbackUrl}, + Scopes: []string{"foo", "bar"}, + Status: testAppCred[0].Status, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierConsumerKey, + PrimaryIdentifierValue: "test-key", + } + + testData := [][]common.AppCredential{ + testAppCred, + nil, + testAppCred, + testAppCred, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierConsumerKey: {"test-key"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierConsumerKey: {"test-key"}, + }, + { + IdentifierConsumerKey: {"test-key"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + dbMan.apiProductNames = testProductNames + dbMan.status = testStatus + dbMan.apps = testApp + for i, data := range testData { + dbMan.appCredentials = data + code, body := clientGet(apiMan.AccessEntityPath+EndpointAppCredentials, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res AppCredentialSuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + }) + + It("CompanyDeveloper", func() { + testDev := []common.CompanyDeveloper{ + { + TenantId: "515211e9", + CompanyId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + DeveloperId: "590f33bf-f05c-48c1-bb93-183759bd9ee1", + Roles: "{foo,bar}", + CreatedAt: "2017-11-02 16:00:16.287+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:16.287+00:00", + UpdatedBy: "haoming@apid.git", + }, + } + + testComNames := []string{"foo"} + testEmail := "haoming@apid.git" + + expected := CompanyDevelopersSuccessResponse{ + CompanyDevelopers: []*CompanyDeveloperDetails{ + { + CompanyName: testComNames[0], + CreatedAt: testDev[0].CreatedAt, + CreatedBy: testDev[0].CreatedBy, + DeveloperEmail: testEmail, + LastModifiedAt: testDev[0].UpdatedAt, + LastModifiedBy: testDev[0].UpdatedBy, + Roles: []string{"foo", "bar"}, + }, + }, + Organization: "test-org", + PrimaryIdentifierType: IdentifierCompanyName, + PrimaryIdentifierValue: "test-com", + } + + testData := [][]common.CompanyDeveloper{ + testDev, + nil, + testDev, + testDev, + } + + testPars := []map[string][]string{ + // positive + { + IdentifierOrganization: {"test-org"}, + IdentifierCompanyName: {"test-com"}, + }, + // negative + { + IdentifierOrganization: {"test-org"}, + IdentifierCompanyName: {"test-com"}, + }, + { + IdentifierCompanyName: {"test-com"}, + }, + { + IdentifierDeveloperId: {"test-dev"}, + }, + } + + results := [][]interface{}{ + {http.StatusOK, expected}, + {http.StatusNotFound, nil}, + {http.StatusBadRequest, nil}, + {http.StatusBadRequest, nil}, + } + + dbMan.comNames = testComNames + dbMan.email = testEmail + + for i, data := range testData { + dbMan.companyDevelopers = data + code, body := clientGet(apiMan.AccessEntityPath+EndpointCompanyDeveloper, testPars[i]) + Expect(code).Should(Equal(results[i][0])) + if results[i][1] != nil { + var res CompanyDevelopersSuccessResponse + Expect(json.Unmarshal(body, &res)).Should(Succeed()) + Expect(res).Should(Equal(results[i][1])) + } + } + + }) +}) + +func setAttrs(dbMan *DummyDbMan, id string) []common.Attribute { + dbMan.attrs = map[string][]common.Attribute{ + id: { + { + Name: "foo", + Value: "bar", + }, + { + Name: "bar", + Value: "foo", + }, + }, + } + return dbMan.attrs[id] +}
diff --git a/accessEntity/data.go b/accessEntity/data.go new file mode 100644 index 0000000..50fcd93 --- /dev/null +++ b/accessEntity/data.go
@@ -0,0 +1,763 @@ +// 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 accessEntity + +import ( + "database/sql" + "fmt" + "github.com/apid/apidVerifyApiKey/common" + "strings" +) + +const ( + sql_select_api_product = `SELECT * FROM kms_api_product AS ap ` + sql_select_tenant_org = ` (SELECT o.tenant_id FROM kms_organization AS o WHERE o.name=?)` +) + +type DbManager struct { + common.DbManager +} + +func (d *DbManager) GetApiProductNames(id string, idType string) ([]string, error) { + var query string + switch idType { + case TypeConsumerKey: + query = selectApiProductsById( + selectAppCredentialMapperByConsumerKey( + "?", + "apiprdt_id", + ), + "name", + ) + case TypeApp: + query = selectApiProductsById( + selectAppCredentialMapperByAppId( + "?", + "apiprdt_id", + ), + "name", + ) + default: + return nil, fmt.Errorf("unsupported idType") + } + + rows, err := d.GetDb().Query(query, id) + if err != nil { + return nil, err + } + defer rows.Close() + var names []string + for rows.Next() { + name := sql.NullString{} + err = rows.Scan(&name) + if err != nil { + return nil, err + } + if name.Valid { + names = append(names, name.String) + } + } + return names, nil +} + +func (d *DbManager) GetComNameByComId(comId string) (string, error) { + query := selectCompanyByComId( + "?", + "name", + ) + name := sql.NullString{} + err := d.GetDb().QueryRow(query, comId).Scan(&name) + if err != nil || !name.Valid { + return "", err + } + return name.String, nil +} + +func (d *DbManager) GetDevEmailByDevId(devId string) (string, error) { + query := selectDeveloperById( + "?", + "email", + ) + email := sql.NullString{} + err := d.GetDb().QueryRow(query, devId).Scan(&email) + if err != nil || !email.Valid { + return "", err + } + return email.String, nil +} + +func (d *DbManager) GetComNames(id string, idType string) ([]string, error) { + var query string + switch idType { + case TypeDeveloper: + query = selectCompanyByComId( + selectCompanyDeveloperByDevId( + "?", + "company_id", + ), + "name", + ) + case TypeCompany: + query = selectCompanyByComId( + "?", + "name", + ) + default: + return nil, fmt.Errorf("unsupported idType") + } + + rows, err := d.GetDb().Query(query, id) + if err != nil { + return nil, err + } + defer rows.Close() + var names []string + for rows.Next() { + name := sql.NullString{} + err = rows.Scan(&name) + if err != nil { + return nil, err + } + if name.Valid { + names = append(names, name.String) + } + } + return names, nil +} + +func (d *DbManager) GetAppNames(id string, t string) ([]string, error) { + var query string + switch t { + case TypeDeveloper: + query = selectAppByDevId( + "?", + "name", + ) + case TypeCompany: + query = selectAppByComId( + "?", + "name", + ) + default: + return nil, fmt.Errorf("app type not supported") + } + rows, err := d.GetDb().Query(query, id) + if err != nil { + return nil, err + } + defer rows.Close() + var names []string + for rows.Next() { + name := sql.NullString{} + err = rows.Scan(&name) + if err != nil { + return nil, err + } + if name.Valid { + names = append(names, name.String) + } + } + return names, nil +} + +func (d *DbManager) GetStatus(id, t string) (string, error) { + var query string + switch t { + case AppTypeDeveloper: + query = selectDeveloperById( + "?", + "status", + ) + case AppTypeCompany: + query = selectCompanyByComId( + "?", + "status", + ) + } + status := sql.NullString{} + err := d.GetDb().QueryRow(query, id).Scan(&status) + if err != nil || !status.Valid { + return "", err + } + + return status.String, nil +} + +func (d *DbManager) GetApiProducts(org, priKey, priVal, secKey, secVal string) (apiProducts []common.ApiProduct, err error) { + if priKey == IdentifierAppId { + apiProducts, err = d.getApiProductsByAppId(priVal, org) + if err != nil { + return + } + } else if priKey == IdentifierApiProductName { + apiProducts, err = d.getApiProductsByName(priVal, org) + if err != nil { + return + } + } else if priKey == IdentifierAppName { + switch secKey { + case IdentifierDeveloperEmail: + apiProducts, err = d.getApiProductsByAppName(priVal, secVal, "", "", org) + case IdentifierDeveloperId: + apiProducts, err = d.getApiProductsByAppName(priVal, "", secVal, "", org) + case IdentifierCompanyName: + apiProducts, err = d.getApiProductsByAppName(priVal, "", "", secVal, org) + case IdentifierApiResource: + fallthrough + case "": + apiProducts, err = d.getApiProductsByAppName(priVal, "", "", "", org) + } + if err != nil { + return + } + } else if priKey == IdentifierConsumerKey { + apiProducts, err = d.getApiProductsByConsumerKey(priVal, org) + if err != nil { + return + } + } + + if secKey == IdentifierApiResource { + apiProducts = filterApiProductsByResource(apiProducts, secVal) + } + return +} + +func (d *DbManager) GetApps(org, priKey, priVal, secKey, secVal string) (apps []common.App, err error) { + switch priKey { + case IdentifierAppId: + return d.getAppByAppId(priVal, org) + case IdentifierAppName: + switch secKey { + case IdentifierDeveloperEmail: + return d.getAppByAppName(priVal, secVal, "", "", org) + case IdentifierDeveloperId: + return d.getAppByAppName(priVal, "", secVal, "", org) + case IdentifierCompanyName: + return d.getAppByAppName(priVal, "", "", secVal, org) + case "": + return d.getAppByAppName(priVal, "", "", "", org) + } + case IdentifierConsumerKey: + return d.getAppByConsumerKey(priVal, org) + } + return +} + +func (d *DbManager) GetCompanies(org, priKey, priVal, secKey, secVal string) (companies []common.Company, err error) { + switch priKey { + case IdentifierAppId: + return d.getCompanyByAppId(priVal, org) + case IdentifierCompanyName: + return d.getCompanyByName(priVal, org) + case IdentifierConsumerKey: + return d.getCompanyByConsumerKey(priVal, org) + } + return +} + +func (d *DbManager) GetCompanyDevelopers(org, priKey, priVal, secKey, secVal string) (companyDevelopers []common.CompanyDeveloper, err error) { + if priKey == IdentifierCompanyName { + return d.getCompanyDeveloperByComName(priVal, org) + } + return +} + +func (d *DbManager) GetAppCredentials(org, priKey, priVal, secKey, secVal string) (appCredentials []common.AppCredential, err error) { + + switch priKey { + case IdentifierConsumerKey: + return d.getAppCredentialByConsumerKey(priVal, org) + case IdentifierAppId: + return d.getAppCredentialByAppId(priVal, org) + } + return +} + +func (d *DbManager) GetDevelopers(org, priKey, priVal, secKey, secVal string) (developers []common.Developer, err error) { + switch priKey { + case IdentifierAppId: + return d.getDeveloperByAppId(priVal, org) + case IdentifierDeveloperEmail: + return d.getDeveloperByEmail(priVal, org) + case IdentifierConsumerKey: + return d.getDeveloperByConsumerKey(priVal, org) + case IdentifierDeveloperId: + return d.getDeveloperById(priVal, org) + } + return +} + +func (d *DbManager) getApiProductsByName(apiProdName string, org string) (apiProducts []common.ApiProduct, err error) { + err = d.GetDb().QueryStructs(&apiProducts, + sql_select_api_product+ + `WHERE ap.name = ? AND ap.tenant_id IN `+ + sql_select_tenant_org, + apiProdName, + org, + ) + return +} + +func (d *DbManager) getApiProductsByAppId(appId string, org string) (apiProducts []common.ApiProduct, err error) { + cols := []string{"*"} + query := selectApiProductsById( + selectAppCredentialMapperByAppId( + "?", + "apiprdt_id", + ), + cols..., + ) + " AND ap.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getApiProductsByAppId: %v", query) + err = d.GetDb().QueryStructs(&apiProducts, query, appId, org) + return +} + +func (d *DbManager) getApiProductsByConsumerKey(consumerKey string, org string) (apiProducts []common.ApiProduct, err error) { + cols := []string{"*"} + query := selectApiProductsById( + selectAppCredentialMapperByConsumerKey( + "?", + "apiprdt_id", + ), + cols..., + ) + " AND ap.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getApiProductsByConsumerKey: %v", query) + err = d.GetDb().QueryStructs(&apiProducts, query, consumerKey, org) + return +} + +func (d *DbManager) getApiProductsByAppName(appName, devEmail, devId, comName, org string) (apiProducts []common.ApiProduct, err error) { + cols := []string{"*"} + var appQuery string + args := []interface{}{appName} + switch { + case devEmail != "": + appQuery = selectAppByNameAndDeveloperId( + "?", + selectDeveloperByEmail( + "?", + "id", + ), + "id", + ) + args = append(args, devEmail) + case devId != "": + appQuery = selectAppByNameAndDeveloperId( + "?", + "?", + "id", + ) + args = append(args, devId) + case comName != "": + appQuery = selectAppByNameAndCompanyId( + "?", + selectCompanyByName( + "?", + "id", + ), + "id", + ) + args = append(args, comName) + default: + appQuery = selectAppByName( + "?", + "id", + ) + } + + args = append(args, org) + + query := selectApiProductsById( + selectAppCredentialMapperByAppId( + appQuery, + "apiprdt_id", + ), + cols..., + ) + " AND ap.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getApiProductsByAppName: %v", query) + err = d.GetDb().QueryStructs(&apiProducts, query, args...) + return +} + +func (d *DbManager) getAppByAppId(id, org string) (apps []common.App, err error) { + cols := []string{"*"} + query := selectAppById( + "?", + cols..., + ) + " AND a.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getAppByAppId: %v \n %v", query, id) + err = d.GetDb().QueryStructs(&apps, query, id, org) + return +} + +func (d *DbManager) getAppByAppName(appName, devEmail, devId, comName, org string) (apps []common.App, err error) { + cols := []string{"*"} + var query string + args := []interface{}{appName} + switch { + case devEmail != "": + query = selectAppByNameAndDeveloperId( + "?", + selectDeveloperByEmail( + "?", + "id", + ), + cols..., + ) + args = append(args, devEmail) + case devId != "": + query = selectAppByNameAndDeveloperId( + "?", + "?", + cols..., + ) + args = append(args, devId) + case comName != "": + query = selectAppByNameAndCompanyId( + "?", + selectCompanyByName( + "?", + "id", + ), + cols..., + ) + args = append(args, comName) + default: + query = selectAppByName( + "?", + cols..., + ) + } + + args = append(args, org) + + query += " AND a.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getAppByAppName: %v", query) + err = d.GetDb().QueryStructs(&apps, query, args...) + return +} + +func (d *DbManager) getAppByConsumerKey(consumerKey, org string) (apps []common.App, err error) { + cols := []string{"*"} + query := selectAppById( + selectAppCredentialMapperByConsumerKey( + "?", + "app_id", + ), + cols..., + ) + " AND a.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getAppByConsumerKey: %v", query) + err = d.GetDb().QueryStructs(&apps, query, consumerKey, org) + return +} + +func (d *DbManager) getAppCredentialByConsumerKey(consumerKey, org string) (appCredentials []common.AppCredential, err error) { + cols := []string{"*"} + query := selectAppCredentialByConsumerKey( + "?", + cols..., + ) + " AND ac.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getAppCredentialByConsumerKey: %v", query) + err = d.GetDb().QueryStructs(&appCredentials, query, consumerKey, org) + return +} + +func (d *DbManager) getAppCredentialByAppId(appId, org string) (appCredentials []common.AppCredential, err error) { + cols := []string{"*"} + query := selectAppCredentialByConsumerKey( + selectAppCredentialMapperByAppId( + "?", + "appcred_id", + ), + cols..., + ) + " AND ac.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getAppCredentialByAppId: %v", query) + err = d.GetDb().QueryStructs(&appCredentials, query, appId, org) + return +} + +func (d *DbManager) getCompanyByAppId(appId, org string) (companies []common.Company, err error) { + cols := []string{"*"} + query := selectCompanyByComId( + selectAppById( + "?", + "company_id", + ), + cols..., + ) + " AND com.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getCompanyByAppId: %v", query) + err = d.GetDb().QueryStructs(&companies, query, appId, org) + return +} + +func (d *DbManager) getCompanyByName(name, org string) (companies []common.Company, err error) { + cols := []string{"*"} + query := selectCompanyByName( + "?", + cols..., + ) + " AND com.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getCompanyByName: %v", query) + err = d.GetDb().QueryStructs(&companies, query, name, org) + return +} + +func (d *DbManager) getCompanyByConsumerKey(consumerKey, org string) (companies []common.Company, err error) { + cols := []string{"*"} + query := selectCompanyByComId( + selectAppById( + selectAppCredentialMapperByConsumerKey( + "?", + "app_id", + ), + "company_id", + ), + cols..., + ) + " AND com.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getCompanyByConsumerKey: %v", query) + err = d.GetDb().QueryStructs(&companies, query, consumerKey, org) + return +} + +func (d *DbManager) getCompanyDeveloperByComName(comName, org string) (companyDevelopers []common.CompanyDeveloper, err error) { + cols := []string{"*"} + query := selectCompanyDeveloperByComId( + selectCompanyByName( + "?", + "id", + ), + cols..., + ) + " AND cd.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getCompanyDeveloperByComName: %v", query) + err = d.GetDb().QueryStructs(&companyDevelopers, query, comName, org) + return +} + +func (d *DbManager) getDeveloperByAppId(appId, org string) (developers []common.Developer, err error) { + cols := []string{"*"} + query := selectDeveloperById( + selectAppById( + "?", + "developer_id", + ), + cols..., + ) + " AND dev.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getDeveloperByAppId: %v", query) + err = d.GetDb().QueryStructs(&developers, query, appId, org) + return +} + +func (d *DbManager) getDeveloperByConsumerKey(consumerKey, org string) (developers []common.Developer, err error) { + cols := []string{"*"} + query := selectDeveloperById( + selectAppById( + selectAppCredentialMapperByConsumerKey( + "?", + "app_id", + ), + "developer_id", + ), + cols..., + ) + " AND dev.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getDeveloperByConsumerKey: %v", query) + err = d.GetDb().QueryStructs(&developers, query, consumerKey, org) + return +} + +func (d *DbManager) getDeveloperByEmail(email, org string) (developers []common.Developer, err error) { + cols := []string{"*"} + query := selectDeveloperByEmail( + "?", + cols..., + ) + " AND dev.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getDeveloperByEmail: %v", query) + err = d.GetDb().QueryStructs(&developers, query, email, org) + return +} + +func (d *DbManager) getDeveloperById(id, org string) (developers []common.Developer, err error) { + cols := []string{"*"} + query := selectDeveloperById( + "?", + cols..., + ) + " AND dev.tenant_id IN " + sql_select_tenant_org + //log.Debugf("getDeveloperById: %v", query) + err = d.GetDb().QueryStructs(&developers, query, id, org) + return +} + +func selectApiProductsById(idQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_api_product AS ap WHERE ap.id IN (" + + idQuery + + ")" + + return query +} + +func selectAppCredentialMapperByAppId(idQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app_credential_apiproduct_mapper AS acm WHERE acm.app_id IN (" + + idQuery + + ")" + return query +} + +func selectAppCredentialMapperByConsumerKey(keyQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app_credential_apiproduct_mapper AS acm WHERE acm.appcred_id IN (" + + keyQuery + + ")" + return query +} + +func selectAppByName(nameQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app AS a WHERE a.name IN (" + + nameQuery + + ")" + return query +} + +func selectAppById(appIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app AS a WHERE a.id IN (" + + appIdQuery + + ")" + return query +} + +func selectAppByComId(comIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app AS a WHERE a.company_id IN (" + + comIdQuery + + ")" + return query +} + +func selectAppByDevId(devIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app AS a WHERE a.developer_id IN (" + + devIdQuery + + ")" + return query +} + +func selectAppByNameAndDeveloperId(nameQuery string, developerIdQuery string, colNames ...string) string { + query := selectAppByName(nameQuery, colNames...) + + " AND developer_id IN (" + + developerIdQuery + + ")" + return query +} + +func selectAppByNameAndCompanyId(nameQuery string, companyIdQuery string, colNames ...string) string { + query := selectAppByName(nameQuery, colNames...) + + " AND company_id IN (" + + companyIdQuery + + ")" + return query +} + +func selectDeveloperByEmail(emailQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_developer AS dev WHERE dev.email IN (" + + emailQuery + + ")" + return query +} + +func selectDeveloperById(idQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_developer AS dev WHERE dev.id IN (" + + idQuery + + ")" + return query +} + +func selectCompanyByName(nameQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_company AS com WHERE com.name IN (" + + nameQuery + + ")" + return query +} + +func selectCompanyByComId(comIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_company AS com WHERE com.id IN (" + + comIdQuery + + ")" + return query +} + +func selectCompanyDeveloperByComId(comIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_company_developer AS cd WHERE cd.company_id IN (" + + comIdQuery + + ")" + return query +} + +func selectCompanyDeveloperByDevId(devIdQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_company_developer AS cd WHERE cd.developer_id IN (" + + devIdQuery + + ")" + return query +} + +func selectAppCredentialByConsumerKey(consumerQuery string, colNames ...string) string { + query := "SELECT " + + strings.Join(colNames, ",") + + " FROM kms_app_credential AS ac WHERE ac.id IN (" + + consumerQuery + + ")" + return query +} + +func filterApiProductsByResource(apiProducts []common.ApiProduct, resource string) []common.ApiProduct { + //log.Debugf("Before filter: %v", apiProducts) + var prods []common.ApiProduct + for _, prod := range apiProducts { + resources := common.JsonToStringArray(prod.ApiResources) + if Contains(resources, resource) { + prods = append(prods, prod) + } + } + //log.Debugf("After filter: %v", prods) + return prods +} + +func Contains(sl []string, str string) bool { + for _, s := range sl { + if s == str { + return true + } + } + return false +}
diff --git a/accessEntity/data_test.go b/accessEntity/data_test.go new file mode 100644 index 0000000..e0e873f --- /dev/null +++ b/accessEntity/data_test.go
@@ -0,0 +1,556 @@ +// 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 accessEntity + +import ( + "github.com/apid/apid-core" + "github.com/apid/apidVerifyApiKey/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "io/ioutil" + "sync" +) + +const ( + fileDataTest = "data_test.sql" + // SQL Injection + // If select foo from bar where id in (' + condition + ') is used, + // the hacked sql would be like "select XXX from XXX where id in ('1') or ('1'=='1');" + sqlInjectionStmt = "1') or ('1'=='1" +) + +var _ = Describe("DataTest", func() { + + Context("query Db to get entities", func() { + var dataTestTempDir string + var dbMan *DbManager + BeforeEach(func() { + var err error + dataTestTempDir, err = ioutil.TempDir(testTempDirBase, "sqlite3") + Expect(err).NotTo(HaveOccurred()) + services.Config().Set("local_storage_path", dataTestTempDir) + + dbMan = &DbManager{ + DbManager: common.DbManager{ + Data: services.Data(), + DbMux: sync.RWMutex{}, + }, + } + dbMan.SetDbVersion(dataTestTempDir) + setupTestDb(dbMan.GetDb()) + }) + + Describe("Get structs", func() { + It("should get apiProducts", func() { + testData := [][]string{ + //positive tests + {IdentifierApiProductName, "apstest", "", "", "apid-haoming"}, + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "apid-haoming"}, + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", IdentifierApiResource, "/**", "apid-haoming"}, + {IdentifierAppName, "apstest", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "abcd", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "abcd", IdentifierApiResource, "/**", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperId, "e41f04e8-9d3f-470a-8bfd-c7939945896c", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperEmail, "bar@google.com", "apid-haoming"}, + {IdentifierAppName, "testappahhis", IdentifierCompanyName, "testcompanyhflxv", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierApiResource, "/**", "apid-haoming"}, + // negative tests + {IdentifierApiProductName, "apstest", "", "", "non-existent"}, + {IdentifierApiProductName, "non-existent", "", "", "apid-haoming"}, + {IdentifierAppId, "non-existent", "", "", "apid-haoming"}, + {IdentifierAppId, "non-existent", IdentifierApiResource, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "non-existent", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "non-existent", IdentifierApiResource, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierDeveloperId, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierDeveloperEmail, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierCompanyName, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierApiResource, "non-existent", "apid-haoming"}, + // SQL Injection + {IdentifierApiProductName, "apstest", "", "", sqlInjectionStmt}, + {IdentifierApiProductName, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppId, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppName, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierConsumerKey, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperId, sqlInjectionStmt, "apid-haoming"}, + {IdentifierAppName, "testappahhis", IdentifierDeveloperEmail, sqlInjectionStmt, "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierCompanyName, sqlInjectionStmt, "apid-haoming"}, + } + + var expectedDevApiProd = common.ApiProduct{ + Id: "b7e0970c-4677-4b05-8105-5ea59fdcf4e7", + Name: "apstest", + DisplayName: "apstest", + Description: "", + ApiResources: "{/**}", + ApprovalType: "AUTO", + Scopes: `{""}`, + Proxies: `{aps,perfBenchmark}`, + Environments: `{prod,test}`, + Quota: "10000000", + QuotaTimeUnit: "MINUTE", + QuotaInterval: 1, + CreatedAt: "2017-08-18 22:12:49.363+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:26:50.153+00:00", + UpdatedBy: "haoming@apid.git", + TenantId: "515211e9", + } + + var expectedComApiProd = common.ApiProduct{ + Id: "fea8a6d5-8d34-477f-ac82-c397eaec06af", + Name: "testproductsdljnkpt", + DisplayName: "testproductsdljnkpt", + Description: "", + ApiResources: "{/res1}", + ApprovalType: "AUTO", + Scopes: `{}`, + Proxies: `{}`, + Environments: `{test}`, + Quota: "", + QuotaTimeUnit: "", + QuotaInterval: 0, + CreatedAt: "2017-11-02 16:00:15.608+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:18.125+00:00", + UpdatedBy: "haoming@apid.git", + TenantId: "515211e9", + } + + results := [][]common.ApiProduct{ + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedDevApiProd}, + {expectedComApiProd}, + {expectedDevApiProd}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + prods, err := dbMan.GetApiProducts(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(prods).Should(Equal(results[i])) + } else { + Expect(prods).Should(BeZero()) + } + } + }) + + It("should get apps", func() { + testData := [][]string{ + //positive tests + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "apid-haoming"}, + {IdentifierAppName, "apstest", "", "", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperId, "e41f04e8-9d3f-470a-8bfd-c7939945896c", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperEmail, "bar@google.com", "apid-haoming"}, + {IdentifierAppName, "testappahhis", IdentifierCompanyName, "testcompanyhflxv", "apid-haoming"}, + {IdentifierConsumerKey, "abcd", "", "", "apid-haoming"}, + // negative tests + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "non-existent"}, + {IdentifierAppId, "non-existent", "", "", "apid-haoming"}, + {IdentifierAppName, "non-existent", "", "", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierDeveloperId, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierDeveloperEmail, "non-existent", "apid-haoming"}, + {IdentifierAppName, "non-existent", IdentifierCompanyName, "non-existent", "apid-haoming"}, + {IdentifierConsumerKey, "non-existent", "", "", "apid-haoming"}, + // SQL Injection + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", sqlInjectionStmt}, + {IdentifierAppId, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppName, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperId, sqlInjectionStmt, "apid-haoming"}, + {IdentifierAppName, "apstest", IdentifierDeveloperEmail, sqlInjectionStmt, "apid-haoming"}, + {IdentifierAppName, "testappahhis", IdentifierCompanyName, sqlInjectionStmt, "apid-haoming"}, + {IdentifierConsumerKey, sqlInjectionStmt, "", "", "apid-haoming"}, + } + + var expectedDevApp = common.App{ + Id: "408ad853-3fa0-402f-90ee-103de98d71a5", + TenantId: "515211e9", + Name: "apstest", + DisplayName: "apstest", + AccessType: "READ", + CallbackUrl: "https://www.google.com", + Status: "APPROVED", + AppFamily: "default", + CompanyId: "", + DeveloperId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + ParentId: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + Type: "DEVELOPER", + CreatedAt: "2017-08-18 22:13:18.325+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-08-18 22:13:18.325+00:00", + UpdatedBy: "haoming@apid.git", + } + + var expectedComApp = common.App{ + Id: "35608afe-2715-4064-bb4d-3cbb4e82c474", + TenantId: "515211e9", + Name: "testappahhis", + DisplayName: "testappahhis", + AccessType: "READ", + CallbackUrl: "", + Status: "APPROVED", + AppFamily: "default", + CompanyId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + DeveloperId: "", + ParentId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + Type: "COMPANY", + CreatedAt: "2017-11-02 16:00:16.504+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:16.504+00:00", + UpdatedBy: "haoming@apid.git", + } + + results := [][]common.App{ + {expectedDevApp}, + {expectedDevApp}, + {expectedDevApp}, + {expectedDevApp}, + {expectedComApp}, + {expectedDevApp}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + apps, err := dbMan.GetApps(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(apps).Should(Equal(results[i])) + } else { + Expect(apps).Should(BeZero()) + } + } + }) + + It("should get Companies", func() { + testData := [][]string{ + //positive tests + {IdentifierAppId, "35608afe-2715-4064-bb4d-3cbb4e82c474", "", "", "apid-haoming"}, + {IdentifierCompanyName, "testcompanyhflxv", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "wxyz", "", "", "apid-haoming"}, + // negative tests + {IdentifierAppId, "35608afe-2715-4064-bb4d-3cbb4e82c474", "", "", "non-existent"}, + {IdentifierAppId, "non-existent", "", "", "apid-haoming"}, + {IdentifierCompanyName, "non-existent", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "non-existent", "", "", "apid-haoming"}, + // SQL Injection + {IdentifierAppId, "35608afe-2715-4064-bb4d-3cbb4e82c474", "", "", sqlInjectionStmt}, + {IdentifierAppId, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierCompanyName, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierConsumerKey, sqlInjectionStmt, "", "", "apid-haoming"}, + } + + var expectedCom = common.Company{ + Id: "a94f75e2-69b0-44af-8776-155df7c7d22e", + TenantId: "515211e9", + Name: "testcompanyhflxv", + DisplayName: "testcompanyhflxv", + Status: "ACTIVE", + CreatedAt: "2017-11-02 16:00:16.287+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:16.287+00:00", + UpdatedBy: "haoming@apid.git", + } + + results := [][]common.Company{ + {expectedCom}, + {expectedCom}, + {expectedCom}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + apps, err := dbMan.GetCompanies(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(apps).Should(Equal(results[i])) + } else { + Expect(apps).Should(BeZero()) + } + } + }) + + It("should get developers", func() { + testData := [][]string{ + //positive tests + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "abcd", "", "", "apid-haoming"}, + {IdentifierDeveloperEmail, "bar@google.com", "", "", "apid-haoming"}, + {IdentifierDeveloperId, "e41f04e8-9d3f-470a-8bfd-c7939945896c", "", "", "apid-haoming"}, + + // negative tests + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "non-existent"}, + {IdentifierAppId, "non-existent", "", "", "apid-haoming"}, + {IdentifierConsumerKey, "non-existent", "", "", "apid-haoming"}, + {IdentifierDeveloperEmail, "non-existent", "", "", "apid-haoming"}, + {IdentifierDeveloperId, "non-existent", "", "", "apid-haoming"}, + // SQL Injection + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", sqlInjectionStmt}, + {IdentifierAppId, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierConsumerKey, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierDeveloperEmail, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierDeveloperId, sqlInjectionStmt, "", "", "apid-haoming"}, + } + + var expectedDev = common.Developer{ + Id: "e41f04e8-9d3f-470a-8bfd-c7939945896c", + TenantId: "515211e9", + UserName: "haoming", + FirstName: "haoming", + LastName: "zhang", + Password: "", + Email: "bar@google.com", + Status: "ACTIVE", + EncryptedPassword: "", + Salt: "", + CreatedAt: "2017-08-16 22:39:46.669+00:00", + CreatedBy: "foo@google.com", + UpdatedAt: "2017-08-16 22:39:46.669+00:00", + UpdatedBy: "foo@google.com", + } + + results := [][]common.Developer{ + {expectedDev}, + {expectedDev}, + {expectedDev}, + {expectedDev}, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + prods, err := dbMan.GetDevelopers(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(prods).Should(Equal(results[i])) + } else { + Expect(prods).Should(BeZero()) + } + } + }) + + It("should get appCredentials", func() { + testData := [][]string{ + // positive tests + {IdentifierConsumerKey, "abcd", "", "", "apid-haoming"}, + {IdentifierAppId, "408ad853-3fa0-402f-90ee-103de98d71a5", "", "", "apid-haoming"}, + // negative tests + {IdentifierConsumerKey, "abcd", "", "", "non-existent"}, + {IdentifierConsumerKey, "non-existent", "", "", "apid-haoming"}, + {IdentifierAppId, "non-existent", "", "", "apid-haoming"}, + // SQL Injection + {IdentifierConsumerKey, "abcd", "", "", sqlInjectionStmt}, + {IdentifierConsumerKey, sqlInjectionStmt, "", "", "apid-haoming"}, + {IdentifierAppId, sqlInjectionStmt, "", "", "apid-haoming"}, + } + + var expectedCred = common.AppCredential{ + Id: "abcd", + TenantId: "515211e9", + ConsumerSecret: "secret1", + AppId: "408ad853-3fa0-402f-90ee-103de98d71a5", + MethodType: "", + Status: "APPROVED", + IssuedAt: "2017-08-18 22:13:18.35+00:00", + ExpiresAt: "", + AppStatus: "", + Scopes: "{}", + CreatedAt: "2017-08-18 22:13:18.35+00:00", + CreatedBy: "-NA-", + UpdatedAt: "2017-08-18 22:13:18.352+00:00", + UpdatedBy: "-NA-", + } + + results := [][]common.AppCredential{ + {expectedCred}, + {expectedCred}, + nil, + nil, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + prods, err := dbMan.GetAppCredentials(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(prods).Should(Equal(results[i])) + } else { + Expect(prods).Should(BeZero()) + } + } + }) + + It("should get CompanyDevelopers", func() { + testData := [][]string{ + // positive tests + {IdentifierCompanyName, "testcompanyhflxv", "", "", "apid-haoming"}, + // negative tests + {IdentifierCompanyName, "testcompanyhflxv", "", "", "non-existent"}, + {IdentifierCompanyName, "non-existent", "", "", "apid-haoming"}, + // SQL Injection + {IdentifierCompanyName, "testcompanyhflxv", "", "", sqlInjectionStmt}, + {IdentifierCompanyName, sqlInjectionStmt, "", "", "apid-haoming"}, + } + + var expectedComDev = common.CompanyDeveloper{ + TenantId: "515211e9", + CompanyId: "a94f75e2-69b0-44af-8776-155df7c7d22e", + DeveloperId: "590f33bf-f05c-48c1-bb93-183759bd9ee1", + Roles: "admin", + CreatedAt: "2017-11-02 16:00:16.287+00:00", + CreatedBy: "haoming@apid.git", + UpdatedAt: "2017-11-02 16:00:16.287+00:00", + UpdatedBy: "haoming@apid.git", + } + + results := [][]common.CompanyDeveloper{ + {expectedComDev}, + nil, + nil, + nil, + nil, + } + + for i, data := range testData { + priKey, priVal, secKey, secVal, org := data[0], data[1], data[2], data[3], data[4] + prods, err := dbMan.GetCompanyDevelopers(org, priKey, priVal, secKey, secVal) + Expect(err).Should(Succeed()) + if len(results[i]) > 0 { + Expect(prods).Should(Equal(results[i])) + } else { + Expect(prods).Should(BeZero()) + } + } + }) + + }) + + Describe("utils", func() { + It("GetApiProductNamesByConsumerKey", func() { + data := "abcd" + expected := []string{"apstest"} + Expect(dbMan.GetApiProductNames(data, TypeConsumerKey)).Should(Equal(expected)) + + data = "408ad853-3fa0-402f-90ee-103de98d71a5" + expected = []string{"apstest"} + Expect(dbMan.GetApiProductNames(data, TypeApp)).Should(Equal(expected)) + }) + + It("GetAppNames", func() { + data := "a94f75e2-69b0-44af-8776-155df7c7d22e" + expected := []string{"testappahhis"} + Expect(dbMan.GetAppNames(data, TypeCompany)).Should(Equal(expected)) + + data = "e41f04e8-9d3f-470a-8bfd-c7939945896c" + expected = []string{"apstest"} + Expect(dbMan.GetAppNames(data, TypeDeveloper)).Should(Equal(expected)) + }) + + It("GetComNames", func() { + data := "8ba5b747-5104-4a40-89ca-a0a51798fe34" + expected := []string{"DevCompany"} + Expect(dbMan.GetComNames(data, TypeCompany)).Should(Equal(expected)) + data = "590f33bf-f05c-48c1-bb93-183759bd9ee1" + expected = []string{"testcompanyhflxv"} + Expect(dbMan.GetComNames(data, TypeDeveloper)).Should(Equal(expected)) + }) + + It("GetDevEmailByDevId", func() { + data := "e41f04e8-9d3f-470a-8bfd-c7939945896c" + expected := "bar@google.com" + Expect(dbMan.GetDevEmailByDevId(data)).Should(Equal(expected)) + }) + + It("GetStatus", func() { + data := "e41f04e8-9d3f-470a-8bfd-c7939945896c" + expected := "ACTIVE" + Expect(dbMan.GetStatus(data, AppTypeDeveloper)).Should(Equal(expected)) + data = "8ba5b747-5104-4a40-89ca-a0a51798fe34" + expected = "ACTIVE" + Expect(dbMan.GetStatus(data, AppTypeCompany)).Should(Equal(expected)) + }) + + }) + + }) + +}) + +func setupTestDb(db apid.DB) { + bytes, err := ioutil.ReadFile(fileDataTest) + Expect(err).Should(Succeed()) + query := string(bytes) + _, err = db.Exec(query) + Expect(err).Should(Succeed()) +}
diff --git a/accessEntity/data_test.sql b/accessEntity/data_test.sql new file mode 100644 index 0000000..8b1590a --- /dev/null +++ b/accessEntity/data_test.sql
@@ -0,0 +1,61 @@ +-- 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. + +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE 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)); +INSERT INTO "kms_app" VALUES('408ad853-3fa0-402f-90ee-103de98d71a5','515211e9','apstest','apstest','READ','https://www.google.com','APPROVED','default','','e41f04e8-9d3f-470a-8bfd-c7939945896c','e41f04e8-9d3f-470a-8bfd-c7939945896c','DEVELOPER','2017-08-18 22:13:18.325+00:00','haoming@apid.git','2017-08-18 22:13:18.325+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_app" VALUES('ae053aee-f12d-4591-84ef-2e6ae0d4205d','515211e9','apigee-remote-proxy','','','','APPROVED','default','','590f33bf-f05c-48c1-bb93-183759bd9ee1','590f33bf-f05c-48c1-bb93-183759bd9ee1','DEVELOPER','2017-09-20 23:05:59.125+00:00','haoming@apid.git','2017-09-20 23:05:59.125+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_app" VALUES('35608afe-2715-4064-bb4d-3cbb4e82c474','515211e9','testappahhis','testappahhis','READ','','APPROVED','default','a94f75e2-69b0-44af-8776-155df7c7d22e','','a94f75e2-69b0-44af-8776-155df7c7d22e','COMPANY','2017-11-02 16:00:16.504+00:00','haoming@apid.git','2017-11-02 16:00:16.504+00:00','haoming@apid.git','515211e9'); +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)); +INSERT INTO "kms_attributes" VALUES('515211e9','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','','','','','features.isSmbOrganization','ORGANIZATION','false','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','','','','','features.mgmtGroup','ORGANIZATION','management-edgex','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','','','','','features.isEdgexEnabled','ORGANIZATION','true','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','e2cc4caf-40d6-4ecb-8149-ed32d04184b2','','','','','','features.isCpsEnabled','ORGANIZATION','true','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','b7e0970c-4677-4b05-8105-5ea59fdcf4e7','','','','','b7e0970c-4677-4b05-8105-5ea59fdcf4e7','','','access','APIPRODUCT','public','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','408ad853-3fa0-402f-90ee-103de98d71a5','','','','','','408ad853-3fa0-402f-90ee-103de98d71a5','','DisplayName','APP','apstest','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','408ad853-3fa0-402f-90ee-103de98d71a5','','','','','','408ad853-3fa0-402f-90ee-103de98d71a5','','Notes','APP','','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','db90a25a-15c8-42ad-96c1-63ed9682b5a9','','','','','db90a25a-15c8-42ad-96c1-63ed9682b5a9','','','access','APIPRODUCT','public','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','ae053aee-f12d-4591-84ef-2e6ae0d4205d','','','','','','ae053aee-f12d-4591-84ef-2e6ae0d4205d','','DisplayName','APP','apigee-remote-proxy','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','ae053aee-f12d-4591-84ef-2e6ae0d4205d','','','','','','ae053aee-f12d-4591-84ef-2e6ae0d4205d','','Notes','APP','','515211e9'); +INSERT INTO "kms_attributes" VALUES('515211e9','fea8a6d5-8d34-477f-ac82-c397eaec06af','','','','','fea8a6d5-8d34-477f-ac82-c397eaec06af','','','Company','APIPRODUCT','Apigee','515211e9'); +CREATE TABLE 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)); +INSERT INTO "kms_company" VALUES('8ba5b747-5104-4a40-89ca-a0a51798fe34','515211e9','DevCompany','East India Company','ACTIVE','2017-08-15 03:29:02.449+00:00','haoming@apid.git','2017-08-15 03:29:02.449+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_company" VALUES('a94f75e2-69b0-44af-8776-155df7c7d22e','515211e9','testcompanyhflxv','testcompanyhflxv','ACTIVE','2017-11-02 16:00:16.287+00:00','haoming@apid.git','2017-11-02 16:00:16.287+00:00','haoming@apid.git','515211e9'); +CREATE TABLE kms_company_developer (tenant_id text,company_id text,developer_id text,roles text,created_at blob,created_by text,updated_at blob,updated_by text,_change_selector text, primary key (tenant_id,company_id,developer_id)); +INSERT INTO "kms_company_developer" VALUES('515211e9','a94f75e2-69b0-44af-8776-155df7c7d22e','590f33bf-f05c-48c1-bb93-183759bd9ee1','admin','2017-11-02 16:00:16.287+00:00','haoming@apid.git','2017-11-02 16:00:16.287+00:00','haoming@apid.git','515211e9'); +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)); +INSERT INTO "kms_developer" VALUES('e41f04e8-9d3f-470a-8bfd-c7939945896c','515211e9','haoming','haoming','zhang','','bar@google.com','ACTIVE','','','2017-08-16 22:39:46.669+00:00','foo@google.com','2017-08-16 22:39:46.669+00:00','foo@google.com','515211e9'); +INSERT INTO "kms_developer" VALUES('47d862db-884f-4b8e-9649-fe6d0be1a739','515211e9','qwe','qwe','qwe','','barfoo@google.com','ACTIVE','','','2017-10-12 19:12:48.306+00:00','haoming@apid.git','2017-10-12 19:12:48.306+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_developer" VALUES('590f33bf-f05c-48c1-bb93-183759bd9ee1','515211e9','remoteproxy','remote','proxy','','fooo@google.com','ACTIVE','','','2017-09-20 23:03:52.327+00:00','haoming@apid.git','2017-09-20 23:03:52.327+00:00','haoming@apid.git','515211e9'); +CREATE TABLE edgex_apid_cluster (id text,name text,description text,umbrella_org_app_name text,created blob,created_by text,updated blob,updated_by text,_change_selector text, last_sequence text DEFAULT '', primary key (id)); +INSERT INTO "edgex_apid_cluster" VALUES('950b30f1-8c41-4bf5-94a3-f10c104ff5d4','apid-haomingOrgCluster','','X-sZXhaOymL6VtWnNQqK7uPsFyPvZYq6FFnrc8','2017-08-23 23:31:49.134+00:00','temp@google.com','2017-08-23 23:31:49.134+00:00','temp@google.com','950b30f1-8c41-4bf5-94a3-f10c104ff5d4',''); +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)); +INSERT INTO "kms_api_product" VALUES('b7e0970c-4677-4b05-8105-5ea59fdcf4e7','515211e9','apstest','apstest','','{/**}','AUTO','{""}','{aps,perfBenchmark}','{prod,test}','10000000','MINUTE',1,'2017-08-18 22:12:49.363+00:00','haoming@apid.git','2017-08-18 22:26:50.153+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_api_product" VALUES('8501392f-c5f7-4d6a-8841-e038ad5913b4','515211e9','ApigeenTestApp','ApigeenTestApp','','{/}','AUTO','{scope1,scope2,scope3}','{}','{prod,test}','','',NULL,'2017-09-20 22:29:06.451+00:00','haoming@apid.git','2017-09-20 22:29:06.451+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_api_product" VALUES('e4ae89d0-ea47-4b23-b0dc-2723efb15c84','515211e9','ApigeenTestApp2','ApigeenTestApp2','','{/}','AUTO','{scope1,scope2,scope3}','{}','{prod,test}','','',NULL,'2017-09-20 22:29:08.988+00:00','haoming@apid.git','2017-09-20 22:29:08.988+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_api_product" VALUES('07419482-e5a1-4fd0-9d78-3560ba522b44','515211e9','ApigeenTestApp3','ApigeenTestApp3','','{/}','AUTO','{}','{}','{prod,test}','','',NULL,'2017-09-20 22:29:11.482+00:00','haoming@apid.git','2017-09-20 22:29:11.482+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_api_product" VALUES('db90a25a-15c8-42ad-96c1-63ed9682b5a9','515211e9','apigee-remote-proxy','apigee-remote-proxy','','{/**,/}','AUTO','{""}','{apigee-remote-proxy}','{prod,test}','','',NULL,'2017-09-20 23:05:09.234+00:00','haoming@apid.git','2017-09-20 23:05:09.234+00:00','haoming@apid.git','515211e9'); +INSERT INTO "kms_api_product" VALUES('fea8a6d5-8d34-477f-ac82-c397eaec06af','515211e9','testproductsdljnkpt','testproductsdljnkpt','','{/res1}','AUTO','{}','{}','{test}','','',NULL,'2017-11-02 16:00:15.608+00:00','haoming@apid.git','2017-11-02 16:00:18.125+00:00','haoming@apid.git','515211e9'); +CREATE TABLE 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)); +INSERT INTO "kms_app_credential" VALUES('abcd','515211e9','secret1','408ad853-3fa0-402f-90ee-103de98d71a5','','APPROVED','2017-08-18 22:13:18.35+00:00','','','{}','2017-08-18 22:13:18.35+00:00','-NA-','2017-08-18 22:13:18.352+00:00','-NA-','515211e9'); +INSERT INTO "kms_app_credential" VALUES('dcba','515211e9','secret2','ae053aee-f12d-4591-84ef-2e6ae0d4205d','','APPROVED','2017-09-20 23:05:59.148+00:00','','','{}','2017-09-20 23:05:59.148+00:00','-NA-','2017-09-20 23:05:59.151+00:00','-NA-','515211e9'); +INSERT INTO "kms_app_credential" VALUES('wxyz','515211e9','secret3','35608afe-2715-4064-bb4d-3cbb4e82c474','','APPROVED','2017-11-02 16:00:16.512+00:00','','','{}','2017-11-02 16:00:16.512+00:00','-NA-','2017-11-02 16:00:16.514+00:00','-NA-','515211e9'); +CREATE TABLE 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)); +INSERT INTO "kms_app_credential_apiproduct_mapper" VALUES('515211e9','abcd','408ad853-3fa0-402f-90ee-103de98d71a5','b7e0970c-4677-4b05-8105-5ea59fdcf4e7','APPROVED','515211e9'); +INSERT INTO "kms_app_credential_apiproduct_mapper" VALUES('515211e9','dcba','ae053aee-f12d-4591-84ef-2e6ae0d4205d','db90a25a-15c8-42ad-96c1-63ed9682b5a9','APPROVED','515211e9'); +INSERT INTO "kms_app_credential_apiproduct_mapper" VALUES('515211e9','wxyz','35608afe-2715-4064-bb4d-3cbb4e82c474','fea8a6d5-8d34-477f-ac82-c397eaec06af','APPROVED','515211e9'); +CREATE TABLE 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)); +INSERT INTO "kms_organization" VALUES('e2cc4caf-40d6-4ecb-8149-ed32d04184b2','apid-haoming','apid-haoming','paid','515211e9','94cd5075-7f33-4afb-9545-a53a254277a1','','2017-08-16 22:16:06.544+00:00','foobar@google.com','2017-08-16 22:29:23.046+00:00','foobar@google.com','515211e9'); +COMMIT;
diff --git a/pluginData.go b/accessEntity/init.go similarity index 73% copy from pluginData.go copy to accessEntity/init.go index 0ebe61b..ed5de94 100644 --- a/pluginData.go +++ b/accessEntity/init.go
@@ -11,15 +11,18 @@ // 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 accessEntity -package apidVerifyApiKey +import ( + "github.com/apid/apid-core" +) -import "github.com/apid/apid-core" +var ( + services apid.Services + log apid.LogService +) -var pluginData = apid.PluginData{ - Name: "apidVerifyAPIKey", - Version: "0.0.4", - ExtraData: map[string]interface{}{ - "schemaVersion": "0.0.3", - }, +func SetApidServices(s apid.Services, l apid.LogService) { + services = s + log = l }
diff --git a/accessEntity/interfaces.go b/accessEntity/interfaces.go new file mode 100644 index 0000000..a580762 --- /dev/null +++ b/accessEntity/interfaces.go
@@ -0,0 +1,40 @@ +// 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 accessEntity + +import ( + "github.com/apid/apidVerifyApiKey/common" + "net/http" +) + +type ApiManagerInterface interface { + common.ApiManagerInterface + HandleRequest(w http.ResponseWriter, r *http.Request) +} + +type DbManagerInterface interface { + common.DbManagerInterface + GetApiProducts(org, priKey, priVal, secKey, secVal string) (apiProducts []common.ApiProduct, err error) + GetApps(org, priKey, priVal, secKey, secVal string) (apps []common.App, err error) + GetCompanies(org, priKey, priVal, secKey, secVal string) (companies []common.Company, err error) + GetCompanyDevelopers(org, priKey, priVal, secKey, secVal string) (companyDevelopers []common.CompanyDeveloper, err error) + GetAppCredentials(org, priKey, priVal, secKey, secVal string) (appCredentials []common.AppCredential, err error) + GetDevelopers(org, priKey, priVal, secKey, secVal string) (developers []common.Developer, err error) + // utils + GetApiProductNames(id string, idType string) ([]string, error) + GetAppNames(id string, idType string) ([]string, error) + GetComNames(id string, idType string) ([]string, error) + GetDevEmailByDevId(devId string) (string, error) + GetStatus(id, t string) (string, error) +}
diff --git a/accessEntity/mock_test.go b/accessEntity/mock_test.go new file mode 100644 index 0000000..18a9bbc --- /dev/null +++ b/accessEntity/mock_test.go
@@ -0,0 +1,89 @@ +// 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 accessEntity + +import ( + "github.com/apid/apidVerifyApiKey/common" +) + +type DummyDbMan struct { + apiProducts []common.ApiProduct + apps []common.App + companies []common.Company + companyDevelopers []common.CompanyDeveloper + appCredentials []common.AppCredential + developers []common.Developer + apiProductNames []string + appNames []string + comNames []string + email string + status string + attrs map[string][]common.Attribute + err error +} + +func (d *DummyDbMan) SetDbVersion(string) { + +} +func (d *DummyDbMan) GetDbVersion() string { + return "" +} + +func (d *DummyDbMan) GetKmsAttributes(tenantId string, entities ...string) map[string][]common.Attribute { + return d.attrs +} + +func (d *DummyDbMan) GetApiProducts(org, priKey, priVal, secKey, secVal string) (apiProducts []common.ApiProduct, err error) { + return d.apiProducts, d.err +} + +func (d *DummyDbMan) GetApps(org, priKey, priVal, secKey, secVal string) (apps []common.App, err error) { + return d.apps, d.err +} + +func (d *DummyDbMan) GetCompanies(org, priKey, priVal, secKey, secVal string) (companies []common.Company, err error) { + return d.companies, d.err +} + +func (d *DummyDbMan) GetCompanyDevelopers(org, priKey, priVal, secKey, secVal string) (companyDevelopers []common.CompanyDeveloper, err error) { + return d.companyDevelopers, d.err +} + +func (d *DummyDbMan) GetAppCredentials(org, priKey, priVal, secKey, secVal string) (appCredentials []common.AppCredential, err error) { + return d.appCredentials, d.err +} + +func (d *DummyDbMan) GetDevelopers(org, priKey, priVal, secKey, secVal string) (developers []common.Developer, err error) { + return d.developers, d.err +} + +func (d *DummyDbMan) GetApiProductNames(id string, idType string) ([]string, error) { + return d.apiProductNames, d.err +} + +func (d *DummyDbMan) GetAppNames(id string, idType string) ([]string, error) { + return d.appNames, d.err +} + +func (d *DummyDbMan) GetComNames(id string, idType string) ([]string, error) { + return d.comNames, d.err +} + +func (d *DummyDbMan) GetDevEmailByDevId(devId string) (string, error) { + return d.email, d.err +} + +func (d *DummyDbMan) GetStatus(id, t string) (string, error) { + return d.status, d.err +}
diff --git a/verifyAPIKey_suite_test.go b/apidApiMetadata_suite_test.go similarity index 86% rename from verifyAPIKey_suite_test.go rename to apidApiMetadata_suite_test.go index fdb5ed2..a66271f 100644 --- a/verifyAPIKey_suite_test.go +++ b/apidApiMetadata_suite_test.go
@@ -11,7 +11,6 @@ // 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 ( @@ -25,25 +24,17 @@ const testTempDirBase = "./tmp/" -var ( - testTempDir string - testSyncHandler apigeeSyncHandler -) - var _ = BeforeSuite(func() { _ = os.MkdirAll(testTempDirBase, os.ModePerm) }) var _ = AfterSuite(func() { apid.Events().Close() - if testServer != nil { - testServer.Close() - } os.RemoveAll(testTempDirBase) }) -func TestVerifyAPIKey(t *testing.T) { +func TestApiMetadata(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "VerifyAPIKey Suite") }
diff --git a/common/api.go b/common/api.go new file mode 100644 index 0000000..9b3f243 --- /dev/null +++ b/common/api.go
@@ -0,0 +1,35 @@ +// 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 common + +import ( + "encoding/json" + "net/http" + "strconv" +) + +func WriteError(w http.ResponseWriter, reason string, errorCode int, statusCode int) { + w.WriteHeader(statusCode) + resp := ErrorResponse{ + ResponseCode: strconv.Itoa(errorCode), + ResponseMessage: reason, + StatusCode: statusCode, + } + bytes, err := json.Marshal(resp) + if err != nil { + w.Write([]byte("unable to marshal errorResponse: " + err.Error())) + } else { + w.Write(bytes) + } +}
diff --git a/common/data.go b/common/data.go new file mode 100644 index 0000000..a592f97 --- /dev/null +++ b/common/data.go
@@ -0,0 +1,110 @@ +// 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 common + +import ( + "database/sql" + "encoding/json" + "github.com/apid/apid-core" + "strings" + "sync" + "unicode/utf8" +) + +type DbManager struct { + Data apid.DataService + Db apid.DB + DbMux sync.RWMutex + dbVersion string +} + +const ( + sql_GET_KMS_ATTRIBUTES_FOR_TENANT = `select entity_id, name, value from kms_attributes where tenant_id = $1` +) + +var ( + services apid.Services + log apid.LogService +) + +func SetApidServices(s apid.Services, l apid.LogService) { + services = s + log = l +} + +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 +} + +func (dbc *DbManager) GetDb() apid.DB { + dbc.DbMux.RLock() + defer dbc.DbMux.RUnlock() + return dbc.Db +} + +func (dbc *DbManager) GetDbVersion() string { + return dbc.dbVersion +} + +func (dbc *DbManager) GetKmsAttributes(tenantId string, entities ...string) map[string][]Attribute { + + db := dbc.Db + var attName, attValue, entity_id sql.NullString + 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) + defer attributes.Close() + 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) + return nil + } + if attName.Valid && entity_id.Valid { + att := Attribute{Name: attName.String, Value: attValue.String} + mapOfAttributes[entity_id.String] = append(mapOfAttributes[entity_id.String], att) + } else { + log.Debugf("Not valid. AttName: %s Entity_id: %s", attName.String, entity_id.String) + } + } + return mapOfAttributes +} + +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, ",") + } + return array +}
diff --git a/common/data_structs.go b/common/data_structs.go new file mode 100644 index 0000000..77c0911 --- /dev/null +++ b/common/data_structs.go
@@ -0,0 +1,127 @@ +// 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 common + +type Attribute struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` + Kind string `json:"kind,omitempty"` +} + +type ErrorResponse struct { + ResponseCode string `json:"response_code,omitempty"` + ResponseMessage string `json:"response_message,omitempty"` + StatusCode int `json:"-"` + Kind string `json:"kind,omitempty"` +} + +func (e *ErrorResponse) Error() string { + return e.ResponseMessage +} + +type ApiProduct struct { + Id string `db:"id"` + TenantId string `db:"tenant_id"` + Name string `db:"name"` + DisplayName string `db:"display_name"` + Description string `db:"description"` + ApiResources string `db:"api_resources"` + ApprovalType string `db:"approval_type"` + Scopes string `db:"scopes"` + Proxies string `db:"proxies"` + Environments string `db:"environments"` + Quota string `db:"quota"` + QuotaTimeUnit string `db:"quota_time_unit"` + QuotaInterval int64 `db:"quota_interval"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +} + +type App struct { + Id string `db:"id"` + TenantId string `db:"tenant_id"` + Name string `db:"name"` + DisplayName string `db:"display_name"` + AccessType string `db:"access_type"` + CallbackUrl string `db:"callback_url"` + Status string `db:"status"` + AppFamily string `db:"app_family"` + CompanyId string `db:"company_id"` + DeveloperId string `db:"developer_id"` + ParentId string `db:"parent_id"` + Type string `db:"type"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +} + +type AppCredential struct { + Id string `db:"id"` + TenantId string `db:"tenant_id"` + ConsumerSecret string `db:"consumer_secret"` + AppId string `db:"app_id"` + MethodType string `db:"method_type"` + Status string `db:"status"` + IssuedAt string `db:"issued_at"` + ExpiresAt string `db:"expires_at"` + AppStatus string `db:"app_status"` + Scopes string `db:"scopes"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +} + +type Company struct { + Id string `db:"id"` + TenantId string `db:"tenant_id"` + Name string `db:"name"` + DisplayName string `db:"display_name"` + Status string `db:"status"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +} + +type Developer struct { + Id string `db:"id"` + TenantId string `db:"tenant_id"` + UserName string `db:"username"` + FirstName string `db:"first_name"` + LastName string `db:"last_name"` + Password string `db:"password"` + Email string `db:"email"` + Status string `db:"status"` + EncryptedPassword string `db:"encrypted_password"` + Salt string `db:"salt"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +} + +type CompanyDeveloper struct { + TenantId string `db:"tenant_id"` + CompanyId string `db:"company_id"` + DeveloperId string `db:"developer_id"` + Roles string `db:"roles"` + CreatedAt string `db:"created_at"` + CreatedBy string `db:"created_by"` + UpdatedAt string `db:"updated_at"` + UpdatedBy string `db:"updated_by"` +}
diff --git a/pluginData.go b/common/interfaces.go similarity index 71% copy from pluginData.go copy to common/interfaces.go index 0ebe61b..59249b5 100644 --- a/pluginData.go +++ b/common/interfaces.go
@@ -11,15 +11,14 @@ // 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 common -package apidVerifyApiKey +type ApiManagerInterface interface { + InitAPI() +} -import "github.com/apid/apid-core" - -var pluginData = apid.PluginData{ - Name: "apidVerifyAPIKey", - Version: "0.0.4", - ExtraData: map[string]interface{}{ - "schemaVersion": "0.0.3", - }, +type DbManagerInterface interface { + SetDbVersion(string) + GetDbVersion() string + GetKmsAttributes(tenantId string, entities ...string) map[string][]Attribute }
diff --git a/pluginData.go b/common/pluginData.go similarity index 86% rename from pluginData.go rename to common/pluginData.go index 0ebe61b..89a7c11 100644 --- a/pluginData.go +++ b/common/pluginData.go
@@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package common import "github.com/apid/apid-core" -var pluginData = apid.PluginData{ +var PluginData = apid.PluginData{ Name: "apidVerifyAPIKey", - Version: "0.0.4", + Version: "0.1.0", ExtraData: map[string]interface{}{ - "schemaVersion": "0.0.3", + "schemaVersion": "0.1.0", }, }
diff --git a/glide.yaml b/glide.yaml index 7f8edff..da46400 100644 --- a/glide.yaml +++ b/glide.yaml
@@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -package: github.com/apid/apidVerifyAPIKey +package: github.com/apid/apidVerifyApiKey import: - package: github.com/apid/apid-core version: master
diff --git a/init.go b/init.go index 37e5a0b..b147a1a 100644 --- a/init.go +++ b/init.go
@@ -15,13 +15,11 @@ package apidVerifyApiKey import ( - "sync" - "github.com/apid/apid-core" -) - -const ( - apiPath = "/verifiers/apikey" + "github.com/apid/apidVerifyApiKey/accessEntity" + "github.com/apid/apidVerifyApiKey/common" + "github.com/apid/apidVerifyApiKey/verifyApiKey" + "sync" ) var ( @@ -30,33 +28,50 @@ ) func init() { - apid.RegisterPlugin(initPlugin, pluginData) + apid.RegisterPlugin(initPlugin, common.PluginData) } func initPlugin(s apid.Services) (apid.PluginData, error) { services = s - - log = services.Log().ForModule("apidVerifyAPIKey") + log = services.Log().ForModule("apidApiMetadata") + verifyApiKey.SetApidServices(services, log) + accessEntity.SetApidServices(services, log) + common.SetApidServices(services, log) log.Debug("start init") + initManagers(services) + log.Debug("end init") - log = services.Log() - dbMan := &dbManager{ - data: services.Data(), - dbMux: sync.RWMutex{}, + return common.PluginData, nil +} + +func initManagers(services apid.Services) apigeeSyncHandler { + verifyDbMan := &verifyApiKey.DbManager{ + DbManager: common.DbManager{ + Data: services.Data(), + DbMux: sync.RWMutex{}, + }, } - apiMan := apiManager{ - dbMan: dbMan, - verifiersEndpoint: apiPath, + verifyApiMan := &verifyApiKey.ApiManager{ + DbMan: verifyDbMan, + VerifiersEndpoint: verifyApiKey.ApiPath, + } + + entityDbMan := &accessEntity.DbManager{ + DbManager: common.DbManager{ + Data: services.Data(), + DbMux: sync.RWMutex{}, + }, + } + + entityApiMan := &accessEntity.ApiManager{ + DbMan: entityDbMan, + AccessEntityPath: accessEntity.AccessEntityPath, } syncHandler := apigeeSyncHandler{ - dbMan: dbMan, - apiMan: apiMan, + dbMans: []common.DbManagerInterface{verifyDbMan, entityDbMan}, + apiMans: []common.ApiManagerInterface{verifyApiMan, entityApiMan}, } - syncHandler.initListener(services) - - log.Debug("end init") - - return pluginData, nil + return syncHandler }
diff --git a/listener.go b/listener.go index db136f6..7f2ec69 100644 --- a/listener.go +++ b/listener.go
@@ -16,7 +16,8 @@ import ( "github.com/apid/apid-core" - "github.com/apigee-labs/transicator/common" + "github.com/apid/apidVerifyApiKey/common" + tran "github.com/apigee-labs/transicator/common" ) const ( @@ -24,8 +25,8 @@ ) type apigeeSyncHandler struct { - dbMan dbManagerInterface - apiMan apiManager + dbMans []common.DbManagerInterface + apiMans []common.ApiManagerInterface } func (h *apigeeSyncHandler) initListener(services apid.Services) { @@ -36,16 +37,22 @@ return "verifyAPIKey" } -func (h *apigeeSyncHandler) processSnapshot(snapshot *common.Snapshot) { +func (h *apigeeSyncHandler) processSnapshot(snapshot *tran.Snapshot) { log.Debugf("Snapshot received. Switching to DB version: %s", snapshot.SnapshotInfo) - h.dbMan.setDbVersion(snapshot.SnapshotInfo) - h.apiMan.InitAPI() + // set db version for all packages + for _, dbMan := range h.dbMans { + dbMan.SetDbVersion(snapshot.SnapshotInfo) + } + // idempotent init api for all packages + for _, apiMan := range h.apiMans { + apiMan.InitAPI() + } log.Debug("Snapshot processed") } func (h *apigeeSyncHandler) Handle(e apid.Event) { - if snapData, ok := e.(*common.Snapshot); ok { + if snapData, ok := e.(*tran.Snapshot); ok { h.processSnapshot(snapData) } else { log.Debugf("Received event. No action required for verifyApiKey plugin. Ignoring. %v", e)
diff --git a/listener_test.go b/listener_test.go index 7ba8379..c82b96a 100644 --- a/listener_test.go +++ b/listener_test.go
@@ -17,12 +17,11 @@ import ( "github.com/apid/apid-core" "github.com/apid/apid-core/factory" - "github.com/apigee-labs/transicator/common" + tran "github.com/apigee-labs/transicator/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "io/ioutil" "os" - "sync" ) var _ = Describe("listener", func() { @@ -39,22 +38,7 @@ Expect(err).NotTo(HaveOccurred()) apid.InitializePlugins("") - - db, err := apid.Data().DB() - Expect(err).NotTo(HaveOccurred()) - - dbMan := &dbManager{ - data: s.Data(), - dbMux: sync.RWMutex{}, - db: db, - } - - listnerTestSyncHandler = apigeeSyncHandler{ - dbMan: dbMan, - apiMan: apiManager{}, - } - - listnerTestSyncHandler.initListener(s) + listnerTestSyncHandler = initManagers(s) }) var _ = AfterEach(func() { @@ -64,24 +48,28 @@ Context("Apigee Sync Event Processing", func() { It("should set DB to appropriate version", func() { - s := &common.Snapshot{ + s := &tran.Snapshot{ SnapshotInfo: "test_snapshot", - Tables: []common.Table{}, + Tables: []tran.Table{}, } listnerTestSyncHandler.Handle(s) - Expect(listnerTestSyncHandler.dbMan.getDbVersion()).Should(BeEquivalentTo(s.SnapshotInfo)) + for _, dbMan := range listnerTestSyncHandler.dbMans { + Expect(dbMan.GetDbVersion()).Should(BeEquivalentTo(s.SnapshotInfo)) + } }) It("should not change version for chang event", func() { - version := listnerTestSyncHandler.dbMan.getDbVersion() - s := &common.Change{ + version := listnerTestSyncHandler.dbMans[0].GetDbVersion() + s := &tran.Change{ ChangeSequence: 12321, Table: "", } - testSyncHandler.Handle(s) - Expect(listnerTestSyncHandler.dbMan.getDbVersion() == version).Should(BeTrue()) + listnerTestSyncHandler.Handle(s) + for _, dbMan := range listnerTestSyncHandler.dbMans { + Expect(dbMan.GetDbVersion() == version).Should(BeTrue()) + } })
diff --git a/api.go b/verifyApiKey/api.go similarity index 89% rename from api.go rename to verifyApiKey/api.go index 36c5058..18d6e51 100644 --- a/api.go +++ b/verifyApiKey/api.go
@@ -12,39 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( "encoding/json" + "github.com/apid/apidVerifyApiKey/common" "io" "io/ioutil" "net/http" "strings" ) -type apiManagerInterface interface { +type ApiManagerInterface interface { InitAPI() - handleRequest(w http.ResponseWriter, r *http.Request) - verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *ErrorResponse) + HandleRequest(w http.ResponseWriter, r *http.Request) + verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *common.ErrorResponse) } -type apiManager struct { - dbMan dbManagerInterface - verifiersEndpoint string +type ApiManager struct { + DbMan DbManagerInterface + VerifiersEndpoint string apiInitialized bool } -func (a *apiManager) InitAPI() { +func (a *ApiManager) InitAPI() { if a.apiInitialized { return } - services.API().HandleFunc(a.verifiersEndpoint, a.handleRequest).Methods("POST") + services.API().HandleFunc(a.VerifiersEndpoint, a.HandleRequest).Methods("POST") a.apiInitialized = true log.Debug("API endpoints initialized") } // handle client API -func (a *apiManager) handleRequest(w http.ResponseWriter, r *http.Request) { +func (a *ApiManager) HandleRequest(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -76,7 +77,7 @@ } -func setResponseHeader(errorResponse *ErrorResponse, w http.ResponseWriter) { +func setResponseHeader(errorResponse *common.ErrorResponse, w http.ResponseWriter) { if errorResponse.StatusCode != 0 { w.WriteHeader(errorResponse.StatusCode) } else { @@ -108,7 +109,7 @@ } // returns []byte to be written to client -func (apiM apiManager) verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *ErrorResponse) { +func (apiM ApiManager) verifyAPIKey(verifyApiKeyReq VerifyApiKeyRequest) (*VerifyApiKeySuccessResponse, *common.ErrorResponse) { dataWrapper := VerifyApiKeyRequestResponseDataWrapper{ verifyApiKeyRequest: verifyApiKeyReq, @@ -116,7 +117,7 @@ dataWrapper.verifyApiKeySuccessResponse.ClientId.ClientId = verifyApiKeyReq.Key dataWrapper.verifyApiKeySuccessResponse.Environment = verifyApiKeyReq.EnvironmentName - err := apiM.dbMan.getApiKeyDetails(&dataWrapper) + err := apiM.DbMan.getApiKeyDetails(&dataWrapper) switch { case err != nil && err.Error() == "InvalidApiKey": @@ -200,7 +201,7 @@ } -func (apiM apiManager) performValidations(dataWrapper VerifyApiKeyRequestResponseDataWrapper) *ErrorResponse { +func (apiM ApiManager) performValidations(dataWrapper VerifyApiKeyRequestResponseDataWrapper) *common.ErrorResponse { clientIdDetails := dataWrapper.verifyApiKeySuccessResponse.ClientId verifyApiKeyReq := dataWrapper.verifyApiKeyRequest appDetails := dataWrapper.verifyApiKeySuccessResponse.App @@ -273,9 +274,9 @@ } -func (a *apiManager) enrichAttributes(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) { +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) + 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] @@ -288,13 +289,13 @@ dataWrapper.tempDeveloperDetails.Attributes = developerAttributes } -func errorResponse(reason, errorCode string, statusCode int) ErrorResponse { +func errorResponse(reason, errorCode string, statusCode int) common.ErrorResponse { if errorCode == "SEARCH_INTERNAL_ERROR" { log.Error(reason) } else { log.Debug(reason) } - resp := ErrorResponse{ + resp := common.ErrorResponse{ ResponseCode: errorCode, ResponseMessage: reason, StatusCode: statusCode,
diff --git a/api_ShortListApiProduct_test.go b/verifyApiKey/api_ShortListApiProduct_test.go similarity index 99% rename from api_ShortListApiProduct_test.go rename to verifyApiKey/api_ShortListApiProduct_test.go index 72c999e..732fda4 100644 --- a/api_ShortListApiProduct_test.go +++ b/verifyApiKey/api_ShortListApiProduct_test.go
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( . "github.com/onsi/ginkgo"
diff --git a/api_performValidations_test.go b/verifyApiKey/api_performValidations_test.go similarity index 98% rename from api_performValidations_test.go rename to verifyApiKey/api_performValidations_test.go index afcb225..f7dcdb3 100644 --- a/api_performValidations_test.go +++ b/verifyApiKey/api_performValidations_test.go
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( "encoding/json" @@ -33,7 +33,7 @@ apid.Initialize(factory.DefaultServicesFactory()) log = factory.DefaultServicesFactory().Log() - a := apiManager{} + a := ApiManager{} Context("performValidationsTest tests", func() { It("happy-path", func() { @@ -343,7 +343,7 @@ } Expect(actual).Should(Equal(td.expectedResult)) }) - It("resources not configured in db", func() { + It("resources not configured in Db", func() { td := performValidationsTestDataStruct{ expectedResult: "", expectedWhenValidateProxyEnvIsTrue: "", @@ -395,7 +395,7 @@ } Expect(actual).Should(Equal(td.expectedResult)) }) - It("proxies not configured in db", func() { + It("proxies not configured in Db", func() { td := performValidationsTestDataStruct{ expectedResult: "", expectedWhenValidateProxyEnvIsTrue: "", @@ -447,7 +447,7 @@ } Expect(actual).Should(Equal(td.expectedResult)) }) - It("environments not configured in db", func() { + It("environments not configured in Db", func() { td := performValidationsTestDataStruct{ expectedResult: "", expectedWhenValidateProxyEnvIsTrue: "",
diff --git a/api_test.go b/verifyApiKey/api_test.go similarity index 91% rename from api_test.go rename to verifyApiKey/api_test.go index 50c6bbc..97e226f 100644 --- a/api_test.go +++ b/verifyApiKey/api_test.go
@@ -11,7 +11,7 @@ // 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 +package verifyApiKey // TODO: end to end IT tests // 1. happy path for developer @@ -25,6 +25,7 @@ "errors" "github.com/apid/apid-core" "github.com/apid/apid-core/factory" + "github.com/apid/apidVerifyApiKey/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "io/ioutil" @@ -42,34 +43,36 @@ var _ = Describe("end to end tests", func() { var dataTestTempDir string - var dbMan *dbManager + var dbMan *DbManager var _ = BeforeEach(func() { var err error dataTestTempDir, err = ioutil.TempDir(testTempDirBase, "api_test_sqlite3") + Expect(err).NotTo(HaveOccurred()) 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) + common.SetApidServices(serviceFactoryForTest, serviceFactoryForTest.Log()) - Expect(err).NotTo(HaveOccurred()) - - dbMan = &dbManager{ - data: serviceFactoryForTest.Data(), - dbMux: sync.RWMutex{}, + dbMan = &DbManager{ + DbManager: common.DbManager{ + Data: serviceFactoryForTest.Data(), + DbMux: sync.RWMutex{}, + }, } - dbMan.setDbVersion(dataTestTempDir) + dbMan.SetDbVersion(dataTestTempDir) - apiMan := apiManager{ - dbMan: dbMan, - verifiersEndpoint: apiPath, + 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) + if req.URL.Path == ApiPath { + apiMan.HandleRequest(w, req) } })) @@ -77,7 +80,7 @@ Context("veriifyApiKey Api test ", func() { It("should return validation error for missing input fields", func() { - var respObj ErrorResponse + var respObj common.ErrorResponse reqInput := VerifyApiKeyRequest{ Key: "test", } @@ -91,7 +94,7 @@ 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 + var respObj common.ErrorResponse reqInput := VerifyApiKeyRequest{ Key: "invalid-key", Action: "verify", @@ -112,8 +115,8 @@ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKey")) }) It("should return validation error for inavlid env", func() { - setupApikeyDeveloperTestDb(dbMan.db) - var respObj ErrorResponse + setupApikeyDeveloperTestDb(dbMan.Db) + var respObj common.ErrorResponse reqInput := VerifyApiKeyRequest{ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0", Action: "verify", @@ -134,8 +137,8 @@ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource")) }) It("should return validation error for inavlid resource", func() { - setupApikeyDeveloperTestDb(dbMan.db) - var respObj ErrorResponse + setupApikeyDeveloperTestDb(dbMan.Db) + var respObj common.ErrorResponse reqInput := VerifyApiKeyRequest{ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0", Action: "verify", @@ -156,8 +159,8 @@ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource")) }) It("should return validation error for inavlid proxies", func() { - setupApikeyDeveloperTestDb(dbMan.db) - var respObj ErrorResponse + setupApikeyDeveloperTestDb(dbMan.Db) + var respObj common.ErrorResponse reqInput := VerifyApiKeyRequest{ Key: "63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0", Action: "verify", @@ -178,7 +181,7 @@ Expect(respObj.ResponseCode).Should(Equal("oauth.v2.InvalidApiKeyForGivenResource")) }) It("should peform verify api key for developer happy path", func() { - setupApikeyDeveloperTestDb(dbMan.db) + setupApikeyDeveloperTestDb(dbMan.Db) var respObj VerifyApiKeySuccessResponse reqInput := VerifyApiKeyRequest{ @@ -229,7 +232,7 @@ }) It("should peform verify api key for company happy path", func() { - setupApikeyCompanyTestDb(dbMan.db) + setupApikeyCompanyTestDb(dbMan.Db) var respObj VerifyApiKeySuccessResponse reqInput := VerifyApiKeyRequest{ @@ -283,11 +286,14 @@ func performTestOperation(jsonBody string, expectedResponseCode int) ([]byte, error) { uri, err := url.Parse(testServer.URL) - uri.Path = apiPath + 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) + if err != nil { + return nil, err + } defer res.Body.Close() responseBody, err := ioutil.ReadAll(res.Body)
diff --git a/data.go b/verifyApiKey/data.go similarity index 60% rename from data.go rename to verifyApiKey/data.go index e2d974e..769a92d 100644 --- a/data.go +++ b/verifyApiKey/data.go
@@ -11,90 +11,25 @@ // 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 +package verifyApiKey import ( - "database/sql" "errors" - "github.com/apid/apid-core" - "strings" - "sync" + "github.com/apid/apidVerifyApiKey/common" ) -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) getDbVersion() string { - return dbc.dbVersion -} - -type dbManagerInterface interface { - setDbVersion(string) - getDb() apid.DB - getDbVersion() string - getKmsAttributes(tenantId string, entities ...string) map[string][]Attribute +type DbManagerInterface interface { + common.DbManagerInterface getApiKeyDetails(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) error } -func (dbc *dbManager) getKmsAttributes(tenantId string, entities ...string) map[string][]Attribute { - - db := dbc.db - var attName, attValue, entity_id sql.NullString - // 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) - defer attributes.Close() - 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) - return nil - } - if attName.Valid && entity_id.Valid { - att := Attribute{Name: attName.String, Value: attValue.String} - mapOfAttributes[entity_id.String] = append(mapOfAttributes[entity_id.String], att) - } else { - log.Debugf("Not valid. AttName: %s Entity_id: %s", attName.String, entity_id.String) - } - } - log.Debug("attributes returned for query ", sql, " are ", mapOfAttributes) - return mapOfAttributes +type DbManager struct { + common.DbManager } -func (dbc dbManager) getApiKeyDetails(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) error { +func (dbc DbManager) getApiKeyDetails(dataWrapper *VerifyApiKeyRequestResponseDataWrapper) error { - db := dbc.db + db := dbc.Db err := db.QueryRow(sql_GET_API_KEY_DETAILS_SQL, dataWrapper.verifyApiKeyRequest.Key, dataWrapper.verifyApiKeyRequest.OrganizationName). Scan( @@ -144,9 +79,9 @@ return err } -func (dbc dbManager) getApiProductsForApiKey(key, tenantId string) []ApiProductDetails { +func (dbc DbManager) getApiProductsForApiKey(key, tenantId string) []ApiProductDetails { - db := dbc.db + db := dbc.Db allProducts := []ApiProductDetails{} var proxies, environments, resources string @@ -174,9 +109,9 @@ &environments, &resources, ) - apiProductDetais.Apiproxies = jsonToStringArray(proxies) - apiProductDetais.Environments = jsonToStringArray(environments) - apiProductDetais.Resources = jsonToStringArray(resources) + apiProductDetais.Apiproxies = common.JsonToStringArray(proxies) + apiProductDetais.Environments = common.JsonToStringArray(environments) + apiProductDetais.Resources = common.JsonToStringArray(resources) allProducts = append(allProducts, apiProductDetais) }
diff --git a/data_helper_test.go b/verifyApiKey/data_helper_test.go similarity index 99% rename from data_helper_test.go rename to verifyApiKey/data_helper_test.go index c5fa0e4..74c19a5 100644 --- a/data_helper_test.go +++ b/verifyApiKey/data_helper_test.go
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( "github.com/apid/apid-core"
diff --git a/data_test.go b/verifyApiKey/data_test.go similarity index 93% rename from data_test.go rename to verifyApiKey/data_test.go index 2a6bdb6..c864339 100644 --- a/data_test.go +++ b/verifyApiKey/data_test.go
@@ -11,11 +11,12 @@ // 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 +package verifyApiKey import ( "github.com/apid/apid-core" "github.com/apid/apid-core/factory" + "github.com/apid/apidVerifyApiKey/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "io/ioutil" @@ -24,30 +25,31 @@ var _ = Describe("DataTest", func() { - Context("query db to get api key details", func() { + Context("query Db to get api key details", func() { var dataTestTempDir string - var dbMan *dbManager + var dbMan *DbManager var _ = BeforeEach(func() { var err error dataTestTempDir, err = ioutil.TempDir(testTempDirBase, "sqlite3") - + Expect(err).NotTo(HaveOccurred()) s := factory.DefaultServicesFactory() apid.Initialize(s) config := apid.Config() config.Set("local_storage_path", dataTestTempDir) + common.SetApidServices(s, s.Log()) - Expect(err).NotTo(HaveOccurred()) - - dbMan = &dbManager{ - data: s.Data(), - dbMux: sync.RWMutex{}, + dbMan = &DbManager{ + DbManager: common.DbManager{ + Data: s.Data(), + DbMux: sync.RWMutex{}, + }, } - dbMan.setDbVersion(dataTestTempDir) + dbMan.SetDbVersion(dataTestTempDir) }) It("should get compnay getApiKeyDetails for happy path", func() { - setupApikeyCompanyTestDb(dbMan.db) + setupApikeyCompanyTestDb(dbMan.Db) dataWrapper := VerifyApiKeyRequestResponseDataWrapper{ verifyApiKeyRequest: VerifyApiKeyRequest{ @@ -90,7 +92,7 @@ }) It("should get developer ApiKeyDetails - happy path", func() { - setupApikeyDeveloperTestDb(dbMan.db) + setupApikeyDeveloperTestDb(dbMan.Db) dataWrapper := VerifyApiKeyRequestResponseDataWrapper{ verifyApiKeyRequest: VerifyApiKeyRequest{ @@ -134,7 +136,7 @@ It("should throw error when apikey not found", func() { - setupApikeyCompanyTestDb(dbMan.db) + setupApikeyCompanyTestDb(dbMan.Db) dataWrapper := VerifyApiKeyRequestResponseDataWrapper{ verifyApiKeyRequest: VerifyApiKeyRequest{ OrganizationName: "apigee-mcrosrvc-client0001", @@ -148,7 +150,7 @@ It("should get api products ", func() { - setupApikeyCompanyTestDb(dbMan.db) + setupApikeyCompanyTestDb(dbMan.Db) apiProducts := dbMan.getApiProductsForApiKey("63tHSNLKJkcc6GENVWGT1Zw5gek7kVJ0", "bc811169") Expect(len(apiProducts)).Should(BeEquivalentTo(1)) @@ -176,7 +178,7 @@ It("should return empty array when no api products found", func() { - setupApikeyCompanyTestDb(dbMan.db) + setupApikeyCompanyTestDb(dbMan.Db) apiProducts := dbMan.getApiProductsForApiKey("invalid-LKJkcc6GENVWGT1Zw5gek7kVJ0", "bc811169") Expect(len(apiProducts)).Should(BeEquivalentTo(0)) @@ -184,8 +186,8 @@ 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") + 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))
diff --git a/pluginData.go b/verifyApiKey/init.go similarity index 70% copy from pluginData.go copy to verifyApiKey/init.go index 0ebe61b..33ac046 100644 --- a/pluginData.go +++ b/verifyApiKey/init.go
@@ -11,15 +11,22 @@ // 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 verifyApiKey -package apidVerifyApiKey +import ( + "github.com/apid/apid-core" +) -import "github.com/apid/apid-core" +const ( + ApiPath = "/verifiers/apikey" +) -var pluginData = apid.PluginData{ - Name: "apidVerifyAPIKey", - Version: "0.0.4", - ExtraData: map[string]interface{}{ - "schemaVersion": "0.0.3", - }, +var ( + services apid.Services + log apid.LogService +) + +func SetApidServices(s apid.Services, l apid.LogService) { + services = s + log = l }
diff --git a/kmsDataTest.sql b/verifyApiKey/kmsDataTest.sql similarity index 100% rename from kmsDataTest.sql rename to verifyApiKey/kmsDataTest.sql
diff --git a/sqlQueries.go b/verifyApiKey/sqlQueries.go similarity index 98% rename from sqlQueries.go rename to verifyApiKey/sqlQueries.go index 504af9a..3a1525e 100644 --- a/sqlQueries.go +++ b/verifyApiKey/sqlQueries.go
@@ -11,7 +11,7 @@ // 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 +package verifyApiKey const sql_GET_API_KEY_DETAILS_SQL = ` SELECT
diff --git a/verifyAPIKey_suite_test.go b/verifyApiKey/verifyAPIKey_suite_test.go similarity index 79% copy from verifyAPIKey_suite_test.go copy to verifyApiKey/verifyAPIKey_suite_test.go index fdb5ed2..67873e7 100644 --- a/verifyAPIKey_suite_test.go +++ b/verifyApiKey/verifyAPIKey_suite_test.go
@@ -12,26 +12,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/apid/apid-core" + "io/ioutil" "os" "testing" ) -const testTempDirBase = "./tmp/" +var testTempDirBase string var ( - testTempDir string - testSyncHandler apigeeSyncHandler + testTempDir string ) var _ = BeforeSuite(func() { - _ = os.MkdirAll(testTempDirBase, os.ModePerm) + var err error + testTempDirBase, err = ioutil.TempDir("", "verify_apikey_") + Expect(err).Should(Succeed()) }) var _ = AfterSuite(func() { @@ -39,8 +41,7 @@ if testServer != nil { testServer.Close() } - os.RemoveAll(testTempDirBase) - + Expect(os.RemoveAll(testTempDirBase)).Should(Succeed()) }) func TestVerifyAPIKey(t *testing.T) {
diff --git a/verifyApiKeyStructs.go b/verifyApiKey/verifyApiKeyStructs.go similarity index 89% rename from verifyApiKeyStructs.go rename to verifyApiKey/verifyApiKeyStructs.go index 28f345b..b2a93e6 100644 --- a/verifyApiKeyStructs.go +++ b/verifyApiKey/verifyApiKeyStructs.go
@@ -11,9 +11,12 @@ // 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 +package verifyApiKey -import "errors" +import ( + "errors" + "github.com/apid/apidVerifyApiKey/common" +) type ClientIdDetails struct { ClientId string `json:"clientId,omitempty"` @@ -21,7 +24,7 @@ RedirectURIs []string `json:"redirectURIs,omitempty"` Status string `json:"status,omitempty"` // Attributes associated with the client Id. - Attributes []Attribute `json:"attributes,omitempty"` + Attributes []common.Attribute `json:"attributes,omitempty"` } type ApiProductDetails struct { @@ -40,8 +43,8 @@ Environments []string `json:"environments,omitempty"` Apiproxies []string `json:"apiproxies,omitempty"` // Attributes associated with the apiproduct. - Attributes []Attribute `json:"attributes,omitempty"` - Resources []string `json:"-"` + Attributes []common.Attribute `json:"attributes,omitempty"` + Resources []string `json:"-"` } type AppDetails struct { @@ -59,13 +62,7 @@ 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"` + Attributes []common.Attribute `json:"attributes,omitempty"` } type CompanyDetails struct { @@ -79,7 +76,7 @@ LastmodifiedAt string `json:"lastmodified_at,omitempty"` LastmodifiedBy string `json:"lastmodified_by,omitempty"` // Attributes associated with the company. - Attributes []Attribute `json:"attributes,omitempty"` + Attributes []common.Attribute `json:"attributes,omitempty"` } type DeveloperDetails struct { @@ -96,14 +93,7 @@ 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"` + Attributes []common.Attribute `json:"attributes,omitempty"` } type VerifyApiKeyRequest struct {
diff --git a/verifyApiKeyUtil.go b/verifyApiKey/verifyApiKeyUtil.go similarity index 77% rename from verifyApiKeyUtil.go rename to verifyApiKey/verifyApiKeyUtil.go index a7d2451..85aa8c5 100644 --- a/verifyApiKeyUtil.go +++ b/verifyApiKey/verifyApiKeyUtil.go
@@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( - "encoding/json" "regexp" "strings" - "unicode/utf8" ) /* @@ -56,20 +54,6 @@ 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 {
diff --git a/verifyApiKeyUtil_test.go b/verifyApiKey/verifyApiKeyUtil_test.go similarity index 81% rename from verifyApiKeyUtil_test.go rename to verifyApiKey/verifyApiKeyUtil_test.go index 4e17289..0ff7f22 100644 --- a/verifyApiKeyUtil_test.go +++ b/verifyApiKey/verifyApiKeyUtil_test.go
@@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( + "github.com/apid/apidVerifyApiKey/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "reflect" @@ -40,30 +41,30 @@ }) }) -var _ = Describe("Validate jsonToStringArray", func() { +var _ = Describe("Validate common.JsonToStringArray", func() { It("should tranform simple valid json", func() { - array := jsonToStringArray("[\"test-1\", \"test-2\"]") + array := common.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\"]") + array := common.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}") + s := common.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}") + s := common.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}") + s := common.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}}") + s := common.JsonToStringArray("{test-1,test-2}}") Expect(reflect.DeepEqual(s, []string{"test-1", "test-2}"})).Should(BeTrue()) })
diff --git a/verifyApiKeyUtil_validate_path_test.go b/verifyApiKey/verifyApiKeyUtil_validate_path_test.go similarity index 98% rename from verifyApiKeyUtil_validate_path_test.go rename to verifyApiKey/verifyApiKeyUtil_validate_path_test.go index eb91d8f..7399309 100644 --- a/verifyApiKeyUtil_validate_path_test.go +++ b/verifyApiKey/verifyApiKeyUtil_validate_path_test.go
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package apidVerifyApiKey +package verifyApiKey import ( . "github.com/onsi/ginkgo"