diff --git a/api/types/constants.go b/api/types/constants.go index 512041e01f185..101f540e50e54 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -560,6 +560,10 @@ const ( // KindStaticHostUser is a host user to be created on matching SSH nodes. KindStaticHostUser = "static_host_user" + // KindContact is a resource that holds contact information + // for Teleport Enterprise customers. + KindContact = "contact" + // KindWorkloadIdentity is the WorkloadIdentity resource. KindWorkloadIdentity = "workload_identity" diff --git a/lib/services/presets.go b/lib/services/presets.go index a2dacee077d35..38b861fd93b72 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -183,6 +183,7 @@ func NewPresetEditorRole() types.Role { types.NewRule(types.KindNotification, RW()), types.NewRule(types.KindStaticHostUser, RW()), types.NewRule(types.KindUserTask, RW()), + types.NewRule(types.KindContact, RW()), }, }, }, diff --git a/lib/services/useracl.go b/lib/services/useracl.go index 5ec6fe73f1ce8..d1511651f8adc 100644 --- a/lib/services/useracl.go +++ b/lib/services/useracl.go @@ -116,6 +116,8 @@ type UserACL struct { AccessGraphSettings ResourceAccess `json:"accessGraphSettings"` // ReviewRequests defines the ability to review requests ReviewRequests bool `json:"reviewRequests"` + // Contact defines the ability to manage contacts + Contact ResourceAccess `json:"contact"` } func hasAccess(roleSet RoleSet, ctx *Context, kind string, verbs ...string) bool { @@ -216,6 +218,8 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des securityReports = newAccess(userRoles, ctx, types.KindSecurityReport) } + contact := newAccess(userRoles, ctx, types.KindContact) + return UserACL{ AccessRequests: requestAccess, AppServers: appServerAccess, @@ -257,5 +261,6 @@ func NewUserACL(user types.User, userRoles RoleSet, features proto.Features, des AccessMonitoringRule: accessMonitoringRules, CrownJewel: crownJewelAccess, AccessGraphSettings: accessGraphSettings, + Contact: contact, } } diff --git a/lib/services/useracl_test.go b/lib/services/useracl_test.go index 4bcb6a75763da..9eb19e199007e 100644 --- a/lib/services/useracl_test.go +++ b/lib/services/useracl_test.go @@ -51,6 +51,10 @@ func TestNewUserACL(t *testing.T) { Resources: []string{types.KindIntegration}, Verbs: append(RW(), types.VerbUse), }, + { + Resources: []string{types.KindContact}, + Verbs: RW(), + }, }) // not setting the rule, or explicitly denying, both denies Access @@ -104,6 +108,7 @@ func TestNewUserACL(t *testing.T) { require.True(t, userContext.DesktopSessionRecording) require.Empty(t, cmp.Diff(userContext.License, denied)) require.Empty(t, cmp.Diff(userContext.Download, denied)) + require.Empty(t, cmp.Diff(userContext.Contact, allowedRW)) // test enabling of the 'Use' verb require.Empty(t, cmp.Diff(userContext.Integrations, ResourceAccess{true, true, true, true, true, true})) diff --git a/web/packages/teleport/src/mocks/contexts.ts b/web/packages/teleport/src/mocks/contexts.ts index 583005a4182e2..9540513d3625e 100644 --- a/web/packages/teleport/src/mocks/contexts.ts +++ b/web/packages/teleport/src/mocks/contexts.ts @@ -74,6 +74,7 @@ export const allAccessAcl: Acl = { accessGraph: fullAccess, bots: fullAccess, accessMonitoringRule: fullAccess, + contacts: fullAccess, }; export function getAcl(cfg?: { noAccess: boolean }) { diff --git a/web/packages/teleport/src/services/user/makeAcl.ts b/web/packages/teleport/src/services/user/makeAcl.ts index 0957aea5893fa..6fba5fe7b5a9f 100644 --- a/web/packages/teleport/src/services/user/makeAcl.ts +++ b/web/packages/teleport/src/services/user/makeAcl.ts @@ -73,6 +73,8 @@ export function makeAcl(json): Acl { const bots = json.bots || defaultAccess; const accessMonitoringRule = json.accessMonitoringRule || defaultAccess; + const contacts = json.contact || defaultAccess; + return { accessList, authConnectors, @@ -109,6 +111,7 @@ export function makeAcl(json): Acl { accessGraph, bots, accessMonitoringRule, + contacts, }; } diff --git a/web/packages/teleport/src/services/user/types.ts b/web/packages/teleport/src/services/user/types.ts index 96b5d268973e0..be84afc059a23 100644 --- a/web/packages/teleport/src/services/user/types.ts +++ b/web/packages/teleport/src/services/user/types.ts @@ -105,6 +105,7 @@ export interface Acl { accessGraph: Access; bots: Access; accessMonitoringRule: Access; + contacts: Access; } // AllTraits represent all the traits defined for a user. diff --git a/web/packages/teleport/src/services/user/user.test.ts b/web/packages/teleport/src/services/user/user.test.ts index 0093f85223693..dc95b4e322a18 100644 --- a/web/packages/teleport/src/services/user/user.test.ts +++ b/web/packages/teleport/src/services/user/user.test.ts @@ -271,6 +271,13 @@ test('undefined values in context response gives proper default values', async ( create: false, remove: false, }, + contacts: { + list: false, + read: false, + edit: false, + create: false, + remove: false, + }, clipboardSharingEnabled: true, desktopSessionRecordingEnabled: true, directorySharingEnabled: true, diff --git a/web/packages/teleport/src/stores/storeUserContext.ts b/web/packages/teleport/src/stores/storeUserContext.ts index b55c7c6c6985e..c80431558f2dc 100644 --- a/web/packages/teleport/src/stores/storeUserContext.ts +++ b/web/packages/teleport/src/stores/storeUserContext.ts @@ -247,4 +247,8 @@ export default class StoreUserContext extends Store { getBotsAccess() { return this.state.acl.bots; } + + getContactsAccess() { + return this.state.acl.contacts; + } }