207 lines
6.0 KiB
Go
207 lines
6.0 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/influxdata/influxdb/v2"
|
|
"github.com/influxdata/influxdb/v2/kit/platform"
|
|
"github.com/influxdata/influxdb/v2/kit/platform/errors"
|
|
"github.com/influxdata/influxdb/v2/rand"
|
|
"github.com/influxdata/influxdb/v2/snowflake"
|
|
)
|
|
|
|
// Service implements the influxdb.SessionService interface and
|
|
// handles communication between session and the necessary user and urm services
|
|
type Service struct {
|
|
store *Storage
|
|
userService influxdb.UserService
|
|
urmService influxdb.UserResourceMappingService
|
|
authService influxdb.AuthorizationService
|
|
sessionLength time.Duration
|
|
|
|
idGen platform.IDGenerator
|
|
tokenGen influxdb.TokenGenerator
|
|
|
|
disableAuthorizationsForMaxPermissions func(context.Context) bool
|
|
}
|
|
|
|
// ServiceOption is a functional option for configuring a *Service
|
|
type ServiceOption func(*Service)
|
|
|
|
// WithSessionLength configures the length of the session with the provided
|
|
// duration when the resulting option is called on a *Service.
|
|
func WithSessionLength(length time.Duration) ServiceOption {
|
|
return func(s *Service) {
|
|
s.sessionLength = length
|
|
}
|
|
}
|
|
|
|
// WithIDGenerator overrides the default ID generator with the one
|
|
// provided to this function when called on a *Service
|
|
func WithIDGenerator(gen platform.IDGenerator) ServiceOption {
|
|
return func(s *Service) {
|
|
s.idGen = gen
|
|
}
|
|
}
|
|
|
|
// WithTokenGenerator overrides the default token generator with the one
|
|
// provided to this function when called on a *Service
|
|
func WithTokenGenerator(gen influxdb.TokenGenerator) ServiceOption {
|
|
return func(s *Service) {
|
|
s.tokenGen = gen
|
|
}
|
|
}
|
|
|
|
// NewService creates a new session service
|
|
func NewService(store *Storage, userService influxdb.UserService, urmService influxdb.UserResourceMappingService, authSvc influxdb.AuthorizationService, opts ...ServiceOption) *Service {
|
|
service := &Service{
|
|
store: store,
|
|
userService: userService,
|
|
urmService: urmService,
|
|
authService: authSvc,
|
|
sessionLength: time.Hour,
|
|
idGen: snowflake.NewIDGenerator(),
|
|
tokenGen: rand.NewTokenGenerator(64),
|
|
disableAuthorizationsForMaxPermissions: func(context.Context) bool {
|
|
return false
|
|
},
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(service)
|
|
}
|
|
|
|
return service
|
|
}
|
|
|
|
// WithMaxPermissionFunc sets the useAuthorizationsForMaxPermissions function
|
|
// which can trigger whether or not max permissions uses the users authorizations
|
|
// to derive maximum permissions.
|
|
func (s *Service) WithMaxPermissionFunc(fn func(context.Context) bool) {
|
|
s.disableAuthorizationsForMaxPermissions = fn
|
|
}
|
|
|
|
// FindSession finds a session based on the session key
|
|
func (s *Service) FindSession(ctx context.Context, key string) (*influxdb.Session, error) {
|
|
session, err := s.store.FindSessionByKey(ctx, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// TODO: We want to be able to store permissions in the session
|
|
// but the contract provided by urm's doesn't give us enough information to quickly repopulate our
|
|
// session permissions on updates so we are required to pull the permissions every time we find the session.
|
|
permissions, err := s.getPermissionSet(ctx, session.UserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
session.Permissions = permissions
|
|
return session, nil
|
|
}
|
|
|
|
// ExpireSession removes a session from the system
|
|
func (s *Service) ExpireSession(ctx context.Context, key string) error {
|
|
session, err := s.store.FindSessionByKey(ctx, key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.store.DeleteSession(ctx, session.ID)
|
|
}
|
|
|
|
// CreateSession
|
|
func (s *Service) CreateSession(ctx context.Context, user string) (*influxdb.Session, error) {
|
|
u, err := s.userService.FindUser(ctx, influxdb.UserFilter{
|
|
Name: &user,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
token, err := s.tokenGen.Token()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// for now we are not storing the permissions because we need to pull them every time we find
|
|
// so we might as well keep the session stored small
|
|
now := time.Now()
|
|
session := &influxdb.Session{
|
|
ID: s.idGen.ID(),
|
|
Key: token,
|
|
CreatedAt: now,
|
|
ExpiresAt: now.Add(s.sessionLength),
|
|
UserID: u.ID,
|
|
}
|
|
|
|
return session, s.store.CreateSession(ctx, session)
|
|
}
|
|
|
|
// RenewSession update the sessions expiration time
|
|
func (s *Service) RenewSession(ctx context.Context, session *influxdb.Session, newExpiration time.Time) error {
|
|
if session == nil {
|
|
return &errors.Error{
|
|
Msg: "session is nil",
|
|
}
|
|
}
|
|
return s.store.RefreshSession(ctx, session.ID, newExpiration)
|
|
}
|
|
|
|
func (s *Service) getPermissionSet(ctx context.Context, uid platform.ID) ([]influxdb.Permission, error) {
|
|
mappings, _, err := s.urmService.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{UserID: uid}, influxdb.FindOptions{Limit: 100})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
permissions, err := permissionFromMapping(mappings)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(mappings) == 100 {
|
|
// if we got 100 mappings we probably need to pull more pages
|
|
// account for paginated results
|
|
for i := len(mappings); len(mappings) > 0; i += len(mappings) {
|
|
mappings, _, err = s.urmService.FindUserResourceMappings(ctx, influxdb.UserResourceMappingFilter{UserID: uid}, influxdb.FindOptions{Offset: i, Limit: 100})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pms, err := permissionFromMapping(mappings)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
permissions = append(permissions, pms...)
|
|
}
|
|
}
|
|
|
|
if !s.disableAuthorizationsForMaxPermissions(ctx) {
|
|
as, _, err := s.authService.FindAuthorizations(ctx, influxdb.AuthorizationFilter{UserID: &uid})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, a := range as {
|
|
permissions = append(permissions, a.Permissions...)
|
|
}
|
|
}
|
|
|
|
permissions = append(permissions, influxdb.MePermissions(uid)...)
|
|
return permissions, nil
|
|
}
|
|
|
|
func permissionFromMapping(mappings []*influxdb.UserResourceMapping) ([]influxdb.Permission, error) {
|
|
ps := make([]influxdb.Permission, 0, len(mappings))
|
|
for _, m := range mappings {
|
|
p, err := m.ToPermissions()
|
|
if err != nil {
|
|
return nil, &errors.Error{
|
|
Err: err,
|
|
}
|
|
}
|
|
|
|
ps = append(ps, p...)
|
|
}
|
|
|
|
return ps, nil
|
|
}
|