-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip: Implementation of v1 authorization
- Loading branch information
1 parent
f46a3bd
commit 3372b8a
Showing
6 changed files
with
643 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.