Add membership setting function (#1259)
This commit is contained in:
1 parent
7da892a054
commit
4363a4084e
14 files changed
+783
-63
No files matched your search
@@ -82,14 +82,14 @@ func (mg *ManagedGroup) SetTableName(n string) {
|
||||
}
|
||||
|
||||
// oplog will create oplog metadata for the ManagedGroup.
|
||||
func (c *ManagedGroup) oplog(op oplog.OpType, authMethodScopeId string) oplog.Metadata {
|
||||
func (mg *ManagedGroup) oplog(op oplog.OpType, authMethodScopeId string) oplog.Metadata {
|
||||
metadata := oplog.Metadata{
|
||||
"resource-public-id": []string{c.GetPublicId()},
|
||||
"resource-public-id": []string{mg.GetPublicId()},
|
||||
"resource-type": []string{"oidc managed group"},
|
||||
"op-type": []string{op.String()},
|
||||
}
|
||||
if c.AuthMethodId != "" {
|
||||
metadata["auth-method-id"] = []string{c.AuthMethodId}
|
||||
if mg.AuthMethodId != "" {
|
||||
metadata["auth-method-id"] = []string{mg.AuthMethodId}
|
||||
}
|
||||
if authMethodScopeId != "" {
|
||||
metadata["scope-id"] = []string{authMethodScopeId}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc/store"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// defaultManagedGroupMemberAccountTableName defines the default table name for a Managed Group
|
||||
const defaultManagedGroupMemberAccountTableName = "auth_oidc_managed_group_member_account"
|
||||
|
||||
// ManagedGroupMemberAccount contains a mapping between a managed group and a
|
||||
// member account
|
||||
type ManagedGroupMemberAccount struct {
|
||||
*store.ManagedGroupMemberAccount
|
||||
tableName string
|
||||
}
|
||||
|
||||
// NewManagedGroupMemberAccount creates a new in memory
|
||||
// ManagedGroupMemberAccount assigned to a managed group within an OIDC
|
||||
// AuthMethod. Supported options are withName and withDescription.
|
||||
func NewManagedGroupMemberAccount(managedGroupId string, memberId string, opt ...Option) (*ManagedGroupMemberAccount, error) {
|
||||
const op = "oidc.NewManagedGroupMemberAccount"
|
||||
mg := &ManagedGroupMemberAccount{
|
||||
ManagedGroupMemberAccount: &store.ManagedGroupMemberAccount{
|
||||
ManagedGroupId: managedGroupId,
|
||||
MemberId: memberId,
|
||||
},
|
||||
}
|
||||
if err := mg.validate(op); err != nil {
|
||||
return nil, err // intentionally not wrapped.
|
||||
}
|
||||
|
||||
return mg, nil
|
||||
}
|
||||
|
||||
// validate the ManagedGroupMemberAccount. On success, it will return nil.
|
||||
func (mg *ManagedGroupMemberAccount) validate(caller errors.Op) error {
|
||||
if mg.ManagedGroupId == "" {
|
||||
return errors.New(errors.InvalidParameter, caller, "missing managed group id")
|
||||
}
|
||||
if mg.MemberId == "" {
|
||||
return errors.New(errors.InvalidParameter, caller, "missing member id")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllocManagedGroupMemberAccount makes an empty one in memory
|
||||
func AllocManagedGroupMemberAccount() *ManagedGroupMemberAccount {
|
||||
return &ManagedGroupMemberAccount{
|
||||
ManagedGroupMemberAccount: &store.ManagedGroupMemberAccount{},
|
||||
}
|
||||
}
|
||||
|
||||
// Clone a ManagedGroupMemberAccount.
|
||||
func (mg *ManagedGroupMemberAccount) Clone() *ManagedGroupMemberAccount {
|
||||
cp := proto.Clone(mg.ManagedGroupMemberAccount)
|
||||
return &ManagedGroupMemberAccount{
|
||||
ManagedGroupMemberAccount: cp.(*store.ManagedGroupMemberAccount),
|
||||
}
|
||||
}
|
||||
|
||||
// TableName returns the table name.
|
||||
func (mg *ManagedGroupMemberAccount) TableName() string {
|
||||
if mg.tableName != "" {
|
||||
return mg.tableName
|
||||
}
|
||||
return defaultManagedGroupMemberAccountTableName
|
||||
}
|
||||
|
||||
// SetTableName sets the table name.
|
||||
func (mg *ManagedGroupMemberAccount) SetTableName(n string) {
|
||||
mg.tableName = n
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package oidc
|
||||
import (
|
||||
"crypto/x509"
|
||||
"net/url"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
)
|
||||
|
||||
// getOpts - iterate the inbound Options and return a struct.
|
||||
@@ -42,6 +44,7 @@ type options struct {
|
||||
withIssuer *url.URL
|
||||
withOperationalState AuthMethodState
|
||||
withAccountClaimMap map[string]AccountToClaim
|
||||
withReader db.Reader
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
@@ -218,3 +221,11 @@ func WithAccountClaimMap(acm map[string]AccountToClaim) Option {
|
||||
o.withAccountClaimMap = acm
|
||||
}
|
||||
}
|
||||
|
||||
// WithReader provides an option for specifying a reader to use for the
|
||||
// operation.
|
||||
func WithReader(reader db.Reader) Option {
|
||||
return func(o *options) {
|
||||
o.withReader = reader
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -194,4 +195,12 @@ func Test_GetOpts(t *testing.T) {
|
||||
testOpts.withAccountClaimMap = acm
|
||||
assert.Equal(opts, testOpts)
|
||||
})
|
||||
t.Run("WithReader", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
testOpts := getDefaultOptions()
|
||||
assert.Nil(testOpts.withReader)
|
||||
var r db.Reader
|
||||
opts := getOpts(WithReader(r))
|
||||
assert.Equal(r, opts.withReader)
|
||||
})
|
||||
}
|
||||
@@ -2,14 +2,14 @@ package oidc
|
||||
|
||||
const (
|
||||
acctUpsertQuery = `
|
||||
insert into auth_oidc_account
|
||||
insert into auth_oidc_account
|
||||
(%s)
|
||||
values
|
||||
values
|
||||
(%s)
|
||||
on conflict on constraint
|
||||
on conflict on constraint
|
||||
auth_oidc_account_auth_method_id_issuer_subject_uq
|
||||
do update set
|
||||
do update set
|
||||
%s
|
||||
returning public_id, version
|
||||
`
|
||||
returning public_id, version
|
||||
`
|
||||
)
|
||||
@@ -0,0 +1,216 @@
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/oplog"
|
||||
)
|
||||
|
||||
// SetManagedGroupMemberships will set the managed groups for the given account
|
||||
// ID. If mgs is empty, the set of groups the account belongs to will be
|
||||
// cleared. It returns the set of managed group IDs.
|
||||
//
|
||||
// mgs contains the set of managed groups that matched. It must contain the
|
||||
// group's version as this is used to ensure consistency between when the filter
|
||||
// attached to the managed group was run and the point at which we are adding
|
||||
// the account to the group.
|
||||
func (r *Repository) SetManagedGroupMemberships(ctx context.Context, am *AuthMethod, acct *Account, mgs []*ManagedGroup, _ ...Option) ([]*ManagedGroupMemberAccount, int, error) {
|
||||
const op = "oidc.(Repository).SetManagedGroupMemberships"
|
||||
if am == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing auth method")
|
||||
}
|
||||
if am.AuthMethod == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing auth method store")
|
||||
}
|
||||
if am.PublicId == "" {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing auth method id")
|
||||
}
|
||||
if am.ScopeId == "" {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing auth method scope id")
|
||||
}
|
||||
if acct == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing account")
|
||||
}
|
||||
if acct.Account == nil {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing account store")
|
||||
}
|
||||
if acct.PublicId == "" {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, "missing account id")
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, am.ScopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return nil, db.NoRowsAffected, errors.Wrap(err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
|
||||
newMgPublicIds := make(map[string]bool, len(mgs))
|
||||
mgsToUpdate := make([]*ManagedGroup, 0, len(mgs))
|
||||
for _, mg := range mgs {
|
||||
if mg.Version == 0 {
|
||||
return nil, db.NoRowsAffected, errors.New(errors.InvalidParameter, op, fmt.Sprintf("missing version for managed group %s", mg.PublicId))
|
||||
}
|
||||
if newMgPublicIds[mg.PublicId] {
|
||||
// We've already seen this -- could be a duplicate in the incoming
|
||||
// MGs. We don't want to add it again because the version won't be
|
||||
// correct, and it's unnecessary.
|
||||
continue
|
||||
}
|
||||
newMgPublicIds[mg.PublicId] = true
|
||||
mgToUpdate := AllocManagedGroup()
|
||||
mgToUpdate.PublicId = mg.PublicId
|
||||
mgToUpdate.AuthMethodId = am.PublicId
|
||||
mgToUpdate.Version = mg.Version + 1
|
||||
mgsToUpdate = append(mgsToUpdate, mgToUpdate)
|
||||
}
|
||||
|
||||
ticketMg := AllocManagedGroup()
|
||||
var totalRowsAffected int
|
||||
var currentMemberships []*ManagedGroupMemberAccount
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(reader db.Reader, w db.Writer) error {
|
||||
// We need a ticket, which won't be redeemed until all the other
|
||||
// writes are successful. We can't just use a single ticket because
|
||||
// we need to write oplog entries for deletes and adds.
|
||||
mgTicket, err := w.GetTicket(ticketMg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to get ticket for oidc managed groups"))
|
||||
}
|
||||
|
||||
msgs := make([]*oplog.Message, 0, len(mgs)+5)
|
||||
metadata := oplog.Metadata{
|
||||
"op-type": []string{oplog.OpType_OP_TYPE_UPDATE.String()},
|
||||
"scope-id": []string{am.ScopeId},
|
||||
"auth-method-id": []string{am.PublicId},
|
||||
"account-id": []string{acct.PublicId},
|
||||
}
|
||||
|
||||
// Ensure that none of the filters have changed or will change
|
||||
// during this operation
|
||||
for _, mgToUpdate := range mgsToUpdate {
|
||||
var mgOplogMsg oplog.Message
|
||||
// mgToUpdate will have come in with an incremented version
|
||||
// already, but WithVersion needs the current version
|
||||
prevVersion := mgToUpdate.Version - 1
|
||||
rowsUpdated, err := w.Update(ctx, mgToUpdate, []string{"Version"}, nil, db.NewOplogMsg(&mgOplogMsg), db.WithVersion(&prevVersion))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op)
|
||||
}
|
||||
if rowsUpdated != 1 {
|
||||
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("updated oidc managed group and %d rows updated", rowsUpdated))
|
||||
}
|
||||
msgs = append(msgs, &mgOplogMsg)
|
||||
}
|
||||
|
||||
currentMemberships, err = r.ListManagedGroupMembershipsByMember(ctx, acct.PublicId, WithReader(reader))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to retrieve current managed group memberships before deletion"))
|
||||
}
|
||||
|
||||
// Figure out which ones to delete and which ones we already have
|
||||
toDelete := make([]interface{}, 0, len(mgs))
|
||||
for _, currMg := range currentMemberships {
|
||||
currMgId := currMg.ManagedGroupId
|
||||
if newMgPublicIds[currMgId] {
|
||||
// We're slated to add it in, but it's already in there, so
|
||||
// take it out of the new list
|
||||
delete(newMgPublicIds, currMgId)
|
||||
} else {
|
||||
// It's not currently matching a filter, so needs to be deleted
|
||||
delMg := AllocManagedGroupMemberAccount()
|
||||
delMg.ManagedGroupId = currMgId
|
||||
delMg.MemberId = acct.PublicId
|
||||
toDelete = append(toDelete, delMg)
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, anything in toDelete should be deleted, and
|
||||
// anything left in newMgPublicIds should be added. However, if we
|
||||
// had no managed group to update, because none were passed in, but
|
||||
// also none to delete, we return at this point. Nothing will have
|
||||
// changed and nothing will be changed either.
|
||||
if len(mgs) == 0 && len(toDelete) == 0 {
|
||||
return errors.New(errors.GracefullyAborted, op, "nothing to do")
|
||||
}
|
||||
|
||||
// Start with deletion
|
||||
if len(toDelete) > 0 {
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_DELETE.String())
|
||||
deleteOplogMsgs := make([]*oplog.Message, 0, len(toDelete))
|
||||
rowsDeleted, err := w.DeleteItems(ctx, toDelete, db.NewOplogMsgs(&deleteOplogMsgs))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to delete managed group member accounts"))
|
||||
}
|
||||
if rowsDeleted != len(toDelete) {
|
||||
return errors.New(errors.MultipleRecords, op, fmt.Sprintf("managed group member accounts deleted %d did not match request for %d", rowsDeleted, len(toDelete)))
|
||||
}
|
||||
totalRowsAffected += rowsDeleted
|
||||
msgs = append(msgs, deleteOplogMsgs...)
|
||||
}
|
||||
|
||||
// Now do insertion
|
||||
if len(newMgPublicIds) > 0 {
|
||||
metadata["op-type"] = append(metadata["op-type"], oplog.OpType_OP_TYPE_CREATE.String())
|
||||
addOplogMsgs := make([]*oplog.Message, 0, len(newMgPublicIds))
|
||||
toAdd := make([]interface{}, 0, len(newMgPublicIds))
|
||||
for mgId := range newMgPublicIds {
|
||||
newMg := AllocManagedGroupMemberAccount()
|
||||
newMg.ManagedGroupId = mgId
|
||||
newMg.MemberId = acct.PublicId
|
||||
toAdd = append(toAdd, newMg)
|
||||
}
|
||||
if err := w.CreateItems(ctx, toAdd, db.NewOplogMsgs(&addOplogMsgs)); err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to add managed group member accounts"))
|
||||
}
|
||||
totalRowsAffected += len(toAdd)
|
||||
msgs = append(msgs, addOplogMsgs...)
|
||||
}
|
||||
|
||||
if len(msgs) > 0 {
|
||||
if err := w.WriteOplogEntryWith(ctx, oplogWrapper, mgTicket, metadata, msgs); err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to write oplog"))
|
||||
}
|
||||
}
|
||||
|
||||
currentMemberships, err = r.ListManagedGroupMembershipsByMember(ctx, acct.PublicId, WithReader(reader))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, op, errors.WithMsg("unable to retrieve current managed group memberships after set"))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil && !errors.Match(errors.T(errors.GracefullyAborted), err) {
|
||||
return nil, db.NoRowsAffected, errors.Wrap(err, op)
|
||||
}
|
||||
return currentMemberships, totalRowsAffected, nil
|
||||
}
|
||||
|
||||
// ListManagedGroupMembershipsByMember lists managed group memberships via the
|
||||
// member (account) ID and supports WithLimit option.
|
||||
func (r *Repository) ListManagedGroupMembershipsByMember(ctx context.Context, withAcctId string, opt ...Option) ([]*ManagedGroupMemberAccount, error) {
|
||||
const op = "oidc.(Repository).ListManagedGroupMembershipsByMember"
|
||||
if withAcctId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing account id")
|
||||
}
|
||||
opts := getOpts(opt...)
|
||||
limit := r.defaultLimit
|
||||
if opts.withLimit != 0 {
|
||||
// non-zero signals an override of the default limit for the repo.
|
||||
limit = opts.withLimit
|
||||
}
|
||||
reader := r.reader
|
||||
if opts.withReader != nil {
|
||||
reader = opts.withReader
|
||||
}
|
||||
var mgs []*ManagedGroupMemberAccount
|
||||
err := reader.SearchWhere(ctx, &mgs, "member_id = ?", []interface{}{withAcctId}, db.WithLimit(limit))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return mgs, nil
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc/store"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/servers/controller"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testFakeManagedGroupFilter = `"/foo" == "bar"`
|
||||
|
||||
func Test_ManagedGroupMemberships(t *testing.T) {
|
||||
// This tests both managed group membership functions (set/list) as list is
|
||||
// always called as a return from set and we are validating the values that
|
||||
// come back against what we expect.
|
||||
|
||||
// This test can be run in parallel; the subtests *cannot*.
|
||||
t.Parallel()
|
||||
|
||||
// Note: using a test controller here for ease of setup as we need a working
|
||||
// dev OIDC auth method and associated accounts. This test is not making API
|
||||
// calls! It's accessing the repo directly via the test controller's
|
||||
// exposure of the underlying DB primitives.
|
||||
tc := controller.NewTestController(t, nil)
|
||||
defer tc.Shutdown()
|
||||
|
||||
conn := tc.DbConn()
|
||||
rw := db.New(conn)
|
||||
|
||||
kmsCache := tc.Kms()
|
||||
iamRepo := tc.IamRepo()
|
||||
org, _ := iam.TestScopes(t, iamRepo)
|
||||
|
||||
ctx := context.Background()
|
||||
databaseWrapper, err := kmsCache.GetWrapper(ctx, org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
|
||||
authMethod := oidc.TestAuthMethod(
|
||||
t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePrivateState,
|
||||
"alice-rp", "fido",
|
||||
oidc.WithSigningAlgs(oidc.RS256),
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://www.alice.com")[0]),
|
||||
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
|
||||
repo, err := oidc.NewRepository(rw, rw, kmsCache)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, repo)
|
||||
|
||||
mgs := make([]*oidc.ManagedGroup, 0, 10)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
mg := oidc.AllocManagedGroup()
|
||||
mg.AuthMethodId = authMethod.PublicId
|
||||
mg.Filter = testFakeManagedGroupFilter
|
||||
got, err := repo.CreateManagedGroup(context.Background(), org.GetPublicId(), mg)
|
||||
require.NoError(t, err)
|
||||
mgs = append(mgs, got)
|
||||
}
|
||||
|
||||
// Fetch valid OIDC accounts. One will be "static" where we will simply
|
||||
// ensure modifying the groups for the other doesn't affect it; the other
|
||||
// will be used for testing.
|
||||
var accts []*oidc.Account
|
||||
err = rw.SearchWhere(ctx, &accts, "", nil, db.WithLimit(2))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, accts, 2)
|
||||
staticAccountId := accts[0].PublicId
|
||||
staticMembershipCount := 20
|
||||
accountId := accts[1].PublicId
|
||||
|
||||
account := oidc.AllocAccount()
|
||||
account.PublicId = accountId
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
// If true, we will auto populate necesary values into the function
|
||||
validPrereqs bool
|
||||
|
||||
// Else these can be used for testing
|
||||
authMethod *oidc.AuthMethod
|
||||
authMethodId string
|
||||
account *oidc.Account
|
||||
accountId string
|
||||
authMethodScopeId string
|
||||
wantPreseededMgsCount int
|
||||
wantMgsCount int
|
||||
specificMgs []*oidc.ManagedGroup
|
||||
|
||||
wantErr errors.Code
|
||||
wantErrContains string
|
||||
}{
|
||||
{
|
||||
name: "nil auth method",
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing auth method",
|
||||
},
|
||||
{
|
||||
name: "missing auth method store",
|
||||
authMethod: &oidc.AuthMethod{},
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing auth method store",
|
||||
},
|
||||
{
|
||||
name: "missing auth method id",
|
||||
authMethod: &oidc.AuthMethod{AuthMethod: &store.AuthMethod{}},
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing auth method id",
|
||||
},
|
||||
{
|
||||
name: "missing auth method scope id",
|
||||
authMethod: &oidc.AuthMethod{AuthMethod: &store.AuthMethod{PublicId: authMethod.PublicId}},
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing auth method scope id",
|
||||
},
|
||||
{
|
||||
name: "missing account",
|
||||
authMethod: authMethod,
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing account",
|
||||
},
|
||||
{
|
||||
name: "missing account store",
|
||||
authMethod: authMethod,
|
||||
account: &oidc.Account{},
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing account store",
|
||||
},
|
||||
{
|
||||
name: "missing account id",
|
||||
authMethod: authMethod,
|
||||
account: &oidc.Account{Account: &store.Account{}},
|
||||
wantErr: errors.InvalidParameter,
|
||||
wantErrContains: "missing account id",
|
||||
},
|
||||
{
|
||||
name: "valid fixed, static",
|
||||
validPrereqs: true,
|
||||
accountId: staticAccountId,
|
||||
specificMgs: mgs[0:staticMembershipCount],
|
||||
},
|
||||
{
|
||||
name: "valid fixed",
|
||||
validPrereqs: true,
|
||||
specificMgs: mgs[0:20],
|
||||
},
|
||||
{
|
||||
name: "valid fixed, same values",
|
||||
validPrereqs: true,
|
||||
specificMgs: mgs[0:20],
|
||||
},
|
||||
{
|
||||
name: "valid fixed, new values",
|
||||
validPrereqs: true,
|
||||
specificMgs: mgs[20:40],
|
||||
},
|
||||
{
|
||||
name: "valid none",
|
||||
validPrereqs: true,
|
||||
wantMgsCount: 0,
|
||||
},
|
||||
{
|
||||
name: "valid none, second test, testing gracefully aborting",
|
||||
validPrereqs: true,
|
||||
wantMgsCount: 0,
|
||||
},
|
||||
{
|
||||
name: "valid fixed, prep for random",
|
||||
validPrereqs: true,
|
||||
specificMgs: mgs[20:50],
|
||||
},
|
||||
{
|
||||
name: "valid random",
|
||||
validPrereqs: true,
|
||||
wantMgsCount: 30,
|
||||
},
|
||||
{
|
||||
name: "valid random, second test",
|
||||
validPrereqs: true,
|
||||
wantMgsCount: 20,
|
||||
},
|
||||
{
|
||||
name: "valid with duplicates",
|
||||
validPrereqs: true,
|
||||
specificMgs: append(mgs[0:20], mgs[0:20]...),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
// We are intentionally carrying things over between tests to be
|
||||
// more realistic but that means we need correct versions, so update
|
||||
// them first.
|
||||
currMgs, err := repo.ListManagedGroups(ctx, authMethod.PublicId)
|
||||
require.NoError(err)
|
||||
require.Len(currMgs, 100)
|
||||
currVersionMap := make(map[string]uint32, len(currMgs))
|
||||
for _, currMg := range currMgs {
|
||||
currVersionMap[currMg.PublicId] = currMg.Version
|
||||
}
|
||||
for _, mg := range mgs {
|
||||
mg.Version = currVersionMap[mg.PublicId]
|
||||
}
|
||||
|
||||
var mgsToTest []*oidc.ManagedGroup
|
||||
var finalMgs map[string]*oidc.ManagedGroup
|
||||
// If we know the inputs are sane, create the test data
|
||||
if tt.validPrereqs {
|
||||
tt.authMethod = authMethod
|
||||
tt.account = oidc.AllocAccount()
|
||||
tt.account.PublicId = accountId
|
||||
if tt.accountId != "" {
|
||||
// This is for the test where we initially populate the
|
||||
// static account
|
||||
tt.account.PublicId = tt.accountId
|
||||
}
|
||||
mgsToTest = tt.specificMgs
|
||||
if mgsToTest == nil {
|
||||
// Select at random
|
||||
mgsToTest = make([]*oidc.ManagedGroup, tt.wantMgsCount)
|
||||
for i := 0; i < tt.wantMgsCount; i++ {
|
||||
mg := mgs[rand.Int()%len(mgs)]
|
||||
mgsToTest[i] = mg
|
||||
}
|
||||
}
|
||||
finalMgs = make(map[string]*oidc.ManagedGroup)
|
||||
for _, v := range mgsToTest {
|
||||
finalMgs[v.PublicId] = v
|
||||
}
|
||||
}
|
||||
|
||||
memberships, _, err := repo.SetManagedGroupMemberships(ctx, tt.authMethod, tt.account, mgsToTest)
|
||||
if tt.wantErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "Unexpected error %s", err)
|
||||
if tt.wantErrContains != "" {
|
||||
assert.True(strings.Contains(err.Error(), tt.wantErrContains))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
assert.Len(memberships, len(finalMgs))
|
||||
|
||||
// Ensure the same set was found; all memberships found should have
|
||||
// been in the finalMgs map, and when they are all removed there
|
||||
// should be nothing left.
|
||||
for _, mship := range memberships {
|
||||
assert.Contains(finalMgs, mship.ManagedGroupId)
|
||||
delete(finalMgs, mship.ManagedGroupId)
|
||||
}
|
||||
assert.Len(finalMgs, 0)
|
||||
|
||||
// Now check that the static account still has the same memberships
|
||||
memberships, err = repo.ListManagedGroupMembershipsByMember(ctx, staticAccountId)
|
||||
require.NoError(err)
|
||||
assert.Len(memberships, staticMembershipCount)
|
||||
finalMgs = make(map[string]*oidc.ManagedGroup, staticMembershipCount)
|
||||
for _, mg := range mgs[0:staticMembershipCount] {
|
||||
finalMgs[mg.PublicId] = mg
|
||||
}
|
||||
for _, mship := range memberships {
|
||||
assert.Contains(finalMgs, mship.ManagedGroupId)
|
||||
delete(finalMgs, mship.ManagedGroupId)
|
||||
}
|
||||
assert.Len(finalMgs, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testFakeFilter = `"/foo" == "bar"`
|
||||
const testFakeManagedGroupFilter = `"/foo" == "bar"`
|
||||
|
||||
func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
@@ -91,7 +91,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
PublicId: "mgoidc_OOOOOOOOOO",
|
||||
},
|
||||
},
|
||||
@@ -103,7 +103,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
},
|
||||
},
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
@@ -115,13 +115,13 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
},
|
||||
},
|
||||
want: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -131,14 +131,14 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
Name: "test-name-repo",
|
||||
},
|
||||
},
|
||||
want: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
Name: "test-name-repo",
|
||||
},
|
||||
},
|
||||
@@ -149,7 +149,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
Description: ("test-description-repo"),
|
||||
Name: "myname",
|
||||
},
|
||||
@@ -157,7 +157,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
want: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
Description: ("test-description-repo"),
|
||||
Name: "myname",
|
||||
},
|
||||
@@ -169,7 +169,7 @@ func TestRepository_CreateManagedGroup(t *testing.T) {
|
||||
in: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
AuthMethodId: authMethod.PublicId,
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
Description: ("test-description-repo"),
|
||||
Name: "myname",
|
||||
},
|
||||
@@ -231,7 +231,7 @@ func TestRepository_LookupManagedGroup(t *testing.T) {
|
||||
WithIssuer(TestConvertToUrls(t, "https://www.alice.com")[0]),
|
||||
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
mg := TestManagedGroup(t, conn, authMethod, testFakeFilter)
|
||||
mg := TestManagedGroup(t, conn, authMethod, testFakeManagedGroupFilter)
|
||||
|
||||
newMgId, err := newManagedGroupId()
|
||||
require.NoError(t, err)
|
||||
@@ -296,7 +296,7 @@ func TestRepository_DeleteManagedGroup(t *testing.T) {
|
||||
WithIssuer(TestConvertToUrls(t, "https://www.alice.com")[0]),
|
||||
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
mg := TestManagedGroup(t, conn, authMethod, testFakeFilter)
|
||||
mg := TestManagedGroup(t, conn, authMethod, testFakeManagedGroupFilter)
|
||||
newMgId, err := newManagedGroupId()
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
@@ -387,18 +387,18 @@ func TestRepository_ListManagedGroups(t *testing.T) {
|
||||
WithApiUrl(TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
mgs1 := []*ManagedGroup{
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
|
||||
TestManagedGroup(t, conn, authMethod1, testFakeManagedGroupFilter),
|
||||
}
|
||||
sort.Slice(mgs1, func(i, j int) bool {
|
||||
return strings.Compare(mgs1[i].PublicId, mgs1[j].PublicId) < 0
|
||||
})
|
||||
|
||||
mgs2 := []*ManagedGroup{
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeFilter),
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
|
||||
TestManagedGroup(t, conn, authMethod2, testFakeManagedGroupFilter),
|
||||
}
|
||||
sort.Slice(mgs2, func(i, j int) bool {
|
||||
return strings.Compare(mgs2[i].PublicId, mgs2[j].PublicId) < 0
|
||||
@@ -789,7 +789,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
|
||||
version: 1,
|
||||
orig: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
},
|
||||
},
|
||||
chgFn: changeFilter(`"/zip" == "zap"`),
|
||||
@@ -865,7 +865,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
|
||||
version: 1,
|
||||
orig: &ManagedGroup{
|
||||
ManagedGroup: &store.ManagedGroup{
|
||||
Filter: testFakeFilter,
|
||||
Filter: testFakeManagedGroupFilter,
|
||||
},
|
||||
},
|
||||
masks: []string{FilterField},
|
||||
@@ -923,7 +923,7 @@ func TestRepository_UpdateManagedGroup(t *testing.T) {
|
||||
assert.NoError(err)
|
||||
require.NotNil(repo)
|
||||
|
||||
orig := TestManagedGroup(t, conn, am, testFakeFilter, WithName(tt.orig.GetName()), WithDescription(tt.orig.GetDescription()))
|
||||
orig := TestManagedGroup(t, conn, am, testFakeManagedGroupFilter, WithName(tt.orig.GetName()), WithDescription(tt.orig.GetDescription()))
|
||||
|
||||
tt.orig.AuthMethodId = am.PublicId
|
||||
if tt.chgFn != nil {
|
||||
|
||||
@@ -203,6 +203,8 @@ func Callback(
|
||||
return "", errors.Wrap(err, op)
|
||||
}
|
||||
|
||||
// Now we need to check filters and assign managed groups by filter.
|
||||
|
||||
// wow, we're getting close. we just need to create a pending token for this
|
||||
// successful authentication process, so it can be retrieved by the polling client
|
||||
// that initialed the authentication attempt.
|
||||
|
||||
@@ -948,6 +948,77 @@ func (x *ManagedGroup) GetFilter() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ManagedGroupMemberAccount contains a mapping between a managed group and a
|
||||
// member account.
|
||||
type ManagedGroupMemberAccount struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The create_time is set by the database.
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
CreateTime *timestamp.Timestamp `protobuf:"bytes,10,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty" gorm:"default:current_timestamp"`
|
||||
// managed_group_id is the fk to the oidc managed group public id
|
||||
// @inject_tag: `gorm:"primary_key"`
|
||||
ManagedGroupId string `protobuf:"bytes,20,opt,name=managed_group_id,json=managedGroupId,proto3" json:"managed_group_id,omitempty" gorm:"primary_key"`
|
||||
// member_id is the fk to the oidc account public id
|
||||
// @inject_tag: `gorm:"primary_key"`
|
||||
MemberId string `protobuf:"bytes,30,opt,name=member_id,json=memberId,proto3" json:"member_id,omitempty" gorm:"primary_key"`
|
||||
}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) Reset() {
|
||||
*x = ManagedGroupMemberAccount{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_controller_storage_auth_oidc_store_v1_oidc_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ManagedGroupMemberAccount) ProtoMessage() {}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_controller_storage_auth_oidc_store_v1_oidc_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ManagedGroupMemberAccount.ProtoReflect.Descriptor instead.
|
||||
func (*ManagedGroupMemberAccount) Descriptor() ([]byte, []int) {
|
||||
return file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) GetCreateTime() *timestamp.Timestamp {
|
||||
if x != nil {
|
||||
return x.CreateTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) GetManagedGroupId() string {
|
||||
if x != nil {
|
||||
return x.ManagedGroupId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ManagedGroupMemberAccount) GetMemberId() string {
|
||||
if x != nil {
|
||||
return x.MemberId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_controller_storage_auth_oidc_store_v1_oidc_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDesc = []byte{
|
||||
@@ -1159,11 +1230,22 @@ var file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDesc = []byte{
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
|
||||
0x72, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0xc2, 0xdd, 0x29, 0x10, 0x0a, 0x06, 0x46,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x61, 0x75, 0x74, 0x68, 0x2f, 0x6f, 0x69, 0x64, 0x63, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b,
|
||||
0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0xaf, 0x01, 0x0a, 0x19, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75,
|
||||
0x70, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x61, 0x6e, 0x61,
|
||||
0x67, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65,
|
||||
0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d,
|
||||
0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x64, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6f, 0x69, 0x64, 0x63, 0x2f, 0x73, 0x74, 0x6f, 0x72,
|
||||
0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -1178,35 +1260,37 @@ func file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDescGZIP() []byte
|
||||
return file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_controller_storage_auth_oidc_store_v1_oidc_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_controller_storage_auth_oidc_store_v1_oidc_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_controller_storage_auth_oidc_store_v1_oidc_proto_goTypes = []interface{}{
|
||||
(*AuthMethod)(nil), // 0: controller.storage.auth.oidc.store.v1.AuthMethod
|
||||
(*Account)(nil), // 1: controller.storage.auth.oidc.store.v1.Account
|
||||
(*SigningAlg)(nil), // 2: controller.storage.auth.oidc.store.v1.SigningAlg
|
||||
(*AudClaim)(nil), // 3: controller.storage.auth.oidc.store.v1.AudClaim
|
||||
(*Certificate)(nil), // 4: controller.storage.auth.oidc.store.v1.Certificate
|
||||
(*ClaimsScope)(nil), // 5: controller.storage.auth.oidc.store.v1.ClaimsScope
|
||||
(*AccountClaimMap)(nil), // 6: controller.storage.auth.oidc.store.v1.AccountClaimMap
|
||||
(*ManagedGroup)(nil), // 7: controller.storage.auth.oidc.store.v1.ManagedGroup
|
||||
(*timestamp.Timestamp)(nil), // 8: controller.storage.timestamp.v1.Timestamp
|
||||
(*AuthMethod)(nil), // 0: controller.storage.auth.oidc.store.v1.AuthMethod
|
||||
(*Account)(nil), // 1: controller.storage.auth.oidc.store.v1.Account
|
||||
(*SigningAlg)(nil), // 2: controller.storage.auth.oidc.store.v1.SigningAlg
|
||||
(*AudClaim)(nil), // 3: controller.storage.auth.oidc.store.v1.AudClaim
|
||||
(*Certificate)(nil), // 4: controller.storage.auth.oidc.store.v1.Certificate
|
||||
(*ClaimsScope)(nil), // 5: controller.storage.auth.oidc.store.v1.ClaimsScope
|
||||
(*AccountClaimMap)(nil), // 6: controller.storage.auth.oidc.store.v1.AccountClaimMap
|
||||
(*ManagedGroup)(nil), // 7: controller.storage.auth.oidc.store.v1.ManagedGroup
|
||||
(*ManagedGroupMemberAccount)(nil), // 8: controller.storage.auth.oidc.store.v1.ManagedGroupMemberAccount
|
||||
(*timestamp.Timestamp)(nil), // 9: controller.storage.timestamp.v1.Timestamp
|
||||
}
|
||||
var file_controller_storage_auth_oidc_store_v1_oidc_proto_depIdxs = []int32{
|
||||
8, // 0: controller.storage.auth.oidc.store.v1.AuthMethod.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 1: controller.storage.auth.oidc.store.v1.AuthMethod.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 2: controller.storage.auth.oidc.store.v1.Account.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 3: controller.storage.auth.oidc.store.v1.Account.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 4: controller.storage.auth.oidc.store.v1.SigningAlg.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 5: controller.storage.auth.oidc.store.v1.AudClaim.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 6: controller.storage.auth.oidc.store.v1.Certificate.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 7: controller.storage.auth.oidc.store.v1.ClaimsScope.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 8: controller.storage.auth.oidc.store.v1.AccountClaimMap.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 9: controller.storage.auth.oidc.store.v1.ManagedGroup.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
8, // 10: controller.storage.auth.oidc.store.v1.ManagedGroup.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
9, // 0: controller.storage.auth.oidc.store.v1.AuthMethod.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 1: controller.storage.auth.oidc.store.v1.AuthMethod.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 2: controller.storage.auth.oidc.store.v1.Account.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 3: controller.storage.auth.oidc.store.v1.Account.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 4: controller.storage.auth.oidc.store.v1.SigningAlg.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 5: controller.storage.auth.oidc.store.v1.AudClaim.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 6: controller.storage.auth.oidc.store.v1.Certificate.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 7: controller.storage.auth.oidc.store.v1.ClaimsScope.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 8: controller.storage.auth.oidc.store.v1.AccountClaimMap.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 9: controller.storage.auth.oidc.store.v1.ManagedGroup.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 10: controller.storage.auth.oidc.store.v1.ManagedGroup.update_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
9, // 11: controller.storage.auth.oidc.store.v1.ManagedGroupMemberAccount.create_time:type_name -> controller.storage.timestamp.v1.Timestamp
|
||||
12, // [12:12] is the sub-list for method output_type
|
||||
12, // [12:12] is the sub-list for method input_type
|
||||
12, // [12:12] is the sub-list for extension type_name
|
||||
12, // [12:12] is the sub-list for extension extendee
|
||||
0, // [0:12] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_controller_storage_auth_oidc_store_v1_oidc_proto_init() }
|
||||
@@ -1311,6 +1395,18 @@ func file_controller_storage_auth_oidc_store_v1_oidc_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_controller_storage_auth_oidc_store_v1_oidc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ManagedGroupMemberAccount); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -1318,7 +1414,7 @@ func file_controller_storage_auth_oidc_store_v1_oidc_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_controller_storage_auth_oidc_store_v1_oidc_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 8,
|
||||
NumMessages: 9,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@@ -79,6 +79,11 @@ const (
|
||||
MaxRetries Code = 1103 // MaxRetries represent that a db Tx hit max retires allowed
|
||||
Exception Code = 1104 // Exception represent that an underlying db exception was raised
|
||||
VersionMismatch Code = 1105 // VersionMismatch represents the update version and the db version for an entry do not match.
|
||||
// GracefullyAborted means we intended to abort a transaction but the
|
||||
// enclosing function should not treat it as an error; we aborted for
|
||||
// reasons related to the state of the DDL and/or inputs (such as we're
|
||||
// already in the right state and don't want to end up writing oplogs).
|
||||
GracefullyAborted Code = 1106
|
||||
|
||||
// Migration setup errors are codes 2000-2999
|
||||
MigrationIntegrity Code = 2000 // MigrationIntegrity represents an error with the generated migration related code
|
||||
|
||||
@@ -252,6 +252,11 @@ func TestCode_Both_String_Info(t *testing.T) {
|
||||
c: OidcProviderCallbackError,
|
||||
want: OidcProviderCallbackError,
|
||||
},
|
||||
{
|
||||
name: "GracefullyAborted",
|
||||
c: GracefullyAborted,
|
||||
want: GracefullyAborted,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -196,4 +196,8 @@ var errorCodeInfo = map[Code]Info{
|
||||
Message: "oidc provider callback error",
|
||||
Kind: External,
|
||||
},
|
||||
GracefullyAborted: {
|
||||
Message: "purposefully aborted without error",
|
||||
Kind: Other,
|
||||
},
|
||||
}
|
||||
@@ -285,4 +285,20 @@ message ManagedGroup {
|
||||
// filter is a go-bexpr filter
|
||||
// @inject_tag: `gorm:"not_null"`
|
||||
string filter = 80 [(custom_options.v1.mask_mapping) = { this: "Filter" that: "filter" }];
|
||||
}
|
||||
|
||||
// ManagedGroupMemberAccount contains a mapping between a managed group and a
|
||||
// member account.
|
||||
message ManagedGroupMemberAccount {
|
||||
// The create_time is set by the database.
|
||||
// @inject_tag: `gorm:"default:current_timestamp"`
|
||||
timestamp.v1.Timestamp create_time = 10;
|
||||
|
||||
// managed_group_id is the fk to the oidc managed group public id
|
||||
// @inject_tag: `gorm:"primary_key"`
|
||||
string managed_group_id = 20;
|
||||
|
||||
// member_id is the fk to the oidc account public id
|
||||
// @inject_tag: `gorm:"primary_key"`
|
||||
string member_id = 30;
|
||||
}
|
||||
Reference in new issue
Block a user