Skip to content
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ SILENT ?= @
# the pattern is passed to: grep -Ev
# usage: "path/to/ignored|another/path"
# TODO: [ROX-19070] Update postgres store test generation to work for foreign keys
UNIT_TEST_IGNORE := "stackrox/rox/sensor/tests|stackrox/rox/operator/tests|stackrox/rox/central/reports/config/store/postgres"
UNIT_TEST_IGNORE := "stackrox/rox/sensor/tests|stackrox/rox/operator/tests|stackrox/rox/central/reports/config/store/postgres|stackrox/rox/central/auth/store/postgres"

ifeq ($(TAG),)
TAG=$(shell git describe --tags --abbrev=10 --dirty --long --exclude '*-nightly-*')
Expand Down
22 changes: 22 additions & 0 deletions central/auth/datastore/datastore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package datastore

import (
"context"

"github.com/stackrox/rox/central/auth/store"
"github.com/stackrox/rox/generated/storage"
)

// DataStore for auth machine to machine configs.
type DataStore interface {
GetAuthM2MConfig(ctx context.Context, id string) (*storage.AuthMachineToMachineConfig, bool, error)
ListAuthM2MConfigs(ctx context.Context) ([]*storage.AuthMachineToMachineConfig, error)
AddAuthM2MConfig(ctx context.Context, config *storage.AuthMachineToMachineConfig) (*storage.AuthMachineToMachineConfig, error)
UpdateAuthM2MConfig(ctx context.Context, config *storage.AuthMachineToMachineConfig) error
RemoveAuthM2MConfig(ctx context.Context, id string) error
}

// New returns an instance of an auth machine to machine Datastore.
func New(store store.Store) DataStore {
return &datastoreImpl{store: store}
}
42 changes: 42 additions & 0 deletions central/auth/datastore/datastore_impl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package datastore

import (
"context"

"github.com/stackrox/rox/central/auth/store"
"github.com/stackrox/rox/generated/storage"
)

var (
_ DataStore = (*datastoreImpl)(nil)
)

type datastoreImpl struct {
store store.Store
}

func (d *datastoreImpl) GetAuthM2MConfig(ctx context.Context, id string) (*storage.AuthMachineToMachineConfig, bool, error) {
return d.store.Get(ctx, id)
}

func (d *datastoreImpl) ListAuthM2MConfigs(ctx context.Context) ([]*storage.AuthMachineToMachineConfig, error) {
return d.store.GetAll(ctx)
}

func (d *datastoreImpl) AddAuthM2MConfig(ctx context.Context, config *storage.AuthMachineToMachineConfig) (*storage.AuthMachineToMachineConfig, error) {
if err := d.store.Upsert(ctx, config); err != nil {
return nil, err
}
return config, nil
}

func (d *datastoreImpl) UpdateAuthM2MConfig(ctx context.Context, config *storage.AuthMachineToMachineConfig) error {
if err := d.store.Upsert(ctx, config); err != nil {
return err
}
return nil
}

func (d *datastoreImpl) RemoveAuthM2MConfig(ctx context.Context, id string) error {
return d.store.Delete(ctx, id)
}
179 changes: 179 additions & 0 deletions central/auth/datastore/datastore_impl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//go:build sql_integration

package datastore

import (
"context"
"testing"

pgStore "github.com/stackrox/rox/central/auth/store/postgres"
roleDataStore "github.com/stackrox/rox/central/role/datastore"
permissionSetPostgresStore "github.com/stackrox/rox/central/role/store/permissionset/postgres"
rolePostgresStore "github.com/stackrox/rox/central/role/store/role/postgres"
accessScopePostgresStore "github.com/stackrox/rox/central/role/store/simpleaccessscope/postgres"
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/errox"
"github.com/stackrox/rox/pkg/postgres/pgtest"
"github.com/stackrox/rox/pkg/sac"
"github.com/stackrox/rox/pkg/sac/resources"
"github.com/stackrox/rox/pkg/set"
"github.com/stackrox/rox/pkg/uuid"
"github.com/stretchr/testify/suite"
)

const (
testRole1 = "New-Admin"
testRole2 = "Super-Admin"
testRole3 = "Super Continuous Integration"
)

var (
testRoles = set.NewFrozenStringSet(testRole1, testRole2, testRole3)
)

func TestAuthDatastorePostgres(t *testing.T) {
suite.Run(t, new(datastorePostgresTestSuite))
}

type datastorePostgresTestSuite struct {
suite.Suite

ctx context.Context
pool *pgtest.TestPostgres
authDataStore DataStore
roleDataStore roleDataStore.DataStore
}

func (s *datastorePostgresTestSuite) SetupTest() {
s.ctx = sac.WithGlobalAccessScopeChecker(context.Background(),
sac.AllowFixedScopes(
sac.AccessModeScopeKeys(storage.Access_READ_ACCESS, storage.Access_READ_WRITE_ACCESS),
sac.ResourceScopeKeys(resources.Access),
),
)

s.pool = pgtest.ForT(s.T())
s.Require().NotNil(s.pool)

store := pgStore.New(s.pool.DB)
s.authDataStore = New(store)

permSetStore := permissionSetPostgresStore.New(s.pool.DB)
accessScopeStore := accessScopePostgresStore.New(s.pool.DB)
roleStore := rolePostgresStore.New(s.pool.DB)
s.roleDataStore = roleDataStore.New(roleStore, permSetStore, accessScopeStore, func(_ context.Context, _ func(*storage.Group) bool) ([]*storage.Group, error) {
return nil, nil
})

s.addRoles()

}

