satellite: Rename "acct mgmt api" to "rest api"

"REST API" is a more accurate descriptor of the generated API in the
console package than "account management API". The generated API is very
flexible and will allow us to implement many more endpoints outside the
scope of "account management", and "account management" is not very well
defined to begin with.

Change-Id: Ie87faeaa3c743ef4371eaf0edd2826303d592da7
This commit is contained in:
Moby von Briesen 2022-04-12 12:59:07 -04:00 committed by Maximillian von Briesen
parent 1ed36e9fea
commit ed5ebb2527
20 changed files with 130 additions and 129 deletions

View File

@ -21,7 +21,7 @@ import (
"storj.io/storj/private/version/checker" "storj.io/storj/private/version/checker"
"storj.io/storj/satellite/admin" "storj.io/storj/satellite/admin"
"storj.io/storj/satellite/buckets" "storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console/accountmanagementapikeys" "storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/metabase" "storj.io/storj/satellite/metabase"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/stripecoinpayments" "storj.io/storj/satellite/payments/stripecoinpayments"
@ -65,8 +65,8 @@ type Admin struct {
Service *buckets.Service Service *buckets.Service
} }
AccountManagementAPIKeys struct { REST struct {
Service *accountmanagementapikeys.Service Keys *restkeys.Service
} }
} }
@ -87,8 +87,8 @@ func NewAdmin(log *zap.Logger, full *identity.FullIdentity, db DB, metabaseDB *m
peer.Buckets.Service = buckets.NewService(db.Buckets(), metabaseDB) peer.Buckets.Service = buckets.NewService(db.Buckets(), metabaseDB)
} }
{ // setup account management api keys { // setup rest keys
peer.AccountManagementAPIKeys.Service = accountmanagementapikeys.NewService(db.OIDC().OAuthTokens(), config.AccountManagementAPIKeys) peer.REST.Keys = restkeys.NewService(db.OIDC().OAuthTokens(), config.RESTKeys)
} }
{ // setup debug { // setup debug
@ -173,7 +173,7 @@ func NewAdmin(log *zap.Logger, full *identity.FullIdentity, db DB, metabaseDB *m
adminConfig := config.Admin adminConfig := config.Admin
adminConfig.AuthorizationToken = config.Console.AuthToken adminConfig.AuthorizationToken = config.Console.AuthToken
peer.Admin.Server = admin.NewServer(log.Named("admin"), peer.Admin.Listener, peer.DB, peer.Buckets.Service, peer.AccountManagementAPIKeys.Service, peer.Payments.Accounts, adminConfig) peer.Admin.Server = admin.NewServer(log.Named("admin"), peer.Admin.Listener, peer.DB, peer.Buckets.Service, peer.REST.Keys, peer.Payments.Accounts, adminConfig)
peer.Servers.Add(lifecycle.Item{ peer.Servers.Add(lifecycle.Item{
Name: "admin", Name: "admin",
Run: peer.Admin.Server.Run, Run: peer.Admin.Server.Run,

View File

@ -15,7 +15,7 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
func (server *Server) addAccountManagementAPIKey(w http.ResponseWriter, r *http.Request) { func (server *Server) addRESTKey(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -66,7 +66,7 @@ func (server *Server) addAccountManagementAPIKey(w http.ResponseWriter, r *http.
} }
} }
apiKey, expiresAt, err := server.accountManagementAPIKeys.Create(ctx, user.ID, expiration) apiKey, expiresAt, err := server.restKeys.Create(ctx, user.ID, expiration)
if err != nil { if err != nil {
sendJSONError(w, "api key creation failed", sendJSONError(w, "api key creation failed",
err.Error(), http.StatusInternalServerError) err.Error(), http.StatusInternalServerError)
@ -91,7 +91,7 @@ func (server *Server) addAccountManagementAPIKey(w http.ResponseWriter, r *http.
sendJSONData(w, http.StatusOK, data) sendJSONData(w, http.StatusOK, data)
} }
func (server *Server) revokeAccountManagementAPIKey(w http.ResponseWriter, r *http.Request) { func (server *Server) revokeRESTKey(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
vars := mux.Vars(r) vars := mux.Vars(r)
@ -102,7 +102,7 @@ func (server *Server) revokeAccountManagementAPIKey(w http.ResponseWriter, r *ht
return return
} }
err := server.accountManagementAPIKeys.Revoke(ctx, apiKey) err := server.restKeys.Revoke(ctx, apiKey)
if err != nil { if err != nil {
sendJSONError(w, "failed to revoke api key", sendJSONError(w, "failed to revoke api key",
err.Error(), http.StatusNotFound) err.Error(), http.StatusNotFound)

View File

@ -22,7 +22,7 @@ import (
"storj.io/storj/satellite/oidc" "storj.io/storj/satellite/oidc"
) )
func TestAccountManagementAPIKeys(t *testing.T) { func TestRESTKeys(t *testing.T) {
testplanet.Run(t, testplanet.Config{ testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, SatelliteCount: 1,
StorageNodeCount: 0, StorageNodeCount: 0,
@ -35,14 +35,14 @@ func TestAccountManagementAPIKeys(t *testing.T) {
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
address := planet.Satellites[0].Admin.Admin.Listener.Addr() address := planet.Satellites[0].Admin.Admin.Listener.Addr()
satellite := planet.Satellites[0] satellite := planet.Satellites[0]
keyService := satellite.API.AccountManagementAPIKeys.Service keyService := satellite.API.REST.Keys
user, err := planet.Satellites[0].DB.Console().Users().GetByEmail(ctx, planet.Uplinks[0].Projects[0].Owner.Email) user, err := planet.Satellites[0].DB.Console().Users().GetByEmail(ctx, planet.Uplinks[0].Projects[0].Owner.Email)
require.NoError(t, err) require.NoError(t, err)
t.Run("create with default expiration", func(t *testing.T) { t.Run("create with default expiration", func(t *testing.T) {
body := strings.NewReader(`{"expiration":""}`) body := strings.NewReader(`{"expiration":""}`)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("http://"+address.String()+"/api/accountmanagementapikeys/%s", user.Email), body) req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("http://"+address.String()+"/api/restkeys/%s", user.Email), body)
require.NoError(t, err) require.NoError(t, err)
req.Header.Set("Authorization", satellite.Config.Console.AuthToken) req.Header.Set("Authorization", satellite.Config.Console.AuthToken)
@ -73,7 +73,7 @@ func TestAccountManagementAPIKeys(t *testing.T) {
require.False(t, exp.Before(now)) require.False(t, exp.Before(now))
// check the expiration is around the time we expect // check the expiration is around the time we expect
defaultExpiration := satellite.Config.AccountManagementAPIKeys.DefaultExpiration defaultExpiration := satellite.Config.RESTKeys.DefaultExpiration
require.True(t, output.ExpiresAt.After(now.Add(defaultExpiration))) require.True(t, output.ExpiresAt.After(now.Add(defaultExpiration)))
require.True(t, output.ExpiresAt.Before(now.Add(defaultExpiration+time.Hour))) require.True(t, output.ExpiresAt.Before(now.Add(defaultExpiration+time.Hour)))
}) })
@ -81,7 +81,7 @@ func TestAccountManagementAPIKeys(t *testing.T) {
t.Run("create with custom expiration", func(t *testing.T) { t.Run("create with custom expiration", func(t *testing.T) {
durationString := "3h" durationString := "3h"
body := strings.NewReader(fmt.Sprintf(`{"expiration":"%s"}`, durationString)) body := strings.NewReader(fmt.Sprintf(`{"expiration":"%s"}`, durationString))
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("http://"+address.String()+"/api/accountmanagementapikeys/%s", user.Email), body) req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("http://"+address.String()+"/api/restkeys/%s", user.Email), body)
require.NoError(t, err) require.NoError(t, err)
req.Header.Set("Authorization", satellite.Config.Console.AuthToken) req.Header.Set("Authorization", satellite.Config.Console.AuthToken)
@ -125,13 +125,13 @@ func TestAccountManagementAPIKeys(t *testing.T) {
expiresAt, err := keyService.InsertIntoDB(ctx, oidc.OAuthToken{ expiresAt, err := keyService.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: user.ID, UserID: user.ID,
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: hash, Token: hash,
}, time.Now(), time.Hour) }, time.Now(), time.Hour)
require.NoError(t, err) require.NoError(t, err)
require.False(t, expiresAt.IsZero()) require.False(t, expiresAt.IsZero())
req, err := http.NewRequestWithContext(ctx, http.MethodPut, fmt.Sprintf("http://"+address.String()+"/api/accountmanagementapikeys/%s/revoke", apiKey), nil) req, err := http.NewRequestWithContext(ctx, http.MethodPut, fmt.Sprintf("http://"+address.String()+"/api/restkeys/%s/revoke", apiKey), nil)
require.NoError(t, err) require.NoError(t, err)
req.Header.Set("Authorization", satellite.Config.Console.AuthToken) req.Header.Set("Authorization", satellite.Config.Console.AuthToken)

View File

@ -21,7 +21,7 @@ import (
adminui "storj.io/storj/satellite/admin/ui" adminui "storj.io/storj/satellite/admin/ui"
"storj.io/storj/satellite/buckets" "storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys" "storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/oidc" "storj.io/storj/satellite/oidc"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/stripecoinpayments" "storj.io/storj/satellite/payments/stripecoinpayments"
@ -59,7 +59,7 @@ type Server struct {
db DB db DB
payments payments.Accounts payments payments.Accounts
buckets *buckets.Service buckets *buckets.Service
accountManagementAPIKeys *accountmanagementapikeys.Service restKeys *restkeys.Service
nowFn func() time.Time nowFn func() time.Time
@ -67,7 +67,7 @@ type Server struct {
} }
// NewServer returns a new administration Server. // NewServer returns a new administration Server.
func NewServer(log *zap.Logger, listener net.Listener, db DB, buckets *buckets.Service, accountManagementAPIKeys *accountmanagementapikeys.Service, accounts payments.Accounts, config Config) *Server { func NewServer(log *zap.Logger, listener net.Listener, db DB, buckets *buckets.Service, restKeys *restkeys.Service, accounts payments.Accounts, config Config) *Server {
server := &Server{ server := &Server{
log: log, log: log,
@ -76,7 +76,7 @@ func NewServer(log *zap.Logger, listener net.Listener, db DB, buckets *buckets.S
db: db, db: db,
payments: accounts, payments: accounts,
buckets: buckets, buckets: buckets,
accountManagementAPIKeys: accountManagementAPIKeys, restKeys: restKeys,
nowFn: time.Now, nowFn: time.Now,
@ -110,8 +110,8 @@ func NewServer(log *zap.Logger, listener net.Listener, db DB, buckets *buckets.S
api.HandleFunc("/projects/{project}/buckets/{bucket}/geofence", server.createGeofenceForBucket).Methods("POST") api.HandleFunc("/projects/{project}/buckets/{bucket}/geofence", server.createGeofenceForBucket).Methods("POST")
api.HandleFunc("/projects/{project}/buckets/{bucket}/geofence", server.deleteGeofenceForBucket).Methods("DELETE") api.HandleFunc("/projects/{project}/buckets/{bucket}/geofence", server.deleteGeofenceForBucket).Methods("DELETE")
api.HandleFunc("/apikeys/{apikey}", server.deleteAPIKey).Methods("DELETE") api.HandleFunc("/apikeys/{apikey}", server.deleteAPIKey).Methods("DELETE")
api.HandleFunc("/accountmanagementapikeys/{useremail}", server.addAccountManagementAPIKey).Methods("POST") api.HandleFunc("/restkeys/{useremail}", server.addRESTKey).Methods("POST")
api.HandleFunc("/accountmanagementapikeys/{apikey}/revoke", server.revokeAccountManagementAPIKey).Methods("PUT") api.HandleFunc("/restkeys/{apikey}/revoke", server.revokeRESTKey).Methods("PUT")
// This handler must be the last one because it uses the root as prefix, // This handler must be the last one because it uses the root as prefix,
// otherwise will try to serve all the handlers set after this one. // otherwise will try to serve all the handlers set after this one.

View File

@ -372,28 +372,28 @@ Blank fields will not be updated.`,
} }
} }
], ],
account_management_api_keys: [ rest_api_keys: [
{ {
name: 'create', name: 'create',
desc: 'Create an account management API key', desc: 'Create a REST key',
//params: [['API key', new InputText('text', true)]], //params: [['API key', new InputText('text', true)]],
params: [ params: [
["user's email", new InputText('text', true)], ["user's email", new InputText('text', true)],
['expiration', new InputText('text', false)] ['expiration', new InputText('text', false)]
], ],
func: async (useremail: string, expiration?: string): Promise<Record<string, unknown>> => { func: async (useremail: string, expiration?: string): Promise<Record<string, unknown>> => {
return this.fetch('POST', `accountmanagementapikeys/${useremail}`, null, { return this.fetch('POST', `restkeys/${useremail}`, null, {
expiration expiration
}); });
} }
}, },
{ {
name: 'revoke', name: 'revoke',
desc: 'Revoke an account management API key', desc: 'Revoke a REST key',
//params: [['API key', new InputText('text', true)]], //params: [['API key', new InputText('text', true)]],
params: [['api key', new InputText('text', true)]], params: [['api key', new InputText('text', true)]],
func: async (apikey: string): Promise<Record<string, unknown>> => { func: async (apikey: string): Promise<Record<string, unknown>> => {
return this.fetch('PUT', `accountmanagementapikeys/${apikey}/revoke`); return this.fetch('PUT', `restkeys/${apikey}/revoke`);
} }
} }
] ]

View File

@ -34,9 +34,9 @@ import (
"storj.io/storj/satellite/analytics" "storj.io/storj/satellite/analytics"
"storj.io/storj/satellite/buckets" "storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys"
"storj.io/storj/satellite/console/consoleauth" "storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/console/consoleweb" "storj.io/storj/satellite/console/consoleweb"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/contact" "storj.io/storj/satellite/contact"
"storj.io/storj/satellite/gracefulexit" "storj.io/storj/satellite/gracefulexit"
"storj.io/storj/satellite/inspector" "storj.io/storj/satellite/inspector"
@ -137,8 +137,8 @@ type API struct {
Stripe stripecoinpayments.StripeClient Stripe stripecoinpayments.StripeClient
} }
AccountManagementAPIKeys struct { REST struct {
Service *accountmanagementapikeys.Service Keys *restkeys.Service
} }
Console struct { Console struct {
@ -578,7 +578,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
} }
{ // setup account management api keys { // setup account management api keys
peer.AccountManagementAPIKeys.Service = accountmanagementapikeys.NewService(peer.DB.OIDC().OAuthTokens(), config.AccountManagementAPIKeys) peer.REST.Keys = restkeys.NewService(peer.DB.OIDC().OAuthTokens(), config.RESTKeys)
} }
{ // setup console { // setup console
@ -595,7 +595,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB,
peer.Log.Named("console:service"), peer.Log.Named("console:service"),
&consoleauth.Hmac{Secret: []byte(consoleConfig.AuthTokenSecret)}, &consoleauth.Hmac{Secret: []byte(consoleConfig.AuthTokenSecret)},
peer.DB.Console(), peer.DB.Console(),
peer.AccountManagementAPIKeys.Service, peer.REST.Keys,
peer.DB.ProjectAccounting(), peer.DB.ProjectAccounting(),
peer.Accounting.ProjectUsage, peer.Accounting.ProjectUsage,
peer.Buckets.Service, peer.Buckets.Service,

View File

@ -30,8 +30,8 @@ type APIKeys interface {
Delete(ctx context.Context, id uuid.UUID) error Delete(ctx context.Context, id uuid.UUID) error
} }
// AccountManagementAPIKeys is an interface for account management api key operations. // RESTKeys is an interface for rest key operations.
type AccountManagementAPIKeys interface { type RESTKeys interface {
Create(ctx context.Context, userID uuid.UUID, expiration time.Duration) (apiKey string, expiresAt time.Time, err error) Create(ctx context.Context, userID uuid.UUID, expiration time.Duration) (apiKey string, expiresAt time.Time, err error)
GetUserAndExpirationFromKey(ctx context.Context, apiKey string) (userID uuid.UUID, exp time.Time, err error) GetUserAndExpirationFromKey(ctx context.Context, apiKey string) (userID uuid.UUID, exp time.Time, err error)
Revoke(ctx context.Context, apiKey string) (err error) Revoke(ctx context.Context, apiKey string) (err error)

View File

@ -15,6 +15,7 @@ import (
) )
func main() { func main() {
// definition for REST API
a := &apigen.API{ a := &apigen.API{
Version: "v0", Version: "v0",
Description: "", Description: "",

View File

@ -24,9 +24,9 @@ import (
"storj.io/storj/satellite/accounting/live" "storj.io/storj/satellite/accounting/live"
"storj.io/storj/satellite/analytics" "storj.io/storj/satellite/analytics"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys"
"storj.io/storj/satellite/console/consoleauth" "storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/console/consoleweb/consoleql" "storj.io/storj/satellite/console/consoleweb/consoleql"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/mailservice" "storj.io/storj/satellite/mailservice"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/paymentsconfig" "storj.io/storj/satellite/payments/paymentsconfig"
@ -99,7 +99,7 @@ func TestGraphqlMutation(t *testing.T) {
log.Named("console"), log.Named("console"),
&consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")}, &consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")},
db.Console(), db.Console(),
accountmanagementapikeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.AccountManagementAPIKeys), restkeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.RESTKeys),
db.ProjectAccounting(), db.ProjectAccounting(),
projectUsage, projectUsage,
sat.API.Buckets.Service, sat.API.Buckets.Service,

View File

@ -21,9 +21,9 @@ import (
"storj.io/storj/satellite/accounting/live" "storj.io/storj/satellite/accounting/live"
"storj.io/storj/satellite/analytics" "storj.io/storj/satellite/analytics"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys"
"storj.io/storj/satellite/console/consoleauth" "storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/console/consoleweb/consoleql" "storj.io/storj/satellite/console/consoleweb/consoleql"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/mailservice" "storj.io/storj/satellite/mailservice"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/paymentsconfig" "storj.io/storj/satellite/payments/paymentsconfig"
@ -83,7 +83,7 @@ func TestGraphqlQuery(t *testing.T) {
log.Named("console"), log.Named("console"),
&consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")}, &consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")},
db.Console(), db.Console(),
accountmanagementapikeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.AccountManagementAPIKeys), restkeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.RESTKeys),
db.ProjectAccounting(), db.ProjectAccounting(),
projectUsage, projectUsage,
sat.API.Buckets.Service, sat.API.Buckets.Service,

View File

@ -1,7 +1,7 @@
// Copyright (C) 2022 Storj Labs, Inc. // Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information. // See LICENSE for copying information.
package accountmanagementapikeys package restkeys
import ( import (
"context" "context"
@ -20,8 +20,8 @@ import (
var mon = monkit.Package() var mon = monkit.Package()
var ( var (
// Error describes internal account management api keys error. // Error describes internal rest keys error.
Error = errs.Class("account management api keys service") Error = errs.Class("rest keys service")
// ErrDuplicateKey is error type that occurs when a generated account // ErrDuplicateKey is error type that occurs when a generated account
// management api key already exists. // management api key already exists.
@ -32,18 +32,18 @@ var (
ErrInvalidKey = errs.Class("invalid key") ErrInvalidKey = errs.Class("invalid key")
) )
// Config contains configuration parameters for account management api keys. // Config contains configuration parameters for rest keys.
type Config struct { type Config struct {
DefaultExpiration time.Duration `help:"expiration to use if user does not specify an account management api key expiration" default:"720h"` DefaultExpiration time.Duration `help:"expiration to use if user does not specify an rest key expiration" default:"720h"`
} }
// Service handles operations regarding account management api keys. // Service handles operations regarding rest keys.
type Service struct { type Service struct {
db oidc.OAuthTokens db oidc.OAuthTokens
config Config config Config
} }
// NewService creates a new account management api keys service. // NewService creates a new rest keys service.
func NewService(db oidc.OAuthTokens, config Config) *Service { func NewService(db oidc.OAuthTokens, config Config) *Service {
return &Service{ return &Service{
db: db, db: db,
@ -51,7 +51,7 @@ func NewService(db oidc.OAuthTokens, config Config) *Service {
} }
} }
// Create creates and inserts an account management api key into the db. // Create creates and inserts an rest key into the db.
func (s *Service) Create(ctx context.Context, userID uuid.UUID, expiration time.Duration) (apiKey string, expiresAt time.Time, err error) { func (s *Service) Create(ctx context.Context, userID uuid.UUID, expiration time.Duration) (apiKey string, expiresAt time.Time, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
@ -61,7 +61,7 @@ func (s *Service) Create(ctx context.Context, userID uuid.UUID, expiration time.
} }
expiresAt, err = s.InsertIntoDB(ctx, oidc.OAuthToken{ expiresAt, err = s.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: userID, UserID: userID,
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: hash, Token: hash,
}, time.Now(), expiration) }, time.Now(), expiration)
if err != nil { if err != nil {
@ -111,7 +111,7 @@ func (s *Service) InsertIntoDB(ctx context.Context, oAuthToken oidc.OAuthToken,
// The token column is the key to the OAuthTokens table, but the Create method does not return an error if a duplicate token insert is attempted. // The token column is the key to the OAuthTokens table, but the Create method does not return an error if a duplicate token insert is attempted.
// We need to make sure a unique api key is created, so check that the value doesn't already exist. // We need to make sure a unique api key is created, so check that the value doesn't already exist.
_, err = s.db.Get(ctx, oidc.KindAccountManagementTokenV0, oAuthToken.Token) _, err = s.db.Get(ctx, oidc.KindRESTTokenV0, oAuthToken.Token)
if err != nil { if err != nil {
if !errors.Is(err, sql.ErrNoRows) { if !errors.Is(err, sql.ErrNoRows) {
return time.Time{}, Error.Wrap(err) return time.Time{}, Error.Wrap(err)
@ -144,7 +144,7 @@ func (s *Service) GetUserAndExpirationFromKey(ctx context.Context, apiKey string
if err != nil { if err != nil {
return uuid.UUID{}, time.Now(), err return uuid.UUID{}, time.Now(), err
} }
keyInfo, err := s.db.Get(ctx, oidc.KindAccountManagementTokenV0, hash) keyInfo, err := s.db.Get(ctx, oidc.KindRESTTokenV0, hash)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
return uuid.UUID{}, time.Now(), Error.Wrap(ErrInvalidKey.New("invalid account management api key")) return uuid.UUID{}, time.Now(), Error.Wrap(ErrInvalidKey.New("invalid account management api key"))
@ -163,11 +163,11 @@ func (s *Service) Revoke(ctx context.Context, apiKey string) (err error) {
return Error.Wrap(err) return Error.Wrap(err)
} }
_, err = s.db.Get(ctx, oidc.KindAccountManagementTokenV0, hash) _, err = s.db.Get(ctx, oidc.KindRESTTokenV0, hash)
if err != nil { if err != nil {
return Error.Wrap(err) return Error.Wrap(err)
} }
err = s.db.RevokeAccountManagementTokenV0(ctx, hash) err = s.db.RevokeRESTTokenV0(ctx, hash)
if err != nil { if err != nil {
return Error.Wrap(err) return Error.Wrap(err)
} }

View File

@ -1,7 +1,7 @@
// Copyright (C) 2020 Storj Labs, Inc. // Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information. // See LICENSE for copying information.
package accountmanagementapikeys_test package restkeys_test
import ( import (
"database/sql" "database/sql"
@ -13,16 +13,16 @@ import (
"storj.io/common/testcontext" "storj.io/common/testcontext"
"storj.io/common/testrand" "storj.io/common/testrand"
"storj.io/storj/private/testplanet" "storj.io/storj/private/testplanet"
"storj.io/storj/satellite/console/accountmanagementapikeys" "storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/oidc" "storj.io/storj/satellite/oidc"
) )
func TestAccountManagementAPIKeys(t *testing.T) { func TestRESTKeys(t *testing.T) {
testplanet.Run(t, testplanet.Config{ testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1, SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
sat := planet.Satellites[0] sat := planet.Satellites[0]
service := sat.API.AccountManagementAPIKeys.Service service := sat.API.REST.Keys
id := testrand.UUID() id := testrand.UUID()
now := time.Now() now := time.Now()
@ -42,14 +42,14 @@ func TestAccountManagementAPIKeys(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
_, err = service.InsertIntoDB(ctx, oidc.OAuthToken{ _, err = service.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: id, UserID: id,
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: hash, Token: hash,
}, now, expires) }, now, expires)
require.True(t, accountmanagementapikeys.ErrDuplicateKey.Has(err)) require.True(t, restkeys.ErrDuplicateKey.Has(err))
// test revocation // test revocation
require.NoError(t, service.Revoke(ctx, apiKey)) require.NoError(t, service.Revoke(ctx, apiKey))
token, err := sat.DB.OIDC().OAuthTokens().Get(ctx, oidc.KindAccountManagementTokenV0, hash) token, err := sat.DB.OIDC().OAuthTokens().Get(ctx, oidc.KindRESTTokenV0, hash)
require.Equal(t, sql.ErrNoRows, err) require.Equal(t, sql.ErrNoRows, err)
require.True(t, token.ExpiresAt.IsZero()) require.True(t, token.ExpiresAt.IsZero())
@ -60,41 +60,41 @@ func TestAccountManagementAPIKeys(t *testing.T) {
// test GetUserFromKey non existent key // test GetUserFromKey non existent key
_, _, err = service.GetUserAndExpirationFromKey(ctx, nonexistent) _, _, err = service.GetUserAndExpirationFromKey(ctx, nonexistent)
require.True(t, accountmanagementapikeys.ErrInvalidKey.Has(err)) require.True(t, restkeys.ErrInvalidKey.Has(err))
}) })
} }
func TestAccountManagementAPIKeysExpiration(t *testing.T) { func TestRESTKeysExpiration(t *testing.T) {
testplanet.Run(t, testplanet.Config{ testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1, SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
sat := planet.Satellites[0] sat := planet.Satellites[0]
service := sat.API.AccountManagementAPIKeys.Service service := sat.API.REST.Keys
now := time.Now() now := time.Now()
// test no expiration uses default // test no expiration uses default
expiresAt, err := service.InsertIntoDB(ctx, oidc.OAuthToken{ expiresAt, err := service.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: testrand.UUID(), UserID: testrand.UUID(),
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: "testhash0", Token: "testhash0",
}, now, 0) }, now, 0)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, now.Add(sat.Config.AccountManagementAPIKeys.DefaultExpiration), expiresAt) require.Equal(t, now.Add(sat.Config.RESTKeys.DefaultExpiration), expiresAt)
// test negative expiration uses default // test negative expiration uses default
expiresAt, err = service.InsertIntoDB(ctx, oidc.OAuthToken{ expiresAt, err = service.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: testrand.UUID(), UserID: testrand.UUID(),
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: "testhash1", Token: "testhash1",
}, now, -10000) }, now, -10000)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, now.Add(sat.Config.AccountManagementAPIKeys.DefaultExpiration), expiresAt) require.Equal(t, now.Add(sat.Config.RESTKeys.DefaultExpiration), expiresAt)
// test regular expiration // test regular expiration
expiration := 14 * time.Hour expiration := 14 * time.Hour
expiresAt, err = service.InsertIntoDB(ctx, oidc.OAuthToken{ expiresAt, err = service.InsertIntoDB(ctx, oidc.OAuthToken{
UserID: testrand.UUID(), UserID: testrand.UUID(),
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: "testhash2", Token: "testhash2",
}, now, expiration) }, now, expiration)
require.NoError(t, err) require.NoError(t, err)

View File

@ -106,7 +106,7 @@ type Service struct {
log, auditLogger *zap.Logger log, auditLogger *zap.Logger
store DB store DB
accountManagementAPIKeys AccountManagementAPIKeys restKeys RESTKeys
projectAccounting accounting.ProjectAccounting projectAccounting accounting.ProjectAccounting
projectUsage *accounting.Service projectUsage *accounting.Service
buckets Buckets buckets Buckets
@ -154,7 +154,7 @@ type PaymentsService struct {
} }
// NewService returns new instance of Service. // NewService returns new instance of Service.
func NewService(log *zap.Logger, signer Signer, store DB, accountManagementAPIKeys AccountManagementAPIKeys, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, buckets Buckets, partners *rewards.PartnersService, accounts payments.Accounts, analytics *analytics.Service, config Config) (*Service, error) { func NewService(log *zap.Logger, signer Signer, store DB, restKeys RESTKeys, projectAccounting accounting.ProjectAccounting, projectUsage *accounting.Service, buckets Buckets, partners *rewards.PartnersService, accounts payments.Accounts, analytics *analytics.Service, config Config) (*Service, error) {
if signer == nil { if signer == nil {
return nil, errs.New("signer can't be nil") return nil, errs.New("signer can't be nil")
} }
@ -173,7 +173,7 @@ func NewService(log *zap.Logger, signer Signer, store DB, accountManagementAPIKe
auditLogger: log.Named("auditlog"), auditLogger: log.Named("auditlog"),
Signer: signer, Signer: signer,
store: store, store: store,
accountManagementAPIKeys: accountManagementAPIKeys, restKeys: restKeys,
projectAccounting: projectAccounting, projectAccounting: projectAccounting,
projectUsage: projectUsage, projectUsage: projectUsage,
buckets: buckets, buckets: buckets,
@ -1815,32 +1815,32 @@ func (s *Service) GetAPIKeys(ctx context.Context, projectID uuid.UUID, cursor AP
return return
} }
// CreateAccountManagementAPIKey creates an account management api key. // CreateRESTKey creates a satellite rest key.
func (s *Service) CreateAccountManagementAPIKey(ctx context.Context, expiration time.Duration) (apiKey string, expiresAt time.Time, err error) { func (s *Service) CreateRESTKey(ctx context.Context, expiration time.Duration) (apiKey string, expiresAt time.Time, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
auth, err := s.getAuthAndAuditLog(ctx, "create account management api key") auth, err := s.getAuthAndAuditLog(ctx, "create rest key")
if err != nil { if err != nil {
return "", time.Time{}, Error.Wrap(err) return "", time.Time{}, Error.Wrap(err)
} }
apiKey, expiresAt, err = s.accountManagementAPIKeys.Create(ctx, auth.User.ID, expiration) apiKey, expiresAt, err = s.restKeys.Create(ctx, auth.User.ID, expiration)
if err != nil { if err != nil {
return "", time.Time{}, Error.Wrap(err) return "", time.Time{}, Error.Wrap(err)
} }
return apiKey, expiresAt, nil return apiKey, expiresAt, nil
} }
// RevokeAccountManagementAPIKey revokes an account management api key. // RevokeRESTKey revokes a satellite REST key.
func (s *Service) RevokeAccountManagementAPIKey(ctx context.Context, apiKey string) (err error) { func (s *Service) RevokeRESTKey(ctx context.Context, apiKey string) (err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
_, err = s.getAuthAndAuditLog(ctx, "revoke account management api key") _, err = s.getAuthAndAuditLog(ctx, "revoke rest key")
if err != nil { if err != nil {
return Error.Wrap(err) return Error.Wrap(err)
} }
err = s.accountManagementAPIKeys.Revoke(ctx, apiKey) err = s.restKeys.Revoke(ctx, apiKey)
if err != nil { if err != nil {
return Error.Wrap(err) return Error.Wrap(err)
} }
@ -2219,7 +2219,7 @@ func (s *Service) keyAuth(ctx context.Context, r *http.Request) (context.Context
ctx = consoleauth.WithAPIKey(ctx, []byte(apikey)) ctx = consoleauth.WithAPIKey(ctx, []byte(apikey))
userID, exp, err := s.accountManagementAPIKeys.GetUserAndExpirationFromKey(ctx, apikey) userID, exp, err := s.restKeys.GetUserAndExpirationFromKey(ctx, apikey)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -692,7 +692,7 @@ func TestActivateAccountToken(t *testing.T) {
}) })
} }
func TestAccountManagementAPIKeys(t *testing.T) { func TestRESTKeys(t *testing.T) {
testplanet.Run(t, testplanet.Config{ testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1, SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) { }, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
@ -710,18 +710,18 @@ func TestAccountManagementAPIKeys(t *testing.T) {
now := time.Now() now := time.Now()
expires := 5 * time.Hour expires := 5 * time.Hour
apiKey, expiresAt, err := service.CreateAccountManagementAPIKey(authCtx, expires) apiKey, expiresAt, err := service.CreateRESTKey(authCtx, expires)
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, apiKey) require.NotEmpty(t, apiKey)
require.True(t, expiresAt.After(now)) require.True(t, expiresAt.After(now))
require.True(t, expiresAt.Before(now.Add(expires+time.Hour))) require.True(t, expiresAt.Before(now.Add(expires+time.Hour)))
// test revocation // test revocation
require.NoError(t, service.RevokeAccountManagementAPIKey(authCtx, apiKey)) require.NoError(t, service.RevokeRESTKey(authCtx, apiKey))
// test revoke non existent key // test revoke non existent key
nonexistent := testrand.UUID() nonexistent := testrand.UUID()
err = service.RevokeAccountManagementAPIKey(authCtx, nonexistent.String()) err = service.RevokeRESTKey(authCtx, nonexistent.String())
require.Error(t, err) require.Error(t, err)
}) })
} }

View File

@ -92,8 +92,8 @@ type OAuthTokens interface {
// Create creates a new OAuthToken. If the token already exists, no value is modified and nil is returned. // Create creates a new OAuthToken. If the token already exists, no value is modified and nil is returned.
Create(ctx context.Context, token OAuthToken) error Create(ctx context.Context, token OAuthToken) error
// RevokeAccountManagementTokenV0 revokes a v0 account management token by setting its expires_at time to zero. // RevokeRESTTokenV0 revokes a v0 rest token by setting its expires_at time to zero.
RevokeAccountManagementTokenV0(ctx context.Context, token string) error RevokeRESTTokenV0(ctx context.Context, token string) error
} }
// OAuthTokenKind defines an enumeration of different types of supported tokens. // OAuthTokenKind defines an enumeration of different types of supported tokens.
@ -106,8 +106,8 @@ const (
KindAccessToken = 1 KindAccessToken = 1
// KindRefreshToken represents a refresh token within the database. // KindRefreshToken represents a refresh token within the database.
KindRefreshToken = 2 KindRefreshToken = 2
// KindAccountManagementTokenV0 represents an account management token within the database. // KindRESTTokenV0 represents a REST token within the database.
KindAccountManagementTokenV0 = 3 KindRESTTokenV0 = 3
) )
// OAuthCode represents a code stored within our database. // OAuthCode represents a code stored within our database.

View File

@ -181,10 +181,10 @@ func (o *tokensDBX) Create(ctx context.Context, token OAuthToken) error {
return err return err
} }
// RevokeAccountManagementTokenV0 revokes a v0 account management token by setting its expires_at time to zero. // RevokeRESTTokenV0 revokes a v0 REST token by setting its expires_at time to zero.
func (o *tokensDBX) RevokeAccountManagementTokenV0(ctx context.Context, token string) error { func (o *tokensDBX) RevokeRESTTokenV0(ctx context.Context, token string) error {
return o.db.UpdateNoReturn_OauthToken_By_Token_And_Kind(ctx, dbx.OauthToken_Token([]byte(token)), return o.db.UpdateNoReturn_OauthToken_By_Token_And_Kind(ctx, dbx.OauthToken_Token([]byte(token)),
dbx.OauthToken_Kind(int(KindAccountManagementTokenV0)), dbx.OauthToken_Kind(int(KindRESTTokenV0)),
dbx.OauthToken_Update_Fields{ dbx.OauthToken_Update_Fields{
ExpiresAt: dbx.OauthToken_ExpiresAt(time.Time{}), ExpiresAt: dbx.OauthToken_ExpiresAt(time.Time{}),
}) })

View File

@ -112,7 +112,7 @@ func TestOAuthTokens(t *testing.T) {
{ {
ClientID: clientID, ClientID: clientID,
UserID: userID, UserID: userID,
Kind: oidc.KindAccountManagementTokenV0, Kind: oidc.KindRESTTokenV0,
Token: "testToken", Token: "testToken",
CreatedAt: start, CreatedAt: start,
ExpiresAt: start.Add(time.Hour), ExpiresAt: start.Add(time.Hour),
@ -135,14 +135,14 @@ func TestOAuthTokens(t *testing.T) {
}{ }{
{oidc.KindAccessToken, "expired", sql.ErrNoRows}, {oidc.KindAccessToken, "expired", sql.ErrNoRows},
{oidc.KindRefreshToken, "valid", nil}, {oidc.KindRefreshToken, "valid", nil},
{oidc.KindAccountManagementTokenV0, "testToken", nil}, {oidc.KindRESTTokenV0, "testToken", nil},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
_, err := tokens.Get(ctx, testCase.kind, testCase.token) _, err := tokens.Get(ctx, testCase.kind, testCase.token)
require.Equal(t, testCase.err, err) require.Equal(t, testCase.err, err)
if testCase.kind == oidc.KindAccountManagementTokenV0 { if testCase.kind == oidc.KindRESTTokenV0 {
err = tokens.RevokeAccountManagementTokenV0(ctx, testCase.token) err = tokens.RevokeRESTTokenV0(ctx, testCase.token)
require.NoError(t, err) require.NoError(t, err)
token, err := tokens.Get(ctx, testCase.kind, testCase.token) token, err := tokens.Get(ctx, testCase.kind, testCase.token)
require.Equal(t, sql.ErrNoRows, err) require.Equal(t, sql.ErrNoRows, err)

View File

@ -18,8 +18,8 @@ import (
"storj.io/storj/satellite/accounting/live" "storj.io/storj/satellite/accounting/live"
"storj.io/storj/satellite/analytics" "storj.io/storj/satellite/analytics"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys"
"storj.io/storj/satellite/console/consoleauth" "storj.io/storj/satellite/console/consoleauth"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
"storj.io/storj/satellite/payments/paymentsconfig" "storj.io/storj/satellite/payments/paymentsconfig"
"storj.io/storj/satellite/payments/stripecoinpayments" "storj.io/storj/satellite/payments/stripecoinpayments"
@ -78,7 +78,7 @@ func TestSignupCouponCodes(t *testing.T) {
log.Named("console"), log.Named("console"),
&consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")}, &consoleauth.Hmac{Secret: []byte("my-suppa-secret-key")},
db.Console(), db.Console(),
accountmanagementapikeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.AccountManagementAPIKeys), restkeys.NewService(db.OIDC().OAuthTokens(), planet.Satellites[0].Config.RESTKeys),
db.ProjectAccounting(), db.ProjectAccounting(),
projectUsage, projectUsage,
sat.API.Buckets.Service, sat.API.Buckets.Service,

View File

@ -26,8 +26,8 @@ import (
"storj.io/storj/satellite/buckets" "storj.io/storj/satellite/buckets"
"storj.io/storj/satellite/compensation" "storj.io/storj/satellite/compensation"
"storj.io/storj/satellite/console" "storj.io/storj/satellite/console"
"storj.io/storj/satellite/console/accountmanagementapikeys"
"storj.io/storj/satellite/console/consoleweb" "storj.io/storj/satellite/console/consoleweb"
"storj.io/storj/satellite/console/restkeys"
"storj.io/storj/satellite/contact" "storj.io/storj/satellite/contact"
"storj.io/storj/satellite/gc" "storj.io/storj/satellite/gc"
"storj.io/storj/satellite/gracefulexit" "storj.io/storj/satellite/gracefulexit"
@ -145,7 +145,7 @@ type Config struct {
Payments paymentsconfig.Config Payments paymentsconfig.Config
AccountManagementAPIKeys accountmanagementapikeys.Config RESTKeys restkeys.Config
Console consoleweb.Config Console consoleweb.Config
Version version_checker.Config Version version_checker.Config

View File

@ -1,6 +1,3 @@
# expiration to use if user does not specify an account management api key expiration
# account-management-api-keys.default-expiration: 720h0m0s
# admin peer http listening address # admin peer http listening address
# admin.address: "" # admin.address: ""
@ -781,6 +778,9 @@ identity.key-path: /root/.local/share/storj/identity/satellite/identity.key
# the time period that must pass before suspended nodes will be disqualified # the time period that must pass before suspended nodes will be disqualified
# reputation.suspension-grace-period: 168h0m0s # reputation.suspension-grace-period: 168h0m0s
# expiration to use if user does not specify an rest key expiration
# rest-keys.default-expiration: 720h0m0s
# age at which a rollup is archived # age at which a rollup is archived
# rollup-archive.archive-age: 2160h0m0s # rollup-archive.archive-age: 2160h0m0s