Fix missing cmid scope

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-06-19 18:49:33 +02:00
parent 8add4713c8
commit 9fd95a0bf9
19 changed files with 611 additions and 646 deletions

View File

@@ -14,45 +14,38 @@
package accessreview
import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam"
)
import "go.probo.inc/probo/pkg/coredata"
const (
ScopeV1AccessReviewRead coredata.OAuth2Scope = "v1:access-review:read"
ScopeV1AccessReview coredata.OAuth2Scope = "v1:access-review"
)
// OAuth2ScopeSet returns OAuth2 scope mappings for access-review actions.
func OAuth2ScopeSet() *iam.ScopeSet {
return iam.CreateScopeSet(
map[coredata.OAuth2Scope][]iam.Action{
ScopeV1AccessReviewRead: {
ActionCampaignGet,
ActionCampaignList,
ActionEntryGet,
ActionEntryList,
ActionSourceGet,
ActionSourceList,
ActionDriverCatalogList,
},
ScopeV1AccessReview: {
ActionCampaignCreate,
ActionCampaignUpdate,
ActionCampaignDelete,
ActionCampaignStart,
ActionCampaignClose,
ActionCampaignCancel,
ActionCampaignAddSource,
ActionCampaignRemoveSource,
ActionEntryDecide,
ActionEntryFlag,
ActionSourceCreate,
ActionSourceUpdate,
ActionSourceDelete,
ActionSourceSync,
},
},
)
// OAuth2ScopeMappings maps OAuth2 scopes to access-review actions.
var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{
ScopeV1AccessReviewRead: {
ActionCampaignGet,
ActionCampaignList,
ActionEntryGet,
ActionEntryList,
ActionSourceGet,
ActionSourceList,
ActionDriverCatalogList,
},
ScopeV1AccessReview: {
ActionCampaignCreate,
ActionCampaignUpdate,
ActionCampaignDelete,
ActionCampaignStart,
ActionCampaignClose,
ActionCampaignCancel,
ActionCampaignAddSource,
ActionCampaignRemoveSource,
ActionEntryDecide,
ActionEntryFlag,
ActionSourceCreate,
ActionSourceUpdate,
ActionSourceDelete,
ActionSourceSync,
},
}

View File

@@ -14,27 +14,19 @@
package agentrun
import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam"
)
import "go.probo.inc/probo/pkg/coredata"
const (
ScopeV1AgentRead coredata.OAuth2Scope = "v1:agent:read"
ScopeV1Agent coredata.OAuth2Scope = "v1:agent"
)
// OAuth2ScopeSet returns OAuth2 scope mappings for agent-run actions.
func OAuth2ScopeSet() *iam.ScopeSet {
return iam.CreateScopeSet(
map[coredata.OAuth2Scope][]iam.Action{
ScopeV1AgentRead: {
ActionAgentRunGet,
ActionAgentRunList,
},
ScopeV1Agent: {
ActionAgentRunApprove,
},
},
)
var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{
ScopeV1AgentRead: {
ActionAgentRunGet,
ActionAgentRunList,
},
ScopeV1Agent: {
ActionAgentRunApprove,
},
}

View File

@@ -29,6 +29,7 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam/oauth2"
"go.probo.inc/probo/pkg/iam/policy"
"go.probo.inc/probo/pkg/iam/scopeset"
)
// AuthorizationAttributer is implemented by entities that can provide
@@ -86,17 +87,17 @@ type Authorizer struct {
pg *pg.Client
evaluator *policy.Evaluator
policySet *PolicySet
oauth2ScopeSet *ScopeSet
oauth2ScopeSet *scopeset.ScopeSet
logger *log.Logger
}
// NewAuthorizer creates a new Authorizer instance.
func NewAuthorizer(pgClient *pg.Client, logger *log.Logger) *Authorizer {
func NewAuthorizer(pgClient *pg.Client, logger *log.Logger, scopeSet *scopeset.ScopeSet) *Authorizer {
return &Authorizer{
pg: pgClient,
evaluator: policy.NewEvaluator(),
policySet: NewPolicySet(),
oauth2ScopeSet: NewScopeSet(),
oauth2ScopeSet: scopeSet,
logger: logger,
}
}
@@ -106,20 +107,6 @@ func (a *Authorizer) RegisterPolicySet(ps *PolicySet) {
a.policySet.Merge(ps)
}
// RegisterScopes merges OAuth2 scope-to-action mappings into the authorizer.
func (a *Authorizer) RegisterScopes(ss *ScopeSet) {
a.oauth2ScopeSet.Merge(ss)
}
// APIScopes returns OAuth2 API scopes advertised in discovery metadata.
func (a *Authorizer) APIScopes() []coredata.OAuth2Scope {
if a.oauth2ScopeSet == nil {
return []coredata.OAuth2Scope{}
}
return a.oauth2ScopeSet.APIScopes()
}
func (a *Authorizer) checkOAuth2Scope(
ctx context.Context,
principal gid.GID,

View File

@@ -32,6 +32,7 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/iam/policy"
"go.probo.inc/probo/pkg/iam/scopeset"
"go.probo.inc/probo/pkg/mail"
)
@@ -216,7 +217,7 @@ func TestAuthorizer_AuthorizeBatch(t *testing.T) {
t.Run("empty input", func(t *testing.T) {
t.Parallel()
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)))
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)), scopeset.New())
_, err := authorizer.AuthorizeBatch(
context.Background(),
@@ -644,7 +645,7 @@ func TestAuthorizer_AuthorizeMulti(t *testing.T) {
t.Run("rejects empty items", func(t *testing.T) {
t.Parallel()
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)))
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)), scopeset.New())
scope, decisions, err := authorizer.AuthorizeMulti(
context.Background(),
@@ -663,7 +664,7 @@ func TestAuthorizer_AuthorizeMulti(t *testing.T) {
t.Run("rejects unsupported principal type", func(t *testing.T) {
t.Parallel()
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)))
authorizer := iam.NewAuthorizer(nil, log.NewLogger(log.WithOutput(io.Discard)), scopeset.New())
scope, decisions, err := authorizer.AuthorizeMulti(
context.Background(),
@@ -782,7 +783,7 @@ func newTestAuthorizer(client *pg.Client, action string, allowResourceID *gid.GI
}
func newTestAuthorizerWithStatements(client *pg.Client, statements ...policy.Statement) *iam.Authorizer {
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(io.Discard)))
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(io.Discard)), scopeset.New())
authorizer.RegisterPolicySet(
iam.NewPolicySet().AddRolePolicy(
string(coredata.MembershipRoleOwner),
@@ -794,7 +795,7 @@ func newTestAuthorizerWithStatements(client *pg.Client, statements ...policy.Sta
}
func newTestAuthorizerWithIdentityScopedStatements(client *pg.Client, statements ...policy.Statement) *iam.Authorizer {
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(io.Discard)))
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(io.Discard)), scopeset.New())
authorizer.RegisterPolicySet(
iam.NewPolicySet().AddIdentityScopedPolicy(
policy.NewPolicy("batch-authorize-identity-test", "Batch Authorize Identity Test", statements...),

View File

@@ -30,6 +30,7 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/iam/policy"
"go.probo.inc/probo/pkg/iam/scopeset"
)
func TestAuthorizer_DecisionLogging(t *testing.T) {
@@ -151,7 +152,7 @@ func newTestAuthorizerWithLogger(
statements = append(statements, extraStatements...)
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(logOutput)))
authorizer := iam.NewAuthorizer(client, log.NewLogger(log.WithOutput(logOutput)), scopeset.New())
authorizer.RegisterPolicySet(
iam.NewPolicySet().AddRolePolicy(
string(coredata.MembershipRoleOwner),

View File

@@ -24,6 +24,7 @@ import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/iam/oauth2"
"go.probo.inc/probo/pkg/iam/scopeset"
)
func TestAuthorizer_checkOAuth2Scope(t *testing.T) {
@@ -65,15 +66,14 @@ func TestAuthorizer_checkOAuth2Scope(t *testing.T) {
t.Run("allows when registered scopes authorize the action", func(t *testing.T) {
t.Parallel()
a := NewAuthorizer(nil, nil)
a.RegisterScopes(
CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
scopeV1OrgRead: {action},
},
),
scopeSet := scopeset.New().Register(
map[coredata.OAuth2Scope][]string{
scopeV1OrgRead: {action},
},
)
a := NewAuthorizer(nil, nil, scopeSet)
ctx := oauth2.ContextWithAccessToken(
context.Background(),
&coredata.OAuth2AccessToken{Scopes: coredata.OAuth2Scopes{scopeV1OrgRead}},

View File

@@ -334,14 +334,6 @@ func (f *cimdFetcher) storeCache(clientIDURL string, doc *ClientMetadataDocument
)
}
func (s *Service) ResolveClient(
ctx context.Context,
clientIDRaw string,
redirectURI string,
) (*coredata.OAuth2Client, error) {
return s.resolveClient(ctx, nil, clientIDRaw, redirectURI)
}
func (s *Service) resolveClient(
ctx context.Context,
tx pg.Tx,
@@ -415,7 +407,7 @@ func (s *Service) upsertCIMDClient(
ScopeEmail,
ScopeOfflineAccess,
},
s.apiScopes,
s.scopeSet.APIScopes(),
)
now := time.Now()

View File

@@ -33,6 +33,7 @@ import (
"go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/net"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/iam/scopeset"
"go.probo.inc/probo/pkg/uri"
)
@@ -62,7 +63,7 @@ type (
gc *GarbageCollector
cimd *cimdFetcher
cimdAllowedClientIDs []string
apiScopes []coredata.OAuth2Scope
scopeSet *scopeset.ScopeSet
accessTokenDuration time.Duration
refreshTokenDuration time.Duration
authorizationCodeDuration time.Duration
@@ -159,9 +160,9 @@ func WithDeviceCodeDuration(d time.Duration) Option {
}
}
func WithAPIScopes(scopes []coredata.OAuth2Scope) Option {
func WithScopeSet(scopeSet *scopeset.ScopeSet) Option {
return func(s *Service) {
s.apiScopes = scopes
s.scopeSet = scopeSet
}
}
@@ -1438,6 +1439,8 @@ func (s *Service) Authorize(
return err
}
fmt.Printf("X: %+v\n", client)
if !client.IsRedirectURIAllowed(req.RedirectURI) {
return ErrInvalidRedirectURI
}
@@ -1736,7 +1739,7 @@ func (s *Service) AuthenticateClient(
clientIDRaw string,
clientSecret string,
) (*coredata.OAuth2Client, error) {
client, err := s.ResolveClient(ctx, clientIDRaw, "")
client, err := s.resolveClient(ctx, nil, clientIDRaw, "")
if err != nil {
return nil, err
}

View File

@@ -22,30 +22,21 @@ import (
"go.probo.inc/probo/pkg/agentrun"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/iam/scopeset"
"go.probo.inc/probo/pkg/probo"
)
func allRegisteredOAuth2ScopeSets() *iam.ScopeSet {
return iam.NewScopeSet().
Merge(iam.IAMOAuth2ScopeSet()).
Merge(probo.OAuth2ScopeSet()).
Merge(accessreview.OAuth2ScopeSet()).
Merge(agentrun.OAuth2ScopeSet())
}
func registerAllOAuth2ScopeSets(authorizer *iam.Authorizer) {
authorizer.RegisterScopes(iam.IAMOAuth2ScopeSet())
authorizer.RegisterScopes(probo.OAuth2ScopeSet())
authorizer.RegisterScopes(accessreview.OAuth2ScopeSet())
authorizer.RegisterScopes(agentrun.OAuth2ScopeSet())
func allRegisteredOAuth2ScopeSets() *scopeset.ScopeSet {
return scopeset.New().
Register(iam.IAMOAuth2ScopeMappings).
Register(probo.OAuth2ScopeMappings).
Register(accessreview.OAuth2ScopeMappings).
Register(agentrun.OAuth2ScopeMappings)
}
func TestRegisteredOAuth2ScopeSets_OrganizationRead(t *testing.T) {
t.Parallel()
authorizer := iam.NewAuthorizer(nil, nil)
registerAllOAuth2ScopeSets(authorizer)
scopeSet := allRegisteredOAuth2ScopeSets()
tokenScopes := coredata.OAuth2Scopes{probo.ScopeV1OrgRead}
@@ -57,9 +48,6 @@ func TestRegisteredOAuth2ScopeSets_OrganizationRead(t *testing.T) {
func TestRegisteredOAuth2ScopeSets_UnmappedActionDenies(t *testing.T) {
t.Parallel()
authorizer := iam.NewAuthorizer(nil, nil)
registerAllOAuth2ScopeSets(authorizer)
scopeSet := allRegisteredOAuth2ScopeSets()
tokenScopes := coredata.OAuth2Scopes{
probo.ScopeV1OrgRead,

View File

@@ -21,69 +21,64 @@ const (
ScopeV1IAM coredata.OAuth2Scope = "v1:iam"
)
// IAMOAuth2ScopeSet returns OAuth2 scope mappings for IAM actions.
func IAMOAuth2ScopeSet() *ScopeSet {
return CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
ScopeV1IAMRead: {
ActionOrganizationGet,
ActionOrganizationList,
ActionIdentityGet,
ActionSessionList,
ActionSessionGet,
ActionInvitationList,
ActionInvitationGet,
ActionMembershipGet,
ActionMembershipList,
ActionMembershipProfileGet,
ActionMembershipProfileList,
ActionPersonalAPIKeyGet,
ActionPersonalAPIKeyList,
ActionSAMLConfigurationGet,
ActionSAMLConfigurationList,
ActionSCIMConfigurationGet,
ActionSCIMEventList,
ActionSCIMEventGet,
ActionSCIMBridgeGet,
ActionOAuth2ConsentGet,
ActionAuditLogEntryGet,
ActionAuditLogEntryList,
ActionOAuth2AccessTokenGet,
ActionOAuth2AccessTokenList,
},
ScopeV1IAM: {
ActionOrganizationCreate,
ActionOrganizationUpdate,
ActionOrganizationDelete,
ActionIdentityUpdate,
ActionIdentityDelete,
ActionSessionRevoke,
ActionSessionRevokeAll,
ActionInvitationCreate,
ActionInvitationAccept,
ActionInvitationDelete,
ActionMembershipUpdate,
ActionMembershipDelete,
ActionMembershipRoleSetOwner,
ActionMembershipProfileCreate,
ActionMembershipProfileUpdate,
ActionMembershipProfileDelete,
ActionMembershipProfileActivate,
ActionMembershipProfileDeactivate,
ActionPersonalAPIKeyCreate,
ActionPersonalAPIKeyUpdate,
ActionPersonalAPIKeyDelete,
ActionSAMLConfigurationCreate,
ActionSAMLConfigurationUpdate,
ActionSAMLConfigurationDelete,
ActionSCIMConfigurationCreate,
ActionSCIMConfigurationUpdate,
ActionSCIMConfigurationDelete,
ActionSCIMBridgeCreate,
ActionSCIMBridgeUpdate,
ActionSCIMBridgeDelete,
ActionOAuth2ConsentApprove,
},
},
)
var IAMOAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{
ScopeV1IAMRead: {
ActionOrganizationGet,
ActionOrganizationList,
ActionIdentityGet,
ActionSessionList,
ActionSessionGet,
ActionInvitationList,
ActionInvitationGet,
ActionMembershipGet,
ActionMembershipList,
ActionMembershipProfileGet,
ActionMembershipProfileList,
ActionPersonalAPIKeyGet,
ActionPersonalAPIKeyList,
ActionSAMLConfigurationGet,
ActionSAMLConfigurationList,
ActionSCIMConfigurationGet,
ActionSCIMEventList,
ActionSCIMEventGet,
ActionSCIMBridgeGet,
ActionOAuth2ConsentGet,
ActionAuditLogEntryGet,
ActionAuditLogEntryList,
ActionOAuth2AccessTokenGet,
ActionOAuth2AccessTokenList,
},
ScopeV1IAM: {
ActionOrganizationCreate,
ActionOrganizationUpdate,
ActionOrganizationDelete,
ActionIdentityUpdate,
ActionIdentityDelete,
ActionSessionRevoke,
ActionSessionRevokeAll,
ActionInvitationCreate,
ActionInvitationAccept,
ActionInvitationDelete,
ActionMembershipUpdate,
ActionMembershipDelete,
ActionMembershipRoleSetOwner,
ActionMembershipProfileCreate,
ActionMembershipProfileUpdate,
ActionMembershipProfileDelete,
ActionMembershipProfileActivate,
ActionMembershipProfileDeactivate,
ActionPersonalAPIKeyCreate,
ActionPersonalAPIKeyUpdate,
ActionPersonalAPIKeyDelete,
ActionSAMLConfigurationCreate,
ActionSAMLConfigurationUpdate,
ActionSAMLConfigurationDelete,
ActionSCIMConfigurationCreate,
ActionSCIMConfigurationUpdate,
ActionSCIMConfigurationDelete,
ActionSCIMBridgeCreate,
ActionSCIMBridgeUpdate,
ActionSCIMBridgeDelete,
ActionOAuth2ConsentApprove,
},
}

View File

@@ -20,65 +20,21 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam/scopeset"
)
func TestScopeSet_Allows(t *testing.T) {
func TestAuthorizer_UsesOAuth2ScopeSet(t *testing.T) {
t.Parallel()
const scopeV1OrgRead = coredata.OAuth2Scope("v1:org:read")
scopeSet := CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
scopeSet := scopeset.New().Register(
map[coredata.OAuth2Scope][]string{
scopeV1OrgRead: {"core:organization:get"},
},
)
tokenScopes := coredata.OAuth2Scopes{scopeV1OrgRead}
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization:get"))
assert.False(t, scopeSet.Allows(tokenScopes, "core:organization:update"))
}
func TestScopeSet_Merge(t *testing.T) {
t.Parallel()
const scopeV1OrgRead = coredata.OAuth2Scope("v1:org:read")
scopeSet := NewScopeSet().
Merge(
CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
scopeV1OrgRead: {"core:organization:get"},
},
),
).
Merge(
CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
scopeV1OrgRead: {"core:organization-context:get"},
},
),
)
tokenScopes := coredata.OAuth2Scopes{scopeV1OrgRead}
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization:get"))
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization-context:get"))
}
func TestAuthorizer_RegisterScopes(t *testing.T) {
t.Parallel()
const scopeV1OrgRead = coredata.OAuth2Scope("v1:org:read")
authorizer := NewAuthorizer(nil, nil)
authorizer.RegisterScopes(
CreateScopeSet(
map[coredata.OAuth2Scope][]Action{
scopeV1OrgRead: {"core:organization:get"},
},
),
)
authorizer := NewAuthorizer(nil, nil, scopeSet)
require.NotNil(t, authorizer.oauth2ScopeSet)

View File

@@ -12,34 +12,32 @@
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package iam
package scopeset
import (
"cmp"
"maps"
"slices"
"sync"
"go.probo.inc/probo/pkg/coredata"
)
// ScopeSet holds OAuth2 scope to IAM action mappings. Services create their
// own ScopeSet and register it on the Authorizer at composition time.
type ScopeSet struct {
scopeActions map[coredata.OAuth2Scope][]Action
actionScopes map[Action][]coredata.OAuth2Scope
mu sync.RWMutex
scopeActions map[coredata.OAuth2Scope][]string
actionScopes map[string][]coredata.OAuth2Scope
}
// NewScopeSet creates an empty ScopeSet.
func NewScopeSet() *ScopeSet {
func New() *ScopeSet {
return &ScopeSet{
scopeActions: make(map[coredata.OAuth2Scope][]Action),
scopeActions: make(map[coredata.OAuth2Scope][]string),
}
}
// CreateScopeSet creates a ScopeSet from scope-to-action mappings. Entries with
// no actions are skipped.
func CreateScopeSet(mappings map[coredata.OAuth2Scope][]Action) *ScopeSet {
s := NewScopeSet()
func (s *ScopeSet) Register(mappings map[coredata.OAuth2Scope][]string) *ScopeSet {
s.mu.Lock()
defer s.mu.Unlock()
for scope, actions := range mappings {
if len(actions) == 0 {
@@ -54,24 +52,17 @@ func CreateScopeSet(mappings map[coredata.OAuth2Scope][]Action) *ScopeSet {
return s
}
// Merge combines another ScopeSet into this one.
func (s *ScopeSet) Merge(other *ScopeSet) *ScopeSet {
for scope, actions := range other.scopeActions {
s.scopeActions[scope] = append(s.scopeActions[scope], actions...)
}
s.rebuildActionScopes()
return s
}
// APIScopes returns every registered OAuth2 API scope in this set.
func (s *ScopeSet) APIScopes() []coredata.OAuth2Scope {
s.mu.RLock()
defer s.mu.RUnlock()
return sortedScopes(slices.Collect(maps.Keys(s.scopeActions)))
}
// Allows reports whether tokenScopes authorize action.
func (s *ScopeSet) Allows(tokenScopes coredata.OAuth2Scopes, action Action) bool {
func (s *ScopeSet) Allows(tokenScopes coredata.OAuth2Scopes, action string) bool {
s.mu.RLock()
defer s.mu.RUnlock()
grantingScopes, ok := s.actionScopes[action]
if !ok {
return false
@@ -81,7 +72,7 @@ func (s *ScopeSet) Allows(tokenScopes coredata.OAuth2Scopes, action Action) bool
}
func (s *ScopeSet) rebuildActionScopes() {
actionScopes := make(map[Action][]coredata.OAuth2Scope, len(s.scopeActions)*4)
actionScopes := make(map[string][]coredata.OAuth2Scope, len(s.scopeActions)*4)
for scope, actions := range s.scopeActions {
for _, action := range actions {
@@ -94,9 +85,12 @@ func (s *ScopeSet) rebuildActionScopes() {
func sortedScopes(scopes []coredata.OAuth2Scope) []coredata.OAuth2Scope {
sorted := slices.Clone(scopes)
slices.SortFunc(sorted, func(a, b coredata.OAuth2Scope) int {
return cmp.Compare(string(a), string(b))
})
slices.SortFunc(
sorted,
func(a, b coredata.OAuth2Scope) int {
return cmp.Compare(string(a), string(b))
},
)
return sorted
}

View File

@@ -0,0 +1,63 @@
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package scopeset_test
import (
"testing"
"github.com/stretchr/testify/assert"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam/scopeset"
)
func TestScopeSet_Allows(t *testing.T) {
t.Parallel()
const scopeV1OrgRead = coredata.OAuth2Scope("v1:org:read")
scopeSet := scopeset.New().Register(
map[coredata.OAuth2Scope][]string{
scopeV1OrgRead: {"core:organization:get"},
},
)
tokenScopes := coredata.OAuth2Scopes{scopeV1OrgRead}
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization:get"))
assert.False(t, scopeSet.Allows(tokenScopes, "core:organization:update"))
}
func TestScopeSet_Register(t *testing.T) {
t.Parallel()
const scopeV1OrgRead = coredata.OAuth2Scope("v1:org:read")
scopeSet := scopeset.New().
Register(
map[coredata.OAuth2Scope][]string{
scopeV1OrgRead: {"core:organization:get"},
},
).
Register(
map[coredata.OAuth2Scope][]string{
scopeV1OrgRead: {"core:organization-context:get"},
},
)
tokenScopes := coredata.OAuth2Scopes{scopeV1OrgRead}
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization:get"))
assert.True(t, scopeSet.Allows(tokenScopes, "core:organization-context:get"))
}

View File

@@ -37,6 +37,7 @@ import (
"go.probo.inc/probo/pkg/iam/oidc"
"go.probo.inc/probo/pkg/iam/saml"
"go.probo.inc/probo/pkg/iam/scim"
"go.probo.inc/probo/pkg/iam/scopeset"
"go.probo.inc/probo/pkg/uri"
)
@@ -69,6 +70,7 @@ type (
APIKeyService *APIKeyService
OAuth2ServerService *oauth2.Service
Authorizer *Authorizer
OAuth2ScopeSet *scopeset.ScopeSet
samlDomainVerifier *SAMLDomainVerifier
}
@@ -157,12 +159,15 @@ func NewService(
svc.AuthService = NewAuthService(svc)
svc.APIKeyService = NewAPIKeyService(svc)
svc.OAuth2ScopeSet = scopeset.New()
svc.OAuth2ScopeSet.Register(IAMOAuth2ScopeMappings)
svc.Authorizer = NewAuthorizer(
pgClient,
cfg.Logger.Named("authorizer"),
svc.OAuth2ScopeSet,
)
svc.Authorizer.RegisterPolicySet(IAMPolicySet())
svc.Authorizer.RegisterScopes(IAMOAuth2ScopeSet())
samlService, err := saml.NewService(svc.pg, svc.baseURL, svc.certificate, svc.privateKey, cfg.Logger)
if err != nil {
@@ -201,7 +206,7 @@ func NewService(
uri.URI(cfg.BaseURL.String()),
cfg.Logger.Named("oauth2"),
append(
[]oauth2.Option{oauth2.WithAPIScopes(svc.Authorizer.APIScopes())},
[]oauth2.Option{oauth2.WithScopeSet(svc.OAuth2ScopeSet)},
cfg.OAuth2ServerOptions...,
)...,
)
@@ -219,12 +224,12 @@ func NewService(
// OAuth2ServerMetadata returns the OIDC discovery document.
func (s *Service) OAuth2ServerMetadata(endpoints oauth2.Endpoints) *oauth2.ServerMetadata {
return oauth2.NewMetadata(uri.URI(s.baseURL), endpoints, s.Authorizer.APIScopes())
return oauth2.NewMetadata(uri.URI(s.baseURL), endpoints, s.OAuth2ScopeSet.APIScopes())
}
// OAuth2ProtectedResourceMetadata returns the RFC 9728 protected resource metadata document.
func (s *Service) OAuth2ProtectedResourceMetadata(resource uri.URI) *oauth2.ProtectedResourceMetadata {
return oauth2.NewProtectedResourceMetadata(resource, resource, s.Authorizer.APIScopes())
return oauth2.NewProtectedResourceMetadata(resource, resource, s.OAuth2ScopeSet.APIScopes())
}
func (s *Service) IsSignUpEnabled() bool {

View File

@@ -16,7 +16,6 @@ package probo
import (
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/iam"
)
const (
@@ -66,383 +65,379 @@ const (
ScopeV1Webhook coredata.OAuth2Scope = "v1:webhook"
)
// OAuth2ScopeSet returns OAuth2 scope mappings for core probo actions.
func OAuth2ScopeSet() *iam.ScopeSet {
return iam.CreateScopeSet(
map[coredata.OAuth2Scope][]iam.Action{
// OAuth2ScopeMappings maps OAuth2 scopes to core probo actions.
var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{
ScopeV1AssetRead: {
ActionAssetGet,
ActionAssetList,
},
ScopeV1Asset: {
ActionAssetCreate,
ActionAssetUpdate,
ActionAssetDelete,
ActionAssetPublish,
},
ScopeV1AuditRead: {
ActionAuditGet,
ActionAuditList,
ActionFindingGet,
ActionFindingList,
ActionReportGet,
ActionReportGetReportUrl,
ActionReportDownloadUrlGet,
},
ScopeV1Audit: {
ActionAuditCreate,
ActionAuditUpdate,
ActionAuditDelete,
ActionAuditReportUpload,
ActionAuditReportDelete,
ActionFindingCreate,
ActionFindingUpdate,
ActionFindingDelete,
ActionFindingAuditMappingCreate,
ActionFindingAuditMappingDelete,
ActionFindingPublish,
},
ScopeV1CommonThirdPartyRead: {
ActionCommonThirdPartyGet,
ActionCommonThirdPartyList,
},
ScopeV1CompliancePageRead: {
ActionTrustCenterGet,
ActionTrustCenterGetNda,
ActionTrustCenterAccessGet,
ActionTrustCenterAccessList,
ActionTrustCenterFileGet,
ActionTrustCenterFileList,
ActionTrustCenterFileGetFileUrl,
ActionTrustCenterReferenceList,
ActionTrustCenterReferenceGetLogoUrl,
ActionTrustCenterDocumentAccessList,
ActionMailingListUpdateList,
ActionMailingListSubscriberList,
ActionComplianceFrameworkList,
ActionComplianceExternalURLList,
ActionCustomDomainGet,
},
ScopeV1CompliancePage: {
ActionTrustCenterUpdate,
ActionTrustCenterNonDisclosureAgreementUpload,
ActionTrustCenterNonDisclosureAgreementDelete,
ActionTrustCenterAccessCreate,
ActionTrustCenterAccessUpdate,
ActionTrustCenterAccessDelete,
ActionTrustCenterFileUpdate,
ActionTrustCenterFileDelete,
ActionTrustCenterFileCreate,
ActionTrustCenterReferenceCreate,
ActionTrustCenterReferenceUpdate,
ActionTrustCenterReferenceDelete,
ActionMailingListUpdateCreate,
ActionMailingListUpdateUpdate,
ActionMailingListUpdateSend,
ActionMailingListUpdateDelete,
ActionMailingListUpdate,
ActionMailingListSubscriberCreate,
ActionMailingListSubscriberDelete,
ActionComplianceFrameworkCreate,
ActionComplianceFrameworkDelete,
ActionComplianceFrameworkUpdateRank,
ActionComplianceExternalURLCreate,
ActionComplianceExternalURLUpdate,
ActionComplianceExternalURLDelete,
ActionCustomDomainCreate,
ActionCustomDomainDelete,
},
ScopeV1ConnectorRead: {
ActionConnectorList,
ActionConnectorGet,
},
ScopeV1Connector: {
ActionConnectorCreate,
ActionConnectorDelete,
ActionConnectorInitiate,
},
ScopeV1ControlRead: {
ActionControlGet,
ActionControlList,
ActionMeasureGet,
ActionMeasureList,
ActionFrameworkGet,
ActionFrameworkList,
ActionFrameworkExport,
ActionObligationGet,
ActionObligationList,
ActionStatementOfApplicabilityList,
ActionStatementOfApplicabilityGet,
ActionApplicabilityStatementGet,
ActionApplicabilityStatementList,
},
ScopeV1Control: {
ActionControlCreate,
ActionControlUpdate,
ActionControlDelete,
ActionControlMeasureMappingCreate,
ActionControlMeasureMappingDelete,
ActionControlDocumentMappingCreate,
ActionControlDocumentMappingDelete,
ActionControlAuditMappingCreate,
ActionControlAuditMappingDelete,
ActionControlObligationMappingCreate,
ActionControlObligationMappingDelete,
ActionMeasureCreate,
ActionMeasureUpdate,
ActionMeasureDelete,
ActionMeasureEvidenceUpload,
ActionMeasureImport,
ActionMeasureDocumentMappingCreate,
ActionMeasureDocumentMappingDelete,
ActionMeasureThirdPartyMappingCreate,
ActionMeasureThirdPartyMappingDelete,
ActionFrameworkCreate,
ActionFrameworkUpdate,
ActionFrameworkDelete,
ActionFrameworkImport,
ActionObligationCreate,
ActionObligationUpdate,
ActionObligationDelete,
ActionObligationPublish,
ActionStatementOfApplicabilityCreate,
ActionStatementOfApplicabilityUpdate,
ActionStatementOfApplicabilityDelete,
ActionStatementOfApplicabilityPublish,
ActionApplicabilityStatementCreate,
ActionApplicabilityStatementUpdate,
ActionApplicabilityStatementDelete,
},
ScopeV1DatumRead: {
ActionDatumGet,
ActionDatumList,
},
ScopeV1Datum: {
ActionDatumCreate,
ActionDatumUpdate,
ActionDatumDelete,
ActionDatumPublish,
},
ScopeV1DocumentRead: {
ActionDocumentGet,
ActionDocumentList,
ActionDocumentVersionGet,
ActionDocumentVersionList,
ActionDocumentVersionExportPDF,
ActionDocumentVersionApprovalList,
ActionDocumentVersionExport,
ActionEmployeeDocumentGet,
ActionEmployeeDocumentList,
ActionEmployeeDocumentVersionExportPDF,
ActionDocumentVersionSignatureGet,
ActionDocumentVersionSignatureList,
ActionElectronicSignatureGet,
ActionFileGet,
},
ScopeV1Document: {
ActionDocumentCreate,
ActionDocumentUpdate,
ActionDocumentDelete,
ActionDocumentChangelogGenerate,
ActionDocumentArchive,
ActionDocumentUnarchive,
ActionDocumentDeleteDraft,
ActionDocumentVersionSign,
ActionDocumentVersionRequestApproval,
ActionDocumentVersionVoidApproval,
ActionDocumentVersionApprove,
ActionDocumentVersionReject,
ActionDocumentVersionPublish,
ActionDocumentVersionSignatureRequest,
ActionDocumentVersionCancelSignature,
},
ScopeV1OrgRead: {
ActionOrganizationGet,
ActionOrganizationGetLogoUrl,
ActionOrganizationGetHorizontalLogoUrl,
ActionOrganizationContextGet,
},
ScopeV1Org: {
ActionOrganizationUpdate,
ActionOrganizationContextUpdate,
},
ScopeV1PrivacyRead: {
ActionProcessingActivityList,
ActionProcessingActivityGet,
ActionDataProtectionImpactAssessmentList,
ActionDataProtectionImpactAssessmentGet,
ActionTransferImpactAssessmentList,
ActionTransferImpactAssessmentGet,
ActionRightsRequestList,
ActionRightsRequestGet,
ActionCookieBannerGet,
ActionCookieBannerList,
ActionCookieBannerVersionGet,
ActionCookieBannerVersionList,
ActionCookieCategoryGet,
ActionCookieCategoryList,
ActionCookieGet,
ActionCookieList,
ActionCookieConsentRecordList,
ActionTrackerPatternGet,
ActionTrackerPatternList,
ActionTrackerResourceGet,
ActionTrackerResourceList,
},
ScopeV1Privacy: {
ActionProcessingActivityCreate,
ActionProcessingActivityUpdate,
ActionProcessingActivityDelete,
ActionProcessingActivityPublish,
ActionDataProtectionImpactAssessmentCreate,
ActionDataProtectionImpactAssessmentUpdate,
ActionDataProtectionImpactAssessmentDelete,
ActionDataProtectionImpactAssessmentPublish,
ActionTransferImpactAssessmentCreate,
ActionTransferImpactAssessmentUpdate,
ActionTransferImpactAssessmentDelete,
ActionTransferImpactAssessmentPublish,
ActionRightsRequestCreate,
ActionRightsRequestUpdate,
ActionRightsRequestDelete,
ActionCookieBannerCreate,
ActionCookieBannerUpdate,
ActionCookieBannerDelete,
ActionCookieBannerActivate,
ActionCookieBannerDeactivate,
ActionCookieBannerRegeneratePolicy,
ActionCookieBannerVersionPublish,
ActionCookieCategoryCreate,
ActionCookieCategoryUpdate,
ActionCookieCategoryDelete,
ActionCookieCreate,
ActionCookieUpdate,
ActionCookieDelete,
ActionTrackerPatternCreate,
ActionTrackerPatternUpdate,
ActionTrackerPatternDelete,
ActionTrackerResourceCreate,
ActionTrackerResourceUpdate,
ActionTrackerResourceDelete,
},
ScopeV1RiskRead: {
ActionRiskGet,
ActionRiskList,
ActionRiskAssessmentGet,
ActionRiskAssessmentList,
ActionRiskAssessmentScopeGet,
ActionRiskAssessmentScopeList,
ActionRiskAssessmentNodeGet,
ActionRiskAssessmentNodeList,
ActionRiskAssessmentBoundaryGet,
ActionRiskAssessmentBoundaryList,
ActionRiskAssessmentProcessGet,
ActionRiskAssessmentProcessList,
ActionRiskAssessmentThreatGet,
ActionRiskAssessmentThreatList,
ActionRiskAssessmentScenarioGet,
ActionRiskAssessmentScenarioList,
},
ScopeV1Risk: {
ActionRiskCreate,
ActionRiskUpdate,
ActionRiskDelete,
ActionRiskMeasureMappingCreate,
ActionRiskMeasureMappingDelete,
ActionRiskDocumentMappingCreate,
ActionRiskDocumentMappingDelete,
ActionRiskObligationMappingCreate,
ActionRiskObligationMappingDelete,
ActionRiskPublish,
ActionRiskAssessmentCreate,
ActionRiskAssessmentUpdate,
ActionRiskAssessmentDelete,
ActionRiskAssessmentScopeCreate,
ActionRiskAssessmentScopeUpdate,
ActionRiskAssessmentScopeDelete,
ActionRiskAssessmentNodeCreate,
ActionRiskAssessmentNodeUpdate,
ActionRiskAssessmentNodeDelete,
ActionRiskAssessmentBoundaryCreate,
ActionRiskAssessmentBoundaryUpdate,
ActionRiskAssessmentBoundaryDelete,
ActionRiskAssessmentProcessCreate,
ActionRiskAssessmentProcessUpdate,
ActionRiskAssessmentProcessDelete,
ActionRiskAssessmentThreatCreate,
ActionRiskAssessmentThreatUpdate,
ActionRiskAssessmentThreatDelete,
ActionRiskAssessmentScenarioCreate,
ActionRiskAssessmentScenarioUpdate,
ActionRiskAssessmentScenarioDelete,
ActionRiskAssessmentScenarioThreatLink,
ActionRiskAssessmentScenarioThreatUnlink,
ActionRiskAssessmentScenarioRiskLink,
ActionRiskAssessmentScenarioRiskUnlink,
},
ScopeV1SlackConnectionRead: {
ActionSlackConnectionList,
},
ScopeV1TaskRead: {
ActionTaskGet,
ActionTaskList,
ActionEvidenceList,
},
ScopeV1Task: {
ActionTaskCreate,
ActionTaskUpdate,
ActionTaskDelete,
ActionTaskAssign,
ActionTaskUnassign,
ActionEvidenceDelete,
},
ScopeV1ThirdPartyRead: {
ActionThirdPartyList,
ActionThirdPartyGet,
ActionThirdPartyRelationList,
ActionThirdPartyContactGet,
ActionThirdPartyContactList,
ActionThirdPartyServiceGet,
ActionThirdPartyServiceList,
ActionThirdPartyComplianceReportGet,
ActionThirdPartyComplianceReportList,
ActionThirdPartyBusinessAssociateAgreementGet,
ActionThirdPartyDataPrivacyAgreementGet,
ActionThirdPartyRiskAssessmentList,
},
ScopeV1ThirdParty: {
ActionThirdPartyCreate,
ActionThirdPartyUpdate,
ActionThirdPartyDelete,
ActionThirdPartyVet,
ActionThirdPartyPublish,
ActionThirdPartyRelationCreate,
ActionThirdPartyContactCreate,
ActionThirdPartyContactUpdate,
ActionThirdPartyContactDelete,
ActionThirdPartyServiceCreate,
ActionThirdPartyServiceUpdate,
ActionThirdPartyServiceDelete,
ActionThirdPartyComplianceReportUpload,
ActionThirdPartyComplianceReportDelete,
ActionThirdPartyBusinessAssociateAgreementUpload,
ActionThirdPartyBusinessAssociateAgreementUpdate,
ActionThirdPartyBusinessAssociateAgreementDelete,
ActionThirdPartyDataPrivacyAgreementUpload,
ActionThirdPartyDataPrivacyAgreementUpdate,
ActionThirdPartyDataPrivacyAgreementDelete,
ActionThirdPartyRiskAssessmentCreate,
},
ScopeV1WebhookRead: {
ActionWebhookSubscriptionList,
ActionWebhookSubscriptionGet,
},
ScopeV1Webhook: {
ActionWebhookSubscriptionCreate,
ActionWebhookSubscriptionUpdate,
ActionWebhookSubscriptionDelete,
},
},
)
ScopeV1AssetRead: {
ActionAssetGet,
ActionAssetList,
},
ScopeV1Asset: {
ActionAssetCreate,
ActionAssetUpdate,
ActionAssetDelete,
ActionAssetPublish,
},
ScopeV1AuditRead: {
ActionAuditGet,
ActionAuditList,
ActionFindingGet,
ActionFindingList,
ActionReportGet,
ActionReportGetReportUrl,
ActionReportDownloadUrlGet,
},
ScopeV1Audit: {
ActionAuditCreate,
ActionAuditUpdate,
ActionAuditDelete,
ActionAuditReportUpload,
ActionAuditReportDelete,
ActionFindingCreate,
ActionFindingUpdate,
ActionFindingDelete,
ActionFindingAuditMappingCreate,
ActionFindingAuditMappingDelete,
ActionFindingPublish,
},
ScopeV1CommonThirdPartyRead: {
ActionCommonThirdPartyGet,
ActionCommonThirdPartyList,
},
ScopeV1CompliancePageRead: {
ActionTrustCenterGet,
ActionTrustCenterGetNda,
ActionTrustCenterAccessGet,
ActionTrustCenterAccessList,
ActionTrustCenterFileGet,
ActionTrustCenterFileList,
ActionTrustCenterFileGetFileUrl,
ActionTrustCenterReferenceList,
ActionTrustCenterReferenceGetLogoUrl,
ActionTrustCenterDocumentAccessList,
ActionMailingListUpdateList,
ActionMailingListSubscriberList,
ActionComplianceFrameworkList,
ActionComplianceExternalURLList,
ActionCustomDomainGet,
},
ScopeV1CompliancePage: {
ActionTrustCenterUpdate,
ActionTrustCenterNonDisclosureAgreementUpload,
ActionTrustCenterNonDisclosureAgreementDelete,
ActionTrustCenterAccessCreate,
ActionTrustCenterAccessUpdate,
ActionTrustCenterAccessDelete,
ActionTrustCenterFileUpdate,
ActionTrustCenterFileDelete,
ActionTrustCenterFileCreate,
ActionTrustCenterReferenceCreate,
ActionTrustCenterReferenceUpdate,
ActionTrustCenterReferenceDelete,
ActionMailingListUpdateCreate,
ActionMailingListUpdateUpdate,
ActionMailingListUpdateSend,
ActionMailingListUpdateDelete,
ActionMailingListUpdate,
ActionMailingListSubscriberCreate,
ActionMailingListSubscriberDelete,
ActionComplianceFrameworkCreate,
ActionComplianceFrameworkDelete,
ActionComplianceFrameworkUpdateRank,
ActionComplianceExternalURLCreate,
ActionComplianceExternalURLUpdate,
ActionComplianceExternalURLDelete,
ActionCustomDomainCreate,
ActionCustomDomainDelete,
},
ScopeV1ConnectorRead: {
ActionConnectorList,
ActionConnectorGet,
},
ScopeV1Connector: {
ActionConnectorCreate,
ActionConnectorDelete,
ActionConnectorInitiate,
},
ScopeV1ControlRead: {
ActionControlGet,
ActionControlList,
ActionMeasureGet,
ActionMeasureList,
ActionFrameworkGet,
ActionFrameworkList,
ActionFrameworkExport,
ActionObligationGet,
ActionObligationList,
ActionStatementOfApplicabilityList,
ActionStatementOfApplicabilityGet,
ActionApplicabilityStatementGet,
ActionApplicabilityStatementList,
},
ScopeV1Control: {
ActionControlCreate,
ActionControlUpdate,
ActionControlDelete,
ActionControlMeasureMappingCreate,
ActionControlMeasureMappingDelete,
ActionControlDocumentMappingCreate,
ActionControlDocumentMappingDelete,
ActionControlAuditMappingCreate,
ActionControlAuditMappingDelete,
ActionControlObligationMappingCreate,
ActionControlObligationMappingDelete,
ActionMeasureCreate,
ActionMeasureUpdate,
ActionMeasureDelete,
ActionMeasureEvidenceUpload,
ActionMeasureImport,
ActionMeasureDocumentMappingCreate,
ActionMeasureDocumentMappingDelete,
ActionMeasureThirdPartyMappingCreate,
ActionMeasureThirdPartyMappingDelete,
ActionFrameworkCreate,
ActionFrameworkUpdate,
ActionFrameworkDelete,
ActionFrameworkImport,
ActionObligationCreate,
ActionObligationUpdate,
ActionObligationDelete,
ActionObligationPublish,
ActionStatementOfApplicabilityCreate,
ActionStatementOfApplicabilityUpdate,
ActionStatementOfApplicabilityDelete,
ActionStatementOfApplicabilityPublish,
ActionApplicabilityStatementCreate,
ActionApplicabilityStatementUpdate,
ActionApplicabilityStatementDelete,
},
ScopeV1DatumRead: {
ActionDatumGet,
ActionDatumList,
},
ScopeV1Datum: {
ActionDatumCreate,
ActionDatumUpdate,
ActionDatumDelete,
ActionDatumPublish,
},
ScopeV1DocumentRead: {
ActionDocumentGet,
ActionDocumentList,
ActionDocumentVersionGet,
ActionDocumentVersionList,
ActionDocumentVersionExportPDF,
ActionDocumentVersionApprovalList,
ActionDocumentVersionExport,
ActionEmployeeDocumentGet,
ActionEmployeeDocumentList,
ActionEmployeeDocumentVersionExportPDF,
ActionDocumentVersionSignatureGet,
ActionDocumentVersionSignatureList,
ActionElectronicSignatureGet,
ActionFileGet,
},
ScopeV1Document: {
ActionDocumentCreate,
ActionDocumentUpdate,
ActionDocumentDelete,
ActionDocumentChangelogGenerate,
ActionDocumentArchive,
ActionDocumentUnarchive,
ActionDocumentDeleteDraft,
ActionDocumentVersionSign,
ActionDocumentVersionRequestApproval,
ActionDocumentVersionVoidApproval,
ActionDocumentVersionApprove,
ActionDocumentVersionReject,
ActionDocumentVersionPublish,
ActionDocumentVersionSignatureRequest,
ActionDocumentVersionCancelSignature,
},
ScopeV1OrgRead: {
ActionOrganizationGet,
ActionOrganizationGetLogoUrl,
ActionOrganizationGetHorizontalLogoUrl,
ActionOrganizationContextGet,
},
ScopeV1Org: {
ActionOrganizationUpdate,
ActionOrganizationContextUpdate,
},
ScopeV1PrivacyRead: {
ActionProcessingActivityList,
ActionProcessingActivityGet,
ActionDataProtectionImpactAssessmentList,
ActionDataProtectionImpactAssessmentGet,
ActionTransferImpactAssessmentList,
ActionTransferImpactAssessmentGet,
ActionRightsRequestList,
ActionRightsRequestGet,
ActionCookieBannerGet,
ActionCookieBannerList,
ActionCookieBannerVersionGet,
ActionCookieBannerVersionList,
ActionCookieCategoryGet,
ActionCookieCategoryList,
ActionCookieGet,
ActionCookieList,
ActionCookieConsentRecordList,
ActionTrackerPatternGet,
ActionTrackerPatternList,
ActionTrackerResourceGet,
ActionTrackerResourceList,
},
ScopeV1Privacy: {
ActionProcessingActivityCreate,
ActionProcessingActivityUpdate,
ActionProcessingActivityDelete,
ActionProcessingActivityPublish,
ActionDataProtectionImpactAssessmentCreate,
ActionDataProtectionImpactAssessmentUpdate,
ActionDataProtectionImpactAssessmentDelete,
ActionDataProtectionImpactAssessmentPublish,
ActionTransferImpactAssessmentCreate,
ActionTransferImpactAssessmentUpdate,
ActionTransferImpactAssessmentDelete,
ActionTransferImpactAssessmentPublish,
ActionRightsRequestCreate,
ActionRightsRequestUpdate,
ActionRightsRequestDelete,
ActionCookieBannerCreate,
ActionCookieBannerUpdate,
ActionCookieBannerDelete,
ActionCookieBannerActivate,
ActionCookieBannerDeactivate,
ActionCookieBannerRegeneratePolicy,
ActionCookieBannerVersionPublish,
ActionCookieCategoryCreate,
ActionCookieCategoryUpdate,
ActionCookieCategoryDelete,
ActionCookieCreate,
ActionCookieUpdate,
ActionCookieDelete,
ActionTrackerPatternCreate,
ActionTrackerPatternUpdate,
ActionTrackerPatternDelete,
ActionTrackerResourceCreate,
ActionTrackerResourceUpdate,
ActionTrackerResourceDelete,
},
ScopeV1RiskRead: {
ActionRiskGet,
ActionRiskList,
ActionRiskAssessmentGet,
ActionRiskAssessmentList,
ActionRiskAssessmentScopeGet,
ActionRiskAssessmentScopeList,
ActionRiskAssessmentNodeGet,
ActionRiskAssessmentNodeList,
ActionRiskAssessmentBoundaryGet,
ActionRiskAssessmentBoundaryList,
ActionRiskAssessmentProcessGet,
ActionRiskAssessmentProcessList,
ActionRiskAssessmentThreatGet,
ActionRiskAssessmentThreatList,
ActionRiskAssessmentScenarioGet,
ActionRiskAssessmentScenarioList,
},
ScopeV1Risk: {
ActionRiskCreate,
ActionRiskUpdate,
ActionRiskDelete,
ActionRiskMeasureMappingCreate,
ActionRiskMeasureMappingDelete,
ActionRiskDocumentMappingCreate,
ActionRiskDocumentMappingDelete,
ActionRiskObligationMappingCreate,
ActionRiskObligationMappingDelete,
ActionRiskPublish,
ActionRiskAssessmentCreate,
ActionRiskAssessmentUpdate,
ActionRiskAssessmentDelete,
ActionRiskAssessmentScopeCreate,
ActionRiskAssessmentScopeUpdate,
ActionRiskAssessmentScopeDelete,
ActionRiskAssessmentNodeCreate,
ActionRiskAssessmentNodeUpdate,
ActionRiskAssessmentNodeDelete,
ActionRiskAssessmentBoundaryCreate,
ActionRiskAssessmentBoundaryUpdate,
ActionRiskAssessmentBoundaryDelete,
ActionRiskAssessmentProcessCreate,
ActionRiskAssessmentProcessUpdate,
ActionRiskAssessmentProcessDelete,
ActionRiskAssessmentThreatCreate,
ActionRiskAssessmentThreatUpdate,
ActionRiskAssessmentThreatDelete,
ActionRiskAssessmentScenarioCreate,
ActionRiskAssessmentScenarioUpdate,
ActionRiskAssessmentScenarioDelete,
ActionRiskAssessmentScenarioThreatLink,
ActionRiskAssessmentScenarioThreatUnlink,
ActionRiskAssessmentScenarioRiskLink,
ActionRiskAssessmentScenarioRiskUnlink,
},
ScopeV1SlackConnectionRead: {
ActionSlackConnectionList,
},
ScopeV1TaskRead: {
ActionTaskGet,
ActionTaskList,
ActionEvidenceList,
},
ScopeV1Task: {
ActionTaskCreate,
ActionTaskUpdate,
ActionTaskDelete,
ActionTaskAssign,
ActionTaskUnassign,
ActionEvidenceDelete,
},
ScopeV1ThirdPartyRead: {
ActionThirdPartyList,
ActionThirdPartyGet,
ActionThirdPartyRelationList,
ActionThirdPartyContactGet,
ActionThirdPartyContactList,
ActionThirdPartyServiceGet,
ActionThirdPartyServiceList,
ActionThirdPartyComplianceReportGet,
ActionThirdPartyComplianceReportList,
ActionThirdPartyBusinessAssociateAgreementGet,
ActionThirdPartyDataPrivacyAgreementGet,
ActionThirdPartyRiskAssessmentList,
},
ScopeV1ThirdParty: {
ActionThirdPartyCreate,
ActionThirdPartyUpdate,
ActionThirdPartyDelete,
ActionThirdPartyVet,
ActionThirdPartyPublish,
ActionThirdPartyRelationCreate,
ActionThirdPartyContactCreate,
ActionThirdPartyContactUpdate,
ActionThirdPartyContactDelete,
ActionThirdPartyServiceCreate,
ActionThirdPartyServiceUpdate,
ActionThirdPartyServiceDelete,
ActionThirdPartyComplianceReportUpload,
ActionThirdPartyComplianceReportDelete,
ActionThirdPartyBusinessAssociateAgreementUpload,
ActionThirdPartyBusinessAssociateAgreementUpdate,
ActionThirdPartyBusinessAssociateAgreementDelete,
ActionThirdPartyDataPrivacyAgreementUpload,
ActionThirdPartyDataPrivacyAgreementUpdate,
ActionThirdPartyDataPrivacyAgreementDelete,
ActionThirdPartyRiskAssessmentCreate,
},
ScopeV1WebhookRead: {
ActionWebhookSubscriptionList,
ActionWebhookSubscriptionGet,
},
ScopeV1Webhook: {
ActionWebhookSubscriptionCreate,
ActionWebhookSubscriptionUpdate,
ActionWebhookSubscriptionDelete,
},
}

View File

@@ -149,7 +149,7 @@ func NewService(
}
iamService.Authorizer.RegisterPolicySet(ProboPolicySet())
iamService.Authorizer.RegisterScopes(OAuth2ScopeSet())
iamService.OAuth2ScopeSet.Register(OAuth2ScopeMappings)
svc := &Service{
pg: pgClient,

View File

@@ -601,8 +601,8 @@ func (impl *Implm) Run(
iamService.Authorizer.RegisterPolicySet(agentrun.PolicySet())
iamService.Authorizer.RegisterPolicySet(accessreview.PolicySet())
iamService.Authorizer.RegisterScopes(agentrun.OAuth2ScopeSet())
iamService.Authorizer.RegisterScopes(accessreview.OAuth2ScopeSet())
iamService.OAuth2ScopeSet.Register(agentrun.OAuth2ScopeMappings)
iamService.OAuth2ScopeSet.Register(accessreview.OAuth2ScopeMappings)
thirdPartyService := thirdparty.NewService(pgClient, fileManagerService, thirdPartyVetter)
riskManagementService := riskmanagement.NewService(pgClient)

View File

@@ -268,7 +268,7 @@ func (r *queryResolver) SignUpEnabled(ctx context.Context) (bool, error) {
// Oauth2ScopesSupported is the resolver for the oauth2ScopesSupported field.
func (r *queryResolver) Oauth2ScopesSupported(ctx context.Context) ([]string, error) {
apiScopes := r.iam.Authorizer.APIScopes()
apiScopes := r.iam.OAuth2ScopeSet.APIScopes()
scopes := make([]string, len(apiScopes))
for i, scope := range apiScopes {

View File

@@ -40,7 +40,7 @@ func (r *mutationResolver) CreateOAuth2AccessToken(ctx context.Context, input ty
Name: strings.TrimSpace(input.Name),
ExpiresAt: input.ExpiresAt,
Scopes: scopes,
AllowedAPIScopes: r.iam.Authorizer.APIScopes(),
AllowedAPIScopes: r.iam.OAuth2ScopeSet.APIScopes(),
},
)
if err != nil {