func (s *datastorePostgresTestSuite) TearDownTest() {
s.pool.Teardown(s.T())
s.pool.Close()
}

func (s *datastorePostgresTestSuite) TestAddFKConstraint() {
config, err := s.authDataStore.AddAuthM2MConfig(s.ctx, &storage.AuthMachineToMachineConfig{
Id: "80c053c2-24a7-4b97-bd69-85b3a511241e",
Type: storage.AuthMachineToMachineConfig_GITHUB_ACTIONS,
TokenExpirationDuration: "5m",
Mappings: []*storage.AuthMachineToMachineConfig_Mapping{
{
Key: "sub",
ValueExpression: "some-value",
Role: "non-existing-role",
},
},
})
s.ErrorIs(err, errox.ReferencedObjectNotFound)
s.Nil(config)
}

func (s *datastorePostgresTestSuite) TestDeleteFKConstraint() {
config, err := s.authDataStore.AddAuthM2MConfig(s.ctx, &storage.AuthMachineToMachineConfig{
Id: "80c053c2-24a7-4b97-bd69-85b3a511241e",
Type: storage.AuthMachineToMachineConfig_GITHUB_ACTIONS,
TokenExpirationDuration: "5m",
Mappings: []*storage.AuthMachineToMachineConfig_Mapping{
{
Key: "sub",
ValueExpression: "some-value",
Role: testRole1,
},
},
})
s.Require().NoError(err)

s.ErrorIs(s.roleDataStore.RemoveRole(s.ctx, testRole1), errox.ReferencedByAnotherObject)

s.NoError(s.authDataStore.RemoveAuthM2MConfig(s.ctx, config.GetId()))

s.NoError(s.roleDataStore.RemoveRole(s.ctx, testRole1))
}

func (s *datastorePostgresTestSuite) TestAddUniqueIssuerConstraint() {
_, err := s.authDataStore.AddAuthM2MConfig(s.ctx, &storage.AuthMachineToMachineConfig{
Id: "80c053c2-24a7-4b97-bd69-85b3a511241e",
Type: storage.AuthMachineToMachineConfig_GENERIC,
TokenExpirationDuration: "5m",
Mappings: []*storage.AuthMachineToMachineConfig_Mapping{
{
Key: "sub",
ValueExpression: "some-value",
Role: testRole1,
},
},
Issuer: "https://stackrox.io",
})

s.NoError(err)

_, err = s.authDataStore.AddAuthM2MConfig(s.ctx, &storage.AuthMachineToMachineConfig{
Id: "12c153c2-24a7-4b97-bd69-85b3a511241e",
Type: storage.AuthMachineToMachineConfig_GENERIC,
TokenExpirationDuration: "5m",
Mappings: []*storage.AuthMachineToMachineConfig_Mapping{
{
Key: "sub",
ValueExpression: "some-value",
Role: testRole2,
},
},
Issuer: "https://stackrox.io",
})

s.Error(err)
s.ErrorIs(err, errox.AlreadyExists)
}

func (s *datastorePostgresTestSuite) addRoles() {
permSetID := uuid.NewV4().String()
accessScopeID := uuid.NewV4().String()
s.Require().NoError(s.roleDataStore.AddPermissionSet(s.ctx, &storage.PermissionSet{
Id: permSetID,
Name: "test permission set",
Description: "test permission set",
ResourceToAccess: map[string]storage.Access{
resources.Access.String(): storage.Access_READ_ACCESS,
},
}))
s.Require().NoError(s.roleDataStore.AddAccessScope(s.ctx, &storage.SimpleAccessScope{
Id: accessScopeID,
Name: "test access scope",
Description: "test access scope",
Rules: &storage.SimpleAccessScope_Rules{
IncludedClusters: []string{"cluster-a"},
},
}))

for _, role := range testRoles.AsSlice() {
s.Require().NoError(s.roleDataStore.AddRole(s.ctx, &storage.Role{
Name: role,
Description: "test role",
PermissionSetId: permSetID,
AccessScopeId: accessScopeID,
}))
}
}
21 changes: 21 additions & 0 deletions central/auth/datastore/singleton.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package datastore

import (
pgStore "github.com/stackrox/rox/central/auth/store/postgres"
"github.com/stackrox/rox/central/globaldb"
"github.com/stackrox/rox/pkg/sync"
)

var (
once sync.Once

ds DataStore
)

// Singleton provides a singleton auth machine to machine DataStore.
func Singleton() DataStore {
once.Do(func() {
ds = New(pgStore.New(globaldb.GetPostgres()))
})
return ds
}
16 changes: 11 additions & 5 deletions central/auth/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package service
import (
"context"

"github.com/stackrox/rox/central/auth/datastore"
v1 "github.com/stackrox/rox/generated/api/v1"
"github.com/stackrox/rox/pkg/grpc"
"github.com/stackrox/rox/pkg/logging"
"github.com/stackrox/rox/pkg/sync"
)

var (
log = logging.LoggerForModule()
once sync.Once

s Service
)

// Service provides the interface to the microservice that serves alert data.
Expand All @@ -20,7 +23,10 @@ type Service interface {
GetAuthStatus(ctx context.Context, request *v1.Empty) (*v1.AuthStatus, error)
}

// New returns a new auth service instance.
func New() Service {
return &serviceImpl{}
// Singleton returns a new auth service instance.
func Singleton() Service {
once.Do(func() {
s = &serviceImpl{authDataStore: datastore.Singleton()}
})
return s
}
Loading