Updated logic to handle bootstrapping, and newer schema for KMS, newer protocol for Snapshot/change server.
diff --git a/api.go b/api.go index 241e472..9bbce01 100644 --- a/api.go +++ b/api.go
@@ -98,12 +98,7 @@ return errorResponse(reason, errorCode) } - /* - * NOTE: that here c.expired_at has been commented out because it is not - * kept track of by Cassandra (hence always defaults to -1). FIXME - */ - - sSql = "SELECT ap.res_names, ap.env, c.issued_at, c.status, a.cback_url, d.username, d.id FROM APP_CREDENTIAL AS c INNER JOIN APP AS a ON c.app_id = a.id INNER JOIN DEVELOPER AS d ON a.dev_id = d.id INNER JOIN APP_AND_API_PRODUCT_MAPPER as mp ON mp.app_cred_id = c.id INNER JOIN API_PRODUCT as ap ON ap.id = mp.api_prdt_id WHERE (UPPER(d.sts) = 'ACTIVE' AND mp.api_prdt_id = ap.id AND mp.app_id = a.id AND mp.app_cred_id = c.id AND UPPER(mp.api_prdt_status) = 'APPROVED' AND UPPER(a.status) = 'APPROVED' AND UPPER(c.status) = 'APPROVED' AND c.id = '" + key + "' AND c.org = '" + org + "');" + sSql = "SELECT ap.api_resources, ap.environments, c.issued_at, c.app_status, a.callback_url, d.username, d.id FROM APP_CREDENTIAL AS c INNER JOIN APP AS a ON c.app_id = a.id INNER JOIN DEVELOPER AS d ON a.developer_id = d.id INNER JOIN APP_CREDENTIAL_APIPRODUCT_MAPPER as mp ON mp.appcred_id = c.id INNER JOIN API_PRODUCT as ap ON ap.id = mp.apiprdt_id WHERE (UPPER(d.status) = 'ACTIVE' AND mp.apiprdt_id = ap.id AND mp.app_id = a.id AND mp.appcred_id = c.id AND UPPER(mp.status) = 'APPROVED' AND UPPER(a.status) = 'APPROVED' AND UPPER(c.status) = 'APPROVED' AND c.id = '" + key + "' AND c._apid_scope = '" + org + "');" err = db.QueryRow(sSql).Scan(&resName, &resEnv, &issuedAt, &status, &redirectionURIs, &developerAppName, &developerId)
diff --git a/init.go b/init.go index 483fa68..bae3a3f 100644 --- a/init.go +++ b/init.go
@@ -7,7 +7,7 @@ ) const ( - apiPath = "/verifyAPIKey" + apiPath = "/verifiers/apikey" ) var ( @@ -33,7 +33,7 @@ } var count int - row := db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='API_PRODUCT';") + row := db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='API_PRODUCT' COLLATE NOCASE;") if err := row.Scan(&count); err != nil { log.Panic("Unable to setup database", err) } @@ -52,26 +52,26 @@ func createTables(db *sql.DB) { _, err := db.Exec(` CREATE TABLE api_product ( - id uuid, + id text, tenant_id text, name text, display_name text, description text, api_resources text[], approval_type text, - scopes text[], + _apid_scope text, proxies text[], environments text[], quota text, quota_time_unit text, quota_interval int, - created_at timestamp, + created_at int64, created_by text, - updated_at timestamp, + updated_at int64, updated_by text, PRIMARY KEY (tenant_id, id)); CREATE TABLE developer ( - id uuid, + id text, tenant_id text, username text, first_name text, @@ -81,41 +81,40 @@ status text, encrypted_password text, salt text, - created_at timestamp, + _apid_scope text, + created_at int64, created_by text, - updated_at timestamp, + updated_at int64, updated_by text, - PRIMARY KEY (tenant_id, id), - constraint developer_email_uq unique(tenant_id, email) + PRIMARY KEY (tenant_id, id) ); CREATE TABLE company ( - id uuid, + id text, tenant_id text, name text, display_name text, status text, - created_at timestamp, + created_at int64, created_by text, - updated_at timestamp, + updated_at int64, updated_by text, - PRIMARY KEY (tenant_id, id), - constraint comp_name_uq unique(tenant_id, name) + _apid_scope text, + PRIMARY KEY (tenant_id, id) ); CREATE TABLE company_developer ( tenant_id text, - company_id uuid, - developer_id uuid, + company_id text, + developer_id text, roles text[], - created_at timestamp, + created_at int64, created_by text, - updated_at timestamp, + updated_at int64, updated_by text, - PRIMARY KEY (tenant_id, company_id,developer_id), - FOREIGN KEY (tenant_id,company_id) references company(tenant_id,id), - FOREIGN KEY (tenant_id,developer_id) references developer(tenant_id,id) + _apid_scope text, + PRIMARY KEY (tenant_id, company_id,developer_id) ); CREATE TABLE app ( - id uuid, + id text, tenant_id text, name text, display_name text, @@ -123,72 +122,37 @@ callback_url text, status text, app_family text, - company_id uuid, - developer_id uuid, - type app_type, - created_at timestamp, + company_id text, + developer_id text, + type int, + created_at int64, created_by text, - updated_at timestamp, + updated_at int64, updated_by text, - PRIMARY KEY (tenant_id, id), - constraint app_name_uq unique(tenant_id, name), - FOREIGN KEY (tenant_id,company_id) references company(tenant_id,id), - FOREIGN KEY (tenant_id,developer_id) references developer(tenant_id,id) + _apid_scope text, + PRIMARY KEY (tenant_id, id) ); CREATE TABLE app_credential ( id text, tenant_id text, consumer_secret text, - app_id uuid, + app_id text, method_type text, status text, - issued_at timestamp, - expires_at timestamp, + issued_at int64, + expires_at int64, app_status text, - scopes text[], - PRIMARY KEY (tenant_id, id), - FOREIGN KEY (tenant_id,app_id) references app(tenant_id,id) + _apid_scope text, + PRIMARY KEY (tenant_id, id) ); CREATE TABLE app_credential_apiproduct_mapper ( tenant_id text, appcred_id text, - app_id uuid, - apiprdt_id uuid, - status appcred_apiprdt_status, - PRIMARY KEY (tenant_id,appcred_id,app_id,apiprdt_id), - FOREIGN KEY (tenant_id,appcred_id) references app_credential(tenant_id,id), - FOREIGN KEY (tenant_id,app_id) references app(tenant_id,id) -); -CREATE TABLE attributes ( - tenant_id text, - dev_id uuid, - comp_id uuid, - apiprdt_id uuid, - app_id uuid, - appcred_id text, - type entity_type, - name text , - value text, - PRIMARY KEY (tenant_id,dev_id,comp_id,apiprdt_id,app_id,appcred_id,type,name), - FOREIGN KEY (tenant_id,appcred_id) references app_credential(tenant_id,id), - FOREIGN KEY (tenant_id,app_id) references app(tenant_id,id), - FOREIGN KEY (tenant_id,dev_id) references developer(tenant_id,id), - FOREIGN KEY (tenant_id,comp_id) references company(tenant_id,id), - FOREIGN KEY (tenant_id,apiprdt_id) references api_product(tenant_id,id) -); -CREATE TABLE apidconfig ( - id uuid, - consumer_key text, - consumer_secret text, - scope text[], - app_id uuid, - created_at timestamp, - created_by text, - updated_at timestamp, - updated_by text, - PRIMARY KEY(id), - constraint apidconfig_key_uq unique(consumer_key), - constraint apidconfig_appid_uq unique(app_id) + app_id text, + apiprdt_id text, + _apid_scope text, + status text, + PRIMARY KEY (appcred_id, app_id, apiprdt_id,tenant_id) ); `) if err != nil {
diff --git a/listener.go b/listener.go index 6aec26f..6c025c7 100644 --- a/listener.go +++ b/listener.go
@@ -2,9 +2,8 @@ import ( "database/sql" - "encoding/json" "github.com/30x/apid" - "github.com/30x/apidApigeeSync" + "github.com/30x/transicator/common" ) type handler struct { @@ -17,174 +16,223 @@ // todo: The following was basically just copied from old APID - needs review. func (h *handler) Handle(e apid.Event) { - changeSet, ok := e.(*apidApigeeSync.ChangeSet) - if !ok { - log.Errorf("Received non-ChangeSet event. This shouldn't happen!") - return - } - log.Debugf("apigeeSyncEvent: %d changes", len(changeSet.Changes)) + snapData, ok := e.(*common.Snapshot) + if ok { + processSnapshot(snapData) + } else { + changeSet, ok := e.(*common.ChangeList) + if ok { + processChange(changeSet) + } else { + log.Errorf("Received Invalid event. This shouldn't happen!") + } + } + return +} + +func processSnapshot(snapshot *common.Snapshot) { + + log.Debugf("Process Snapshot data") db, err := data.DB() if err != nil { - panic("help me!") // todo: handle + panic("Unable to access Sqlite DB") } - for _, payload := range changeSet.Changes { + for _, payload := range snapshot.Tables { - org := payload.Data.PldCont.Organization - - switch payload.Data.EntityType { + switch payload.Name { case "developer": - switch payload.Data.Operation { - case "create": - insertCreateDeveloper(payload.Data, db, org) + for _, row := range payload.Rows { + insertCreateDeveloper(row, db) } - case "app": - switch payload.Data.Operation { - case "create": - insertCreateApplication(payload.Data, db, org) + for _, row := range payload.Rows { + insertCreateApplication(row, db) + } + case "app_credential": + for _, row := range payload.Rows { + insertCreateCredential(row, db) + } + case "api_product": + for _, row := range payload.Rows { + insertAPIproduct(row, db) + } + case "app_credential_apiproduct_mapper": + for _, row := range payload.Rows { + insertApiProductMapper(row, db) } - case "credential": - switch payload.Data.Operation { - case "create": - insertCreateCredential(payload.Data, db, org) - - case "delete": - deleteCredential(payload.Data, db, org) - } - - case "apiproduct": - switch payload.Data.Operation { - case "create": - insertAPIproduct(payload.Data, db, org) - } } + } +} +func processChange(changes *common.ChangeList) { + + log.Debugf("apigeeSyncEvent: %d changes", len(changes.Changes)) + + db, err := data.DB() + if err != nil { + panic("Unable to access Sqlite DB") + } + + for _, payload := range changes.Changes { + + switch payload.Table { + case "public.developer": + switch payload.Operation { + case 1: + insertCreateDeveloper(payload.NewRow, db) + } + + case "public.app": + switch payload.Operation { + case 1: + insertCreateApplication(payload.NewRow, db) + } + + case "public.app_credential": + switch payload.Operation { + case 1: + insertCreateCredential(payload.NewRow, db) + } + case "public.api_product": + switch payload.Operation { + case 1: + insertAPIproduct(payload.NewRow, db) + } + + case "public.app_credential_apiproduct_mapper": + switch payload.Operation { + case 1: + insertApiProductMapper(payload.NewRow, db) + } + + } } } /* * INSERT INTO APP_CREDENTIAL op */ -func insertCreateCredential(ele apidApigeeSync.DataPayload, db *sql.DB, org string) bool { +func insertCreateCredential(ele common.Row, db *sql.DB) { + + var scope, id, appId, consumerSecret, appstatus, status, tenantId string + var issuedAt int64 txn, _ := db.Begin() - isPass := true - _, err := txn.Exec("INSERT INTO APP_CREDENTIAL (org, id, app_id, cons_secret, status, issued_at)VALUES(?,?,?,?,?,?);", - org, - ele.EntityIdentifier, - ele.PldCont.AppId, - ele.PldCont.ConsumerSecret, - ele.PldCont.Status, - ele.PldCont.IssuedAt) + err := ele.Get("_apid_scope", &scope) + err = ele.Get("id", &id) + err = ele.Get("app_id", &appId) + err = ele.Get("consumer_secret", &consumerSecret) + err = ele.Get("app_status", &appstatus) + err = ele.Get("status", &status) + err = ele.Get("issued_at", &issuedAt) + err = ele.Get("tenant_id", &tenantId) + + _, err = txn.Exec("INSERT INTO APP_CREDENTIAL (_apid_scope, id, app_id, consumer_secret, app_status, status, issued_at, tenant_id)VALUES(?,?,?,?,?,?,?,?);", + scope, + id, + appId, + consumerSecret, + appstatus, + status, + issuedAt, + tenantId) if err != nil { - isPass = false - log.Error("INSERT CRED Failed: ", ele.EntityIdentifier, org, ")", err) - goto OT + log.Error("INSERT CRED Failed: ", id, ", ", scope, ")", err) + txn.Rollback() } else { - log.Info("INSERT CRED Success: (", ele.EntityIdentifier, org, ")") + log.Info("INSERT CRED Success: (", id, ", ", scope, ")") + txn.Commit() } +} +func insertApiProductMapper(ele common.Row, db *sql.DB) { + + var ApiProduct, AppId, EntityIdentifier, tenantId, Scope, Status string + + txn, _ := db.Begin() + err := ele.Get("apiprdt_id", &ApiProduct) + err = ele.Get("app_id", &AppId) + err = ele.Get("appcred_id", &EntityIdentifier) + err = ele.Get("tenant_id", &tenantId) + err = ele.Get("_apid_scope", &Scope) + err = ele.Get("status", &Status) + /* * If the credentials has been successfully inserted, insert the * mapping entries associated with the credential */ - for _, elem := range ele.PldCont.ApiProducts { + _, err = txn.Exec("INSERT INTO APP_CREDENTIAL_APIPRODUCT_MAPPER(apiprdt_id, app_id, appcred_id, tenant_id, _apid_scope, status) VALUES(?,?,?,?,?,?);", + ApiProduct, + AppId, + EntityIdentifier, + tenantId, + Scope, + Status) - _, err = txn.Exec("INSERT INTO APP_AND_API_PRODUCT_MAPPER (org, api_prdt_id, app_id, app_cred_id, api_prdt_status) VALUES(?,?,?,?,?);", - org, - elem.ApiProduct, - ele.PldCont.AppId, - ele.EntityIdentifier, - elem.Status) - - if err != nil { - isPass = false - log.Error("INSERT APP_AND_API_PRODUCT_MAPPER Failed: (", - org, - elem.ApiProduct, - ele.PldCont.AppId, - ele.EntityIdentifier, - ")", - err) - break - } else { - log.Info("INSERT APP_AND_API_PRODUCT_MAPPER Success: (", - org, - elem.ApiProduct, - ele.PldCont.AppId, - ele.EntityIdentifier, - ")") - } - } -OT: - if isPass == true { - txn.Commit() - } else { + if err != nil { + log.Error("INSERT APP_CREDENTIAL_APIPRODUCT_MAPPER Failed: (", + ApiProduct, + AppId, + EntityIdentifier, + tenantId, + Scope, + Status, + ")", + err) txn.Rollback() + } else { + log.Info("INSERT APP_CREDENTIAL_APIPRODUCT_MAPPER Success: (", + ApiProduct, + AppId, + EntityIdentifier, + tenantId, + Scope, + Status, + ")") + txn.Commit() } - return isPass - } /* * DELETE CRED */ -func deleteCredential(ele apidApigeeSync.DataPayload, db *sql.DB, org string) bool { +func deleteCredential(ele common.Row, db *sql.DB) { - txn, _ := db.Begin() - - _, err := txn.Exec("DELETE FROM APP_CREDENTIAL WHERE org=? AND id=?;", org, ele.EntityIdentifier) - - if err != nil { - log.Error("DELETE CRED Failed: (", ele.EntityIdentifier, org, ")", err) - txn.Rollback() - return false - } else { - log.Info("DELETE CRED Success: (", ele.EntityIdentifier, org, ")") - txn.Commit() - return true - } - -} - -/* - * Helper function to convert string slice in to JSON format - */ -func convertSlicetoStringFormat(inpslice []string) string { - - bytes, _ := json.Marshal(inpslice) - return string(bytes) } /* * INSERT INTO API product op */ -func insertAPIproduct(ele apidApigeeSync.DataPayload, db *sql.DB, org string) bool { +func insertAPIproduct(ele common.Row, db *sql.DB) { + + var scope, apiProduct, res, env, tenantId string txn, _ := db.Begin() - restr := convertSlicetoStringFormat(ele.PldCont.Resources) - envstr := convertSlicetoStringFormat(ele.PldCont.Environments) + err := ele.Get("_apid_scope", &scope) + err = ele.Get("id", &apiProduct) + err = ele.Get("api_resources", &res) + err = ele.Get("environments", &env) + err = ele.Get("tenant_id", &tenantId) - _, err := txn.Exec("INSERT INTO API_PRODUCT (org, id, res_names, env) VALUES(?,?,?,?)", - org, - ele.PldCont.AppName, - restr, - envstr) + _, err = txn.Exec("INSERT INTO API_PRODUCT (id, api_resources, environments, tenant_id,_apid_scope) VALUES(?,?,?,?,?)", + apiProduct, + res, + env, + tenantId, + scope) if err != nil { - log.Error("INSERT API_PRODUCT Failed: (", ele.PldCont.AppName, org, ")", err) + log.Error("INSERT API_PRODUCT Failed: (", apiProduct, tenantId, ")", err) txn.Rollback() - return false } else { - log.Info("INSERT API_PRODUCT Success: (", ele.PldCont.AppName, org, ")") + log.Info("INSERT API_PRODUCT Success: (", apiProduct, tenantId, ")") txn.Commit() - return true } } @@ -192,31 +240,45 @@ /* * INSERT INTO APP op */ -func insertCreateApplication(ele apidApigeeSync.DataPayload, db *sql.DB, org string) bool { +func insertCreateApplication(ele common.Row, db *sql.DB) { + var scope, EntityIdentifier, DeveloperId, CallbackUrl, Status, AppName, AppFamily, tenantId, CreatedBy, LastModifiedBy string + var CreatedAt, LastModifiedAt int64 txn, _ := db.Begin() - _, err := txn.Exec("INSERT INTO APP (org, id, dev_id,cback_url,status, name, app_family, created_at, created_by,updated_at, updated_by) VALUES(?,?,?,?,?,?,?,?,?,?,?);", - org, - ele.EntityIdentifier, - ele.PldCont.DeveloperId, - ele.PldCont.CallbackUrl, - ele.PldCont.Status, - ele.PldCont.AppName, - ele.PldCont.AppFamily, - ele.PldCont.CreatedAt, - ele.PldCont.CreatedBy, - ele.PldCont.LastModifiedAt, - ele.PldCont.LastModifiedBy) + err := ele.Get("_apid_scope", &scope) + err = ele.Get("id", &EntityIdentifier) + err = ele.Get("developer_id", &DeveloperId) + err = ele.Get("callback_url", &CallbackUrl) + err = ele.Get("status", &Status) + err = ele.Get("name", &AppName) + err = ele.Get("app_family", &AppFamily) + err = ele.Get("created_at", &CreatedAt) + err = ele.Get("created_by", &CreatedBy) + err = ele.Get("updated_at", &LastModifiedAt) + err = ele.Get("updated_by", &LastModifiedBy) + err = ele.Get("tenant_id", &tenantId) + + _, err = txn.Exec("INSERT INTO APP (_apid_scope, id, developer_id,callback_url,status, name, app_family, created_at, created_by,updated_at, updated_by,tenant_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,?);", + scope, + EntityIdentifier, + DeveloperId, + CallbackUrl, + Status, + AppName, + AppFamily, + CreatedAt, + CreatedBy, + LastModifiedAt, + LastModifiedBy, + tenantId) if err != nil { - log.Error("INSERT APP Failed: (", ele.EntityIdentifier, org, ")", err) + log.Error("INSERT APP Failed: (", EntityIdentifier, tenantId, ")", err) txn.Rollback() - return false } else { - log.Info("INSERT APP Success: (", ele.EntityIdentifier, org, ")") + log.Info("INSERT APP Success: (", EntityIdentifier, tenantId, ")") txn.Commit() - return true } } @@ -224,31 +286,43 @@ /* * INSERT INTO DEVELOPER op */ -func insertCreateDeveloper(ele apidApigeeSync.DataPayload, db *sql.DB, org string) bool { - +func insertCreateDeveloper(ele common.Row, db *sql.DB) { + var scope, EntityIdentifier, Email, Status, UserName, FirstName, LastName, tenantId, CreatedBy, LastModifiedBy, Username string + var CreatedAt, LastModifiedAt int64 txn, _ := db.Begin() - _, err := txn.Exec("INSERT INTO DEVELOPER (org, email, id, sts, username, firstname, lastname, created_at,created_by, updated_at, updated_by) VALUES(?,?,?,?,?,?,?,?,?,?,?);", - org, - ele.PldCont.Email, - ele.EntityIdentifier, - ele.PldCont.Status, - ele.PldCont.UserName, - ele.PldCont.FirstName, - ele.PldCont.LastName, - ele.PldCont.CreatedAt, - ele.PldCont.CreatedBy, - ele.PldCont.LastModifiedAt, - ele.PldCont.LastModifiedBy) + err := ele.Get("_apid_scope", &scope) + err = ele.Get("email", &Email) + err = ele.Get("id", &EntityIdentifier) + err = ele.Get("tenant_id", &tenantId) + err = ele.Get("status", &Status) + err = ele.Get("username", &Username) + err = ele.Get("first_name", &FirstName) + err = ele.Get("last_name", &LastName) + err = ele.Get("created_at", &CreatedAt) + err = ele.Get("created_by", &CreatedBy) + err = ele.Get("updated_at", &LastModifiedAt) + err = ele.Get("updated_by", &LastModifiedBy) + + _, err = txn.Exec("INSERT INTO DEVELOPER (_apid_scope,email,id,tenant_id,status,username,first_name,last_name,created_at,created_by,updated_at,updated_by) VALUES(?,?,?,?,?,?,?,?,?,?,?,?);", + scope, + Email, + EntityIdentifier, + tenantId, + Status, + UserName, + FirstName, + LastName, + CreatedAt, + CreatedBy, + LastModifiedAt, + LastModifiedBy) if err != nil { - log.Error("INSERT DEVELOPER Failed: (", ele.PldCont.UserName, org, ")", err) + log.Error("INSERT DEVELOPER Failed: (", EntityIdentifier, scope, ")", err) txn.Rollback() - return false } else { - log.Info("INSERT DEVELOPER Success: (", ele.PldCont.UserName, org, ")") + log.Info("INSERT DEVELOPER Success: (", EntityIdentifier, scope, ")") txn.Commit() - return true } - }
diff --git a/validate_env.go b/validate_env.go index df0382d..d90e27c 100644 --- a/validate_env.go +++ b/validate_env.go
@@ -1,15 +1,16 @@ package apidVerifyApiKey -import "encoding/json" +import "strings" /* * Ensure the ENV matches. */ -func validateEnv(envLocal, envInPath string) bool { +func validateEnv(envLocal string, envInPath string) bool { - var ePaths []string - json.Unmarshal([]byte(envLocal), &ePaths) - for _, a := range ePaths { + s := strings.TrimPrefix(envLocal, "{") + s = strings.TrimSuffix(s, "}") + fs := strings.Split(s, ",") + for _, a := range fs { if a == envInPath { return true }
diff --git a/validate_path.go b/validate_path.go index f3cfb99..ac107cb 100644 --- a/validate_path.go +++ b/validate_path.go
@@ -1,7 +1,6 @@ package apidVerifyApiKey import ( - "encoding/json" "regexp" "strings" ) @@ -14,9 +13,10 @@ */ func validatePath(basePath, requestBase string) bool { - var basePaths []string - json.Unmarshal([]byte(basePath), &basePaths) - for _, a := range basePaths { + s := strings.TrimPrefix(basePath, "{") + s = strings.TrimSuffix(s, "}") + fs := strings.Split(s, ",") + for _, a := range fs { str1 := strings.Replace(a, "**", "(.*)", -1) str2 := strings.Replace(a, "*", "([^/]+)", -1) if a != str1 { @@ -41,5 +41,5 @@ } /* if the i/p resource is empty, no checks need to be made */ - return len(basePaths) == 0 + return len(fs) == 0 }