From 77d27908e36aa1badde63e9e8a2064a6d013d443 Mon Sep 17 00:00:00 2001 From: Joakim Bygdell Date: Mon, 28 Oct 2024 15:06:37 +0100 Subject: [PATCH 1/4] [api] list key hashes --- sda/cmd/api/api.go | 22 ++++++++++++ sda/cmd/api/api_test.go | 37 ++++++++++++++++++++ sda/internal/database/db_functions.go | 40 ++++++++++++++++++++++ sda/internal/database/db_functions_test.go | 30 ++++++++++++++++ sda/internal/database/db_test.go | 2 +- 5 files changed, 130 insertions(+), 1 deletion(-) diff --git a/sda/cmd/api/api.go b/sda/cmd/api/api.go index b0efe1476..7d7b6ebf4 100644 --- a/sda/cmd/api/api.go +++ b/sda/cmd/api/api.go @@ -87,6 +87,7 @@ func setup(config *config.Config) *http.Server { r.POST("/dataset/create", isAdmin(), createDataset) // maps a set of files to a dataset r.POST("/dataset/release/*dataset", isAdmin(), releaseDataset) // Releases a dataset to be accessible r.POST("/c4gh-keys/add", isAdmin(), addC4ghHash) // Adds a key hash to the database + r.GET("/c4gh-keys/list", isAdmin(), listC4ghHashes) // Lists keyhashes in the database r.GET("/users", isAdmin(), listActiveUsers) // Lists all users r.GET("/users/:username/files", isAdmin(), listUserFiles) // Lists all unmapped files for a user } @@ -501,3 +502,24 @@ func addC4ghHash(c *gin.Context) { c.Status(http.StatusOK) } + +func listC4ghHashes(c *gin.Context) { + hashes, err := Conf.API.DB.ListKeyHashes() + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) + + return + } + + for n, h := range hashes { + ct, _ := time.Parse(time.RFC3339, h.CreatedAt) + hashes[n].CreatedAt = ct.Format(time.DateTime) + + if h.DeprecatedAt != "" { + dt, _ := time.Parse(time.RFC3339, h.DeprecatedAt) + hashes[n].DeprecatedAt = dt.Format(time.DateTime) + } + } + c.Writer.Header().Set("Content-Type", "application/json") + c.JSON(200, hashes) +} \ No newline at end of file diff --git a/sda/cmd/api/api_test.go b/sda/cmd/api/api_test.go index 9332893ae..7ce8e2f58 100644 --- a/sda/cmd/api/api_test.go +++ b/sda/cmd/api/api_test.go @@ -1374,3 +1374,40 @@ func (suite *TestSuite) TestAddC4ghHash_notBase64() { assert.Equal(suite.T(), http.StatusBadRequest, resp.StatusCode) defer resp.Body.Close() } + +func (suite *TestSuite) TestListC4ghHashes() { + assert.NoError(suite.T(), Conf.API.DB.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23", "this is a test key"), "failed to register key in database") + + expectedResponse := database.C4ghKeyHash{ + Hash: "cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23", + Description: "this is a test key", + CreatedAt: time.Now().UTC().Format(time.DateTime), + DeprecatedAt: "", + } + + gin.SetMode(gin.ReleaseMode) + assert.NoError(suite.T(), setupJwtAuth()) + Conf.API.Admins = []string{"dummy"} + + r := gin.Default() + r.GET("/c4gh-keys/list", isAdmin(), listC4ghHashes) + ts := httptest.NewServer(r) + defer ts.Close() + + client := &http.Client{} + assert.NoError(suite.T(), setupJwtAuth()) + + req, err := http.NewRequest("GET", ts.URL+"/c4gh-keys/list", nil) + assert.NoError(suite.T(), err) + req.Header.Add("Authorization", "Bearer "+suite.Token) + + resp, err := client.Do(req) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), http.StatusOK, resp.StatusCode) + defer resp.Body.Close() + + hashes := []database.C4ghKeyHash{} + err = json.NewDecoder(resp.Body).Decode(&hashes) + assert.NoError(suite.T(), err, "failed to list users from DB") + assert.Equal(suite.T(), expectedResponse, hashes[0]) +} diff --git a/sda/internal/database/db_functions.go b/sda/internal/database/db_functions.go index f9cf2eb66..5b30bada8 100644 --- a/sda/internal/database/db_functions.go +++ b/sda/internal/database/db_functions.go @@ -3,6 +3,7 @@ package database import ( + "database/sql" "encoding/hex" "errors" "math" @@ -782,3 +783,42 @@ func (dbs *SDAdb) addKeyHash(keyHash, keyDescription string) error { return nil } + +type C4ghKeyHash struct { + Hash string `json:"hash"` + Description string `json:"description"` + CreatedAt string `json:"created_at"` + DeprecatedAt string `json:"deprecated_at"` +} + +// ListKeyHashes lists the hashes from the encryption_keys table +func (dbs *SDAdb) ListKeyHashes() ([]C4ghKeyHash, error) { + dbs.checkAndReconnectIfNeeded() + db := dbs.DB + + const query = "SELECT key_hash, description, created_at, deprecated_at FROM sda.encryption_keys ORDER BY created_at ASC;" + + hashList := []C4ghKeyHash{} + rows, err := db.Query(query) + if err != nil { + return nil, err + } + if rows.Err() != nil { + return nil, rows.Err() + } + defer rows.Close() + + for rows.Next() { + h := &C4ghKeyHash{} + depr := sql.NullString{} + err := rows.Scan(&h.Hash, &h.Description, &h.CreatedAt, &depr) + if err != nil { + return nil, err + } + h.DeprecatedAt = depr.String + + hashList = append(hashList, *h) + } + + return hashList, nil +} diff --git a/sda/internal/database/db_functions_test.go b/sda/internal/database/db_functions_test.go index 2b2235736..45c6a72d2 100644 --- a/sda/internal/database/db_functions_test.go +++ b/sda/internal/database/db_functions_test.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "fmt" "regexp" + "time" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -657,3 +658,32 @@ func (suite *DatabaseTests) TestAddKeyHash() { assert.NoError(suite.T(), err, "failed to verify key hash existence") assert.True(suite.T(), exists, "key hash was not added to the database") } + +func (suite *DatabaseTests) TestListKeyHashes() { + db, err := NewSDAdb(suite.dbConf) + assert.NoError(suite.T(), err, "got (%v) when creating new connection", err) + + assert.NoError(suite.T(), db.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23", "this is a test key"), "failed to register key in database") + assert.NoError(suite.T(), db.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc99", "this is a another key"), "failed to register key in database") + + expectedResponse := C4ghKeyHash{ + Hash: "cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23", + Description: "this is a test key", + CreatedAt: time.Now().UTC().Format(time.DateOnly), + DeprecatedAt: "", + } + hashList, err := db.ListKeyHashes() + ct, _ := time.Parse(time.RFC3339, hashList[0].CreatedAt) + hashList[0].CreatedAt = ct.Format(time.DateOnly) + assert.NoError(suite.T(), err, "failed to verify key hash existence") + assert.Equal(suite.T(), expectedResponse, hashList[0], "key hash was not added to the database") +} + +func (suite *DatabaseTests) TestListKeyHashes_emptyTable() { + db, err := NewSDAdb(suite.dbConf) + assert.NoError(suite.T(), err, "got (%v) when creating new connection", err) + + hashList, err := db.ListKeyHashes() + assert.NoError(suite.T(), err, "failed to verify key hash existence") + assert.Equal(suite.T(), []C4ghKeyHash{}, hashList, "fuu") +} \ No newline at end of file diff --git a/sda/internal/database/db_test.go b/sda/internal/database/db_test.go index 9868fcc6f..554a2385b 100644 --- a/sda/internal/database/db_test.go +++ b/sda/internal/database/db_test.go @@ -120,7 +120,7 @@ func (suite *DatabaseTests) SetupTest() { db, err := NewSDAdb(suite.dbConf) assert.Nil(suite.T(), err, "got %v when creating new connection", err) - _, err = db.DB.Exec("TRUNCATE sda.files CASCADE") + _, err = db.DB.Exec("TRUNCATE sda.files, sda.encryption_keys CASCADE") assert.NoError(suite.T(), err) } From b40beb6835a8f2ebee01537eb946dfc4d58ded78 Mon Sep 17 00:00:00 2001 From: Joakim Bygdell Date: Tue, 29 Oct 2024 09:23:15 +0100 Subject: [PATCH 2/4] [api] deprecate keyhashes --- sda/cmd/api/api.go | 50 ++++++++++++--- sda/cmd/api/api_test.go | 71 +++++++++++++++++++++- sda/internal/database/db_functions.go | 17 ++++++ sda/internal/database/db_functions_test.go | 29 ++++++++- 4 files changed, 155 insertions(+), 12 deletions(-) diff --git a/sda/cmd/api/api.go b/sda/cmd/api/api.go index 7d7b6ebf4..649a7231e 100644 --- a/sda/cmd/api/api.go +++ b/sda/cmd/api/api.go @@ -82,14 +82,15 @@ func setup(config *config.Config) *http.Server { r.GET("/files", getFiles) // admin endpoints below here if len(config.API.Admins) > 0 { - r.POST("/file/ingest", isAdmin(), ingestFile) // start ingestion of a file - r.POST("/file/accession", isAdmin(), setAccession) // assign accession ID to a file - r.POST("/dataset/create", isAdmin(), createDataset) // maps a set of files to a dataset - r.POST("/dataset/release/*dataset", isAdmin(), releaseDataset) // Releases a dataset to be accessible - r.POST("/c4gh-keys/add", isAdmin(), addC4ghHash) // Adds a key hash to the database - r.GET("/c4gh-keys/list", isAdmin(), listC4ghHashes) // Lists keyhashes in the database - r.GET("/users", isAdmin(), listActiveUsers) // Lists all users - r.GET("/users/:username/files", isAdmin(), listUserFiles) // Lists all unmapped files for a user + r.POST("/file/ingest", isAdmin(), ingestFile) // start ingestion of a file + r.POST("/file/accession", isAdmin(), setAccession) // assign accession ID to a file + r.POST("/dataset/create", isAdmin(), createDataset) // maps a set of files to a dataset + r.POST("/dataset/release/*dataset", isAdmin(), releaseDataset) // Releases a dataset to be accessible + r.POST("/c4gh-keys/add", isAdmin(), addC4ghHash) // Adds a key hash to the database + r.POST("/c4gh-keys/deprecate/*keyHash", isAdmin(), deprecateC4ghHash) // Deprecate a given key hash + r.GET("/c4gh-keys/list", isAdmin(), listC4ghHashes) // Lists key hashes in the database + r.GET("/users", isAdmin(), listActiveUsers) // Lists all users + r.GET("/users/:username/files", isAdmin(), listUserFiles) // Lists all unmapped files for a user } cfg := &tls.Config{MinVersion: tls.VersionTLS12} @@ -522,4 +523,35 @@ func listC4ghHashes(c *gin.Context) { } c.Writer.Header().Set("Content-Type", "application/json") c.JSON(200, hashes) -} \ No newline at end of file +} + +func deprecateC4ghHash(c *gin.Context) { + keyHash := strings.TrimPrefix(c.Param("keyHash"), "/") + + hashes, err := Conf.API.DB.ListKeyHashes() + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) + + return + } + found := false + for _, h := range hashes { + if h.Hash == keyHash { + found = true + + break + } + } + if !found { + c.AbortWithStatusJSON(http.StatusBadRequest, fmt.Errorf("%s not found", keyHash)) + + return + } + + err = Conf.API.DB.DeprecateKeyHash(keyHash) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) + + return + } +} diff --git a/sda/cmd/api/api_test.go b/sda/cmd/api/api_test.go index 7ce8e2f58..bab7e247d 100644 --- a/sda/cmd/api/api_test.go +++ b/sda/cmd/api/api_test.go @@ -220,6 +220,9 @@ func TestMain(m *testing.M) { if err := pool.Purge(oidc); err != nil { log.Fatalf("Could not purge resource: %s", err) } + // cleanup temp files + _ = os.RemoveAll(ECPath) + _ = os.RemoveAll(RSAPath) os.Exit(code) } @@ -376,7 +379,9 @@ func (suite *TestSuite) SetupSuite() { assert.NoError(suite.T(), err) } - +func (suite *TestSuite) TearDownSuite() { + assert.NoError(suite.T(), os.RemoveAll(suite.Path)) +} func (suite *TestSuite) SetupTest() { Conf.Database = database.DBConf{ Host: "localhost", @@ -1409,5 +1414,67 @@ func (suite *TestSuite) TestListC4ghHashes() { hashes := []database.C4ghKeyHash{} err = json.NewDecoder(resp.Body).Decode(&hashes) assert.NoError(suite.T(), err, "failed to list users from DB") - assert.Equal(suite.T(), expectedResponse, hashes[0]) + for n, h := range hashes { + if h.Hash == "cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23" { + assert.Equal(suite.T(), expectedResponse, hashes[n]) + + break + } + } +} + +func (suite *TestSuite) TestDeprecateC4ghHash() { + assert.NoError(suite.T(), Conf.API.DB.AddKeyHash("abc8f5cc8d936ce437a52cd9991453839581fc69ee26e0daefde6a5d2660fc23", "this is a deprecation test key"), "failed to register key in database") + + gin.SetMode(gin.ReleaseMode) + assert.NoError(suite.T(), setupJwtAuth()) + Conf.API.Admins = []string{"dummy"} + + r := gin.Default() + r.POST("/c4gh-keys/deprecate/*keyHash", isAdmin(), deprecateC4ghHash) + ts := httptest.NewServer(r) + defer ts.Close() + + client := &http.Client{} + assert.NoError(suite.T(), setupJwtAuth()) + + req, err := http.NewRequest("POST", ts.URL+"/c4gh-keys/deprecate/abc8f5cc8d936ce437a52cd9991453839581fc69ee26e0daefde6a5d2660fc23", http.NoBody) + assert.NoError(suite.T(), err) + req.Header.Add("Authorization", "Bearer "+suite.Token) + + resp, err := client.Do(req) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), http.StatusOK, resp.StatusCode) + defer resp.Body.Close() + + // a second time gives an error since the key is alreadu deprecated + resp2, err := client.Do(req) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), http.StatusInternalServerError, resp2.StatusCode) + defer resp2.Body.Close() +} + +func (suite *TestSuite) TestDeprecateC4ghHash_wrongHash() { + assert.NoError(suite.T(), Conf.API.DB.AddKeyHash("abc8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc99", "this is a deprecation test key"), "failed to register key in database") + + gin.SetMode(gin.ReleaseMode) + assert.NoError(suite.T(), setupJwtAuth()) + Conf.API.Admins = []string{"dummy"} + + r := gin.Default() + r.POST("/c4gh-keys/deprecate/*keyHash", isAdmin(), deprecateC4ghHash) + ts := httptest.NewServer(r) + defer ts.Close() + + client := &http.Client{} + assert.NoError(suite.T(), setupJwtAuth()) + + req, err := http.NewRequest("POST", ts.URL+"/c4gh-keys/deprecate/xyz8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc23", http.NoBody) + assert.NoError(suite.T(), err) + req.Header.Add("Authorization", "Bearer "+suite.Token) + + resp, err := client.Do(req) + assert.NoError(suite.T(), err) + assert.Equal(suite.T(), http.StatusBadRequest, resp.StatusCode) + defer resp.Body.Close() } diff --git a/sda/internal/database/db_functions.go b/sda/internal/database/db_functions.go index 5b30bada8..97d72c647 100644 --- a/sda/internal/database/db_functions.go +++ b/sda/internal/database/db_functions.go @@ -822,3 +822,20 @@ func (dbs *SDAdb) ListKeyHashes() ([]C4ghKeyHash, error) { return hashList, nil } + +func (dbs *SDAdb) DeprecateKeyHash(keyHash string) error { + dbs.checkAndReconnectIfNeeded() + db := dbs.DB + + const query = "UPDATE sda.encryption_keys set deprecated_at = NOW() WHERE key_hash = $1 AND deprecated_at IS NULL;" + result, err := db.Exec(query, keyHash) + if err != nil { + return err + } + + if rowsAffected, _ := result.RowsAffected(); rowsAffected == 0 { + return errors.New("key hash not found or already deprecated") + } + + return nil +} diff --git a/sda/internal/database/db_functions_test.go b/sda/internal/database/db_functions_test.go index 45c6a72d2..a92fe877c 100644 --- a/sda/internal/database/db_functions_test.go +++ b/sda/internal/database/db_functions_test.go @@ -686,4 +686,31 @@ func (suite *DatabaseTests) TestListKeyHashes_emptyTable() { hashList, err := db.ListKeyHashes() assert.NoError(suite.T(), err, "failed to verify key hash existence") assert.Equal(suite.T(), []C4ghKeyHash{}, hashList, "fuu") -} \ No newline at end of file +} + +func (suite *DatabaseTests) TestDeprecateKeyHashes() { + db, err := NewSDAdb(suite.dbConf) + assert.NoError(suite.T(), err, "got (%v) when creating new connection", err) + assert.NoError(suite.T(), db.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc32", "this is a test key"), "failed to register key in database") + + assert.NoError(suite.T(), db.DeprecateKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc32"), "failure when deprecating keyhash") +} + +func (suite *DatabaseTests) TestDeprecateKeyHashes_wrongHash() { + db, err := NewSDAdb(suite.dbConf) + assert.NoError(suite.T(), err, "got (%v) when creating new connection", err) + assert.NoError(suite.T(), db.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc11", "this is a another key"), "failed to register key in database") + + assert.EqualError(suite.T(), db.DeprecateKeyHash("wr0n6h4sh"), "key hash not found or already deprecated", "failure when deprecating non existing keyhash") +} + +func (suite *DatabaseTests) TestDeprecateKeyHashes_alreadyDeprecated() { + db, err := NewSDAdb(suite.dbConf) + assert.NoError(suite.T(), err, "got (%v) when creating new connection", err) + assert.NoError(suite.T(), db.AddKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc54", "this is a test key"), "failed to register key in database") + + assert.NoError(suite.T(), db.DeprecateKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc54"), "failure when deprecating keyhash") + + // we should not be able to change the deprecation date + assert.EqualError(suite.T(), db.DeprecateKeyHash("cbd8f5cc8d936ce437a52cd7991453839581fc69ee26e0daefde6a5d2660fc54"), "key hash not found or already deprecated", "failure when deprecating keyhash") +} From 2d828b44b8ba44d915d7697db1e0167ef510c8c6 Mon Sep 17 00:00:00 2001 From: Joakim Bygdell Date: Tue, 29 Oct 2024 12:31:48 +0100 Subject: [PATCH 3/4] [integration tests] expand the tests for the API --- .../integration/tests/sda/10_upload_test.sh | 2 +- .../tests/sda/11_api-getfiles_test.sh | 41 ---------- .github/integration/tests/sda/11_api_test.sh | 76 +++++++++++++++++++ 3 files changed, 77 insertions(+), 42 deletions(-) delete mode 100644 .github/integration/tests/sda/11_api-getfiles_test.sh create mode 100644 .github/integration/tests/sda/11_api_test.sh diff --git a/.github/integration/tests/sda/10_upload_test.sh b/.github/integration/tests/sda/10_upload_test.sh index e20939cf4..640045454 100644 --- a/.github/integration/tests/sda/10_upload_test.sh +++ b/.github/integration/tests/sda/10_upload_test.sh @@ -18,7 +18,7 @@ for q in accession archived backup completed inbox ingest mappings verified; do curl -s -k -u guest:guest -X DELETE "$URI/api/queues/sda/$q/contents" done ## truncate database -psql -U postgres -h postgres -d sda -At -c "TRUNCATE TABLE sda.files CASCADE;" +psql -U postgres -h postgres -d sda -At -c "TRUNCATE TABLE sda.files, sda.encryption_keys CASCADE;" pip -q install s3cmd diff --git a/.github/integration/tests/sda/11_api-getfiles_test.sh b/.github/integration/tests/sda/11_api-getfiles_test.sh deleted file mode 100644 index a99bb9eaa..000000000 --- a/.github/integration/tests/sda/11_api-getfiles_test.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -set -e - -# Test the API files endpoint -token="$(curl http://oidc:8080/tokens | jq -r '.[0]')" -response="$(curl -s -k -L "http://api:8080/files" -H "Authorization: Bearer $token" | jq -r 'sort_by(.inboxPath)|.[-1].fileStatus')" -if [ "$response" != "uploaded" ]; then - echo "API returned incorrect value, expected ready got: $response" - exit 1 -fi - -# test inserting a c4gh public key hash -payload=$( - jq -c -n \ - --arg description "this is the key description" \ - --arg pubkey "$( base64 -w0 /shared/c4gh.pub.pem)" \ - '$ARGS.named' -) - -resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$payload" "http://api:8080/c4gh-keys/add")" -if [ "$resp" != "200" ]; then - echo "Error when adding a public key hash, expected 200 got: $resp" - exit 1 -fi - -# again to verify we get an error -resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$payload" "http://api:8080/c4gh-keys/add")" -if [ "$resp" != "409" ]; then - echo "Error when adding a public key hash, expected 409 got: $resp" - exit 1 -fi - -manual_hash=$(sed -n '2p' /shared/c4gh.pub.pem | base64 -d -w0 | xxd -c64 -ps) - -db_hash=$(psql -U postgres -h postgres -d sda -At -c "SELECT key_hash FROM sda.encryption_keys WHERE description = 'this is the key description';") -if [ "$db_hash" != "$manual_hash" ]; then - echo "wrong hash in the database, expected $manual_hash got $db_hash" - exit 1 -fi - -echo "api test completed successfully" diff --git a/.github/integration/tests/sda/11_api_test.sh b/.github/integration/tests/sda/11_api_test.sh new file mode 100644 index 000000000..5970e4ab8 --- /dev/null +++ b/.github/integration/tests/sda/11_api_test.sh @@ -0,0 +1,76 @@ +#!/bin/sh +set -e + +# Test the API files endpoint +token="$(curl http://oidc:8080/tokens | jq -r '.[0]')" +response="$(curl -s -k -L "http://api:8080/files" -H "Authorization: Bearer $token" | jq -r 'sort_by(.inboxPath)|.[-1].fileStatus')" +if [ "$response" != "uploaded" ]; then + echo "API returned incorrect value, expected ready got: $response" + exit 1 +fi + +# test inserting a c4gh public key hash +payload=$( + jq -c -n \ + --arg description "this is the key description" \ + --arg pubkey "$( base64 -w0 /shared/c4gh.pub.pem)" \ + '$ARGS.named' +) + +resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$payload" "http://api:8080/c4gh-keys/add")" +if [ "$resp" != "200" ]; then + echo "Error when adding a public key hash, expected 200 got: $resp" + exit 1 +fi + +# again to verify we get an error +resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$payload" "http://api:8080/c4gh-keys/add")" +if [ "$resp" != "409" ]; then + echo "Error when adding a public key hash, expected 409 got: $resp" + exit 1 +fi + +# add key that will be deprecated +new_payload=$( + jq -c -n \ + --arg description "this key will be deprecated" \ + --arg pubkey "LS0tLS1CRUdJTiBDUllQVDRHSCBQVUJMSUMgS0VZLS0tLS0KTmdUdEFNLzRIUVR4b0I5bHZlRHVaYW5sRmVpWXVHRzBQTTg1eHNBU2xrZz0KLS0tLS1FTkQgQ1JZUFQ0R0ggUFVCTElDIEtFWS0tLS0tCg==" \ + '$ARGS.named' +) + +resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$new_payload" "http://api:8080/c4gh-keys/add")" +if [ "$resp" != "200" ]; then + echo "Error when adding a public key hash, expected 200 got: $resp" + exit 1 +fi + +deprecated_hash="3604ed00cff81d04f1a01f65bde0ee65a9e515e898b861b43ccf39c6c0129648" + +resp="$(curl -s -k -L -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST "http://api:8080/c4gh-keys/deprecate/$deprecated_hash")" +if [ "$resp" != "200" ]; then + echo "Error when adding a public key hash, expected 200 got: $resp" + exit 1 +fi + + +# list key hashes +resp="$(curl -s -k -L -H "Authorization: Bearer $token" -X GET "http://api:8080/c4gh-keys/list" | jq '. | length')" +if [ "$resp" -ne 2 ]; then + echo "Error when listing key hash, expected 2 entries got: $resp" + exit 1 +fi + +manual_hash=$(sed -n '2p' /shared/c4gh.pub.pem | base64 -d -w0 | xxd -c64 -ps) +resp="$(curl -s -k -L -H "Authorization: Bearer $token" -X GET "http://api:8080/c4gh-keys/list" | jq -r .[0].hash)" +if [ "$resp" != "$manual_hash" ]; then + echo "Error when listing key hash, expected $manual_hash got: $resp" + exit 1 +fi +ts=$(date +"%F %T") +depr="$(curl -s -k -L -H "Authorization: Bearer $token" -X GET "http://api:8080/c4gh-keys/list" | jq -r .[1].deprecated_at)" +if [ "$depr" != "$ts" ]; then + echo "Error when listing key hash, expected $ts got: $depr" + exit 1 +fi + +echo "api test completed successfully" From 38a1b7ad442124e1bb4c89c16cf7b3ebc33c8c92 Mon Sep 17 00:00:00 2001 From: Joakim Bygdell Date: Mon, 4 Nov 2024 13:01:20 +0100 Subject: [PATCH 4/4] Simplify deprecation function The heavy lifting is down in the database function. --- sda/cmd/api/api.go | 23 +---------------------- sda/cmd/api/api_test.go | 2 +- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/sda/cmd/api/api.go b/sda/cmd/api/api.go index 649a7231e..8eb2f004a 100644 --- a/sda/cmd/api/api.go +++ b/sda/cmd/api/api.go @@ -527,30 +527,9 @@ func listC4ghHashes(c *gin.Context) { func deprecateC4ghHash(c *gin.Context) { keyHash := strings.TrimPrefix(c.Param("keyHash"), "/") - - hashes, err := Conf.API.DB.ListKeyHashes() - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) - - return - } - found := false - for _, h := range hashes { - if h.Hash == keyHash { - found = true - - break - } - } - if !found { - c.AbortWithStatusJSON(http.StatusBadRequest, fmt.Errorf("%s not found", keyHash)) - - return - } - err = Conf.API.DB.DeprecateKeyHash(keyHash) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, err.Error()) + c.AbortWithStatusJSON(http.StatusBadRequest, err.Error()) return } diff --git a/sda/cmd/api/api_test.go b/sda/cmd/api/api_test.go index bab7e247d..cdbeb75ed 100644 --- a/sda/cmd/api/api_test.go +++ b/sda/cmd/api/api_test.go @@ -1450,7 +1450,7 @@ func (suite *TestSuite) TestDeprecateC4ghHash() { // a second time gives an error since the key is alreadu deprecated resp2, err := client.Do(req) assert.NoError(suite.T(), err) - assert.Equal(suite.T(), http.StatusInternalServerError, resp2.StatusCode) + assert.Equal(suite.T(), http.StatusBadRequest, resp2.StatusCode) defer resp2.Body.Close() }