Skip to content

Commit

Permalink
[api] deprecate keyhashes
Browse files Browse the repository at this point in the history
  • Loading branch information
jbygdell committed Nov 4, 2024
1 parent fd1e382 commit 9028513
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 12 deletions.
50 changes: 41 additions & 9 deletions sda/cmd/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -522,4 +523,35 @@ func listC4ghHashes(c *gin.Context) {
}
c.Writer.Header().Set("Content-Type", "application/json")
c.JSON(200, hashes)
}
}

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
}
}
71 changes: 69 additions & 2 deletions sda/cmd/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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()
}
17 changes: 17 additions & 0 deletions sda/internal/database/db_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
29 changes: 28 additions & 1 deletion sda/internal/database/db_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

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")
}

0 comments on commit 9028513

Please sign in to comment.