334ae5b164
This change allows the creation and deletion of api keys via the admin API. It adds two methods for deletion, one via the name and projectID and the second one via the serialized apikey directly. Change-Id: Ida8aa729e716db58c671a901e5f7e39253e89a0d
184 lines
4.2 KiB
Go
184 lines
4.2 KiB
Go
// Copyright (C) 2020 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package admin
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"storj.io/common/macaroon"
|
|
"storj.io/common/uuid"
|
|
"storj.io/storj/satellite/console"
|
|
)
|
|
|
|
func (server *Server) addAPIKey(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
vars := mux.Vars(r)
|
|
projectUUIDString, ok := vars["project"]
|
|
if !ok {
|
|
httpJSONError(w, "project-uuid missing",
|
|
"", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
projectUUID, err := uuid.FromString(projectUUIDString)
|
|
if err != nil {
|
|
httpJSONError(w, "invalid project-uuid",
|
|
err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
httpJSONError(w, "failed to read body",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
var input struct {
|
|
PartnerID uuid.UUID `json:"partnerId"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
var output struct {
|
|
APIKey string `json:"apikey"`
|
|
}
|
|
|
|
err = json.Unmarshal(body, &input)
|
|
if err != nil {
|
|
httpJSONError(w, "failed to unmarshal request",
|
|
err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if input.Name == "" {
|
|
httpJSONError(w, "Name is not set",
|
|
"", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
_, err = server.db.Console().APIKeys().GetByNameAndProjectID(ctx, input.Name, projectUUID)
|
|
if err == nil {
|
|
httpJSONError(w, "api-key with given name already exists",
|
|
"", http.StatusConflict)
|
|
return
|
|
}
|
|
|
|
secret, err := macaroon.NewSecret()
|
|
if err != nil {
|
|
httpJSONError(w, "could not create macaroon secret",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
key, err := macaroon.NewAPIKey(secret)
|
|
if err != nil {
|
|
httpJSONError(w, "could not create api-key",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
apikey := console.APIKeyInfo{
|
|
Name: input.Name,
|
|
ProjectID: projectUUID,
|
|
Secret: secret,
|
|
PartnerID: input.PartnerID,
|
|
}
|
|
|
|
_, err = server.db.Console().APIKeys().Create(ctx, key.Head(), apikey)
|
|
if err != nil {
|
|
httpJSONError(w, "unable to add api-key to database",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
output.APIKey = key.Serialize()
|
|
data, err := json.Marshal(output)
|
|
if err != nil {
|
|
httpJSONError(w, "json encoding failed",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write(data) // nothing to do with the error response, probably the client requesting disappeared
|
|
}
|
|
|
|
func (server *Server) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
vars := mux.Vars(r)
|
|
apikeyString, ok := vars["apikey"]
|
|
if !ok {
|
|
httpJSONError(w, "apikey missing",
|
|
"", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
apikey, err := macaroon.ParseAPIKey(apikeyString)
|
|
if err != nil {
|
|
httpJSONError(w, "invalid apikey format",
|
|
err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
info, err := server.db.Console().APIKeys().GetByHead(ctx, apikey.Head())
|
|
if err != nil {
|
|
httpJSONError(w, "could not get apikey id",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
|
|
if err != nil {
|
|
httpJSONError(w, "unable to delete apikey",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
func (server *Server) deleteAPIKeyByName(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
vars := mux.Vars(r)
|
|
projectUUIDString, ok := vars["project"]
|
|
if !ok {
|
|
httpJSONError(w, "project-uuid missing",
|
|
"", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
projectUUID, err := uuid.FromString(projectUUIDString)
|
|
if err != nil {
|
|
httpJSONError(w, "invalid project-uuid",
|
|
err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
apikeyName, ok := vars["name"]
|
|
if !ok {
|
|
httpJSONError(w, "apikey name missing",
|
|
"", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
info, err := server.db.Console().APIKeys().GetByNameAndProjectID(ctx, apikeyName, projectUUID)
|
|
if err != nil {
|
|
httpJSONError(w, "could not get apikey id",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
|
|
if err != nil {
|
|
httpJSONError(w, "unable to delete apikey",
|
|
err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|