[ISSUE-67869881] update url path
diff --git a/common/cipher.go b/common/cipher.go index 0b665df..f67b893 100644 --- a/common/cipher.go +++ b/common/cipher.go
@@ -15,6 +15,8 @@ import ( "encoding/base64" + "encoding/json" + "encoding/xml" "fmt" "github.com/apid/apid-core/cipher" "io/ioutil" @@ -26,12 +28,21 @@ ) const RegEncrypted = `^\{[0-9A-Za-z]+/[0-9A-Za-z]+/[0-9A-Za-z]+\}.` -const retrieveEncryptKeyPath = "/encryptionkey" +const retrieveEncryptKeyPath = "/config/organizations/{org}/kmsencryptionkey" const EncryptAes = "AES" -const retrieveKeyRetryInterval = time.Duration(5 * time.Second) -const retrieveKeyTimeout = time.Duration(5 * time.Minute) + +const ( + retrieveKeyRetryInterval = time.Duration(5 * time.Second) + retrieveKeyTimeout = time.Duration(5 * time.Minute) +) const parameterOrganization = "organization" const configBearerToken = "apigeesync_bearer_token" +const headerContentType = "Content-Type" +const ( + typeJson = "application/json" + typeXml = "text/xml" +) +const errorCodeNoKey = "organizations.EncryptionKeyDoesNotExist" var RegexpEncrypted = regexp.MustCompile(RegEncrypted) @@ -80,6 +91,7 @@ return case <-ticker.C: if err := c.retrieveKey(org); err != nil { + log.Error(err) } else { return @@ -90,10 +102,11 @@ func (c *KmsCipherManager) retrieveKey(org string) error { var key []byte - req, err := http.NewRequest(http.MethodGet, c.serverUrlBase+retrieveEncryptKeyPath, nil) - pars := req.URL.Query() - pars[parameterOrganization] = []string{org} - req.URL.RawQuery = pars.Encode() + path := strings.Replace(retrieveEncryptKeyPath, "{org}", org, 1) + req, err := http.NewRequest(http.MethodGet, c.serverUrlBase+path, nil) + //pars := req.URL.Query() + //pars[parameterOrganization] = []string{org} + //req.URL.RawQuery = pars.Encode() req.Header.Set("Authorization", "Bearer "+services.Config().GetString(configBearerToken)) log.Debugf("Retrieving key: %s", req.URL.String()) if err != nil { @@ -103,6 +116,21 @@ if err != nil { return fmt.Errorf("failed to retrieve key for org=%s : %v", org, err) } + + // if 404 + if res.StatusCode == http.StatusNotFound { + e, err := parseErrorResponse(res) + if err != nil { + log.Errorf("Failed to parse error response: %v", err) + return err + } + // is this org has no key, stop retrying + if e.Code == errorCodeNoKey { + log.Debugf("No key is associated with org %v", org) + return nil + } + } + if res.StatusCode != http.StatusOK { err = fmt.Errorf("failed to retrieve key for org [%v] with status: %v", org, res.Status) return fmt.Errorf("failed to retrieve key for org [%v] with status: %v", org, res.Status) @@ -130,6 +158,7 @@ return nil } +// return val is nullable func (c *KmsCipherManager) getAesCipher(org string) *cipher.AesCipher { // if exists c.mutex.RLock() @@ -139,7 +168,10 @@ } // if not exists c.mutex.RUnlock() - c.startRetrieve(org, c.interval, c.timeout) + if err := c.retrieveKey(org); err != nil { + log.Errorf("Failed to get encryption key for org=%s : %v", org, err) + return nil + } c.mutex.RLock() defer c.mutex.RUnlock() return c.aes[org] @@ -165,7 +197,12 @@ log.Errorf("Decode base64 of [%v] failed: [%v], considered as unencrypted!", text, err) return } - plaintext, err := c.getAesCipher(org).Decrypt(bytes, mode, padding) + aes := c.getAesCipher(org) + if aes == nil { + err = fmt.Errorf("failed to get decryption key for org: %s", org) + return + } + plaintext, err := aes.Decrypt(bytes, mode, padding) if err != nil { log.Errorf("Decrypt of [%v] failed: [%v], considered as unencrypted!", bytes, err) return @@ -178,7 +215,13 @@ // The returned string is the base64 encoding of the encrypted input, prepended with algorithm. // An example output is "{AES/ECB/PKCS5Padding}2jX3V3dQ5xB9C9Zl9sqyo8pmkvVP10rkEVPVhmnLHw4=" func (c *KmsCipherManager) EncryptBase64(input string, org string, mode cipher.Mode, padding cipher.Padding) (output string, err error) { - ciphertext, err := c.getAesCipher(org).Encrypt([]byte(input), mode, padding) + aes := c.getAesCipher(org) + // TODO: make sure this logic is expected + // if failed to get key and cipher, considered this org as unencrypted + if aes == nil { + return input, nil + } + ciphertext, err := aes.Encrypt([]byte(input), mode, padding) if err != nil { return } @@ -214,3 +257,25 @@ padding = cipher.Padding(l[2]) return } + +type ErrorRes struct { + Code string + Message string +} + +func parseErrorResponse(res *http.Response) (*ErrorRes, error) { + contentType := res.Header.Get("Content-Type") + defer res.Body.Close() + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + ret := &ErrorRes{} + if contentType == typeJson { + return ret, json.Unmarshal(body, ret) + } else if contentType == typeXml { + return ret, xml.Unmarshal(body, ret) + } else { + return nil, fmt.Errorf("unknown error: %v", string(body)) + } +}
diff --git a/common/data_test.go b/common/data_test.go index 4a3ecdc..7070890 100644 --- a/common/data_test.go +++ b/common/data_test.go
@@ -19,6 +19,7 @@ . "github.com/onsi/gomega" "io/ioutil" "reflect" + "sort" "sync" ) @@ -53,6 +54,13 @@ Expect(len(attributes["test-invalid"])).Should(BeEquivalentTo(0)) }) + It("Should get all orgs", func() { + orgs, err := testDbMan.GetOrgs() + Expect(err).Should(Succeed()) + sort.Strings(orgs) + Expect(orgs).Should(Equal([]string{"apid-haoming", "apid-test"})) + }) + }) Context("Validate common.JsonToStringArray", func() {
diff --git a/common/data_test.sql b/common/data_test.sql index 1a12c2f..1b5349b 100644 --- a/common/data_test.sql +++ b/common/data_test.sql
@@ -24,4 +24,9 @@ INSERT INTO "kms_attributes" VALUES('bc811169','50321842-d6ee-4e92-91b9-37234a7920c1','','','','','50321842-d6ee-4e92-91b9-37234a7920c1','','','Threshold','APIPRODUCT','TX100','bc811169'); INSERT INTO "kms_attributes" VALUES('bc811169','40753e12-a50a-429d-9121-e571eb4e43a9','','','','','40753e12-a50a-429d-9121-e571eb4e43a9','','','access','APIPRODUCT','public','bc811169'); INSERT INTO "kms_attributes" VALUES('bc811169','2d373ed6-e38f-453b-bb34-6d731d9c4815','','','','','','2d373ed6-e38f-453b-bb34-6d731d9c4815','','DisplayName','APP','demo-app','bc811169'); +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'); +CREATE TABLE edgex_data_scope (id text,apid_cluster_id text,scope text,org text,env text,created blob,created_by text,updated blob,updated_by text,_change_selector text,org_scope text,env_scope text, primary key (id)); +INSERT INTO "edgex_data_scope" VALUES('cc066263-6355-416d-9d59-7f3135d64953','543230f1-8c41-4bf5-94a3-f10c104ff5d4','155211e9','apid-haoming','test','2017-08-27 22:53:33.859+00:00','foobar@google.com','2017-08-27 22:53:33.859+00:00','foobar@google.com','543230f1-8c41-4bf5-94a3-f10c104ff5d4','12344caf-40d6-4ecb-8149-ed32d04184b2','1234203e-ba88-4cd5-967d-4caa88f64909'); +INSERT INTO "edgex_data_scope" VALUES('08c81eeb-57ec-43fe-8fed-cdff5494406f','123430f1-8c41-4bf5-94a3-f10c104ff5d4','165211e9','apid-test','prod','2017-08-29 02:39:34.093+00:00','foobar@google.com','2017-08-29 02:39:34.093+00:00','foobar@google.com','123430f1-8c41-4bf5-94a3-f10c104ff5d4','43214caf-40d6-4ecb-8149-ed32d04184b2','43211cae-f2a6-4663-9f36-eb17d76e6c32'); COMMIT;