Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(authorization): Create a v1 authorization service #19815

Merged
merged 1 commit into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions cmd/influxd/launcher/launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import (
"github.com/influxdata/influxdb/v2/tenant"
_ "github.com/influxdata/influxdb/v2/tsdb/engine/tsm1" // needed for tsm1
_ "github.com/influxdata/influxdb/v2/tsdb/index/tsi1" // needed for tsi1
authv1 "github.com/influxdata/influxdb/v2/v1/authorization"
iqlcoordinator "github.com/influxdata/influxdb/v2/v1/coordinator"
"github.com/influxdata/influxdb/v2/v1/services/meta"
storage2 "github.com/influxdata/influxdb/v2/v1/services/storage"
Expand Down Expand Up @@ -1249,6 +1250,27 @@ func (m *Launcher) run(ctx context.Context) (err error) {
authHTTPServer = authorization.NewHTTPAuthHandler(m.log, authService, ts)
}

var v1AuthHTTPServer *authv1.AuthHandler
{
var v1AuthSvc platform.AuthorizationService
{
authStore, err := authv1.NewStore(m.kvStore)
if err != nil {
m.log.Error("Failed creating new authorization store", zap.Error(err))
return err
}
v1AuthSvc = authv1.NewService(authStore, ts)
}

authLogger := m.log.With(zap.String("handler", "v1_authorization"))

var authService platform.AuthorizationService
authService = authorization.NewAuthedAuthorizationService(v1AuthSvc, ts)
authService = authorization.NewAuthLogger(authLogger, authService)

v1AuthHTTPServer = authv1.NewHTTPAuthHandler(m.log, authService, ts)
}

var sessionHTTPServer *session.SessionHandler
{
sessionHTTPServer = session.NewSessionHandler(m.log.With(zap.String("handler", "session")), sessionSvc, ts.UserService, ts.PasswordsService)
Expand All @@ -1271,6 +1293,7 @@ func (m *Launcher) run(ctx context.Context) (err error) {
http.WithResourceHandler(userHTTPServer.UserResourceHandler()),
http.WithResourceHandler(orgHTTPServer),
http.WithResourceHandler(bucketHTTPServer),
http.WithResourceHandler(v1AuthHTTPServer),
)

httpLogger := m.log.With(zap.String("service", "http"))
Expand Down
3 changes: 2 additions & 1 deletion http/platform_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ func (h *PlatformHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// of the platform API.
if !strings.HasPrefix(r.URL.Path, "/v1") &&
!strings.HasPrefix(r.URL.Path, "/api/v2") &&
!strings.HasPrefix(r.URL.Path, "/chronograf/") {
!strings.HasPrefix(r.URL.Path, "/chronograf/") &&
!strings.HasPrefix(r.URL.Path, "/private/") {
h.AssetHandler.ServeHTTP(w, r)
return
}
Expand Down
9 changes: 9 additions & 0 deletions kv/migration/all/0008_LegacyAuthBuckets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package all

import (
"github.com/influxdata/influxdb/v2/kv/migration"
)

var Migration0008_LegacyAuthBuckets = migration.CreateBuckets(
"Create Legacy authorization buckets",
[]byte("legacy/authorizationsv1"), []byte("legacy/authorizationindexv1"))
2 changes: 2 additions & 0 deletions kv/migration/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ var Migrations = [...]migration.Spec{
Migration0006_DeleteBucketSessionsv1,
// CreateMetaDataBucket
Migration0007_CreateMetaDataBucket,
// LegacyAuthBuckets
Migration0008_LegacyAuthBuckets,
// {{ do_not_edit . }}
}
66 changes: 66 additions & 0 deletions v1/authorization/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package authorization

import (
"fmt"

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

var (
// ErrInvalidAuthID is used when the Authorization's ID cannot be encoded
ErrInvalidAuthID = &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "authorization ID is invalid",
}

// ErrAuthNotFound is used when the specified auth cannot be found
ErrAuthNotFound = &influxdb.Error{
Code: influxdb.ENotFound,
Msg: "authorization not found",
}

// NotUniqueIDError occurs when attempting to create an Authorization with an ID that already belongs to another one
NotUniqueIDError = &influxdb.Error{
Code: influxdb.EConflict,
Msg: "ID already exists",
}

// ErrFailureGeneratingID occurs ony when the random number generator
// cannot generate an ID in MaxIDGenerationN times.
ErrFailureGeneratingID = &influxdb.Error{
Code: influxdb.EInternal,
Msg: "unable to generate valid id",
}

// ErrTokenAlreadyExistsError is used when attempting to create an authorization
// with a token that already exists
ErrTokenAlreadyExistsError = &influxdb.Error{
Code: influxdb.EConflict,
Msg: "token already exists",
}
)

// ErrInvalidAuthIDError is used when a service was provided an invalid ID.
func ErrInvalidAuthIDError(err error) *influxdb.Error {
return &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "auth id provided is invalid",
Err: err,
}
}

// ErrInternalServiceError is used when the error comes from an internal system.
func ErrInternalServiceError(err error) *influxdb.Error {
return &influxdb.Error{
Code: influxdb.EInternal,
Err: err,
}
}

// UnexpectedAuthIndexError is used when the error comes from an internal system.
func UnexpectedAuthIndexError(err error) *influxdb.Error {
return &influxdb.Error{
Code: influxdb.EInternal,
Msg: fmt.Sprintf("unexpected error retrieving auth index; Err: %v", err),
}
}
106 changes: 106 additions & 0 deletions v1/authorization/http_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package authorization

import (
"context"
"errors"

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

var _ influxdb.AuthorizationService = (*Client)(nil)

// Client connects to Influx via HTTP using tokens to manage authorizations
type Client struct {
Client *httpc.Client
}

// CreateAuthorization creates a new authorization and sets b.ID with the new identifier.
func (s *Client) CreateAuthorization(ctx context.Context, a *influxdb.Authorization) error {
newAuth, err := newPostAuthorizationRequest(a)
if err != nil {
return err
}

return s.Client.
PostJSON(newAuth, prefixAuthorization).
DecodeJSON(a).
Do(ctx)
}

// FindAuthorizations returns a list of authorizations that match filter and the total count of matching authorizations.
// Additional options provide pagination & sorting.
func (s *Client) FindAuthorizations(ctx context.Context, filter influxdb.AuthorizationFilter, opt ...influxdb.FindOptions) ([]*influxdb.Authorization, int, error) {
params := influxdb.FindOptionParams(opt...)
if filter.ID != nil {
params = append(params, [2]string{"id", filter.ID.String()})
}
if filter.UserID != nil {
params = append(params, [2]string{"userID", filter.UserID.String()})
}
if filter.User != nil {
params = append(params, [2]string{"user", *filter.User})
}
if filter.OrgID != nil {
params = append(params, [2]string{"orgID", filter.OrgID.String()})
}
if filter.Org != nil {
params = append(params, [2]string{"org", *filter.Org})
}

var as authsResponse
err := s.Client.
Get(prefixAuthorization).
QueryParams(params...).
DecodeJSON(&as).
Do(ctx)
if err != nil {
return nil, 0, err
}

auths := make([]*influxdb.Authorization, 0, len(as.Auths))
for _, a := range as.Auths {
auths = append(auths, a.toInfluxdb())
}

return auths, len(auths), nil
}

// FindAuthorizationByToken is not supported by the HTTP authorization service.
func (s *Client) FindAuthorizationByToken(ctx context.Context, token string) (*influxdb.Authorization, error) {
return nil, errors.New("not supported in HTTP authorization service")
}

// FindAuthorizationByID finds a single Authorization by its ID against a remote influx server.
func (s *Client) FindAuthorizationByID(ctx context.Context, id influxdb.ID) (*influxdb.Authorization, error) {
var b influxdb.Authorization
err := s.Client.
Get(prefixAuthorization, id.String()).
DecodeJSON(&b).
Do(ctx)
if err != nil {
return nil, err
}
return &b, nil
}

// UpdateAuthorization updates the status and description if available.
func (s *Client) UpdateAuthorization(ctx context.Context, id influxdb.ID, upd *influxdb.AuthorizationUpdate) (*influxdb.Authorization, error) {
var res authResponse
err := s.Client.
PatchJSON(upd, prefixAuthorization, id.String()).
DecodeJSON(&res).
Do(ctx)
if err != nil {
return nil, err
}

return res.toInfluxdb(), nil
}

// DeleteAuthorization removes a authorization by id.
func (s *Client) DeleteAuthorization(ctx context.Context, id influxdb.ID) error {
return s.Client.
Delete(prefixAuthorization, id.String()).
Do(ctx)
}
Loading