127 lines
3.3 KiB
Go
127 lines
3.3 KiB
Go
package authorization
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors"
|
|
)
|
|
|
|
var (
|
|
ErrUnsupportedScheme = &errors2.Error{
|
|
Code: errors2.EInternal,
|
|
Msg: "unsupported authorization scheme",
|
|
}
|
|
)
|
|
|
|
type UserFinder interface {
|
|
// Returns a single user by ID.
|
|
FindUserByID(ctx context.Context, id platform.ID) (*influxdb.User, error)
|
|
}
|
|
|
|
type PasswordComparer interface {
|
|
ComparePassword(ctx context.Context, authID platform.ID, password string) error
|
|
}
|
|
|
|
type AuthTokenFinder interface {
|
|
FindAuthorizationByToken(ctx context.Context, token string) (*influxdb.Authorization, error)
|
|
}
|
|
|
|
// A type that is used to verify credentials.
|
|
type Authorizer struct {
|
|
AuthV1 AuthTokenFinder // A service to find V1 tokens
|
|
AuthV2 AuthTokenFinder // A service to find V2 tokens
|
|
Comparer PasswordComparer // A service to compare passwords for V1 tokens
|
|
User UserFinder // A service to find users
|
|
}
|
|
|
|
// Authorize returns an influxdb.Authorization if c can be verified; otherwise, an error.
|
|
// influxdb.ErrCredentialsUnauthorized will be returned if the credentials are invalid.
|
|
func (v *Authorizer) Authorize(ctx context.Context, c influxdb.CredentialsV1) (auth *influxdb.Authorization, err error) {
|
|
defer func() {
|
|
auth, err = v.checkAuthError(ctx, auth, err)
|
|
}()
|
|
|
|
switch c.Scheme {
|
|
case influxdb.SchemeV1Basic, influxdb.SchemeV1URL:
|
|
auth, err = v.tryV1Authorization(ctx, c)
|
|
if errors.Is(err, ErrAuthNotFound) {
|
|
return v.tryV2Authorization(ctx, c)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, v.normalizeError(err)
|
|
}
|
|
return
|
|
|
|
case influxdb.SchemeV1Token:
|
|
return v.tryV2Authorization(ctx, c)
|
|
|
|
default:
|
|
// this represents a programmer error
|
|
return nil, ErrUnsupportedScheme
|
|
}
|
|
}
|
|
|
|
func (v *Authorizer) checkAuthError(ctx context.Context, auth *influxdb.Authorization, err error) (*influxdb.Authorization, error) {
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if auth == nil {
|
|
return nil, influxdb.ErrCredentialsUnauthorized
|
|
}
|
|
|
|
if auth.Status != influxdb.Active {
|
|
return nil, influxdb.ErrCredentialsUnauthorized
|
|
}
|
|
|
|
// check the user is still active
|
|
if user, userErr := v.User.FindUserByID(ctx, auth.UserID); userErr != nil {
|
|
return nil, v.normalizeError(userErr)
|
|
} else if user == nil || user.Status != influxdb.Active {
|
|
return nil, influxdb.ErrCredentialsUnauthorized
|
|
}
|
|
|
|
return auth, nil
|
|
}
|
|
|
|
func (v *Authorizer) tryV1Authorization(ctx context.Context, c influxdb.CredentialsV1) (auth *influxdb.Authorization, err error) {
|
|
auth, err = v.AuthV1.FindAuthorizationByToken(ctx, c.Username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := v.Comparer.ComparePassword(ctx, auth.ID, c.Token); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return auth, nil
|
|
}
|
|
|
|
func (v *Authorizer) tryV2Authorization(ctx context.Context, c influxdb.CredentialsV1) (auth *influxdb.Authorization, err error) {
|
|
auth, err = v.AuthV2.FindAuthorizationByToken(ctx, c.Token)
|
|
if err != nil {
|
|
return nil, v.normalizeError(err)
|
|
}
|
|
return auth, nil
|
|
}
|
|
|
|
func (v *Authorizer) normalizeError(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var erri *errors2.Error
|
|
if errors.As(err, &erri) {
|
|
switch erri.Code {
|
|
case errors2.ENotFound, errors2.EForbidden:
|
|
return influxdb.ErrCredentialsUnauthorized
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|