storj/satellite/oidc/database.go
Cameron 84b522bc06 satellite/console: create account management api keys service
We are in the process of creating an api to allow users to manage their
accounts programmatically. We would like to use api keys for
authorization. We were originally going to create an entirely new table
for these api keys, but seeing as we already have 2 other tables for
keys/tokens, api_keys and oauth_tokens, we thought it might be better to
use one of these. We're using oauth_tokens.

We create a new oidc.OAuthTokenKind for account management api keys:
KindAccountManagementTokenV0. We made the key versioned because we
likely want to improve the implementation in the future, but we want to
get something functional out the door ASAP because the account management
api feature is highly desired.

Add a new method to oidc.OAuthTokens interface for revoking v0 account
management api keys, RevokeAccountManagementTokenV0. Add update method
to dbx implementation to allow updating the expiration. We will revoke
these keys by setting the expiration to 0 so they are expired.

Change-Id: Ideb8ae04b23aa55d5825b064b5e43e32eadc1fba
2022-03-23 17:02:20 +00:00

172 lines
4.9 KiB
Go

// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
package oidc
import (
"context"
"time"
"storj.io/common/uuid"
"storj.io/storj/satellite/satellitedb/dbx"
)
// DB defines a collection of resources that fall under the scope of OIDC and OAuth operations.
//
// architecture: Database
type DB interface {
// OAuthClients returns an API for the oauthclients repository.
OAuthClients() OAuthClients
// OAuthCodes returns an API for the oauthcodes repository.
OAuthCodes() OAuthCodes
// OAuthTokens returns an API for the oauthtokens repository.
OAuthTokens() OAuthTokens
}
// OAuthClients defines an interface for creating, updating, and obtaining information about oauth clients known to our
// system.
type OAuthClients interface {
// Get returns the OAuthClient associated with the provided id.
Get(ctx context.Context, id uuid.UUID) (OAuthClient, error)
// Create creates a new OAuthClient.
Create(ctx context.Context, client OAuthClient) error
// Update modifies information for the provided OAuthClient.
Update(ctx context.Context, client OAuthClient) error
// Delete deletes the identified client from the database.
Delete(ctx context.Context, id uuid.UUID) error
}
// OAuthClient defines a concrete representation of an oauth client.
type OAuthClient struct {
ID uuid.UUID `json:"id"`
Secret []byte `json:"secret"`
UserID uuid.UUID `json:"userID"`
RedirectURL string `json:"redirectURL"`
AppName string `json:"appName"`
AppLogoURL string `json:"appLogoURL"`
}
// GetID returns the clients id.
func (o OAuthClient) GetID() string {
return o.ID.String()
}
// GetSecret returns the clients secret.
func (o OAuthClient) GetSecret() string {
return string(o.Secret)
}
// GetDomain returns the allowed redirect url associated with the client.
func (o OAuthClient) GetDomain() string {
return o.RedirectURL
}
// GetUserID returns the owners' user id.
func (o OAuthClient) GetUserID() string {
return o.UserID.String()
}
// OAuthCodes defines a set of operations allowed to be performed against oauth codes.
type OAuthCodes interface {
// Get retrieves the OAuthCode for the specified code. Implementations should only return unexpired, unclaimed
// codes. Once a code has been claimed, it should be marked as such to prevent future calls from exchanging the
// value for an access tokens.
Get(ctx context.Context, code string) (OAuthCode, error)
// Create creates a new OAuthCode.
Create(ctx context.Context, code OAuthCode) error
// Claim marks that the provided code has been claimed and should not be issued to another caller.
Claim(ctx context.Context, code string) error
}
// OAuthTokens defines a set of operations that ca be performed against oauth tokens.
type OAuthTokens interface {
// Get retrieves the OAuthToken for the specified kind and token value. This can be used to look up either refresh
// or access tokens that have not expired.
Get(ctx context.Context, kind OAuthTokenKind, token string) (OAuthToken, error)
// 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
// RevokeAccountManagementTokenV0 revokes a v0 account management token by setting its expires_at time to zero.
RevokeAccountManagementTokenV0(ctx context.Context, token string) error
}
// OAuthTokenKind defines an enumeration of different types of supported tokens.
type OAuthTokenKind int8
const (
// KindUnknown is used to represent an entry for which we do not recognize the value.
KindUnknown = 0
// KindAccessToken represents an access token within the database.
KindAccessToken = 1
// KindRefreshToken represents a refresh token within the database.
KindRefreshToken = 2
// KindAccountManagementTokenV0 represents an account management token within the database.
KindAccountManagementTokenV0 = 3
)
// OAuthCode represents a code stored within our database.
type OAuthCode struct {
ClientID uuid.UUID
UserID uuid.UUID
Scope string
RedirectURL string
Challenge string
ChallengeMethod string
Code string
CreatedAt time.Time
ExpiresAt time.Time
ClaimedAt *time.Time
}
// OAuthToken represents a token stored within our database (either access / refresh).
type OAuthToken struct {
ClientID uuid.UUID
UserID uuid.UUID
Scope string
Kind OAuthTokenKind
Token string
CreatedAt time.Time
ExpiresAt time.Time
}
// NewDB constructs a database using the provided dbx db.
func NewDB(dbxdb *dbx.DB) DB {
return &db{
clients: &clientsDBX{
db: dbxdb,
},
codes: &codesDBX{
db: dbxdb,
},
tokens: &tokensDBX{
db: dbxdb,
},
}
}
type db struct {
clients OAuthClients
codes OAuthCodes
tokens OAuthTokens
}
func (d *db) OAuthClients() OAuthClients {
return d.clients
}
func (d *db) OAuthCodes() OAuthCodes {
return d.codes
}
func (d *db) OAuthTokens() OAuthTokens {
return d.tokens
}
var _ DB = &db{}