Skip to content

Commit

Permalink
wip: Implementation of v1 authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartcarnie committed Oct 30, 2020
1 parent f46a3bd commit 3372b8a
Show file tree
Hide file tree
Showing 6 changed files with 643 additions and 0 deletions.
31 changes: 31 additions & 0 deletions credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package influxdb

var (
// ErrCredentialsUnauthorized is the error returned when CredentialsV1 cannot be
// authorized.
ErrCredentialsUnauthorized = &Error{
Code: EUnauthorized,
Msg: "Unauthorized",
}
)

// SchemeV1 is an enumeration of supported authorization types
type SchemeV1 string

const (
// SchemeV1Basic indicates the credentials came from an Authorization header using the BASIC scheme
SchemeV1Basic SchemeV1 = "basic"

// SchemeToken indicates the credentials came from an Authorization header using the Token scheme
SchemeV1Token SchemeV1 = "token"

// SchemeURL indicates the credentials came from the u and p query parameters
SchemeV1URL SchemeV1 = "url"
)

// CredentialsV1 encapsulates the required credentials to authorize a v1 HTTP request.
type CredentialsV1 struct {
Scheme SchemeV1
Username string
Token string
}
124 changes: 124 additions & 0 deletions v1/authorization/authorizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package authorization

import (
"context"
"errors"

"github.com/influxdata/influxdb/v2"
)

var (
ErrUnsupportedScheme = &influxdb.Error{
Code: influxdb.EInternal,
Msg: "unsupported authorization scheme",
}
)

type UserFinder interface {
// Returns a single user by ID.
FindUserByID(ctx context.Context, id influxdb.ID) (*influxdb.User, error)
}

type PasswordComparer interface {
ComparePassword(ctx context.Context, authID influxdb.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) {
// the defer function provides the following guarantees:
// * the authorization token status is active and
// * the user status is active
defer func() {
if err != nil {
return
}

if auth == nil {
return
}

if auth.Status != influxdb.Active {
auth, err = nil, influxdb.ErrCredentialsUnauthorized
return
}

// check the user is still active
if user, userErr := v.User.FindUserByID(ctx, auth.UserID); err != nil {
auth, err = nil, v.normalizeError(userErr)
return
} else if user == nil || user.Status != influxdb.Active {
auth, err = nil, influxdb.ErrCredentialsUnauthorized
return
}
}()

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) 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 *influxdb.Error
if errors.As(err, &erri) {
switch erri.Code {
case influxdb.ENotFound, influxdb.EForbidden:
return influxdb.ErrCredentialsUnauthorized
}
}

return err
}
Loading

0 comments on commit 3372b8a

Please sign in to comment.