Add role setup for Connect My Computer in tshd (#28891)

* Ignore specific teleterm proto file rather than whole package

* clusters.Storage: Avoid unnecessary casting of URI back to string

* Storage.fromProfile: Move loading profile status to separate function

* Return client.TeleportClient together with clusters.Cluster

This is a stopgap to make clusters.Cluster a regular struct with no extra
behavior and a much smaller interface.

At the moment, almost all RPCs go through layers like these:

gRPC handler → daemon.Service → clusters.Storage → clusters.Cluster →
→ TeleportClient

As a result, clusters.Cluster has a gigantic interface that's hard to test.

Instead, we want to make it hold basic information about the cluster.
The real work will be done by collaborator structs which take clusters.Cluster
and TeleportClient as args. This way we can mock them out more easily in tests.

See the issue linked in the comment of clusters.Storage.GetByResourceURI
for more details.

* Make AddMetadataToRetryableError public

Since we're moving away from doing everything in clusters.Cluster, we'll
need to use this function from within the daemon package.

* Add IsRoot and IsLeaf methods to uri.ResourceURI

These methods will be used to return early if someone tries to set up
roles for a leaf cluster. Connect My Computer works with root clusters only.

* Add handler for creating Connect My Computer role

* Add test for calling GenerateUserCerts with bogus request ID

* Fix checking logins of existing role

* Remove commented out argument to ReissueUserCerts

* Add a stopgap comment to Storage.GetByURI

* Remove invalid doc links

* Ensure owner node label has expected value if role already exists

* Add unit test which checks RoleSetup.Run idempotency

* Add godoc for Resolver

* Simplify watcher equality check, add a comment

* Expand the comment for DropAccessRequests

* Fix position of Connect My Computer popover

* Integrate role setup with setup document

* Add temporary action to additional actions

This will be removed once the parent PR is approved. I just wanted to give
reviewers a shortcut to triggering the endpoint from the actual app.

* Add return type to createRole

* Add useRetryWithRelogin

* Wrap role setup in retryWithRelogin

* Remove useRetryWithRelogin in favor of retryWithRelogin & useCallback

* Remove CMC role setup from AdditionalActions

* Prettier fix

* Fix eslint
This commit is contained in:
Rafał Cieślak
2023-07-20 11:42:22 +00:00
committed by GitHub
parent d58f364bf4
commit fc49acb722
47 changed files with 2137 additions and 458 deletions
+10
View File
@@ -738,6 +738,16 @@ type UserCertsRequest struct {
UseRoleRequests bool `protobuf:"varint,14,opt,name=UseRoleRequests,proto3" json:"use_role_requests,omitempty"`
// DropAccessRequests is an optional list of request IDs indicating requests
// whose escalated privileges should be removed from the certificate.
// IDs pointing at non-existent requests are ignored.
//
// If present, the roles and traits in the generated cert will be based on
// the state of the user resource on the backend, active requests (not being
// dropped) and new access requests specified through AccessRequests (if any).
//
// This means that technically sending UserCertsRequest with bogus IDs in
// DropAccessRequests can be used to refresh the role list based on backend
// state. A better long-term solution would be to add a dedicated field for
// this to avoid sending bogus IDs.
DropAccessRequests []string `protobuf:"bytes,15,rep,name=DropAccessRequests,proto3" json:"drop_access_requests,omitempty"`
// ConnectionDiagnosticID is the ID of the ConnectionDiagnostic resource we should use to add
// traces as we pass certain checkpoints.
@@ -205,6 +205,16 @@ message UserCertsRequest {
// DropAccessRequests is an optional list of request IDs indicating requests
// whose escalated privileges should be removed from the certificate.
// IDs pointing at non-existent requests are ignored.
//
// If present, the roles and traits in the generated cert will be based on
// the state of the user resource on the backend, active requests (not being
// dropped) and new access requests specified through AccessRequests (if any).
//
// This means that technically sending UserCertsRequest with bogus IDs in
// DropAccessRequests can be used to refresh the role list based on backend
// state. A better long-term solution would be to add a dedicated field for
// this to avoid sending bogus IDs.
repeated string DropAccessRequests = 15 [(gogoproto.jsontag) = "drop_access_requests,omitempty"];
// ConnectionDiagnosticID is the ID of the ConnectionDiagnostic resource we should use to add
+4
View File
@@ -614,6 +614,10 @@ const (
// TeleportAzureMSIEndpoint is a special URL intercepted by TSH local proxy, serving Azure credentials.
TeleportAzureMSIEndpoint = "azure-msi." + TeleportNamespace
// ConnectMyComputerNodeOwnerLabel is a label used to control access to the node managed by
// Teleport Connect as part of Connect My Computer. See [teleterm.connectmycomputer.RoleSetup].
ConnectMyComputerNodeOwnerLabel = TeleportNamespace + "/connect-my-computer/owner"
)
var (
+5
View File
@@ -631,6 +631,11 @@ const (
// SystemAutomaticAccessApprovalRoleName names a preset role that may
// automatically approve any Role Access Request
SystemAutomaticAccessApprovalRoleName = "@teleport-access-approver"
// ConnectMyComputerRoleNamePrefix is the prefix used for roles prepared for individual users
// during the setup of Connect My Computer. The prefix is followed by the name of the cluster
// user. See [teleterm.connectmycomputer.RoleSetup].
ConnectMyComputerRoleNamePrefix = "connect-my-computer-"
)
var PresetRoles = []string{PresetEditorRoleName, PresetAccessRoleName, PresetAuditorRoleName}
@@ -2772,6 +2772,102 @@ func (*UpdateHeadlessAuthenticationStateResponse) Descriptor() ([]byte, []int) {
return file_teleport_lib_teleterm_v1_service_proto_rawDescGZIP(), []int{44}
}
type CreateConnectMyComputerRoleRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RootClusterUri string `protobuf:"bytes,1,opt,name=root_cluster_uri,json=rootClusterUri,proto3" json:"root_cluster_uri,omitempty"`
}
func (x *CreateConnectMyComputerRoleRequest) Reset() {
*x = CreateConnectMyComputerRoleRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[45]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateConnectMyComputerRoleRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateConnectMyComputerRoleRequest) ProtoMessage() {}
func (x *CreateConnectMyComputerRoleRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[45]
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 CreateConnectMyComputerRoleRequest.ProtoReflect.Descriptor instead.
func (*CreateConnectMyComputerRoleRequest) Descriptor() ([]byte, []int) {
return file_teleport_lib_teleterm_v1_service_proto_rawDescGZIP(), []int{45}
}
func (x *CreateConnectMyComputerRoleRequest) GetRootClusterUri() string {
if x != nil {
return x.RootClusterUri
}
return ""
}
type CreateConnectMyComputerRoleResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// certs_reloaded signals to the Electron app that tshd has reloaded the certs in order to refresh
// the role list. The Electron app should refresh the details from the user cert as well.
CertsReloaded bool `protobuf:"varint,1,opt,name=certs_reloaded,json=certsReloaded,proto3" json:"certs_reloaded,omitempty"`
}
func (x *CreateConnectMyComputerRoleResponse) Reset() {
*x = CreateConnectMyComputerRoleResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[46]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CreateConnectMyComputerRoleResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateConnectMyComputerRoleResponse) ProtoMessage() {}
func (x *CreateConnectMyComputerRoleResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[46]
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 CreateConnectMyComputerRoleResponse.ProtoReflect.Descriptor instead.
func (*CreateConnectMyComputerRoleResponse) Descriptor() ([]byte, []int) {
return file_teleport_lib_teleterm_v1_service_proto_rawDescGZIP(), []int{46}
}
func (x *CreateConnectMyComputerRoleResponse) GetCertsReloaded() bool {
if x != nil {
return x.CertsReloaded
}
return false
}
// LoginPasswordlessRequestInit contains fields needed to init the stream request.
type LoginPasswordlessRequest_LoginPasswordlessRequestInit struct {
state protoimpl.MessageState
@@ -2785,7 +2881,7 @@ type LoginPasswordlessRequest_LoginPasswordlessRequestInit struct {
func (x *LoginPasswordlessRequest_LoginPasswordlessRequestInit) Reset() {
*x = LoginPasswordlessRequest_LoginPasswordlessRequestInit{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[45]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[47]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2798,7 +2894,7 @@ func (x *LoginPasswordlessRequest_LoginPasswordlessRequestInit) String() string
func (*LoginPasswordlessRequest_LoginPasswordlessRequestInit) ProtoMessage() {}
func (x *LoginPasswordlessRequest_LoginPasswordlessRequestInit) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[45]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[47]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2834,7 +2930,7 @@ type LoginPasswordlessRequest_LoginPasswordlessPINResponse struct {
func (x *LoginPasswordlessRequest_LoginPasswordlessPINResponse) Reset() {
*x = LoginPasswordlessRequest_LoginPasswordlessPINResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[46]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[48]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2847,7 +2943,7 @@ func (x *LoginPasswordlessRequest_LoginPasswordlessPINResponse) String() string
func (*LoginPasswordlessRequest_LoginPasswordlessPINResponse) ProtoMessage() {}
func (x *LoginPasswordlessRequest_LoginPasswordlessPINResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[46]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[48]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2885,7 +2981,7 @@ type LoginPasswordlessRequest_LoginPasswordlessCredentialResponse struct {
func (x *LoginPasswordlessRequest_LoginPasswordlessCredentialResponse) Reset() {
*x = LoginPasswordlessRequest_LoginPasswordlessCredentialResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[47]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[49]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2898,7 +2994,7 @@ func (x *LoginPasswordlessRequest_LoginPasswordlessCredentialResponse) String()
func (*LoginPasswordlessRequest_LoginPasswordlessCredentialResponse) ProtoMessage() {}
func (x *LoginPasswordlessRequest_LoginPasswordlessCredentialResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[47]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[49]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2938,7 +3034,7 @@ type LoginRequest_LocalParams struct {
func (x *LoginRequest_LocalParams) Reset() {
*x = LoginRequest_LocalParams{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[48]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[50]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -2951,7 +3047,7 @@ func (x *LoginRequest_LocalParams) String() string {
func (*LoginRequest_LocalParams) ProtoMessage() {}
func (x *LoginRequest_LocalParams) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[48]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[50]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -3003,7 +3099,7 @@ type LoginRequest_SsoParams struct {
func (x *LoginRequest_SsoParams) Reset() {
*x = LoginRequest_SsoParams{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[49]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[51]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -3016,7 +3112,7 @@ func (x *LoginRequest_SsoParams) String() string {
func (*LoginRequest_SsoParams) ProtoMessage() {}
func (x *LoginRequest_SsoParams) ProtoReflect() protoreflect.Message {
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[49]
mi := &file_teleport_lib_teleterm_v1_service_proto_msgTypes[51]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -3416,257 +3512,277 @@ var file_teleport_lib_teleterm_v1_service_proto_rawDesc = []byte{
0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x2b,
0x0a, 0x29, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73,
0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74,
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x97, 0x01, 0x0a, 0x12,
0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x6d,
0x70, 0x74, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45,
0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57,
0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x50,
0x49, 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44,
0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x54, 0x41, 0x50, 0x10,
0x02, 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53,
0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54,
0x49, 0x41, 0x4c, 0x10, 0x03, 0x2a, 0x8a, 0x01, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x27, 0x0a, 0x23, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52,
0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45,
0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54,
0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22,
0x0a, 0x1e, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f,
0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44,
0x10, 0x02, 0x2a, 0xcd, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x12, 0x2d, 0x0a, 0x29, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41,
0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54,
0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
0x00, 0x12, 0x29, 0x0a, 0x25, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55,
0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41,
0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24,
0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54,
0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45,
0x4e, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45,
0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f,
0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x44,
0x10, 0x03, 0x32, 0xcb, 0x1a, 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x4c, 0x69, 0x73,
0x74, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73,
0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x10,
0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73,
0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x4c, 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
0x73, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47,
0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69,
0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x7c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55,
0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62,
0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x67, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2b,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x11, 0x47, 0x65, 0x74,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x32,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63,
0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69,
0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63,
0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x74, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65,
0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65,
0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x0a, 0x22, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f,
0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x6f,
0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x55, 0x72, 0x69, 0x22, 0x4c, 0x0a, 0x23, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f,
0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x6c, 0x6f,
0x61, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74,
0x73, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2a, 0x97, 0x01, 0x0a, 0x12, 0x50, 0x61,
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74,
0x12, 0x23, 0x0a, 0x1f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53,
0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52,
0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x50, 0x49, 0x4e,
0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45,
0x53, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x54, 0x41, 0x50, 0x10, 0x02, 0x12,
0x22, 0x0a, 0x1e, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f,
0x50, 0x52, 0x4f, 0x4d, 0x50, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41,
0x4c, 0x10, 0x03, 0x2a, 0x8a, 0x01, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x66, 0x65, 0x72, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a,
0x23, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44,
0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54,
0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f,
0x4e, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e,
0x46, 0x49, 0x4c, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x44, 0x49,
0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x02,
0x2a, 0xcd, 0x01, 0x0a, 0x1b, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74,
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
0x12, 0x2d, 0x0a, 0x29, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54,
0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54,
0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
0x29, 0x0a, 0x25, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48,
0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45,
0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x48, 0x45,
0x41, 0x44, 0x4c, 0x45, 0x53, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43,
0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x4e, 0x49,
0x45, 0x44, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x48, 0x45, 0x41, 0x44, 0x4c, 0x45, 0x53, 0x53,
0x5f, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x03,
0x32, 0xe8, 0x1b, 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0xa0, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54,
0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01,
0x0a, 0x13, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65,
0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52,
0x6f, 0x6f, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63,
0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74,
0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x75, 0x6d,
0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x10, 0x4c, 0x69,
0x73, 0x74, 0x4c, 0x65, 0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x65,
0x61, 0x66, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x44,
0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x7c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65,
0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69,
0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x08, 0x47,
0x65, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69,
0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c,
0x0a, 0x0a, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65,
0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x68, 0x0a, 0x0d,
0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43,
0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73,
0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67,
0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x63,
0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x32, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41,
0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65,
0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x74, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61,
0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13,
0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x82, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61,
0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x61, 0x62,
0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0a, 0x41, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x52,
0x6f, 0x6c, 0x65, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41,
0x73, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x08, 0x47, 0x65, 0x74,
0x4b, 0x75, 0x62, 0x65, 0x73, 0x12, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47,
0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6d,
0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c,
0x2e, 0x47, 0x65, 0x74, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4b,
0x75, 0x62, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0a,
0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65,
0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77,
0x61, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x61, 0x72,
0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6e, 0x0a, 0x13,
0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50,
0x6f, 0x72, 0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f,
0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6b, 0x0a, 0x0f,
0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75,
0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74,
0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x0a, 0x47, 0x65, 0x74,
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71,
0x76, 0x31, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x68, 0x0a, 0x0d, 0x52, 0x65,
0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6c, 0x75,
0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65,
0x77, 0x61, 0x79, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74,
0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e,
0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
0x12, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76,
0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61,
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x80, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77,
0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x28, 0x01, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x27,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x6f, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x65,
0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x30,
0x01, 0x12, 0x6e, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x65, 0x12, 0x86, 0x01, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d,
0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64,
0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x2e, 0x53, 0x65, 0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65,
0x74, 0x53, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73,
0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61,
0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x42, 0x54, 0x5a, 0x52, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67,
0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f,
0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6e, 0x0a, 0x13, 0x53, 0x65,
0x74, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72,
0x74, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74,
0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x6f, 0x72, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x6b, 0x0a, 0x0f, 0x47, 0x65,
0x74, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x30, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x53,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5c, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x43, 0x6c,
0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69,
0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c,
0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x58, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x26,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x80, 0x01, 0x0a, 0x11, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x6c, 0x65, 0x73, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x65,
0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01,
0x30, 0x01, 0x12, 0x5a, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x27, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f,
0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x2d,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x54, 0x72, 0x61,
0x6e, 0x73, 0x66, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x30, 0x01, 0x12,
0x6e, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76,
0x65, 0x6e, 0x74, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c,
0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76,
0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0xac, 0x01, 0x0a, 0x21, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65,
0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x42, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31,
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61,
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72,
0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x65, 0x61, 0x64, 0x6c,
0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x9a,
0x01, 0x0a, 0x1b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x3c,
0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65,
0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x4d, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x52,
0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x54, 0x5a, 0x52, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x72, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -3682,7 +3798,7 @@ func file_teleport_lib_teleterm_v1_service_proto_rawDescGZIP() []byte {
}
var file_teleport_lib_teleterm_v1_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_teleport_lib_teleterm_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 50)
var file_teleport_lib_teleterm_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 52)
var file_teleport_lib_teleterm_v1_service_proto_goTypes = []interface{}{
(PasswordlessPrompt)(0), // 0: teleport.lib.teleterm.v1.PasswordlessPrompt
(FileTransferDirection)(0), // 1: teleport.lib.teleterm.v1.FileTransferDirection
@@ -3732,41 +3848,43 @@ var file_teleport_lib_teleterm_v1_service_proto_goTypes = []interface{}{
(*UpdateTshdEventsServerAddressResponse)(nil), // 45: teleport.lib.teleterm.v1.UpdateTshdEventsServerAddressResponse
(*UpdateHeadlessAuthenticationStateRequest)(nil), // 46: teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateRequest
(*UpdateHeadlessAuthenticationStateResponse)(nil), // 47: teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse
(*LoginPasswordlessRequest_LoginPasswordlessRequestInit)(nil), // 48: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessRequestInit
(*LoginPasswordlessRequest_LoginPasswordlessPINResponse)(nil), // 49: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessPINResponse
(*LoginPasswordlessRequest_LoginPasswordlessCredentialResponse)(nil), // 50: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessCredentialResponse
(*LoginRequest_LocalParams)(nil), // 51: teleport.lib.teleterm.v1.LoginRequest.LocalParams
(*LoginRequest_SsoParams)(nil), // 52: teleport.lib.teleterm.v1.LoginRequest.SsoParams
(*AccessRequest)(nil), // 53: teleport.lib.teleterm.v1.AccessRequest
(*ResourceID)(nil), // 54: teleport.lib.teleterm.v1.ResourceID
(*Cluster)(nil), // 55: teleport.lib.teleterm.v1.Cluster
(*Gateway)(nil), // 56: teleport.lib.teleterm.v1.Gateway
(*Server)(nil), // 57: teleport.lib.teleterm.v1.Server
(*Database)(nil), // 58: teleport.lib.teleterm.v1.Database
(*Kube)(nil), // 59: teleport.lib.teleterm.v1.Kube
(*ReportUsageEventRequest)(nil), // 60: teleport.lib.teleterm.v1.ReportUsageEventRequest
(*AuthSettings)(nil), // 61: teleport.lib.teleterm.v1.AuthSettings
(*CreateConnectMyComputerRoleRequest)(nil), // 48: teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest
(*CreateConnectMyComputerRoleResponse)(nil), // 49: teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse
(*LoginPasswordlessRequest_LoginPasswordlessRequestInit)(nil), // 50: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessRequestInit
(*LoginPasswordlessRequest_LoginPasswordlessPINResponse)(nil), // 51: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessPINResponse
(*LoginPasswordlessRequest_LoginPasswordlessCredentialResponse)(nil), // 52: teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessCredentialResponse
(*LoginRequest_LocalParams)(nil), // 53: teleport.lib.teleterm.v1.LoginRequest.LocalParams
(*LoginRequest_SsoParams)(nil), // 54: teleport.lib.teleterm.v1.LoginRequest.SsoParams
(*AccessRequest)(nil), // 55: teleport.lib.teleterm.v1.AccessRequest
(*ResourceID)(nil), // 56: teleport.lib.teleterm.v1.ResourceID
(*Cluster)(nil), // 57: teleport.lib.teleterm.v1.Cluster
(*Gateway)(nil), // 58: teleport.lib.teleterm.v1.Gateway
(*Server)(nil), // 59: teleport.lib.teleterm.v1.Server
(*Database)(nil), // 60: teleport.lib.teleterm.v1.Database
(*Kube)(nil), // 61: teleport.lib.teleterm.v1.Kube
(*ReportUsageEventRequest)(nil), // 62: teleport.lib.teleterm.v1.ReportUsageEventRequest
(*AuthSettings)(nil), // 63: teleport.lib.teleterm.v1.AuthSettings
}
var file_teleport_lib_teleterm_v1_service_proto_depIdxs = []int32{
53, // 0: teleport.lib.teleterm.v1.GetAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
53, // 1: teleport.lib.teleterm.v1.GetAccessRequestsResponse.requests:type_name -> teleport.lib.teleterm.v1.AccessRequest
54, // 2: teleport.lib.teleterm.v1.CreateAccessRequestRequest.resource_ids:type_name -> teleport.lib.teleterm.v1.ResourceID
53, // 3: teleport.lib.teleterm.v1.CreateAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
54, // 4: teleport.lib.teleterm.v1.GetRequestableRolesRequest.resource_ids:type_name -> teleport.lib.teleterm.v1.ResourceID
53, // 5: teleport.lib.teleterm.v1.ReviewAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
55, // 0: teleport.lib.teleterm.v1.GetAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
55, // 1: teleport.lib.teleterm.v1.GetAccessRequestsResponse.requests:type_name -> teleport.lib.teleterm.v1.AccessRequest
56, // 2: teleport.lib.teleterm.v1.CreateAccessRequestRequest.resource_ids:type_name -> teleport.lib.teleterm.v1.ResourceID
55, // 3: teleport.lib.teleterm.v1.CreateAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
56, // 4: teleport.lib.teleterm.v1.GetRequestableRolesRequest.resource_ids:type_name -> teleport.lib.teleterm.v1.ResourceID
55, // 5: teleport.lib.teleterm.v1.ReviewAccessRequestResponse.request:type_name -> teleport.lib.teleterm.v1.AccessRequest
0, // 6: teleport.lib.teleterm.v1.LoginPasswordlessResponse.prompt:type_name -> teleport.lib.teleterm.v1.PasswordlessPrompt
19, // 7: teleport.lib.teleterm.v1.LoginPasswordlessResponse.credentials:type_name -> teleport.lib.teleterm.v1.CredentialInfo
48, // 8: teleport.lib.teleterm.v1.LoginPasswordlessRequest.init:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessRequestInit
49, // 9: teleport.lib.teleterm.v1.LoginPasswordlessRequest.pin:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessPINResponse
50, // 10: teleport.lib.teleterm.v1.LoginPasswordlessRequest.credential:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessCredentialResponse
50, // 8: teleport.lib.teleterm.v1.LoginPasswordlessRequest.init:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessRequestInit
51, // 9: teleport.lib.teleterm.v1.LoginPasswordlessRequest.pin:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessPINResponse
52, // 10: teleport.lib.teleterm.v1.LoginPasswordlessRequest.credential:type_name -> teleport.lib.teleterm.v1.LoginPasswordlessRequest.LoginPasswordlessCredentialResponse
1, // 11: teleport.lib.teleterm.v1.FileTransferRequest.direction:type_name -> teleport.lib.teleterm.v1.FileTransferDirection
51, // 12: teleport.lib.teleterm.v1.LoginRequest.local:type_name -> teleport.lib.teleterm.v1.LoginRequest.LocalParams
52, // 13: teleport.lib.teleterm.v1.LoginRequest.sso:type_name -> teleport.lib.teleterm.v1.LoginRequest.SsoParams
55, // 14: teleport.lib.teleterm.v1.ListClustersResponse.clusters:type_name -> teleport.lib.teleterm.v1.Cluster
56, // 15: teleport.lib.teleterm.v1.ListGatewaysResponse.gateways:type_name -> teleport.lib.teleterm.v1.Gateway
57, // 16: teleport.lib.teleterm.v1.GetServersResponse.agents:type_name -> teleport.lib.teleterm.v1.Server
58, // 17: teleport.lib.teleterm.v1.GetDatabasesResponse.agents:type_name -> teleport.lib.teleterm.v1.Database
59, // 18: teleport.lib.teleterm.v1.GetKubesResponse.agents:type_name -> teleport.lib.teleterm.v1.Kube
53, // 12: teleport.lib.teleterm.v1.LoginRequest.local:type_name -> teleport.lib.teleterm.v1.LoginRequest.LocalParams
54, // 13: teleport.lib.teleterm.v1.LoginRequest.sso:type_name -> teleport.lib.teleterm.v1.LoginRequest.SsoParams
57, // 14: teleport.lib.teleterm.v1.ListClustersResponse.clusters:type_name -> teleport.lib.teleterm.v1.Cluster
58, // 15: teleport.lib.teleterm.v1.ListGatewaysResponse.gateways:type_name -> teleport.lib.teleterm.v1.Gateway
59, // 16: teleport.lib.teleterm.v1.GetServersResponse.agents:type_name -> teleport.lib.teleterm.v1.Server
60, // 17: teleport.lib.teleterm.v1.GetDatabasesResponse.agents:type_name -> teleport.lib.teleterm.v1.Database
61, // 18: teleport.lib.teleterm.v1.GetKubesResponse.agents:type_name -> teleport.lib.teleterm.v1.Kube
2, // 19: teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateRequest.state:type_name -> teleport.lib.teleterm.v1.HeadlessAuthenticationState
44, // 20: teleport.lib.teleterm.v1.TerminalService.UpdateTshdEventsServerAddress:input_type -> teleport.lib.teleterm.v1.UpdateTshdEventsServerAddressRequest
26, // 21: teleport.lib.teleterm.v1.TerminalService.ListRootClusters:input_type -> teleport.lib.teleterm.v1.ListClustersRequest
@@ -3795,39 +3913,41 @@ var file_teleport_lib_teleterm_v1_service_proto_depIdxs = []int32{
21, // 44: teleport.lib.teleterm.v1.TerminalService.LoginPasswordless:input_type -> teleport.lib.teleterm.v1.LoginPasswordlessRequest
6, // 45: teleport.lib.teleterm.v1.TerminalService.Logout:input_type -> teleport.lib.teleterm.v1.LogoutRequest
22, // 46: teleport.lib.teleterm.v1.TerminalService.TransferFile:input_type -> teleport.lib.teleterm.v1.FileTransferRequest
60, // 47: teleport.lib.teleterm.v1.TerminalService.ReportUsageEvent:input_type -> teleport.lib.teleterm.v1.ReportUsageEventRequest
62, // 47: teleport.lib.teleterm.v1.TerminalService.ReportUsageEvent:input_type -> teleport.lib.teleterm.v1.ReportUsageEventRequest
46, // 48: teleport.lib.teleterm.v1.TerminalService.UpdateHeadlessAuthenticationState:input_type -> teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateRequest
45, // 49: teleport.lib.teleterm.v1.TerminalService.UpdateTshdEventsServerAddress:output_type -> teleport.lib.teleterm.v1.UpdateTshdEventsServerAddressResponse
27, // 50: teleport.lib.teleterm.v1.TerminalService.ListRootClusters:output_type -> teleport.lib.teleterm.v1.ListClustersResponse
27, // 51: teleport.lib.teleterm.v1.TerminalService.ListLeafClusters:output_type -> teleport.lib.teleterm.v1.ListClustersResponse
40, // 52: teleport.lib.teleterm.v1.TerminalService.GetDatabases:output_type -> teleport.lib.teleterm.v1.GetDatabasesResponse
31, // 53: teleport.lib.teleterm.v1.TerminalService.ListDatabaseUsers:output_type -> teleport.lib.teleterm.v1.ListDatabaseUsersResponse
39, // 54: teleport.lib.teleterm.v1.TerminalService.GetServers:output_type -> teleport.lib.teleterm.v1.GetServersResponse
10, // 55: teleport.lib.teleterm.v1.TerminalService.GetAccessRequests:output_type -> teleport.lib.teleterm.v1.GetAccessRequestsResponse
9, // 56: teleport.lib.teleterm.v1.TerminalService.GetAccessRequest:output_type -> teleport.lib.teleterm.v1.GetAccessRequestResponse
3, // 57: teleport.lib.teleterm.v1.TerminalService.DeleteAccessRequest:output_type -> teleport.lib.teleterm.v1.EmptyResponse
13, // 58: teleport.lib.teleterm.v1.TerminalService.CreateAccessRequest:output_type -> teleport.lib.teleterm.v1.CreateAccessRequestResponse
18, // 59: teleport.lib.teleterm.v1.TerminalService.ReviewAccessRequest:output_type -> teleport.lib.teleterm.v1.ReviewAccessRequestResponse
16, // 60: teleport.lib.teleterm.v1.TerminalService.GetRequestableRoles:output_type -> teleport.lib.teleterm.v1.GetRequestableRolesResponse
3, // 61: teleport.lib.teleterm.v1.TerminalService.AssumeRole:output_type -> teleport.lib.teleterm.v1.EmptyResponse
42, // 62: teleport.lib.teleterm.v1.TerminalService.GetKubes:output_type -> teleport.lib.teleterm.v1.GetKubesResponse
55, // 63: teleport.lib.teleterm.v1.TerminalService.AddCluster:output_type -> teleport.lib.teleterm.v1.Cluster
3, // 64: teleport.lib.teleterm.v1.TerminalService.RemoveCluster:output_type -> teleport.lib.teleterm.v1.EmptyResponse
34, // 65: teleport.lib.teleterm.v1.TerminalService.ListGateways:output_type -> teleport.lib.teleterm.v1.ListGatewaysResponse
56, // 66: teleport.lib.teleterm.v1.TerminalService.CreateGateway:output_type -> teleport.lib.teleterm.v1.Gateway
3, // 67: teleport.lib.teleterm.v1.TerminalService.RemoveGateway:output_type -> teleport.lib.teleterm.v1.EmptyResponse
56, // 68: teleport.lib.teleterm.v1.TerminalService.SetGatewayTargetSubresourceName:output_type -> teleport.lib.teleterm.v1.Gateway
56, // 69: teleport.lib.teleterm.v1.TerminalService.SetGatewayLocalPort:output_type -> teleport.lib.teleterm.v1.Gateway
61, // 70: teleport.lib.teleterm.v1.TerminalService.GetAuthSettings:output_type -> teleport.lib.teleterm.v1.AuthSettings
55, // 71: teleport.lib.teleterm.v1.TerminalService.GetCluster:output_type -> teleport.lib.teleterm.v1.Cluster
3, // 72: teleport.lib.teleterm.v1.TerminalService.Login:output_type -> teleport.lib.teleterm.v1.EmptyResponse
20, // 73: teleport.lib.teleterm.v1.TerminalService.LoginPasswordless:output_type -> teleport.lib.teleterm.v1.LoginPasswordlessResponse
3, // 74: teleport.lib.teleterm.v1.TerminalService.Logout:output_type -> teleport.lib.teleterm.v1.EmptyResponse
23, // 75: teleport.lib.teleterm.v1.TerminalService.TransferFile:output_type -> teleport.lib.teleterm.v1.FileTransferProgress
3, // 76: teleport.lib.teleterm.v1.TerminalService.ReportUsageEvent:output_type -> teleport.lib.teleterm.v1.EmptyResponse
47, // 77: teleport.lib.teleterm.v1.TerminalService.UpdateHeadlessAuthenticationState:output_type -> teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse
49, // [49:78] is the sub-list for method output_type
20, // [20:49] is the sub-list for method input_type
48, // 49: teleport.lib.teleterm.v1.TerminalService.CreateConnectMyComputerRole:input_type -> teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest
45, // 50: teleport.lib.teleterm.v1.TerminalService.UpdateTshdEventsServerAddress:output_type -> teleport.lib.teleterm.v1.UpdateTshdEventsServerAddressResponse
27, // 51: teleport.lib.teleterm.v1.TerminalService.ListRootClusters:output_type -> teleport.lib.teleterm.v1.ListClustersResponse
27, // 52: teleport.lib.teleterm.v1.TerminalService.ListLeafClusters:output_type -> teleport.lib.teleterm.v1.ListClustersResponse
40, // 53: teleport.lib.teleterm.v1.TerminalService.GetDatabases:output_type -> teleport.lib.teleterm.v1.GetDatabasesResponse
31, // 54: teleport.lib.teleterm.v1.TerminalService.ListDatabaseUsers:output_type -> teleport.lib.teleterm.v1.ListDatabaseUsersResponse
39, // 55: teleport.lib.teleterm.v1.TerminalService.GetServers:output_type -> teleport.lib.teleterm.v1.GetServersResponse
10, // 56: teleport.lib.teleterm.v1.TerminalService.GetAccessRequests:output_type -> teleport.lib.teleterm.v1.GetAccessRequestsResponse
9, // 57: teleport.lib.teleterm.v1.TerminalService.GetAccessRequest:output_type -> teleport.lib.teleterm.v1.GetAccessRequestResponse
3, // 58: teleport.lib.teleterm.v1.TerminalService.DeleteAccessRequest:output_type -> teleport.lib.teleterm.v1.EmptyResponse
13, // 59: teleport.lib.teleterm.v1.TerminalService.CreateAccessRequest:output_type -> teleport.lib.teleterm.v1.CreateAccessRequestResponse
18, // 60: teleport.lib.teleterm.v1.TerminalService.ReviewAccessRequest:output_type -> teleport.lib.teleterm.v1.ReviewAccessRequestResponse
16, // 61: teleport.lib.teleterm.v1.TerminalService.GetRequestableRoles:output_type -> teleport.lib.teleterm.v1.GetRequestableRolesResponse
3, // 62: teleport.lib.teleterm.v1.TerminalService.AssumeRole:output_type -> teleport.lib.teleterm.v1.EmptyResponse
42, // 63: teleport.lib.teleterm.v1.TerminalService.GetKubes:output_type -> teleport.lib.teleterm.v1.GetKubesResponse
57, // 64: teleport.lib.teleterm.v1.TerminalService.AddCluster:output_type -> teleport.lib.teleterm.v1.Cluster
3, // 65: teleport.lib.teleterm.v1.TerminalService.RemoveCluster:output_type -> teleport.lib.teleterm.v1.EmptyResponse
34, // 66: teleport.lib.teleterm.v1.TerminalService.ListGateways:output_type -> teleport.lib.teleterm.v1.ListGatewaysResponse
58, // 67: teleport.lib.teleterm.v1.TerminalService.CreateGateway:output_type -> teleport.lib.teleterm.v1.Gateway
3, // 68: teleport.lib.teleterm.v1.TerminalService.RemoveGateway:output_type -> teleport.lib.teleterm.v1.EmptyResponse
58, // 69: teleport.lib.teleterm.v1.TerminalService.SetGatewayTargetSubresourceName:output_type -> teleport.lib.teleterm.v1.Gateway
58, // 70: teleport.lib.teleterm.v1.TerminalService.SetGatewayLocalPort:output_type -> teleport.lib.teleterm.v1.Gateway
63, // 71: teleport.lib.teleterm.v1.TerminalService.GetAuthSettings:output_type -> teleport.lib.teleterm.v1.AuthSettings
57, // 72: teleport.lib.teleterm.v1.TerminalService.GetCluster:output_type -> teleport.lib.teleterm.v1.Cluster
3, // 73: teleport.lib.teleterm.v1.TerminalService.Login:output_type -> teleport.lib.teleterm.v1.EmptyResponse
20, // 74: teleport.lib.teleterm.v1.TerminalService.LoginPasswordless:output_type -> teleport.lib.teleterm.v1.LoginPasswordlessResponse
3, // 75: teleport.lib.teleterm.v1.TerminalService.Logout:output_type -> teleport.lib.teleterm.v1.EmptyResponse
23, // 76: teleport.lib.teleterm.v1.TerminalService.TransferFile:output_type -> teleport.lib.teleterm.v1.FileTransferProgress
3, // 77: teleport.lib.teleterm.v1.TerminalService.ReportUsageEvent:output_type -> teleport.lib.teleterm.v1.EmptyResponse
47, // 78: teleport.lib.teleterm.v1.TerminalService.UpdateHeadlessAuthenticationState:output_type -> teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse
49, // 79: teleport.lib.teleterm.v1.TerminalService.CreateConnectMyComputerRole:output_type -> teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse
50, // [50:80] is the sub-list for method output_type
20, // [20:50] is the sub-list for method input_type
20, // [20:20] is the sub-list for extension type_name
20, // [20:20] is the sub-list for extension extendee
0, // [0:20] is the sub-list for field type_name
@@ -4388,7 +4508,7 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessRequestInit); i {
switch v := v.(*CreateConnectMyComputerRoleRequest); i {
case 0:
return &v.state
case 1:
@@ -4400,7 +4520,7 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessPINResponse); i {
switch v := v.(*CreateConnectMyComputerRoleResponse); i {
case 0:
return &v.state
case 1:
@@ -4412,7 +4532,7 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessCredentialResponse); i {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessRequestInit); i {
case 0:
return &v.state
case 1:
@@ -4424,7 +4544,7 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginRequest_LocalParams); i {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessPINResponse); i {
case 0:
return &v.state
case 1:
@@ -4436,6 +4556,30 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginPasswordlessRequest_LoginPasswordlessCredentialResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginRequest_LocalParams); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_teleport_lib_teleterm_v1_service_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*LoginRequest_SsoParams); i {
case 0:
return &v.state
@@ -4463,7 +4607,7 @@ func file_teleport_lib_teleterm_v1_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_teleport_lib_teleterm_v1_service_proto_rawDesc,
NumEnums: 3,
NumMessages: 50,
NumMessages: 52,
NumExtensions: 0,
NumServices: 1,
},
@@ -62,6 +62,7 @@ const (
TerminalService_TransferFile_FullMethodName = "/teleport.lib.teleterm.v1.TerminalService/TransferFile"
TerminalService_ReportUsageEvent_FullMethodName = "/teleport.lib.teleterm.v1.TerminalService/ReportUsageEvent"
TerminalService_UpdateHeadlessAuthenticationState_FullMethodName = "/teleport.lib.teleterm.v1.TerminalService/UpdateHeadlessAuthenticationState"
TerminalService_CreateConnectMyComputerRole_FullMethodName = "/teleport.lib.teleterm.v1.TerminalService/CreateConnectMyComputerRole"
)
// TerminalServiceClient is the client API for TerminalService service.
@@ -153,6 +154,10 @@ type TerminalServiceClient interface {
// UpdateHeadlessAuthenticationState updates a headless authentication resource's state.
// An MFA challenge will be prompted when approving a headless authentication.
UpdateHeadlessAuthenticationState(ctx context.Context, in *UpdateHeadlessAuthenticationStateRequest, opts ...grpc.CallOption) (*UpdateHeadlessAuthenticationStateResponse, error)
// CreateConnectMyComputerRole creates a role which allows access to nodes with the label
// teleport.dev/connect-my-computer/owner: <cluster user> and allows logging in to those nodes as
// the current system user.
CreateConnectMyComputerRole(ctx context.Context, in *CreateConnectMyComputerRoleRequest, opts ...grpc.CallOption) (*CreateConnectMyComputerRoleResponse, error)
}
type terminalServiceClient struct {
@@ -469,6 +474,15 @@ func (c *terminalServiceClient) UpdateHeadlessAuthenticationState(ctx context.Co
return out, nil
}
func (c *terminalServiceClient) CreateConnectMyComputerRole(ctx context.Context, in *CreateConnectMyComputerRoleRequest, opts ...grpc.CallOption) (*CreateConnectMyComputerRoleResponse, error) {
out := new(CreateConnectMyComputerRoleResponse)
err := c.cc.Invoke(ctx, TerminalService_CreateConnectMyComputerRole_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// TerminalServiceServer is the server API for TerminalService service.
// All implementations must embed UnimplementedTerminalServiceServer
// for forward compatibility
@@ -558,6 +572,10 @@ type TerminalServiceServer interface {
// UpdateHeadlessAuthenticationState updates a headless authentication resource's state.
// An MFA challenge will be prompted when approving a headless authentication.
UpdateHeadlessAuthenticationState(context.Context, *UpdateHeadlessAuthenticationStateRequest) (*UpdateHeadlessAuthenticationStateResponse, error)
// CreateConnectMyComputerRole creates a role which allows access to nodes with the label
// teleport.dev/connect-my-computer/owner: <cluster user> and allows logging in to those nodes as
// the current system user.
CreateConnectMyComputerRole(context.Context, *CreateConnectMyComputerRoleRequest) (*CreateConnectMyComputerRoleResponse, error)
mustEmbedUnimplementedTerminalServiceServer()
}
@@ -652,6 +670,9 @@ func (UnimplementedTerminalServiceServer) ReportUsageEvent(context.Context, *Rep
func (UnimplementedTerminalServiceServer) UpdateHeadlessAuthenticationState(context.Context, *UpdateHeadlessAuthenticationStateRequest) (*UpdateHeadlessAuthenticationStateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateHeadlessAuthenticationState not implemented")
}
func (UnimplementedTerminalServiceServer) CreateConnectMyComputerRole(context.Context, *CreateConnectMyComputerRoleRequest) (*CreateConnectMyComputerRoleResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateConnectMyComputerRole not implemented")
}
func (UnimplementedTerminalServiceServer) mustEmbedUnimplementedTerminalServiceServer() {}
// UnsafeTerminalServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -1198,6 +1219,24 @@ func _TerminalService_UpdateHeadlessAuthenticationState_Handler(srv interface{},
return interceptor(ctx, in, info, handler)
}
func _TerminalService_CreateConnectMyComputerRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateConnectMyComputerRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TerminalServiceServer).CreateConnectMyComputerRole(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TerminalService_CreateConnectMyComputerRole_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TerminalServiceServer).CreateConnectMyComputerRole(ctx, req.(*CreateConnectMyComputerRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
// TerminalService_ServiceDesc is the grpc.ServiceDesc for TerminalService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -1313,6 +1352,10 @@ var TerminalService_ServiceDesc = grpc.ServiceDesc{
MethodName: "UpdateHeadlessAuthenticationState",
Handler: _TerminalService_UpdateHeadlessAuthenticationState_Handler,
},
{
MethodName: "CreateConnectMyComputerRole",
Handler: _TerminalService_CreateConnectMyComputerRole_Handler,
},
},
Streams: []grpc.StreamDesc{
{
+17
View File
@@ -45,6 +45,7 @@ interface ITerminalServiceService extends grpc.ServiceDefinition<grpc.UntypedSer
transferFile: ITerminalServiceService_ITransferFile;
reportUsageEvent: ITerminalServiceService_IReportUsageEvent;
updateHeadlessAuthenticationState: ITerminalServiceService_IUpdateHeadlessAuthenticationState;
createConnectMyComputerRole: ITerminalServiceService_ICreateConnectMyComputerRole;
}
interface ITerminalServiceService_IUpdateTshdEventsServerAddress extends grpc.MethodDefinition<teleport_lib_teleterm_v1_service_pb.UpdateTshdEventsServerAddressRequest, teleport_lib_teleterm_v1_service_pb.UpdateTshdEventsServerAddressResponse> {
@@ -308,6 +309,15 @@ interface ITerminalServiceService_IUpdateHeadlessAuthenticationState extends grp
responseSerialize: grpc.serialize<teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse>;
responseDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse>;
}
interface ITerminalServiceService_ICreateConnectMyComputerRole extends grpc.MethodDefinition<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse> {
path: "/teleport.lib.teleterm.v1.TerminalService/CreateConnectMyComputerRole";
requestStream: false;
responseStream: false;
requestSerialize: grpc.serialize<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest>;
requestDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest>;
responseSerialize: grpc.serialize<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse>;
responseDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse>;
}
export const TerminalServiceService: ITerminalServiceService;
@@ -341,6 +351,7 @@ export interface ITerminalServiceServer {
transferFile: grpc.handleServerStreamingCall<teleport_lib_teleterm_v1_service_pb.FileTransferRequest, teleport_lib_teleterm_v1_service_pb.FileTransferProgress>;
reportUsageEvent: grpc.handleUnaryCall<teleport_lib_teleterm_v1_usage_events_pb.ReportUsageEventRequest, teleport_lib_teleterm_v1_service_pb.EmptyResponse>;
updateHeadlessAuthenticationState: grpc.handleUnaryCall<teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse>;
createConnectMyComputerRole: grpc.handleUnaryCall<teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse>;
}
export interface ITerminalServiceClient {
@@ -430,6 +441,9 @@ export interface ITerminalServiceClient {
updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
}
export class TerminalServiceClient extends grpc.Client implements ITerminalServiceClient {
@@ -519,4 +533,7 @@ export class TerminalServiceClient extends grpc.Client implements ITerminalServi
public updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
public updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
public updateHeadlessAuthenticationState(request: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.UpdateHeadlessAuthenticationStateResponse) => void): grpc.ClientUnaryCall;
public createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
public createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
public createConnectMyComputerRole(request: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse) => void): grpc.ClientUnaryCall;
}
+36
View File
@@ -93,6 +93,28 @@ function deserialize_teleport_lib_teleterm_v1_CreateAccessRequestResponse(buffer
return teleport_lib_teleterm_v1_service_pb.CreateAccessRequestResponse.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleRequest(arg) {
if (!(arg instanceof teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest)) {
throw new Error('Expected argument of type teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleRequest(buffer_arg) {
return teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleResponse(arg) {
if (!(arg instanceof teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse)) {
throw new Error('Expected argument of type teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleResponse(buffer_arg) {
return teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_teleport_lib_teleterm_v1_CreateGatewayRequest(arg) {
if (!(arg instanceof teleport_lib_teleterm_v1_service_pb.CreateGatewayRequest)) {
throw new Error('Expected argument of type teleport.lib.teleterm.v1.CreateGatewayRequest');
@@ -938,6 +960,20 @@ updateHeadlessAuthenticationState: {
responseSerialize: serialize_teleport_lib_teleterm_v1_UpdateHeadlessAuthenticationStateResponse,
responseDeserialize: deserialize_teleport_lib_teleterm_v1_UpdateHeadlessAuthenticationStateResponse,
},
// CreateConnectMyComputerRole creates a role which allows access to nodes with the label
// teleport.dev/connect-my-computer/owner: <cluster user> and allows logging in to those nodes as
// the current system user.
createConnectMyComputerRole: {
path: '/teleport.lib.teleterm.v1.TerminalService/CreateConnectMyComputerRole',
requestStream: false,
responseStream: false,
requestType: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleRequest,
responseType: teleport_lib_teleterm_v1_service_pb.CreateConnectMyComputerRoleResponse,
requestSerialize: serialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleRequest,
requestDeserialize: deserialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleRequest,
responseSerialize: serialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleResponse,
responseDeserialize: deserialize_teleport_lib_teleterm_v1_CreateConnectMyComputerRoleResponse,
},
};
exports.TerminalServiceClient = grpc.makeGenericClientConstructor(TerminalServiceService);
+42
View File
@@ -1360,6 +1360,48 @@ export namespace UpdateHeadlessAuthenticationStateResponse {
}
}
export class CreateConnectMyComputerRoleRequest extends jspb.Message {
getRootClusterUri(): string;
setRootClusterUri(value: string): CreateConnectMyComputerRoleRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateConnectMyComputerRoleRequest.AsObject;
static toObject(includeInstance: boolean, msg: CreateConnectMyComputerRoleRequest): CreateConnectMyComputerRoleRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CreateConnectMyComputerRoleRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateConnectMyComputerRoleRequest;
static deserializeBinaryFromReader(message: CreateConnectMyComputerRoleRequest, reader: jspb.BinaryReader): CreateConnectMyComputerRoleRequest;
}
export namespace CreateConnectMyComputerRoleRequest {
export type AsObject = {
rootClusterUri: string,
}
}
export class CreateConnectMyComputerRoleResponse extends jspb.Message {
getCertsReloaded(): boolean;
setCertsReloaded(value: boolean): CreateConnectMyComputerRoleResponse;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateConnectMyComputerRoleResponse.AsObject;
static toObject(includeInstance: boolean, msg: CreateConnectMyComputerRoleResponse): CreateConnectMyComputerRoleResponse.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CreateConnectMyComputerRoleResponse, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateConnectMyComputerRoleResponse;
static deserializeBinaryFromReader(message: CreateConnectMyComputerRoleResponse, reader: jspb.BinaryReader): CreateConnectMyComputerRoleResponse;
}
export namespace CreateConnectMyComputerRoleResponse {
export type AsObject = {
certsReloaded: boolean,
}
}
export enum PasswordlessPrompt {
PASSWORDLESS_PROMPT_UNSPECIFIED = 0,
PASSWORDLESS_PROMPT_PIN = 1,
+304
View File
@@ -35,6 +35,8 @@ goog.exportSymbol('proto.teleport.lib.teleterm.v1.AddClusterRequest', null, glob
goog.exportSymbol('proto.teleport.lib.teleterm.v1.AssumeRoleRequest', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CreateAccessRequestRequest', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CreateAccessRequestResponse', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CreateGatewayRequest', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CredentialInfo', null, global);
goog.exportSymbol('proto.teleport.lib.teleterm.v1.DeleteAccessRequestRequest', null, global);
@@ -1136,6 +1138,48 @@ if (goog.DEBUG && !COMPILED) {
*/
proto.teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse.displayName = 'proto.teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.displayName = 'proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.displayName = 'proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse';
}
@@ -9872,6 +9916,266 @@ proto.teleport.lib.teleterm.v1.UpdateHeadlessAuthenticationStateResponse.seriali
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.prototype.toObject = function(opt_includeInstance) {
return proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.toObject = function(includeInstance, msg) {
var f, obj = {
rootClusterUri: jspb.Message.getFieldWithDefault(msg, 1, "")
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest;
return proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setRootClusterUri(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getRootClusterUri();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
};
/**
* optional string root_cluster_uri = 1;
* @return {string}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.prototype.getRootClusterUri = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest} returns this
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleRequest.prototype.setRootClusterUri = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.prototype.toObject = function(opt_includeInstance) {
return proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.toObject = function(includeInstance, msg) {
var f, obj = {
certsReloaded: jspb.Message.getBooleanFieldWithDefault(msg, 1, false)
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse;
return proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {boolean} */ (reader.readBool());
msg.setCertsReloaded(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getCertsReloaded();
if (f) {
writer.writeBool(
1,
f
);
}
};
/**
* optional bool certs_reloaded = 1;
* @return {boolean}
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.prototype.getCertsReloaded = function() {
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false));
};
/**
* @param {boolean} value
* @return {!proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse} returns this
*/
proto.teleport.lib.teleterm.v1.CreateConnectMyComputerRoleResponse.prototype.setCertsReloaded = function(value) {
return jspb.Message.setProto3BooleanField(this, 1, value);
};
/**
* @enum {number}
*/
+2 -1
View File
@@ -84,7 +84,8 @@ func testGatewayCertRenewal(t *testing.T, pack *dbhelpers.DatabasePack, albAddr
}, *creds)
require.NoError(t, err)
// Save the profile yaml file to disk as NewClientWithCreds doesn't do that by itself.
tc.SaveProfile(false /* makeCurrent */)
err = tc.SaveProfile(false /* makeCurrent */)
require.NoError(t, err)
fakeClock := clockwork.NewFakeClockAt(time.Now())
+257 -2
View File
@@ -18,6 +18,7 @@ import (
"context"
"fmt"
"net"
"os/user"
"sync/atomic"
"testing"
"time"
@@ -29,11 +30,14 @@ import (
"google.golang.org/grpc/credentials/insecure"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils"
api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1"
dbhelpers "github.com/gravitational/teleport/integration/db"
"github.com/gravitational/teleport/integration/helpers"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/service/servicecfg"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/teleterm/apiserver/handler"
"github.com/gravitational/teleport/lib/teleterm/clusters"
@@ -69,6 +73,7 @@ func TestTeleterm(t *testing.T) {
testListRootClustersReturnsLoggedInUser(t, pack, creds)
})
t.Run("GetCluster returns properties from auth server", func(t *testing.T) {
t.Parallel()
@@ -80,6 +85,11 @@ func TestTeleterm(t *testing.T) {
testHeadlessWatcher(t, pack, creds)
})
t.Run("CreateConnectMyComputerRole", func(t *testing.T) {
t.Parallel()
testCreateConnectMyComputerRole(t, pack)
})
}
func testAddingRootCluster(t *testing.T, pack *dbhelpers.DatabasePack, creds *helpers.UserCreds) {
@@ -241,7 +251,7 @@ func testHeadlessWatcher(t *testing.T, pack *dbhelpers.DatabasePack, creds *help
})
require.NoError(t, err)
cluster, err := storage.Add(ctx, tc.WebProxyAddr)
cluster, _, err := storage.Add(ctx, tc.WebProxyAddr)
require.NoError(t, err)
daemonService, err := daemon.New(daemon.Config{
@@ -304,6 +314,250 @@ func testHeadlessWatcher(t *testing.T, pack *dbhelpers.DatabasePack, creds *help
}, time.Second, 100*time.Millisecond)
}
func testCreateConnectMyComputerRole(t *testing.T, pack *dbhelpers.DatabasePack) {
systemUser, err := user.Current()
require.NoError(t, err)
tests := []struct {
name string
userAlreadyHasRole bool
existingRole func(userName string) types.RoleV6
}{
{
name: "role does not exist",
},
{
name: "role exists and includes current system username",
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{userName},
},
Logins: []string{systemUser.Username},
},
},
}
},
},
{
name: "role exists and does not include current system username",
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{userName},
},
Logins: []string{fmt.Sprintf("bogus-login-%v", uuid.NewString())},
},
},
}
},
},
{
name: "role exists and has no logins",
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{userName},
},
Logins: []string{},
},
},
}
},
},
{
name: "role exists and owner node label was changed",
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{"bogus-username"},
},
Logins: []string{systemUser.Username},
},
},
}
},
},
{
name: "user already has existing role that includes current system username",
userAlreadyHasRole: true,
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{userName},
},
Logins: []string{systemUser.Username},
},
},
}
},
},
{
name: "user already has existing role that does not include current system username",
userAlreadyHasRole: true,
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{userName},
},
Logins: []string{fmt.Sprintf("bogus-login-%v", uuid.NewString())},
},
},
}
},
},
{
name: "user already has existing role with modified owner node label",
userAlreadyHasRole: true,
existingRole: func(userName string) types.RoleV6 {
return types.RoleV6{
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{"bogus-username"},
},
Logins: []string{fmt.Sprintf("bogus-login-%v", uuid.NewString())},
},
},
}
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
authServer := pack.Root.Cluster.Process.GetAuthServer()
uuid := uuid.NewString()
userName := fmt.Sprintf("user-cmc-%s", uuid)
roleName := fmt.Sprintf("connect-my-computer-%v", userName)
var existingRole *types.RoleV6
// Prepare an existing role if present.
if test.existingRole != nil {
role := test.existingRole(userName)
role.SetMetadata(types.Metadata{
Name: roleName,
})
existingRole = &role
err = authServer.UpsertRole(ctx, &role)
require.NoError(t, err)
}
// Prepare a role with rules required to call CreateConnectMyComputerRole.
ruleWithAllowRules, err := types.NewRole(fmt.Sprintf("cmc-allow-rules-%v", uuid),
types.RoleSpecV6{
Allow: types.RoleConditions{
Rules: []types.Rule{
types.NewRule(types.KindUser, services.RW()),
types.NewRule(types.KindRole, services.RW()),
},
},
})
require.NoError(t, err)
userRoles := []types.Role{ruleWithAllowRules}
// Create a new user to avoid colliding with other tests.
// Assign to the user the role with allow rules and the existing role if present.
if test.userAlreadyHasRole {
if existingRole == nil {
t.Log("userAlreadyHasRole must be used together with existingRole")
t.Fail()
return
}
userRoles = append(userRoles, existingRole)
}
_, err = auth.CreateUser(authServer, userName, userRoles...)
require.NoError(t, err)
// Log in as the new user.
creds, err := helpers.GenerateUserCreds(helpers.UserCredsRequest{
Process: pack.Root.Cluster.Process,
Username: userName,
})
require.NoError(t, err)
tc := mustLogin(t, userName, pack, creds)
// Prepare daemon.Service.
storage, err := clusters.NewStorage(clusters.Config{
Dir: tc.KeysDir,
InsecureSkipVerify: tc.InsecureSkipVerify,
})
require.NoError(t, err)
daemonService, err := daemon.New(daemon.Config{
Storage: storage,
})
require.NoError(t, err)
t.Cleanup(func() {
daemonService.Stop()
})
handler, err := handler.New(
handler.Config{
DaemonService: daemonService,
},
)
require.NoError(t, err)
// Call CreateConnectMyComputerRole.
rootClusterName, _, err := net.SplitHostPort(pack.Root.Cluster.Web)
require.NoError(t, err)
rootClusterURI := uri.NewClusterURI(rootClusterName).String()
response, err := handler.CreateConnectMyComputerRole(ctx, &api.CreateConnectMyComputerRoleRequest{
RootClusterUri: rootClusterURI,
})
require.NoError(t, err)
if test.userAlreadyHasRole {
require.False(t, response.CertsReloaded,
"expected the handler to signal that the certs were not reloaded since the user was already assigned the role")
} else {
require.True(t, response.CertsReloaded,
"expected the handler to signal that the certs were reloaded since the user was just assigned a new role")
}
// Verify that the role exists.
role, err := authServer.GetRole(ctx, roleName)
require.NoError(t, err)
// Verify that the role grants expected privileges.
require.Contains(t, role.GetNodeLabels(types.Allow), types.ConnectMyComputerNodeOwnerLabel)
expectedNodeLabelValue := utils.Strings{userName}
actualNodeLabelValue := role.GetNodeLabels(types.Allow)[types.ConnectMyComputerNodeOwnerLabel]
require.Equal(t, expectedNodeLabelValue, actualNodeLabelValue)
require.Contains(t, role.GetLogins(types.Allow), systemUser.Username)
// Verify that the certs have been reloaded and that the user is assigned the role.
//
// GetCluster reads data from the cert. If the certs were not reloaded properly, GetCluster
// will not return the role that's just been assigned to the user.
clusterDetails, err := handler.GetCluster(ctx, &api.GetClusterRequest{
ClusterUri: rootClusterURI,
})
require.NoError(t, err)
require.Contains(t, clusterDetails.LoggedInUser.Roles, roleName,
"the user certs don't include the freshly added role; the certs might have not been reloaded properly")
})
}
}
func mustLogin(t *testing.T, userName string, pack *dbhelpers.DatabasePack, creds *helpers.UserCreds) *client.TeleportClient {
tc, err := pack.Root.Cluster.NewClientWithCreds(helpers.ClientConfig{
Login: userName,
@@ -311,7 +565,8 @@ func mustLogin(t *testing.T, userName string, pack *dbhelpers.DatabasePack, cred
}, *creds)
require.NoError(t, err)
// Save the profile yaml file to disk as NewClientWithCreds doesn't do that by itself.
tc.SaveProfile(false /* makeCurrent */)
err = tc.SaveProfile(false /* makeCurrent */)
require.NoError(t, err)
return tc
}
+43
View File
@@ -179,6 +179,7 @@ func TestAccessRequest(t *testing.T) {
testPack := newAccessRequestTestPack(ctx, t)
t.Run("single", func(t *testing.T) { testSingleAccessRequests(t, testPack) })
t.Run("multi", func(t *testing.T) { testMultiAccessRequests(t, testPack) })
t.Run("role refresh with bogus request ID", func(t *testing.T) { testRoleRefreshWithBogusRequestID(t, testPack) })
}
func testSingleAccessRequests(t *testing.T, testPack *accessRequestTestPack) {
@@ -629,6 +630,48 @@ func testMultiAccessRequests(t *testing.T, testPack *accessRequestTestPack) {
}
}
// testRoleRefreshWithBogusRequestID verifies that GenerateUserCerts refreshes the role list based
// on the server state, even when supplied an ID for a nonexistent access request.
//
// Teleport Connect depends on this behavior when setting up roles for Connect My Computer.
// See [teleterm.connectmycomputer.RoleSetup].
func testRoleRefreshWithBogusRequestID(t *testing.T, testPack *accessRequestTestPack) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
username := "user-for-role-refresh"
auth := testPack.tlsServer.Auth()
// Create a user.
user, err := types.NewUser(username)
require.NoError(t, err)
user.AddRole("requesters")
err = auth.UpsertUser(user)
require.NoError(t, err)
// Create a client with the old set of roles.
clt, err := testPack.tlsServer.NewClient(TestUser(username))
require.NoError(t, err)
// Add a new role to the user on the server.
user.AddRole("operators")
err = auth.UpdateUser(ctx, user)
require.NoError(t, err)
certs, err := clt.GenerateUserCerts(ctx, proto.UserCertsRequest{
PublicKey: testPack.pubKey,
Username: username,
Expires: time.Now().Add(time.Hour).UTC(),
DropAccessRequests: []string{"bogus-request-id"},
})
require.NoError(t, err)
// Verify that the new certs issued for the old client have the new role.
checkCerts(t, certs, []string{"requesters", "operators"}, nil, nil, nil)
}
// checkCerts checks that the ssh and tls certs include the given roles, logins,
// accessRequests, and resourceIDs
func checkCerts(t *testing.T,
+5 -4
View File
@@ -211,10 +211,11 @@ func (proxy *ProxyClient) GetLeafClusters(ctx context.Context) ([]types.RemoteCl
// ReissueParams encodes optional parameters for
// user certificate reissue.
type ReissueParams struct {
RouteToCluster string
NodeName string
KubernetesCluster string
AccessRequests []string
RouteToCluster string
NodeName string
KubernetesCluster string
AccessRequests []string
// See [proto.UserCertsRequest.DropAccessRequests].
DropAccessRequests []string
RouteToDatabase proto.RouteToDatabase
RouteToApp proto.RouteToApp
+12
View File
@@ -76,6 +76,18 @@ func (r ResourceURI) GetLeafClusterName() string {
return result.Params["leaf"]
}
// IsRoot indicates whether the URI points at a resource that belongs to a root cluster.
func (r ResourceURI) IsRoot() bool {
// Inspect profile name first to filter our non-cluster URIs.
return r.GetProfileName() != "" && r.GetLeafClusterName() == ""
}
// IsLeaf indicates whether the URI points at a resource that belongs to a leaf cluster.
func (r ResourceURI) IsLeaf() bool {
// Inspect profile name first to filter our non-cluster URIs.
return r.GetProfileName() != "" && r.GetLeafClusterName() != ""
}
// GetDbName extracts the database name from r. Returns an empty string if path is not a database URI.
func (r ResourceURI) GetDbName() string {
result, ok := pathDbs.Match(r.path)
+80
View File
@@ -324,3 +324,83 @@ func TestIsKube(t *testing.T) {
tt.check(t, tt.in.IsKube())
}
}
func TestIsRoot(t *testing.T) {
tests := []struct {
name string
in uri.ResourceURI
expect require.BoolAssertionFunc
}{
{
name: "root cluster URI",
in: uri.NewClusterURI("foo"),
expect: require.True,
},
{
name: "leaf cluster URI",
in: uri.NewClusterURI("foo").AppendLeafCluster("leaf"),
expect: require.False,
},
{
name: "root cluster resource URI",
in: uri.NewClusterURI("foo").AppendServer("bar"),
expect: require.True,
},
{
name: "leaf cluster resource URI",
in: uri.NewClusterURI("foo").AppendLeafCluster("leaf").AppendServer("bar"),
expect: require.False,
},
{
name: "gateway URI",
in: uri.NewGatewayURI("gateway"),
expect: require.False,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.expect(t, tt.in.IsRoot())
})
}
}
func TestIsLeaf(t *testing.T) {
tests := []struct {
name string
in uri.ResourceURI
expect require.BoolAssertionFunc
}{
{
name: "root cluster URI",
in: uri.NewClusterURI("foo"),
expect: require.False,
},
{
name: "leaf cluster URI",
in: uri.NewClusterURI("foo").AppendLeafCluster("leaf"),
expect: require.True,
},
{
name: "root cluster resource URI",
in: uri.NewClusterURI("foo").AppendServer("bar"),
expect: require.False,
},
{
name: "leaf cluster resource URI",
in: uri.NewClusterURI("foo").AppendLeafCluster("leaf").AppendServer("bar"),
expect: require.True,
},
{
name: "gateway URI",
in: uri.NewGatewayURI("gateway"),
expect: require.False,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.expect(t, tt.in.IsLeaf())
})
}
}
@@ -24,7 +24,7 @@ import (
// Login logs in a user to a cluster
func (s *Handler) Login(ctx context.Context, req *api.LoginRequest) (*api.EmptyResponse, error) {
cluster, err := s.DaemonService.ResolveCluster(req.ClusterUri)
cluster, _, err := s.DaemonService.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -66,7 +66,7 @@ func (s *Handler) LoginPasswordless(stream api.TerminalService_LoginPasswordless
return trace.BadParameter("cluster URI is required")
}
cluster, err := s.DaemonService.ResolveCluster(initReq.GetClusterUri())
cluster, _, err := s.DaemonService.ResolveCluster(initReq.GetClusterUri())
if err != nil {
return trace.Wrap(err)
}
@@ -94,7 +94,7 @@ func (s *Handler) Logout(ctx context.Context, req *api.LogoutRequest) (*api.Empt
// GetAuthSettings returns cluster auth preferences
func (s *Handler) GetAuthSettings(ctx context.Context, req *api.GetAuthSettingsRequest) (*api.AuthSettings, error) {
cluster, err := s.DaemonService.ResolveCluster(req.ClusterUri)
cluster, _, err := s.DaemonService.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -76,7 +76,7 @@ func (s *Handler) RemoveCluster(ctx context.Context, req *api.RemoveClusterReque
// GetCluster returns a cluster
func (s *Handler) GetCluster(ctx context.Context, req *api.GetClusterRequest) (*api.Cluster, error) {
cluster, err := s.DaemonService.ResolveClusterWithDetails(ctx, req.ClusterUri)
cluster, _, err := s.DaemonService.ResolveClusterWithDetails(ctx, req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -0,0 +1,28 @@
// Copyright 2023 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package handler
import (
"context"
"github.com/gravitational/trace"
api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1"
)
func (s *Handler) CreateConnectMyComputerRole(ctx context.Context, req *api.CreateConnectMyComputerRoleRequest) (*api.CreateConnectMyComputerRoleResponse, error) {
res, err := s.DaemonService.CreateConnectMyComputerRole(ctx, req)
return res, trace.Wrap(err)
}
@@ -26,7 +26,7 @@ import (
// GetDatabases gets databses with filters and returns paginated results
func (s *Handler) GetDatabases(ctx context.Context, req *api.GetDatabasesRequest) (*api.GetDatabasesResponse, error) {
cluster, err := s.DaemonService.ResolveCluster(req.ClusterUri)
cluster, _, err := s.DaemonService.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -54,7 +54,7 @@ func (s *Handler) GetDatabases(ctx context.Context, req *api.GetDatabasesRequest
// The list is based on whatever we can deduce from the role set, so it's similar to the behavior of
// `tsh db ls -v`, with the exception that Teleterm is interested only in the allowed usernames.
func (s *Handler) ListDatabaseUsers(ctx context.Context, req *api.ListDatabaseUsersRequest) (*api.ListDatabaseUsersResponse, error) {
cluster, err := s.DaemonService.ResolveCluster(req.DbUri)
cluster, _, err := s.DaemonService.ResolveCluster(req.DbUri)
if err != nil {
return nil, trace.Wrap(err)
}
+6 -6
View File
@@ -38,7 +38,7 @@ import (
type Cluster struct {
// URI is the cluster URI
URI uri.ResourceURI
// Name is the cluster name
// Name is the cluster name, AKA SiteName.
Name string
// ProfileName is the name of the tsh profile
ProfileName string
@@ -85,7 +85,7 @@ func (c *Cluster) GetWithDetails(ctx context.Context) (*ClusterWithDetails, erro
acl *api.ACL
)
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -177,7 +177,7 @@ func convertToAPIResourceAccess(access services.ResourceAccess) *api.ResourceAcc
// GetRoles returns currently logged-in user roles
func (c *Cluster) GetRoles(ctx context.Context) ([]*types.Role, error) {
var roles []*types.Role
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -220,7 +220,7 @@ func (c *Cluster) GetRequestableRoles(ctx context.Context, req *api.GetRequestab
})
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -277,10 +277,10 @@ type LoggedInUser struct {
ActiveRequests []string
}
// addMetadataToRetryableError is Connect's equivalent of client.RetryWithRelogin. By adding the
// AddMetadataToRetryableError is Connect's equivalent of client.RetryWithRelogin. By adding the
// metadata to the error, we're letting the Electron app know that the given error was caused by
// expired certs and letting the user log in again should resolve the error upon another attempt.
func addMetadataToRetryableError(ctx context.Context, fn func() error) error {
func AddMetadataToRetryableError(ctx context.Context, fn func() error) error {
err := fn()
if err == nil {
return nil
@@ -50,7 +50,7 @@ func (c *Cluster) GetAccessRequest(ctx context.Context, req types.AccessRequestF
err error
)
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -96,7 +96,7 @@ func (c *Cluster) GetAccessRequests(ctx context.Context, req types.AccessRequest
requests []types.AccessRequest
err error
)
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
requests, err = c.clusterClient.GetAccessRequests(ctx, req)
return err
})
@@ -145,7 +145,7 @@ func (c *Cluster) CreateAccessRequest(ctx context.Context, req *api.CreateAccess
request.SetRequestReason(req.Reason)
request.SetSuggestedReviewers(req.SuggestedReviewers)
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
return c.clusterClient.CreateAccessRequest(ctx, request)
})
if err != nil {
@@ -171,7 +171,7 @@ func (c *Cluster) ReviewAccessRequest(ctx context.Context, req *api.ReviewAccess
return nil, trace.Wrap(err)
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -215,7 +215,7 @@ func (c *Cluster) DeleteAccessRequest(ctx context.Context, req *api.DeleteAccess
proxyClient *client.ProxyClient
)
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -240,7 +240,7 @@ func (c *Cluster) DeleteAccessRequest(ctx context.Context, req *api.DeleteAccess
func (c *Cluster) AssumeRole(ctx context.Context, req *api.AssumeRoleRequest) error {
var err error
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
params := client.ReissueParams{
AccessRequests: req.AccessRequestIds,
DropAccessRequests: req.DropRequestIds,
+4 -4
View File
@@ -66,7 +66,7 @@ func (c *Cluster) GetDatabase(ctx context.Context, dbURI uri.ResourceURI) (*Data
// https://github.com/gravitational/teleport/pull/14690#discussion_r927720600
func (c *Cluster) getAllDatabases(ctx context.Context) ([]Database, error) {
var dbs []types.Database
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -117,7 +117,7 @@ func (c *Cluster) GetDatabases(ctx context.Context, r *api.GetDatabasesRequest)
UseSearchAsRoles: r.SearchAsRoles == "yes",
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -160,7 +160,7 @@ func (c *Cluster) ReissueDBCerts(ctx context.Context, routeToDatabase tlsca.Rout
return trace.BadParameter("the username must be present for MongoDB connections")
}
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
// Refresh the certs to account for clusterClient.SiteName pointing at a leaf cluster.
err := c.clusterClient.ReissueUserCerts(ctx, client.CertCacheKeep, client.ReissueParams{
RouteToCluster: c.clusterClient.SiteName,
@@ -209,7 +209,7 @@ func (c *Cluster) GetAllowedDatabaseUsers(ctx context.Context, dbURI string) ([]
return nil, trace.Wrap(err)
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
@@ -48,7 +48,7 @@ func (c *Cluster) TransferFile(ctx context.Context, request *api.FileTransferReq
return trace.BadParameter("server URI does not include server UUID")
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
err := c.clusterClient.TransferFiles(ctx, request.GetLogin(), serverUUID+":0", config)
return trace.Wrap(err)
})
+1 -1
View File
@@ -55,7 +55,7 @@ func (c *Cluster) WatchPendingHeadlessAuthentications(ctx context.Context) (watc
// UpdateHeadlessAuthenticationState updates the headless authentication matching the given id to the given state.
// MFA will be prompted when updating to the approve state.
func (c *Cluster) UpdateHeadlessAuthenticationState(ctx context.Context, headlessID string, state types.HeadlessAuthenticationState) error {
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
+1 -1
View File
@@ -59,7 +59,7 @@ func (c *Cluster) GetKubes(ctx context.Context, r *api.GetKubesRequest) (*GetKub
UseSearchAsRoles: r.SearchAsRoles == "yes",
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
+1 -1
View File
@@ -41,7 +41,7 @@ type LeafCluster struct {
// GetLeafClusters returns leaf clusters
func (c *Cluster) GetLeafClusters(ctx context.Context) ([]LeafCluster, error) {
var remoteClusters []types.RemoteCluster
err := addMetadataToRetryableError(ctx, func() error {
err := AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
+1 -1
View File
@@ -59,7 +59,7 @@ func (c *Cluster) GetServers(ctx context.Context, r *api.GetServersRequest) (*Ge
UseSearchAsRoles: r.SearchAsRoles == "yes",
}
err = addMetadataToRetryableError(ctx, func() error {
err = AddMetadataToRetryableError(ctx, func() error {
proxyClient, err = c.clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
+6 -2
View File
@@ -19,6 +19,7 @@ import (
"github.com/gravitational/trace"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/teleterm/gateway"
)
@@ -34,7 +35,7 @@ func NewGatewayCreator(resolver Resolver) GatewayCreator {
}
func (g GatewayCreator) CreateGateway(ctx context.Context, params CreateGatewayParams) (gateway.Gateway, error) {
cluster, err := g.resolver.ResolveCluster(params.TargetURI)
cluster, _, err := g.resolver.ResolveCluster(params.TargetURI)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -43,6 +44,9 @@ func (g GatewayCreator) CreateGateway(ctx context.Context, params CreateGatewayP
return gateway, trace.Wrap(err)
}
// Resolver is a subset of [Storage], mostly so that it's possible to provide a mock implementation
// in tests.
type Resolver interface {
ResolveCluster(uri.ResourceURI) (*Cluster, error)
// ResolveCluster returns a cluster from storage given the URI. See [Storage.ResolveCluster].
ResolveCluster(uri.ResourceURI) (*Cluster, *client.TeleportClient, error)
}
+80 -53
View File
@@ -46,7 +46,7 @@ func (s *Storage) ReadAll() ([]*Cluster, error) {
clusters := make([]*Cluster, 0, len(pfNames))
for _, name := range pfNames {
cluster, err := s.fromProfile(name, "")
cluster, _, err := s.fromProfile(name, "")
if err != nil {
return nil, trace.Wrap(err)
}
@@ -57,34 +57,47 @@ func (s *Storage) ReadAll() ([]*Cluster, error) {
return clusters, nil
}
// GetByURI returns a cluster by URI
func (s *Storage) GetByURI(clusterURI uri.ResourceURI) (*Cluster, error) {
// GetByURI returns a cluster by URI. Assumes the URI has been successfully parsed and is of a
// cluster.
//
// clusterClient being returned as the second return value is a stopgap in an effort to make
// clusters.Cluster a regular struct with no extra behavior and a much smaller interface.
// https://github.com/gravitational/teleport/issues/13278
func (s *Storage) GetByURI(clusterURI uri.ResourceURI) (*Cluster, *client.TeleportClient, error) {
profileName := clusterURI.GetProfileName()
leafClusterName := clusterURI.GetLeafClusterName()
cluster, err := s.fromProfile(profileName, leafClusterName)
cluster, clusterClient, err := s.fromProfile(profileName, leafClusterName)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return cluster, nil
return cluster, clusterClient, nil
}
// GetByResourceURI returns a cluster by a URI of its resource. Accepts both root and leaf cluster
// resources and will return a root or leaf cluster accordingly.
func (s *Storage) GetByResourceURI(resourceURI uri.ResourceURI) (*Cluster, error) {
cluster, err := s.GetByURI(resourceURI.GetClusterURI())
// resources and will return a root or a leaf cluster accordingly.
//
// clusterClient being returned as the second return value is a stopgap in an effort to make
// clusters.Cluster a regular struct with no extra behavior and a much smaller interface.
// https://github.com/gravitational/teleport/issues/13278
func (s *Storage) GetByResourceURI(resourceURI uri.ResourceURI) (*Cluster, *client.TeleportClient, error) {
cluster, clusterClient, err := s.GetByURI(resourceURI.GetClusterURI())
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return cluster, nil
return cluster, clusterClient, nil
}
// ResolveCluster is an alias for GetByResourceURI.
func (s *Storage) ResolveCluster(resourceURI uri.ResourceURI) (*Cluster, error) {
cluster, err := s.GetByResourceURI(resourceURI)
return cluster, trace.Wrap(err)
//
// clusterClient being returned as the second return value is a stopgap in an effort to make
// clusters.Cluster a regular struct with no extra behavior and a much smaller interface.
// https://github.com/gravitational/teleport/issues/13278
func (s *Storage) ResolveCluster(resourceURI uri.ResourceURI) (*Cluster, *client.TeleportClient, error) {
cluster, clusterClient, err := s.GetByResourceURI(resourceURI)
return cluster, clusterClient, trace.Wrap(err)
}
// Remove removes a cluster
@@ -97,41 +110,45 @@ func (s *Storage) Remove(ctx context.Context, profileName string) error {
}
// Add adds a cluster
func (s *Storage) Add(ctx context.Context, webProxyAddress string) (*Cluster, error) {
//
// clusterClient being returned as the second return value is a stopgap in an effort to make
// clusters.Cluster a regular struct with no extra behavior and a much smaller interface.
// https://github.com/gravitational/teleport/issues/13278
func (s *Storage) Add(ctx context.Context, webProxyAddress string) (*Cluster, *client.TeleportClient, error) {
profiles, err := profile.ListProfileNames(s.Dir)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
clusterName := parseName(webProxyAddress)
for _, pname := range profiles {
if pname == clusterName {
cluster, err := s.fromProfile(clusterName, "")
cluster, clusterClient, err := s.fromProfile(clusterName, "")
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return cluster, nil
return cluster, clusterClient, nil
}
}
cluster, err := s.addCluster(ctx, s.Dir, webProxyAddress)
cluster, clusterClient, err := s.addCluster(ctx, s.Dir, webProxyAddress)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return cluster, nil
return cluster, clusterClient, nil
}
// addCluster adds a new cluster. This makes the underlying profile .yaml file to be saved to the
// tsh home dir without logging in the user yet. Adding a cluster makes it show up in the UI as the
// list of clusters depends on the profiles in the home dir of tsh.
func (s *Storage) addCluster(ctx context.Context, dir, webProxyAddress string) (*Cluster, error) {
func (s *Storage) addCluster(ctx context.Context, dir, webProxyAddress string) (*Cluster, *client.TeleportClient, error) {
if webProxyAddress == "" {
return nil, trace.BadParameter("cluster address is missing")
return nil, nil, trace.BadParameter("cluster address is missing")
}
if dir == "" {
return nil, trace.BadParameter("cluster directory is missing")
return nil, nil, trace.BadParameter("cluster directory is missing")
}
cfg := client.MakeDefaultConfig()
@@ -144,14 +161,14 @@ func (s *Storage) addCluster(ctx context.Context, dir, webProxyAddress string) (
clusterURI := uri.NewClusterURI(profileName)
clusterClient, err := client.NewClient(cfg)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
// Ping verifies that the cluster is reachable. It also updates a couple of TeleportClient fields
// automatically based on the ping response – those fields are then saved to the profile file.
pingResponse, err := clusterClient.Ping(ctx)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
// Do the ALPN handshake test to decide if connection upgrades are required
@@ -160,7 +177,7 @@ func (s *Storage) addCluster(ctx context.Context, dir, webProxyAddress string) (
clusterClient.TLSRoutingConnUpgradeRequired = apiclient.IsALPNConnUpgradeRequired(ctx, webProxyAddress, s.InsecureSkipVerify)
if err := clusterClient.SaveProfile(false); err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return &Cluster{
@@ -173,13 +190,13 @@ func (s *Storage) addCluster(ctx context.Context, dir, webProxyAddress string) (
dir: s.Dir,
clock: s.Clock,
Log: s.Log.WithField("cluster", clusterURI),
}, nil
}, clusterClient, nil
}
// fromProfile creates a new cluster from its profile
func (s *Storage) fromProfile(profileName, leafClusterName string) (*Cluster, error) {
func (s *Storage) fromProfile(profileName, leafClusterName string) (*Cluster, *client.TeleportClient, error) {
if profileName == "" {
return nil, trace.BadParameter("cluster name is missing")
return nil, nil, trace.BadParameter("cluster name is missing")
}
clusterNameForKey := profileName
@@ -189,7 +206,7 @@ func (s *Storage) fromProfile(profileName, leafClusterName string) (*Cluster, er
cfg := client.MakeDefaultConfig()
if err := cfg.LoadProfile(profileStore, profileName); err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
cfg.KeysDir = s.Dir
cfg.HomePath = s.Dir
@@ -203,29 +220,12 @@ func (s *Storage) fromProfile(profileName, leafClusterName string) (*Cluster, er
clusterClient, err := client.NewClient(cfg)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
status := &client.ProfileStatus{}
// load profile status if key exists
_, err = clusterClient.LocalAgent().GetKey(clusterNameForKey)
status, err := s.loadProfileStatusAndClusterKey(clusterClient, clusterNameForKey)
if err != nil {
if trace.IsNotFound(err) {
s.Log.Infof("No keys found for cluster %v.", clusterNameForKey)
} else {
return nil, trace.Wrap(err)
}
}
if err == nil && cfg.Username != "" {
status, err = clusterClient.ProfileStatus()
if err != nil {
return nil, trace.Wrap(err)
}
if err := clusterClient.LoadKeyForCluster(context.Background(), status.Cluster); err != nil {
return nil, trace.Wrap(err)
}
return nil, nil, trace.Wrap(err)
}
return &Cluster{
@@ -237,7 +237,34 @@ func (s *Storage) fromProfile(profileName, leafClusterName string) (*Cluster, er
clock: s.Clock,
status: *status,
Log: s.Log.WithField("cluster", clusterURI),
}, nil
}, clusterClient, nil
}
func (s *Storage) loadProfileStatusAndClusterKey(clusterClient *client.TeleportClient, clusterNameForKey string) (*client.ProfileStatus, error) {
status := &client.ProfileStatus{}
// load profile status if key exists
_, err := clusterClient.LocalAgent().GetKey(clusterNameForKey)
if err != nil {
if trace.IsNotFound(err) {
s.Log.Infof("No keys found for cluster %v.", clusterNameForKey)
} else {
return nil, trace.Wrap(err)
}
}
if err == nil && clusterClient.Username != "" {
status, err = clusterClient.ProfileStatus()
if err != nil {
return nil, trace.Wrap(err)
}
if err := clusterClient.LoadKeyForCluster(context.Background(), status.Cluster); err != nil {
return nil, trace.Wrap(err)
}
}
return status, nil
}
// parseName gets cluster name from cluster web proxy address
+3 -2
View File
@@ -19,6 +19,7 @@ import (
"github.com/gravitational/trace"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/client/db/dbcmd"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/teleterm/clusters"
@@ -34,7 +35,7 @@ type DBCLICommandProvider struct {
}
type StorageByResourceURI interface {
GetByResourceURI(uri.ResourceURI) (*clusters.Cluster, error)
GetByResourceURI(uri.ResourceURI) (*clusters.Cluster, *client.TeleportClient, error)
}
func NewDBCLICommandProvider(storage StorageByResourceURI, execer dbcmd.Execer) DBCLICommandProvider {
@@ -45,7 +46,7 @@ func NewDBCLICommandProvider(storage StorageByResourceURI, execer dbcmd.Execer)
}
func (d DBCLICommandProvider) GetCommand(gateway gateway.Gateway) (*exec.Cmd, error) {
cluster, err := d.storage.GetByResourceURI(gateway.TargetURI())
cluster, _, err := d.storage.GetByResourceURI(gateway.TargetURI())
if err != nil {
return nil, trace.Wrap(err)
}
+14 -3
View File
@@ -24,6 +24,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/teleterm/clusters"
@@ -52,14 +53,24 @@ type fakeStorage struct {
clusters []*clusters.Cluster
}
func (f fakeStorage) GetByResourceURI(resourceURI uri.ResourceURI) (*clusters.Cluster, error) {
func (f fakeStorage) GetByResourceURI(resourceURI uri.ResourceURI) (*clusters.Cluster, *client.TeleportClient, error) {
for _, cluster := range f.clusters {
if strings.HasPrefix(resourceURI.String(), cluster.URI.String()) {
return cluster, nil
siteName := ""
if cluster.URI.IsLeaf() {
siteName = cluster.Name
}
tc := &client.TeleportClient{
Config: client.Config{
SiteName: siteName,
},
}
return cluster, tc, nil
}
}
return nil, trace.NotFound("not found")
return nil, nil, trace.NotFound("not found")
}
type fakeDatabaseGateway struct {
+15 -3
View File
@@ -25,6 +25,7 @@ import (
"github.com/gravitational/teleport/lib/teleterm/clusters"
"github.com/gravitational/teleport/lib/teleterm/cmd"
"github.com/gravitational/teleport/lib/teleterm/gateway"
"github.com/gravitational/teleport/lib/teleterm/services/connectmycomputer"
)
// Config is the cluster service config
@@ -32,7 +33,10 @@ type Config struct {
// Storage is a storage service that reads/writes to tsh profiles
Storage *clusters.Storage
// Log is a component logger
Log *logrus.Entry
Log *logrus.Entry
// PrehogAddr is the URL where prehog events should be submitted.
PrehogAddr string
GatewayCreator GatewayCreator
TCPPortAllocator gateway.TCPPortAllocator
DBCLICommandProvider gateway.CLICommandProvider
@@ -41,8 +45,7 @@ type Config struct {
// Electron app. This is to ensure that the server public key is written to the disk under the
// expected location by the time we get around to creating the client.
CreateTshdEventsClientCredsFunc CreateTshdEventsClientCredsFunc
// PrehogAddr is the URL where prehog events should be submitted.
PrehogAddr string
ConnectMyComputerRoleSetup *connectmycomputer.RoleSetup
}
type CreateTshdEventsClientCredsFunc func() (grpc.DialOption, error)
@@ -72,5 +75,14 @@ func (c *Config) CheckAndSetDefaults() error {
if c.KubeCLICommandProvider == nil {
c.KubeCLICommandProvider = cmd.NewKubeCLICommandProvider()
}
if c.ConnectMyComputerRoleSetup == nil {
roleSetup, err := connectmycomputer.NewRoleSetup(&connectmycomputer.RoleSetupConfig{})
if err != nil {
return trace.Wrap(err)
}
c.ConnectMyComputerRoleSetup = roleSetup
}
return nil
}
+68 -35
View File
@@ -129,7 +129,7 @@ func (s *Service) ListRootClusters(ctx context.Context) ([]*clusters.Cluster, er
// ListLeafClusters returns a list of leaf clusters
func (s *Service) ListLeafClusters(ctx context.Context, uri string) ([]clusters.LeafCluster, error) {
cluster, err := s.ResolveCluster(uri)
cluster, _, err := s.ResolveCluster(uri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -149,7 +149,7 @@ func (s *Service) ListLeafClusters(ctx context.Context, uri string) ([]clusters.
// AddCluster adds a cluster
func (s *Service) AddCluster(ctx context.Context, webProxyAddress string) (*clusters.Cluster, error) {
cluster, err := s.cfg.Storage.Add(ctx, webProxyAddress)
cluster, _, err := s.cfg.Storage.Add(ctx, webProxyAddress)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -159,7 +159,7 @@ func (s *Service) AddCluster(ctx context.Context, webProxyAddress string) (*clus
// RemoveCluster removes cluster
func (s *Service) RemoveCluster(ctx context.Context, uri string) error {
cluster, err := s.ResolveCluster(uri)
cluster, _, err := s.ResolveCluster(uri)
if err != nil {
return trace.Wrap(err)
}
@@ -181,39 +181,39 @@ func (s *Service) RemoveCluster(ctx context.Context, uri string) error {
//
// It doesn't make network requests so the returned clusters.Cluster will not include full
// information returned from the web/auth servers.
func (s *Service) ResolveCluster(path string) (*clusters.Cluster, error) {
func (s *Service) ResolveCluster(path string) (*clusters.Cluster, *client.TeleportClient, error) {
resourceURI, err := uri.Parse(path)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
cluster, err := s.resolveCluster(resourceURI)
return cluster, trace.Wrap(err)
cluster, clusterClient, err := s.resolveCluster(resourceURI)
return cluster, clusterClient, trace.Wrap(err)
}
func (s *Service) resolveCluster(uri uri.ResourceURI) (*clusters.Cluster, error) {
cluster, err := s.cfg.Storage.GetByResourceURI(uri)
return cluster, trace.Wrap(err)
func (s *Service) resolveCluster(uri uri.ResourceURI) (*clusters.Cluster, *client.TeleportClient, error) {
cluster, clusterClient, err := s.cfg.Storage.GetByResourceURI(uri)
return cluster, clusterClient, trace.Wrap(err)
}
// ResolveClusterWithDetails returns fully detailed cluster information. It makes requests to the auth server and includes
// details about the cluster and logged in user.
func (s *Service) ResolveClusterWithDetails(ctx context.Context, uri string) (*clusters.ClusterWithDetails, error) {
cluster, err := s.ResolveCluster(uri)
func (s *Service) ResolveClusterWithDetails(ctx context.Context, uri string) (*clusters.ClusterWithDetails, *client.TeleportClient, error) {
cluster, clusterClient, err := s.ResolveCluster(uri)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
withDetails, err := cluster.GetWithDetails(ctx)
if err != nil {
return nil, trace.Wrap(err)
return nil, nil, trace.Wrap(err)
}
return withDetails, nil
return withDetails, clusterClient, nil
}
// ClusterLogout logs a user out from the cluster
func (s *Service) ClusterLogout(ctx context.Context, uri string) error {
cluster, err := s.ResolveCluster(uri)
cluster, _, err := s.ResolveCluster(uri)
if err != nil {
return trace.Wrap(err)
}
@@ -308,7 +308,7 @@ func (s *Service) reissueGatewayCerts(ctx context.Context, g gateway.Gateway) er
}
reissueDBCerts := func() error {
cluster, err := s.resolveCluster(g.TargetURI())
cluster, _, err := s.resolveCluster(g.TargetURI())
if err != nil {
return trace.Wrap(err)
}
@@ -475,7 +475,7 @@ func (s *Service) SetGatewayLocalPort(gatewayURI, localPort string) (gateway.Gat
// GetServers accepts parameterized input to enable searching, sorting, and pagination.
func (s *Service) GetServers(ctx context.Context, req *api.GetServersRequest) (*clusters.GetServersResponse, error) {
cluster, err := s.ResolveCluster(req.ClusterUri)
cluster, _, err := s.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -489,7 +489,7 @@ func (s *Service) GetServers(ctx context.Context, req *api.GetServersRequest) (*
}
func (s *Service) GetRequestableRoles(ctx context.Context, req *api.GetRequestableRolesRequest) (*api.GetRequestableRolesResponse, error) {
cluster, err := s.ResolveCluster(req.ClusterUri)
cluster, _, err := s.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -507,7 +507,7 @@ func (s *Service) GetRequestableRoles(ctx context.Context, req *api.GetRequestab
// GetAccessRequests returns all access requests with filtered input
func (s *Service) GetAccessRequests(ctx context.Context, req *api.GetAccessRequestsRequest) ([]clusters.AccessRequest, error) {
cluster, err := s.ResolveCluster(req.ClusterUri)
cluster, _, err := s.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -525,7 +525,7 @@ func (s *Service) GetAccessRequest(ctx context.Context, req *api.GetAccessReques
return nil, trace.BadParameter("missing request id")
}
cluster, err := s.ResolveCluster(req.ClusterUri)
cluster, _, err := s.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -542,7 +542,7 @@ func (s *Service) GetAccessRequest(ctx context.Context, req *api.GetAccessReques
// CreateAccessRequest creates an access request
func (s *Service) CreateAccessRequest(ctx context.Context, req *api.CreateAccessRequestRequest) (*clusters.AccessRequest, error) {
cluster, err := s.ResolveCluster(req.RootClusterUri)
cluster, _, err := s.ResolveCluster(req.RootClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -555,7 +555,7 @@ func (s *Service) CreateAccessRequest(ctx context.Context, req *api.CreateAccess
}
func (s *Service) ReviewAccessRequest(ctx context.Context, req *api.ReviewAccessRequestRequest) (*clusters.AccessRequest, error) {
cluster, err := s.ResolveCluster(req.RootClusterUri)
cluster, _, err := s.ResolveCluster(req.RootClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -572,7 +572,7 @@ func (s *Service) DeleteAccessRequest(ctx context.Context, req *api.DeleteAccess
return trace.BadParameter("missing request id")
}
cluster, err := s.ResolveCluster((req.RootClusterUri))
cluster, _, err := s.ResolveCluster(req.RootClusterUri)
if err != nil {
return trace.Wrap(err)
}
@@ -586,7 +586,7 @@ func (s *Service) DeleteAccessRequest(ctx context.Context, req *api.DeleteAccess
}
func (s *Service) AssumeRole(ctx context.Context, req *api.AssumeRoleRequest) error {
cluster, err := s.ResolveCluster(req.RootClusterUri)
cluster, _, err := s.ResolveCluster(req.RootClusterUri)
if err != nil {
return trace.Wrap(err)
}
@@ -601,7 +601,7 @@ func (s *Service) AssumeRole(ctx context.Context, req *api.AssumeRoleRequest) er
// GetKubes accepts parameterized input to enable searching, sorting, and pagination.
func (s *Service) GetKubes(ctx context.Context, req *api.GetKubesRequest) (*clusters.GetKubesResponse, error) {
cluster, err := s.ResolveCluster(req.ClusterUri)
cluster, _, err := s.ResolveCluster(req.ClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -681,15 +681,6 @@ func (s *Service) UpdateAndDialTshdEventsServerAddress(serverAddress string) err
return nil
}
func (s *Service) TransferFile(ctx context.Context, request *api.FileTransferRequest, sendProgress clusters.FileTransferProgressSender) error {
cluster, err := s.ResolveCluster(request.GetServerUri())
if err != nil {
return trace.Wrap(err)
}
return cluster.TransferFile(ctx, request, sendProgress)
}
// notifyApp sends a notification (usually an error) to the Electron App.
func (s *Service) notifyApp(ctx context.Context, notification *api.SendNotificationRequest) error {
tshdEventsCtx, cancelTshdEventsCtx := context.WithTimeout(ctx, tshdEventsTimeout)
@@ -699,6 +690,48 @@ func (s *Service) notifyApp(ctx context.Context, notification *api.SendNotificat
return trace.Wrap(err)
}
func (s *Service) TransferFile(ctx context.Context, request *api.FileTransferRequest, sendProgress clusters.FileTransferProgressSender) error {
cluster, _, err := s.ResolveCluster(request.GetServerUri())
if err != nil {
return trace.Wrap(err)
}
return cluster.TransferFile(ctx, request, sendProgress)
}
// CreateConnectMyComputerRole creates a role which allows access to nodes with the label
// teleport.dev/connect-my-computer/owner: <cluster user> and allows logging in to those nodes as
// the current system user.
func (s *Service) CreateConnectMyComputerRole(ctx context.Context, req *api.CreateConnectMyComputerRoleRequest) (*api.CreateConnectMyComputerRoleResponse, error) {
cluster, clusterClient, err := s.ResolveCluster(req.RootClusterUri)
if err != nil {
return nil, trace.Wrap(err)
}
response := &api.CreateConnectMyComputerRoleResponse{}
err = clusters.AddMetadataToRetryableError(ctx, func() error {
proxyClient, err := clusterClient.ConnectToProxy(ctx)
if err != nil {
return trace.Wrap(err)
}
defer proxyClient.Close()
authClient, err := proxyClient.ConnectToCluster(ctx, clusterClient.SiteName)
if err != nil {
return trace.Wrap(err)
}
defer authClient.Close()
result, err := s.cfg.ConnectMyComputerRoleSetup.Run(ctx, authClient, proxyClient, cluster)
if err != nil {
return trace.Wrap(err)
}
response.CertsReloaded = result.CertsReloaded
return nil
})
return response, trace.Wrap(err)
}
// Service is the daemon service
type Service struct {
cfg *Config
+2 -2
View File
@@ -29,7 +29,7 @@ import (
// UpdateHeadlessAuthenticationState updates a headless authentication state.
func (s *Service) UpdateHeadlessAuthenticationState(ctx context.Context, clusterURI, headlessID string, state api.HeadlessAuthenticationState) error {
cluster, err := s.ResolveCluster(clusterURI)
cluster, _, err := s.ResolveCluster(clusterURI)
if err != nil {
return trace.Wrap(err)
}
@@ -46,7 +46,7 @@ func (s *Service) StartHeadlessWatcher(uri string) error {
s.headlessWatcherClosersMu.Lock()
defer s.headlessWatcherClosersMu.Unlock()
cluster, err := s.ResolveCluster(uri)
cluster, _, err := s.ResolveCluster(uri)
if err != nil {
return trace.Wrap(err)
}
@@ -0,0 +1,283 @@
// Copyright 2023 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package connectmycomputer
import (
"context"
"fmt"
"os/user"
"time"
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/teleterm/clusters"
)
type RoleSetup struct {
cfg *RoleSetupConfig
}
func NewRoleSetup(cfg *RoleSetupConfig) (*RoleSetup, error) {
err := cfg.CheckAndSetDefaults()
if err != nil {
return nil, err
}
return &RoleSetup{cfg: cfg}, nil
}
type RoleSetupResult struct {
CertsReloaded bool
}
// Run ensures that at the end of its execution the user has their own individual Connect My
// Computer role and that the role includes the current system username in allowed logins.
//
// If the role list of the user got updated, the return value has CertsReloaded set to true.
func (s *RoleSetup) Run(ctx context.Context, accessAndIdentity AccessAndIdentity, certManager CertManager, cluster *clusters.Cluster) (RoleSetupResult, error) {
noCertsReloaded := RoleSetupResult{}
if !cluster.URI.IsRoot() {
return noCertsReloaded, trace.BadParameter("Connect My Computer works only with root clusters")
}
// Do not use GetCurrentUser – it returns the current view of the user given the certs, not merely
// the resource from the backend. This means that GetCurrentUser includes any roles granted
// through access requests. We don't want that since we're later going to update the user.
clusterUser, err := accessAndIdentity.GetUser(cluster.GetLoggedInUser().Name, false /* withSecrets */)
if err != nil {
return noCertsReloaded, trace.Wrap(err)
}
isLocalUser := clusterUser.GetCreatedBy().Connector == nil
if !isLocalUser {
return noCertsReloaded,
trace.BadParameter("Connect My Computer works only with local users, the user %v was created by %v connector",
clusterUser.GetName(), clusterUser.GetCreatedBy().Connector.Type)
}
roleName := fmt.Sprintf("%v%v", teleport.ConnectMyComputerRoleNamePrefix, clusterUser.GetName())
doesRoleExist := true
existingRole, err := accessAndIdentity.GetRole(ctx, roleName)
if err != nil {
if trace.IsNotFound(err) {
doesRoleExist = false
} else {
return noCertsReloaded, trace.Wrap(err)
}
}
systemUser, err := user.Current()
if err != nil {
return noCertsReloaded, trace.Wrap(err)
}
if !doesRoleExist {
s.cfg.Log.Infof("Creating the role %v.", roleName)
role, err := types.NewRole(roleName, types.RoleSpecV6{
Allow: types.RoleConditions{
NodeLabels: types.Labels{
types.ConnectMyComputerNodeOwnerLabel: []string{clusterUser.GetName()},
},
Logins: []string{systemUser.Username},
},
})
if err != nil {
return noCertsReloaded, trace.Wrap(err)
}
if err = accessAndIdentity.UpsertRole(ctx, role); err != nil {
return noCertsReloaded, trace.Wrap(err, "creating role %v", role.GetName())
}
} else {
s.cfg.Log.Infof("The role %v already exists", roleName)
isRoleDirty := false
// Ensure that the current system username is in the role.
//
// This is to account for a use case where the same cluster user attempts to set up the role on
// two different devices, potentially using two different system usernames. Since the role is
// scoped per cluster user, it must include both system username
allowedLogins := existingRole.GetLogins(types.Allow)
if !slices.Contains(allowedLogins, systemUser.Username) {
s.cfg.Log.Infof("Adding %v to the logins of the role %v.", systemUser.Username, roleName)
existingRole.SetLogins(types.Allow, append(allowedLogins, systemUser.Username))
isRoleDirty = true
}
// Ensure that the owner label has the expected value.
//
// This can happen only if someone has manually edited the role. Ensuring it has the expected
// value will make sure that the user is able to connect to relevant nodes. This is done more to
// reduce the support load than to make the feature more secure.
allowedNodeLabels := existingRole.GetNodeLabels(types.Allow)
ownerNodeLabelValue := allowedNodeLabels[types.ConnectMyComputerNodeOwnerLabel]
expectedOwnerNodeLabelValue := []string{clusterUser.GetName()}
if !slices.Equal(ownerNodeLabelValue, expectedOwnerNodeLabelValue) {
s.cfg.Log.Infof("Overwriting the owner node label in the role %v.", roleName)
allowedNodeLabels[types.ConnectMyComputerNodeOwnerLabel] = expectedOwnerNodeLabelValue
isRoleDirty = true
}
if isRoleDirty {
timeoutCtx, cancel := context.WithTimeout(ctx, resourceUpdateTimeout)
defer cancel()
err = s.syncResourceUpdate(timeoutCtx, accessAndIdentity, existingRole, func(ctx context.Context) error {
return trace.Wrap(accessAndIdentity.UpsertRole(ctx, existingRole),
"updating role %v", existingRole.GetName())
})
if err != nil {
return noCertsReloaded, trace.Wrap(err)
}
}
}
hasCMCRole := slices.Contains(clusterUser.GetRoles(), roleName)
if hasCMCRole {
s.cfg.Log.Infof("The user %v already has the role %v.", clusterUser.GetName(), roleName)
return noCertsReloaded, nil
}
s.cfg.Log.Infof("Adding the role %v to the user %v.", roleName, clusterUser.GetName())
clusterUser.AddRole(roleName)
timeoutCtx, cancel := context.WithTimeout(ctx, resourceUpdateTimeout)
defer cancel()
err = s.syncResourceUpdate(timeoutCtx, accessAndIdentity, clusterUser, func(ctx context.Context) error {
return trace.Wrap(accessAndIdentity.UpdateUser(ctx, clusterUser),
"updating user %v", clusterUser.GetName())
})
if err != nil {
return noCertsReloaded, trace.Wrap(err)
}
s.cfg.Log.Info("Reissuing certs.")
// ReissueUserCerts called with CertCacheDrop and a bogus access request ID in DropAccessRequests
// allows us to refresh the role list in the certs without forcing the user to relogin.
//
// Sending bogus request IDs is not documented but it is covered by tests. Refreshing roles based
// on the server state is necessary for tsh request drop to work.
//
// If passing bogus request IDs ever needs to be removed, then there are two options here:
// * Pass a wildcard instead. This will break setups where people use access requests to make
// Connect My Computer work. Most users will probably not use access requests for that though.
// * Invalidate the stored certs somehow to force the user to relogin. If Connect makes a request
// after role setup and [client.IsErrorResolvableWithRelogin] returns true for the error from
// the response, Connect will ask the user to relogin.
//
// TODO(ravicious): Expand auth.ServerWithRoles.GenerateUserCerts to support refreshing role
// list without having to send a bogus request ID.
err = certManager.ReissueUserCerts(ctx, client.CertCacheDrop, client.ReissueParams{
RouteToCluster: cluster.Name,
DropAccessRequests: []string{fmt.Sprintf("bogus-request-id-%v", uuid.NewString())},
})
return RoleSetupResult{CertsReloaded: true}, trace.Wrap(err)
}
const resourceUpdateTimeout = 15 * time.Second
// syncResourceUpdate calls a function which updates the given resource and then waits until the
// cache propagates the change.
func (s *RoleSetup) syncResourceUpdate(ctx context.Context, accessAndIdentity AccessAndIdentity, resource types.Resource, updateFunc func(context.Context) error) error {
watcher, err := accessAndIdentity.NewWatcher(ctx, types.Watch{
Kinds: []types.WatchKind{
{Kind: resource.GetKind()},
},
})
if err != nil {
return trace.Wrap(err)
}
defer watcher.Close()
// Wait for OpInit.
select {
case <-ctx.Done():
return trace.Wrap(ctx.Err(), "initializing watcher")
case <-watcher.Done():
return trace.Wrap(watcher.Error(), "initializing watcher")
case event := <-watcher.Events():
if event.Type != types.OpInit {
return trace.Errorf("unexpected event type %q received from resource watcher", event.Type)
}
}
err = updateFunc(ctx)
if err != nil {
return trace.Wrap(err, "calling update function")
}
for {
select {
case <-ctx.Done():
return trace.Wrap(ctx.Err(), "waiting for OpPut event for %v", resource.GetName())
case <-watcher.Done():
return trace.Wrap(watcher.Error(), "waiting for OpPut event for %v", resource.GetName())
case event := <-watcher.Events():
if event.Type != types.OpPut {
continue
}
// Kind + name combo is enough to uniquely identify a resource within a single cluster.
if event.Resource.GetKind() == resource.GetKind() && event.Resource.GetName() == resource.GetName() {
return nil
}
}
}
}
// AccessAndIdentity represents services.Access, services.Identity and auth.Cache methods used
// by [RoleSetup]. During a normal operation, auth.ClientI is passed as this interface.
type AccessAndIdentity interface {
// See services.Access.GetRole.
GetRole(ctx context.Context, name string) (types.Role, error)
// See services.Access.UpsertRole.
UpsertRole(context.Context, types.Role) error
// See auth.Cache.NewWatcher.
NewWatcher(ctx context.Context, watch types.Watch) (types.Watcher, error)
// See services.Identity.GetUser.
GetUser(name string, withSecrets bool) (types.User, error)
// See services.Identity.UpdateUser.
UpdateUser(context.Context, types.User) error
}
// CertManager enables the usage of only select methods from [client.ProxyClient] so that there
// is no need to mock the whole ProxyClient interface in tests.
type CertManager interface {
// See [client.ProxyClient.ReissueUserCerts].
ReissueUserCerts(context.Context, client.CertCachePolicy, client.ReissueParams) error
}
type RoleSetupConfig struct {
Log *logrus.Entry
}
func (c *RoleSetupConfig) CheckAndSetDefaults() error {
if c.Log == nil {
c.Log = logrus.NewEntry(logrus.StandardLogger()).WithField(trace.Component, "CMC role")
}
return nil
}
@@ -0,0 +1,188 @@
// Copyright 2023 Gravitational, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package connectmycomputer
import (
"context"
"sync"
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/teleterm/api/uri"
"github.com/gravitational/teleport/lib/teleterm/clusters"
)
func TestRoleSetupRun_WithNonLocalUser(t *testing.T) {
roleSetup, err := NewRoleSetup(&RoleSetupConfig{})
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
oidcUser, err := types.NewUser("alice")
require.NoError(t, err)
oidcUser.SetCreatedBy(types.CreatedBy{
Connector: &types.ConnectorRef{Type: "oidc", ID: "google"},
})
accessAndIdentity := &mockAccessAndIdentity{user: oidcUser}
certManager := &mockCertManager{}
_, err = roleSetup.Run(ctx, accessAndIdentity, certManager, &clusters.Cluster{URI: uri.NewClusterURI("foo")})
require.True(t, trace.IsBadParameter(err))
}
// During development, I already managed to introduce a bug in a conditional which resulted in a
// resource being updated on every run of RoleSetup.
// The integration tests won't catch that since they worry about the end result only.
func TestRoleSetupRun_Idempotency(t *testing.T) {
roleSetup, err := NewRoleSetup(&RoleSetupConfig{})
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
user, err := types.NewUser("alice")
require.NoError(t, err)
events := &mockEvents{}
accessAndIdentity := &mockAccessAndIdentity{
user: user,
callCounts: make(map[string]int),
events: events,
}
certManager := &mockCertManager{}
_, err = roleSetup.Run(ctx, accessAndIdentity, certManager, &clusters.Cluster{URI: uri.NewClusterURI("foo")})
require.NoError(t, err)
_, err = roleSetup.Run(ctx, accessAndIdentity, certManager, &clusters.Cluster{URI: uri.NewClusterURI("foo")})
require.NoError(t, err)
require.Equal(t, 1, accessAndIdentity.callCounts["UpsertRole"], "expected two runs to update the role only once")
require.Equal(t, 1, accessAndIdentity.callCounts["UpdateUser"], "expected two runs to update the user only once")
}
type mockAccessAndIdentity struct {
user types.User
role types.Role
callCounts map[string]int
events *mockEvents
}
func (m *mockAccessAndIdentity) GetUser(name string, withSecrets bool) (types.User, error) {
return m.user, nil
}
func (m *mockAccessAndIdentity) GetRole(ctx context.Context, name string) (types.Role, error) {
if m.role != nil {
return m.role, nil
}
return nil, trace.NotFound("role not found")
}
func (m *mockAccessAndIdentity) UpsertRole(ctx context.Context, role types.Role) error {
m.callCounts["UpsertRole"]++
m.role = role
m.events.Fire(types.Event{
Type: types.OpPut,
Resource: role,
})
return nil
}
func (m *mockAccessAndIdentity) NewWatcher(ctx context.Context, watch types.Watch) (types.Watcher, error) {
watcher, err := m.events.NewWatcher(ctx, watch)
if err != nil {
return nil, trace.Wrap(err)
}
m.events.Fire(types.Event{Type: types.OpInit})
return watcher, nil
}
func (m *mockAccessAndIdentity) UpdateUser(ctx context.Context, user types.User) error {
m.callCounts["UpdateUser"]++
m.user = user
m.events.Fire(types.Event{
Type: types.OpPut,
Resource: user,
})
return nil
}
type mockCertManager struct{}
func (m *mockCertManager) ReissueUserCerts(context.Context, client.CertCachePolicy, client.ReissueParams) error {
return nil
}
// mockEvents enables sending out events to watchers from within a test or other mocks.
// The implementation is copied from integrations/lib/watcherjob/helpers_test.go.
type mockEvents struct {
sync.Mutex
channels []chan<- types.Event
}
// NewWatcher creates a new watcher.
func (e *mockEvents) NewWatcher(ctx context.Context, watch types.Watch) (types.Watcher, error) {
events := make(chan types.Event, 1000)
e.Lock()
e.channels = append(e.channels, events)
e.Unlock()
ctx, cancel := context.WithCancel(ctx)
return mockWatcher{events: events, ctx: ctx, cancel: cancel}, ctx.Err()
}
// Fire emits a watcher events for all the subscribers to consume.
func (e *mockEvents) Fire(event types.Event) {
e.Lock()
channels := e.channels
e.Unlock()
for _, events := range channels {
events <- event
}
}
// mockWatcher is copied from integrations/lib/watcherjob/helpers_test.go.
type mockWatcher struct {
events <-chan types.Event
ctx context.Context
cancel context.CancelFunc
}
// Events returns a stream of events.
func (w mockWatcher) Events() <-chan types.Event {
return w.events
}
// Done returns a completion channel.
func (w mockWatcher) Done() <-chan struct{} {
return w.ctx.Done()
}
// Close sends a termination signal to watcher.
func (w mockWatcher) Close() error {
w.cancel()
return nil
}
// Error returns a watcher error.
func (w mockWatcher) Error() error {
return trace.Wrap(w.ctx.Err())
}
+1 -1
View File
@@ -33,7 +33,7 @@ lint:
- teleport/lib/teleterm/v1/service.proto
# TODO(ravicious): Fix protos and re-enable lib/teleterm lint rules below.
RPC_REQUEST_STANDARD_NAME:
- teleport/lib/teleterm
- teleport/lib/teleterm/v1/service.proto
# TODO(espadolini): Fix protos and re-enable prehog lint rules below.
COMMENT_MESSAGE:
- teleport/lib/teleterm
@@ -123,6 +123,11 @@ service TerminalService {
// UpdateHeadlessAuthenticationState updates a headless authentication resource's state.
// An MFA challenge will be prompted when approving a headless authentication.
rpc UpdateHeadlessAuthenticationState(UpdateHeadlessAuthenticationStateRequest) returns (UpdateHeadlessAuthenticationStateResponse);
// CreateConnectMyComputerRole creates a role which allows access to nodes with the label
// teleport.dev/connect-my-computer/owner: <cluster user> and allows logging in to those nodes as
// the current system user.
rpc CreateConnectMyComputerRole(CreateConnectMyComputerRoleRequest) returns (CreateConnectMyComputerRoleResponse);
}
message EmptyResponse {}
@@ -439,3 +444,12 @@ enum HeadlessAuthenticationState {
}
message UpdateHeadlessAuthenticationStateResponse {}
message CreateConnectMyComputerRoleRequest {
string root_cluster_uri = 1;
}
message CreateConnectMyComputerRoleResponse {
// certs_reloaded signals to the Electron app that tshd has reloaded the certs in order to refresh
// the role list. The Electron app should refresh the details from the user cert as well.
bool certs_reloaded = 1;
}
@@ -648,7 +648,27 @@ export default function createClient(
});
});
},
createConnectMyComputerRole(rootClusterUri: uri.RootClusterUri) {
const req =
new api.CreateConnectMyComputerRoleRequest().setRootClusterUri(
rootClusterUri
);
return new Promise<types.CreateConnectMyComputerRoleResponse>(
(resolve, reject) => {
tshd.createConnectMyComputerRole(req, (err, response) => {
if (err) {
reject(err);
} else {
resolve(response.toObject());
}
});
}
);
},
};
return client;
}
@@ -34,6 +34,7 @@ import {
TshAbortSignal,
TshClient,
GetRequestableRolesResponse,
CreateConnectMyComputerRoleResponse,
} from '../types';
export class MockTshClient implements TshClient {
@@ -97,4 +98,6 @@ export class MockTshClient implements TshClient {
logout = () => Promise.resolve();
transferFile: () => undefined;
reportUsageEvent: () => undefined;
createConnectMyComputerRole: () => Promise<CreateConnectMyComputerRoleResponse>;
}
@@ -229,6 +229,10 @@ export type TshClient = {
abortSignal?: TshAbortSignal
) => FileTransferListeners;
reportUsageEvent: (event: ReportUsageEventRequest) => Promise<void>;
createConnectMyComputerRole: (
rootClusterUri: uri.RootClusterUri
) => Promise<CreateConnectMyComputerRoleResponse>;
};
export type TshAbortController = {
@@ -316,5 +320,8 @@ export { FileTransferDirection };
export type Label = apiLabel.Label.AsObject;
export type CreateConnectMyComputerRoleResponse =
apiService.CreateConnectMyComputerRoleResponse.AsObject;
// Replaces object property with a new type
type Modify<T, R> = Omit<T, keyof R> & R;
@@ -24,6 +24,8 @@ import { CircleCheck, CircleCross, CirclePlay, Spinner } from 'design/Icon';
import * as types from 'teleterm/ui/services/workspacesService';
import { useAppContext } from 'teleterm/ui/appContextProvider';
import Document from 'teleterm/ui/Document';
import { useWorkspaceContext } from 'teleterm/ui/Documents';
import { retryWithRelogin } from 'teleterm/ui/utils';
interface DocumentConnectMyComputerSetupProps {
visible: boolean;
@@ -82,9 +84,34 @@ function Information(props: { onSetUpAgentClick(): void }) {
function AgentSetup() {
const ctx = useAppContext();
const { rootClusterUri } = useWorkspaceContext();
const [setUpRolesAttempt, runSetUpRolesAttempt] = useAsync(
useCallback(() => wait(1_000), [])
useCallback(async () => {
retryWithRelogin(ctx, rootClusterUri, async () => {
let certsReloaded = false;
try {
const response = await ctx.connectMyComputerService.createRole(
rootClusterUri
);
certsReloaded = response.certsReloaded;
} catch (error) {
if ((error.message as string)?.includes('access denied')) {
throw new Error(
'Access denied. Contact your administrator for permissions to manage users and roles.'
);
}
throw error;
}
// If tshd reloaded the certs to refresh the role list, the Electron app must resync details
// of the cluster to also update the role list in the UI.
if (certsReloaded) {
await ctx.clustersService.syncRootCluster(rootClusterUri);
}
});
}, [ctx, rootClusterUri])
);
const [downloadAgentAttempt, runDownloadAgentAttempt] = useAsync(
useCallback(
@@ -101,7 +128,7 @@ function AgentSetup() {
const steps = [
{
name: 'Setting up roles',
name: 'Setting up the role',
attempt: setUpRolesAttempt,
},
{
@@ -121,7 +148,7 @@ function AgentSetup() {
const runSteps = useCallback(async () => {
// uncomment when implemented
const actions = [
// runSetUpRolesAttempt,
runSetUpRolesAttempt,
runDownloadAgentAttempt,
// runGenerateConfigFileAttempt,
// runJoinClusterAttempt,
@@ -74,10 +74,8 @@ export function NavigationMenu(props: NavigationMenuProps) {
<Popover
open={isPopoverOpened}
anchorEl={iconRef.current}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
onClose={() => setIsPopoverOpened(false)}
>
<Container width="200px">
+2 -1
View File
@@ -134,7 +134,8 @@ export default class AppContext implements IAppContext {
this.clustersService
);
this.connectMyComputerService = new ConnectMyComputerService(
this.mainProcessClient
this.mainProcessClient,
tshClient
);
}
@@ -149,7 +149,7 @@ export class ClustersService extends ImmutableStore<types.ClustersServiceState>
* syncRootCluster is useful in situations where we want to sync the cluster _and_ propagate any
* errors up.
*/
private async syncRootCluster(clusterUri: uri.RootClusterUri) {
async syncRootCluster(clusterUri: uri.RootClusterUri) {
await Promise.all([
this.syncClusterInfo(clusterUri),
this.syncLeafClustersList(clusterUri),
@@ -15,11 +15,26 @@
*/
import { MainProcessClient } from 'teleterm/mainProcess/types';
import {
CreateConnectMyComputerRoleResponse,
TshClient,
} from 'teleterm/services/tshd/types';
import type * as uri from 'teleterm/ui/uri';
export class ConnectMyComputerService {
constructor(private mainProcessClient: MainProcessClient) {}
constructor(
private mainProcessClient: MainProcessClient,
private tshClient: TshClient
) {}
async downloadAgent(): Promise<void> {
await this.mainProcessClient.downloadAgent();
}
createRole(
rootClusterUri: uri.RootClusterUri
): Promise<CreateConnectMyComputerRoleResponse> {
return this.tshClient.createConnectMyComputerRole(rootClusterUri);
}
}