-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds CRUD service for Identity Center resources (#47609)
* Adds CRUD service for Identity Center resources This is just the pure CRUD read/write. Caching & watching support coming as necessary in subsequent PRs. Co-authored-by: Pawel Kopiczko <[email protected]> Co-authored-by: Sakshyam Shah <[email protected]> * Update identitycenter.go * linter appeasement --------- Co-authored-by: Pawel Kopiczko <[email protected]> Co-authored-by: Sakshyam Shah <[email protected]>
- Loading branch information
1 parent
28a6848
commit bc06d0f
Showing
10 changed files
with
1,046 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
// Teleport | ||
// Copyright (C) 2024 Gravitational, Inc. | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Affero General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package services | ||
|
||
import ( | ||
"context" | ||
|
||
"google.golang.org/protobuf/proto" | ||
|
||
identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" | ||
"github.com/gravitational/teleport/lib/utils/pagination" | ||
) | ||
|
||
// IdentityCenterAccount wraps a raw identity center record in a new type to | ||
// allow it to implement the interfaces required for use with the Unified | ||
// Resource listing. | ||
// | ||
// IdentityCenterAccount simply wraps a pointer to the underlying | ||
// identitycenterv1.Account record, and can be treated as a reference-like type. | ||
// Copies of an IdentityCenterAccount will point to the same record. | ||
type IdentityCenterAccount struct { | ||
// This wrapper needs to: | ||
// - implement the interfaces required for use with the Unified Resource | ||
// service. | ||
// - expose the existing interfaces & methods on the underlying | ||
// identitycenterv1.Account | ||
// - avoid copying the underlying identitycenterv1.Account due to embedded | ||
// mutexes in the protobuf-generated code | ||
// | ||
// Given those requirements, storing an embedded pointer seems to be the | ||
// least-bad approach. | ||
|
||
*identitycenterv1.Account | ||
} | ||
|
||
// CloneResource creates a deep copy of the underlying account resource | ||
func (a IdentityCenterAccount) CloneResource() IdentityCenterAccount { | ||
return IdentityCenterAccount{ | ||
Account: proto.Clone(a.Account).(*identitycenterv1.Account), | ||
} | ||
} | ||
|
||
// IdentityCenterAccountID is a strongly-typed Identity Center account ID. | ||
type IdentityCenterAccountID string | ||
|
||
// IdentityCenterAccountGetter provides read-only access to Identity Center | ||
// Account records | ||
type IdentityCenterAccountGetter interface { | ||
// ListIdentityCenterAccounts provides a paged list of all known identity | ||
// center accounts | ||
ListIdentityCenterAccounts(context.Context, int, *pagination.PageRequestToken) ([]IdentityCenterAccount, pagination.NextPageToken, error) | ||
|
||
// GetIdentityCenterAccount fetches a specific Identity Center Account | ||
GetIdentityCenterAccount(context.Context, IdentityCenterAccountID) (IdentityCenterAccount, error) | ||
} | ||
|
||
// IdentityCenterAccounts defines read/write access to Identity Center account | ||
// resources | ||
type IdentityCenterAccounts interface { | ||
IdentityCenterAccountGetter | ||
|
||
// CreateIdentityCenterAccount creates a new Identity Center Account record | ||
CreateIdentityCenterAccount(context.Context, IdentityCenterAccount) (IdentityCenterAccount, error) | ||
|
||
// UpdateIdentityCenterAccount performs a conditional update on an Identity | ||
// Center Account record, returning the updated record on success. | ||
UpdateIdentityCenterAccount(context.Context, IdentityCenterAccount) (IdentityCenterAccount, error) | ||
|
||
// UpsertIdentityCenterAccount performs an *unconditional* upsert on an | ||
// Identity Center Account record, returning the updated record on success. | ||
// Be careful when mixing UpsertIdentityCenterAccount() with resources | ||
// protected by optimistic locking | ||
UpsertIdentityCenterAccount(context.Context, IdentityCenterAccount) (IdentityCenterAccount, error) | ||
|
||
// DeleteIdentityCenterAccount deletes an Identity Center Account record | ||
DeleteIdentityCenterAccount(context.Context, IdentityCenterAccountID) error | ||
|
||
// DeleteAllIdentityCenterAccounts deletes all Identity Center Account records | ||
DeleteAllIdentityCenterAccounts(context.Context) error | ||
} | ||
|
||
// PrincipalAssignmentID is a strongly-typed ID for Identity Center Principal | ||
// Assignments | ||
type PrincipalAssignmentID string | ||
|
||
// IdentityCenterPrincipalAssignments defines operations on an Identity Center | ||
// principal assignment database | ||
type IdentityCenterPrincipalAssignments interface { | ||
// ListPrincipalAssignments lists all PrincipalAssignment records in the | ||
// service | ||
ListPrincipalAssignments(context.Context, int, *pagination.PageRequestToken) ([]*identitycenterv1.PrincipalAssignment, pagination.NextPageToken, error) | ||
|
||
// CreatePrincipalAssignment creates a new Principal Assignment record in | ||
// the service from the supplied in-memory representation. Returns the | ||
// created record on success. | ||
CreatePrincipalAssignment(context.Context, *identitycenterv1.PrincipalAssignment) (*identitycenterv1.PrincipalAssignment, error) | ||
|
||
// GetPrincipalAssignment fetches a specific Principal Assignment record. | ||
GetPrincipalAssignment(context.Context, PrincipalAssignmentID) (*identitycenterv1.PrincipalAssignment, error) | ||
|
||
// UpdatePrincipalAssignment performs a conditional update on a Principal | ||
// Assignment record | ||
UpdatePrincipalAssignment(context.Context, *identitycenterv1.PrincipalAssignment) (*identitycenterv1.PrincipalAssignment, error) | ||
|
||
// UpsertPrincipalAssignment performs an unconditional update on a Principal | ||
// Assignment record | ||
UpsertPrincipalAssignment(context.Context, *identitycenterv1.PrincipalAssignment) (*identitycenterv1.PrincipalAssignment, error) | ||
|
||
// DeletePrincipalAssignment deletes a specific principal assignment record | ||
DeletePrincipalAssignment(context.Context, PrincipalAssignmentID) error | ||
|
||
// DeleteAllPrincipalAssignments deletes all assignment record | ||
DeleteAllPrincipalAssignments(context.Context) error | ||
} | ||
|
||
// PermissionSetID is a strongly typed ID for an identitycenterv1.PermissionSet | ||
type PermissionSetID string | ||
|
||
// IdentityCenterPermissionSets defines the operations to create and maintain | ||
// identitycenterv1.PermissionSet records in the service. | ||
type IdentityCenterPermissionSets interface { | ||
// ListPermissionSets list the known Permission Sets | ||
ListPermissionSets(context.Context, int, *pagination.PageRequestToken) ([]*identitycenterv1.PermissionSet, pagination.NextPageToken, error) | ||
|
||
// CreatePermissionSet creates a new PermissionSet record based on the | ||
// supplied in-memory representation, returning the created record on | ||
// success | ||
CreatePermissionSet(context.Context, *identitycenterv1.PermissionSet) (*identitycenterv1.PermissionSet, error) | ||
|
||
// GetPermissionSet fetches a specific PermissionSet record | ||
GetPermissionSet(context.Context, PermissionSetID) (*identitycenterv1.PermissionSet, error) | ||
|
||
// UpdatePermissionSet performs a conditional update on the supplied Identity | ||
// Center Permission Set | ||
UpdatePermissionSet(context.Context, *identitycenterv1.PermissionSet) (*identitycenterv1.PermissionSet, error) | ||
|
||
// DeletePermissionSet deletes a specific Identity Center PermissionSet | ||
DeletePermissionSet(context.Context, PermissionSetID) error | ||
} | ||
|
||
// IdentityCenterAccountAssignment wraps a raw identitycenterv1.AccountAssignment | ||
// record in a new type to allow it to implement the interfaces required for use | ||
// with the Unified Resource listing. IdentityCenterAccountAssignment simply | ||
// wraps a pointer to the underlying account record, and can be treated as a | ||
// reference-like type. | ||
// | ||
// Copies of an IdentityCenterAccountAssignment will point to the same record. | ||
type IdentityCenterAccountAssignment struct { | ||
// This wrapper needs to: | ||
// - implement the interfaces required for use with the Unified Resource | ||
// service. | ||
// - expose the existing interfaces & methods on the underlying | ||
// identitycenterv1.AccountAssignment | ||
// - avoid copying the underlying identitycenterv1.AccountAssignment due to | ||
// embedded mutexes in the protobuf-generated code | ||
// | ||
// Given those requirements, storing an embedded pointer seems to be the | ||
// least-bad approach. | ||
|
||
*identitycenterv1.AccountAssignment | ||
} | ||
|
||
// CloneResource creates a deep copy of the underlying account resource | ||
func (a IdentityCenterAccountAssignment) CloneResource() IdentityCenterAccountAssignment { | ||
return IdentityCenterAccountAssignment{ | ||
AccountAssignment: proto.Clone(a.AccountAssignment).(*identitycenterv1.AccountAssignment), | ||
} | ||
} | ||
|
||
// IdentityCenterAccountAssignmentID is a strongly typed ID for an | ||
// IdentityCenterAccountAssignment | ||
type IdentityCenterAccountAssignmentID string | ||
|
||
// IdentityCenterAccountAssignments defines the operations to create and maintain | ||
// Identity Center account assignment records in the service. | ||
type IdentityCenterAccountAssignments interface { | ||
// ListAccountAssignments lists all IdentityCenterAccountAssignment record | ||
// known to the service | ||
ListAccountAssignments(context.Context, int, *pagination.PageRequestToken) ([]IdentityCenterAccountAssignment, pagination.NextPageToken, error) | ||
|
||
// CreateAccountAssignment creates a new Account Assignment record in | ||
// the service from the supplied in-memory representation. Returns the | ||
// created record on success. | ||
CreateAccountAssignment(context.Context, IdentityCenterAccountAssignment) (IdentityCenterAccountAssignment, error) | ||
|
||
// GetAccountAssignment fetches a specific Account Assignment record. | ||
GetAccountAssignment(context.Context, IdentityCenterAccountAssignmentID) (IdentityCenterAccountAssignment, error) | ||
|
||
// UpdateAccountAssignment performs a conditional update on the supplied | ||
// Account Assignment, returning the updated record on success. | ||
UpdateAccountAssignment(context.Context, IdentityCenterAccountAssignment) (IdentityCenterAccountAssignment, error) | ||
|
||
// DeleteAccountAssignment deletes a specific account assignment | ||
DeleteAccountAssignment(context.Context, IdentityCenterAccountAssignmentID) error | ||
|
||
// DeleteAllAccountAssignments deletes all known account assignments | ||
DeleteAllAccountAssignments(context.Context) error | ||
} | ||
|
||
// IdentityCenter combines all the resource managers used by the Identity Center plugin | ||
type IdentityCenter interface { | ||
IdentityCenterAccounts | ||
IdentityCenterPermissionSets | ||
IdentityCenterPrincipalAssignments | ||
IdentityCenterAccountAssignments | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Teleport | ||
// Copyright (C) 2024 Gravitational, Inc. | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Affero General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package services | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" | ||
identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" | ||
"github.com/gravitational/teleport/api/types" | ||
) | ||
|
||
func TestIdentityCenterAccountClone(t *testing.T) { | ||
// GIVEN an Account Record | ||
src := IdentityCenterAccount{ | ||
Account: &identitycenterv1.Account{ | ||
Kind: types.KindIdentityCenterAccount, | ||
Version: types.V1, | ||
Metadata: &headerv1.Metadata{Name: "some-account"}, | ||
Spec: &identitycenterv1.AccountSpec{ | ||
Id: "aws-account-id", | ||
Arn: "arn:aws:sso::account-id:", | ||
Description: "Test account", | ||
PermissionSetInfo: []*identitycenterv1.PermissionSetInfo{ | ||
{ | ||
Name: "original value", | ||
Arn: "arn:aws:sso:::permissionSet/ic-instance/ps-instance", | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
// WHEN I clone the resource | ||
dst := src.CloneResource() | ||
|
||
// EXPECT that the resulting clone compares equally | ||
require.Equal(t, src, dst) | ||
|
||
// WHEN I modify the source object in a way that would be shared with a | ||
// shallow copy | ||
src.Spec.PermissionSetInfo[0].Name = "some new value" | ||
|
||
// EXPECT that the cloned object DOES NOT inherit the update | ||
require.NotEqual(t, src, dst) | ||
require.Equal(t, "original value", dst.Spec.PermissionSetInfo[0].Name) | ||
} | ||
|
||
func TestIdentityCenterAccountAssignmentClone(t *testing.T) { | ||
// GIVEN an Account Assignment Record | ||
src := IdentityCenterAccountAssignment{ | ||
AccountAssignment: &identitycenterv1.AccountAssignment{ | ||
Kind: types.KindIdentityCenterAccountAssignment, | ||
Version: types.V1, | ||
Metadata: &headerv1.Metadata{Name: "[email protected]"}, | ||
Spec: &identitycenterv1.AccountAssignmentSpec{ | ||
Display: "Some-Permission-set on Some-AWS-account", | ||
PermissionSet: &identitycenterv1.PermissionSetInfo{ | ||
Arn: "arn:aws:sso:::permissionSet/ic-instance/ps-instance", | ||
Name: "original name", | ||
}, | ||
AccountName: "Some Account Name", | ||
AccountId: "some account id", | ||
}, | ||
}, | ||
} | ||
|
||
// WHEN I clone the resource | ||
dst := src.CloneResource() | ||
|
||
// EXPECT that the resulting clone compares equally | ||
require.Equal(t, src, dst) | ||
|
||
// WHEN I modify the source object in a way that would be shared with a | ||
// shallow copy | ||
src.Spec.PermissionSet.Name = "some new name" | ||
|
||
// EXPECT that the cloned object DOES NOT inherit the update | ||
require.NotEqual(t, src, dst) | ||
require.Equal(t, "original name", dst.Spec.PermissionSet.Name) | ||
} |
Oops, something went wrong.