mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Teleport Connect MFA prompt (#34135)
* Add PromptMFA to tshd event service. * Add custom MFA prompt using the tshd event service PromptMFA method. * Generalize and reuse mfa prompt goroutine logic. * Use important modal sempahore for MFA prompts. * Update lib/client/api.go Co-authored-by: Lisa Kim <[email protected]> * Fix file name. * Fix lint. --------- Co-authored-by: Lisa Kim <[email protected]>
This commit is contained in:
co-authored by
Lisa Kim
parent
c8a81a4b0f
commit
704f3fccd3
@@ -484,6 +484,124 @@ func (*SendPendingHeadlessAuthenticationResponse) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
type PromptMFARequest 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"`
|
||||
Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
|
||||
Totp bool `protobuf:"varint,3,opt,name=totp,proto3" json:"totp,omitempty"`
|
||||
Webauthn bool `protobuf:"varint,4,opt,name=webauthn,proto3" json:"webauthn,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) Reset() {
|
||||
*x = PromptMFARequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PromptMFARequest) ProtoMessage() {}
|
||||
|
||||
func (x *PromptMFARequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PromptMFARequest.ProtoReflect.Descriptor instead.
|
||||
func (*PromptMFARequest) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) GetRootClusterUri() string {
|
||||
if x != nil {
|
||||
return x.RootClusterUri
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) GetReason() string {
|
||||
if x != nil {
|
||||
return x.Reason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) GetTotp() bool {
|
||||
if x != nil {
|
||||
return x.Totp
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PromptMFARequest) GetWebauthn() bool {
|
||||
if x != nil {
|
||||
return x.Webauthn
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type PromptMFAResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TotpCode string `protobuf:"bytes,1,opt,name=totp_code,json=totpCode,proto3" json:"totp_code,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PromptMFAResponse) Reset() {
|
||||
*x = PromptMFAResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PromptMFAResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PromptMFAResponse) ProtoMessage() {}
|
||||
|
||||
func (x *PromptMFAResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[9]
|
||||
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 PromptMFAResponse.ProtoReflect.Descriptor instead.
|
||||
func (*PromptMFAResponse) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *PromptMFAResponse) GetTotpCode() string {
|
||||
if x != nil {
|
||||
return x.TotpCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_teleport_lib_teleterm_v1_tshd_events_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDesc = []byte{
|
||||
@@ -545,39 +663,57 @@ var file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x22, 0x2b, 0x0a, 0x29, 0x53, 0x65,
|
||||
0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73,
|
||||
0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9d, 0x03, 0x0a, 0x11, 0x54, 0x73, 0x68, 0x64,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5e, 0x0a,
|
||||
0x07, 0x52, 0x65, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x28, 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, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 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, 0x52, 0x65,
|
||||
0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a,
|
||||
0x10, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 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, 0x53, 0x65, 0x6e,
|
||||
0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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,
|
||||
0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x53, 0x65, 0x6e,
|
||||
0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73,
|
||||
0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65,
|
||||
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65,
|
||||
0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73,
|
||||
0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x84, 0x01, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x6d,
|
||||
0x70, 0x74, 0x4d, 0x46, 0x41, 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, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x74, 0x6f, 0x74, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x74, 0x6f,
|
||||
0x74, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x22, 0x30,
|
||||
0x0a, 0x11, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x6f, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x6f, 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65,
|
||||
0x32, 0x83, 0x04, 0x0a, 0x11, 0x54, 0x73, 0x68, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x07, 0x52, 0x65, 0x6c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x12, 0x28, 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, 0x6c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x52, 0x65, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f,
|
||||
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65, 0x6e, 0x64, 0x4e, 0x6f, 0x74,
|
||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0xac, 0x01, 0x0a, 0x21, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e,
|
||||
0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65,
|
||||
0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 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, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x65, 0x6e, 0x64, 0x69,
|
||||
0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x64, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 0x12, 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, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d,
|
||||
0x46, 0x41, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 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, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4d, 0x46, 0x41, 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 (
|
||||
@@ -592,7 +728,7 @@ func file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescGZIP() []byt
|
||||
return file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_teleport_lib_teleterm_v1_tshd_events_service_proto_goTypes = []interface{}{
|
||||
(*ReloginRequest)(nil), // 0: teleport.lib.teleterm.v1.ReloginRequest
|
||||
(*GatewayCertExpired)(nil), // 1: teleport.lib.teleterm.v1.GatewayCertExpired
|
||||
@@ -602,6 +738,8 @@ var file_teleport_lib_teleterm_v1_tshd_events_service_proto_goTypes = []interfac
|
||||
(*SendNotificationResponse)(nil), // 5: teleport.lib.teleterm.v1.SendNotificationResponse
|
||||
(*SendPendingHeadlessAuthenticationRequest)(nil), // 6: teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationRequest
|
||||
(*SendPendingHeadlessAuthenticationResponse)(nil), // 7: teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse
|
||||
(*PromptMFARequest)(nil), // 8: teleport.lib.teleterm.v1.PromptMFARequest
|
||||
(*PromptMFAResponse)(nil), // 9: teleport.lib.teleterm.v1.PromptMFAResponse
|
||||
}
|
||||
var file_teleport_lib_teleterm_v1_tshd_events_service_proto_depIdxs = []int32{
|
||||
1, // 0: teleport.lib.teleterm.v1.ReloginRequest.gateway_cert_expired:type_name -> teleport.lib.teleterm.v1.GatewayCertExpired
|
||||
@@ -609,11 +747,13 @@ var file_teleport_lib_teleterm_v1_tshd_events_service_proto_depIdxs = []int32{
|
||||
0, // 2: teleport.lib.teleterm.v1.TshdEventsService.Relogin:input_type -> teleport.lib.teleterm.v1.ReloginRequest
|
||||
3, // 3: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:input_type -> teleport.lib.teleterm.v1.SendNotificationRequest
|
||||
6, // 4: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:input_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationRequest
|
||||
2, // 5: teleport.lib.teleterm.v1.TshdEventsService.Relogin:output_type -> teleport.lib.teleterm.v1.ReloginResponse
|
||||
5, // 6: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:output_type -> teleport.lib.teleterm.v1.SendNotificationResponse
|
||||
7, // 7: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:output_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse
|
||||
5, // [5:8] is the sub-list for method output_type
|
||||
2, // [2:5] is the sub-list for method input_type
|
||||
8, // 5: teleport.lib.teleterm.v1.TshdEventsService.PromptMFA:input_type -> teleport.lib.teleterm.v1.PromptMFARequest
|
||||
2, // 6: teleport.lib.teleterm.v1.TshdEventsService.Relogin:output_type -> teleport.lib.teleterm.v1.ReloginResponse
|
||||
5, // 7: teleport.lib.teleterm.v1.TshdEventsService.SendNotification:output_type -> teleport.lib.teleterm.v1.SendNotificationResponse
|
||||
7, // 8: teleport.lib.teleterm.v1.TshdEventsService.SendPendingHeadlessAuthentication:output_type -> teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse
|
||||
9, // 9: teleport.lib.teleterm.v1.TshdEventsService.PromptMFA:output_type -> teleport.lib.teleterm.v1.PromptMFAResponse
|
||||
6, // [6:10] is the sub-list for method output_type
|
||||
2, // [2:6] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
@@ -721,6 +861,30 @@ func file_teleport_lib_teleterm_v1_tshd_events_service_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PromptMFARequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PromptMFAResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_teleport_lib_teleterm_v1_tshd_events_service_proto_msgTypes[0].OneofWrappers = []interface{}{
|
||||
(*ReloginRequest_GatewayCertExpired)(nil),
|
||||
@@ -734,7 +898,7 @@ func file_teleport_lib_teleterm_v1_tshd_events_service_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_teleport_lib_teleterm_v1_tshd_events_service_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 8,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -39,6 +39,7 @@ const (
|
||||
TshdEventsService_Relogin_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/Relogin"
|
||||
TshdEventsService_SendNotification_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/SendNotification"
|
||||
TshdEventsService_SendPendingHeadlessAuthentication_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/SendPendingHeadlessAuthentication"
|
||||
TshdEventsService_PromptMFA_FullMethodName = "/teleport.lib.teleterm.v1.TshdEventsService/PromptMFA"
|
||||
)
|
||||
|
||||
// TshdEventsServiceClient is the client API for TshdEventsService service.
|
||||
@@ -55,6 +56,8 @@ type TshdEventsServiceClient interface {
|
||||
// SendPendingHeadlessAuthentication notifies the Electron app of a pending headless authentication,
|
||||
// which it can use to initiate headless authentication resolution in the UI.
|
||||
SendPendingHeadlessAuthentication(ctx context.Context, in *SendPendingHeadlessAuthenticationRequest, opts ...grpc.CallOption) (*SendPendingHeadlessAuthenticationResponse, error)
|
||||
// PromptMFA notifies the Electron app that the daemon is waiting for the user to answer an MFA prompt.
|
||||
PromptMFA(ctx context.Context, in *PromptMFARequest, opts ...grpc.CallOption) (*PromptMFAResponse, error)
|
||||
}
|
||||
|
||||
type tshdEventsServiceClient struct {
|
||||
@@ -92,6 +95,15 @@ func (c *tshdEventsServiceClient) SendPendingHeadlessAuthentication(ctx context.
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tshdEventsServiceClient) PromptMFA(ctx context.Context, in *PromptMFARequest, opts ...grpc.CallOption) (*PromptMFAResponse, error) {
|
||||
out := new(PromptMFAResponse)
|
||||
err := c.cc.Invoke(ctx, TshdEventsService_PromptMFA_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TshdEventsServiceServer is the server API for TshdEventsService service.
|
||||
// All implementations must embed UnimplementedTshdEventsServiceServer
|
||||
// for forward compatibility
|
||||
@@ -106,6 +118,8 @@ type TshdEventsServiceServer interface {
|
||||
// SendPendingHeadlessAuthentication notifies the Electron app of a pending headless authentication,
|
||||
// which it can use to initiate headless authentication resolution in the UI.
|
||||
SendPendingHeadlessAuthentication(context.Context, *SendPendingHeadlessAuthenticationRequest) (*SendPendingHeadlessAuthenticationResponse, error)
|
||||
// PromptMFA notifies the Electron app that the daemon is waiting for the user to answer an MFA prompt.
|
||||
PromptMFA(context.Context, *PromptMFARequest) (*PromptMFAResponse, error)
|
||||
mustEmbedUnimplementedTshdEventsServiceServer()
|
||||
}
|
||||
|
||||
@@ -122,6 +136,9 @@ func (UnimplementedTshdEventsServiceServer) SendNotification(context.Context, *S
|
||||
func (UnimplementedTshdEventsServiceServer) SendPendingHeadlessAuthentication(context.Context, *SendPendingHeadlessAuthenticationRequest) (*SendPendingHeadlessAuthenticationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SendPendingHeadlessAuthentication not implemented")
|
||||
}
|
||||
func (UnimplementedTshdEventsServiceServer) PromptMFA(context.Context, *PromptMFARequest) (*PromptMFAResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method PromptMFA not implemented")
|
||||
}
|
||||
func (UnimplementedTshdEventsServiceServer) mustEmbedUnimplementedTshdEventsServiceServer() {}
|
||||
|
||||
// UnsafeTshdEventsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -189,6 +206,24 @@ func _TshdEventsService_SendPendingHeadlessAuthentication_Handler(srv interface{
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TshdEventsService_PromptMFA_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PromptMFARequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TshdEventsServiceServer).PromptMFA(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: TshdEventsService_PromptMFA_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TshdEventsServiceServer).PromptMFA(ctx, req.(*PromptMFARequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// TshdEventsService_ServiceDesc is the grpc.ServiceDesc for TshdEventsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -208,6 +243,10 @@ var TshdEventsService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "SendPendingHeadlessAuthentication",
|
||||
Handler: _TshdEventsService_SendPendingHeadlessAuthentication_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "PromptMFA",
|
||||
Handler: _TshdEventsService_PromptMFA_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "teleport/lib/teleterm/v1/tshd_events_service.proto",
|
||||
|
||||
+17
@@ -11,6 +11,7 @@ interface ITshdEventsServiceService extends grpc.ServiceDefinition<grpc.UntypedS
|
||||
relogin: ITshdEventsServiceService_IRelogin;
|
||||
sendNotification: ITshdEventsServiceService_ISendNotification;
|
||||
sendPendingHeadlessAuthentication: ITshdEventsServiceService_ISendPendingHeadlessAuthentication;
|
||||
promptMFA: ITshdEventsServiceService_IPromptMFA;
|
||||
}
|
||||
|
||||
interface ITshdEventsServiceService_IRelogin extends grpc.MethodDefinition<teleport_lib_teleterm_v1_tshd_events_service_pb.ReloginRequest, teleport_lib_teleterm_v1_tshd_events_service_pb.ReloginResponse> {
|
||||
@@ -40,6 +41,15 @@ interface ITshdEventsServiceService_ISendPendingHeadlessAuthentication extends g
|
||||
responseSerialize: grpc.serialize<teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse>;
|
||||
responseDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse>;
|
||||
}
|
||||
interface ITshdEventsServiceService_IPromptMFA extends grpc.MethodDefinition<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse> {
|
||||
path: "/teleport.lib.teleterm.v1.TshdEventsService/PromptMFA";
|
||||
requestStream: false;
|
||||
responseStream: false;
|
||||
requestSerialize: grpc.serialize<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest>;
|
||||
requestDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest>;
|
||||
responseSerialize: grpc.serialize<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse>;
|
||||
responseDeserialize: grpc.deserialize<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse>;
|
||||
}
|
||||
|
||||
export const TshdEventsServiceService: ITshdEventsServiceService;
|
||||
|
||||
@@ -47,6 +57,7 @@ export interface ITshdEventsServiceServer {
|
||||
relogin: grpc.handleUnaryCall<teleport_lib_teleterm_v1_tshd_events_service_pb.ReloginRequest, teleport_lib_teleterm_v1_tshd_events_service_pb.ReloginResponse>;
|
||||
sendNotification: grpc.handleUnaryCall<teleport_lib_teleterm_v1_tshd_events_service_pb.SendNotificationRequest, teleport_lib_teleterm_v1_tshd_events_service_pb.SendNotificationResponse>;
|
||||
sendPendingHeadlessAuthentication: grpc.handleUnaryCall<teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse>;
|
||||
promptMFA: grpc.handleUnaryCall<teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse>;
|
||||
}
|
||||
|
||||
export interface ITshdEventsServiceClient {
|
||||
@@ -59,6 +70,9 @@ export interface ITshdEventsServiceClient {
|
||||
sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
}
|
||||
|
||||
export class TshdEventsServiceClient extends grpc.Client implements ITshdEventsServiceClient {
|
||||
@@ -72,4 +86,7 @@ export class TshdEventsServiceClient extends grpc.Client implements ITshdEventsS
|
||||
public sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
public sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
public sendPendingHeadlessAuthentication(request: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.SendPendingHeadlessAuthenticationResponse) => void): grpc.ClientUnaryCall;
|
||||
public promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
public promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
public promptMFA(request: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse) => void): grpc.ClientUnaryCall;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,28 @@
|
||||
var grpc = require('@grpc/grpc-js');
|
||||
var teleport_lib_teleterm_v1_tshd_events_service_pb = require('../../../../teleport/lib/teleterm/v1/tshd_events_service_pb.js');
|
||||
|
||||
function serialize_teleport_lib_teleterm_v1_PromptMFARequest(arg) {
|
||||
if (!(arg instanceof teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest)) {
|
||||
throw new Error('Expected argument of type teleport.lib.teleterm.v1.PromptMFARequest');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_teleport_lib_teleterm_v1_PromptMFARequest(buffer_arg) {
|
||||
return teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_teleport_lib_teleterm_v1_PromptMFAResponse(arg) {
|
||||
if (!(arg instanceof teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse)) {
|
||||
throw new Error('Expected argument of type teleport.lib.teleterm.v1.PromptMFAResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_teleport_lib_teleterm_v1_PromptMFAResponse(buffer_arg) {
|
||||
return teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_teleport_lib_teleterm_v1_ReloginRequest(arg) {
|
||||
if (!(arg instanceof teleport_lib_teleterm_v1_tshd_events_service_pb.ReloginRequest)) {
|
||||
throw new Error('Expected argument of type teleport.lib.teleterm.v1.ReloginRequest');
|
||||
@@ -132,6 +154,18 @@ sendPendingHeadlessAuthentication: {
|
||||
responseSerialize: serialize_teleport_lib_teleterm_v1_SendPendingHeadlessAuthenticationResponse,
|
||||
responseDeserialize: deserialize_teleport_lib_teleterm_v1_SendPendingHeadlessAuthenticationResponse,
|
||||
},
|
||||
// PromptMFA notifies the Electron app that the daemon is waiting for the user to answer an MFA prompt.
|
||||
promptMFA: {
|
||||
path: '/teleport.lib.teleterm.v1.TshdEventsService/PromptMFA',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFARequest,
|
||||
responseType: teleport_lib_teleterm_v1_tshd_events_service_pb.PromptMFAResponse,
|
||||
requestSerialize: serialize_teleport_lib_teleterm_v1_PromptMFARequest,
|
||||
requestDeserialize: deserialize_teleport_lib_teleterm_v1_PromptMFARequest,
|
||||
responseSerialize: serialize_teleport_lib_teleterm_v1_PromptMFAResponse,
|
||||
responseDeserialize: deserialize_teleport_lib_teleterm_v1_PromptMFAResponse,
|
||||
},
|
||||
};
|
||||
|
||||
exports.TshdEventsServiceClient = grpc.makeGenericClientConstructor(TshdEventsServiceService);
|
||||
|
||||
+54
@@ -211,3 +211,57 @@ export namespace SendPendingHeadlessAuthenticationResponse {
|
||||
export type AsObject = {
|
||||
}
|
||||
}
|
||||
|
||||
export class PromptMFARequest extends jspb.Message {
|
||||
getRootClusterUri(): string;
|
||||
setRootClusterUri(value: string): PromptMFARequest;
|
||||
|
||||
getReason(): string;
|
||||
setReason(value: string): PromptMFARequest;
|
||||
|
||||
getTotp(): boolean;
|
||||
setTotp(value: boolean): PromptMFARequest;
|
||||
|
||||
getWebauthn(): boolean;
|
||||
setWebauthn(value: boolean): PromptMFARequest;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): PromptMFARequest.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: PromptMFARequest): PromptMFARequest.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: PromptMFARequest, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): PromptMFARequest;
|
||||
static deserializeBinaryFromReader(message: PromptMFARequest, reader: jspb.BinaryReader): PromptMFARequest;
|
||||
}
|
||||
|
||||
export namespace PromptMFARequest {
|
||||
export type AsObject = {
|
||||
rootClusterUri: string,
|
||||
reason: string,
|
||||
totp: boolean,
|
||||
webauthn: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export class PromptMFAResponse extends jspb.Message {
|
||||
getTotpCode(): string;
|
||||
setTotpCode(value: string): PromptMFAResponse;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): PromptMFAResponse.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: PromptMFAResponse): PromptMFAResponse.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: PromptMFAResponse, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): PromptMFAResponse;
|
||||
static deserializeBinaryFromReader(message: PromptMFAResponse, reader: jspb.BinaryReader): PromptMFAResponse;
|
||||
}
|
||||
|
||||
export namespace PromptMFAResponse {
|
||||
export type AsObject = {
|
||||
totpCode: string,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ var global = (function() { return this || window || global || self || Function('
|
||||
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.CannotProxyGatewayConnection', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.GatewayCertExpired', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.PromptMFARequest', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.PromptMFAResponse', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.ReloginRequest', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.ReloginRequest.ReasonCase', null, global);
|
||||
goog.exportSymbol('proto.teleport.lib.teleterm.v1.ReloginResponse', null, global);
|
||||
@@ -193,6 +195,48 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse.displayName = 'proto.teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse';
|
||||
}
|
||||
/**
|
||||
* 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.PromptMFARequest = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.teleport.lib.teleterm.v1.PromptMFARequest, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.displayName = 'proto.teleport.lib.teleterm.v1.PromptMFARequest';
|
||||
}
|
||||
/**
|
||||
* 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.PromptMFAResponse = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.teleport.lib.teleterm.v1.PromptMFAResponse, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.displayName = 'proto.teleport.lib.teleterm.v1.PromptMFAResponse';
|
||||
}
|
||||
|
||||
/**
|
||||
* Oneof group definitions for this message. Each group defines the field
|
||||
@@ -1418,4 +1462,354 @@ proto.teleport.lib.teleterm.v1.SendPendingHeadlessAuthenticationResponse.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.PromptMFARequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.teleport.lib.teleterm.v1.PromptMFARequest.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.PromptMFARequest} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
rootClusterUri: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
reason: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
totp: jspb.Message.getBooleanFieldWithDefault(msg, 3, false),
|
||||
webauthn: jspb.Message.getBooleanFieldWithDefault(msg, 4, 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.PromptMFARequest}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.teleport.lib.teleterm.v1.PromptMFARequest;
|
||||
return proto.teleport.lib.teleterm.v1.PromptMFARequest.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.PromptMFARequest} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFARequest}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.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;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setReason(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setTotp(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setWebauthn(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.PromptMFARequest.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.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.PromptMFARequest} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getRootClusterUri();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getReason();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getTotp();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getWebauthn();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string root_cluster_uri = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.getRootClusterUri = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFARequest} returns this
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.setRootClusterUri = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string reason = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.getReason = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFARequest} returns this
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.setReason = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool totp = 3;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.getTotp = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFARequest} returns this
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.setTotp = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool webauthn = 4;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.getWebauthn = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFARequest} returns this
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFARequest.prototype.setWebauthn = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 4, 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.PromptMFAResponse.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.teleport.lib.teleterm.v1.PromptMFAResponse.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.PromptMFAResponse} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
totpCode: 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.PromptMFAResponse}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.teleport.lib.teleterm.v1.PromptMFAResponse;
|
||||
return proto.teleport.lib.teleterm.v1.PromptMFAResponse.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.PromptMFAResponse} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFAResponse}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.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.setTotpCode(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.PromptMFAResponse.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.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.PromptMFAResponse} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getTotpCode();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string totp_code = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.prototype.getTotpCode = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.teleport.lib.teleterm.v1.PromptMFAResponse} returns this
|
||||
*/
|
||||
proto.teleport.lib.teleterm.v1.PromptMFAResponse.prototype.setTotpCode = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.teleport.lib.teleterm.v1);
|
||||
|
||||
@@ -72,6 +72,7 @@ import (
|
||||
"github.com/gravitational/teleport/lib/auth/touchid"
|
||||
wancli "github.com/gravitational/teleport/lib/auth/webauthncli"
|
||||
"github.com/gravitational/teleport/lib/authz"
|
||||
libmfa "github.com/gravitational/teleport/lib/client/mfa"
|
||||
"github.com/gravitational/teleport/lib/client/terminal"
|
||||
"github.com/gravitational/teleport/lib/defaults"
|
||||
"github.com/gravitational/teleport/lib/devicetrust"
|
||||
@@ -474,6 +475,9 @@ type Config struct {
|
||||
// SSHLogDir is the directory to log the output of multiple SSH commands to.
|
||||
// If not set, no logs will be created.
|
||||
SSHLogDir string
|
||||
|
||||
// MFAPromptConstructor is a custom MFA prompt constructor to use when prompting for MFA.
|
||||
MFAPromptConstructor func(cfg *libmfa.PromptConfig) mfa.Prompt
|
||||
}
|
||||
|
||||
// CachePolicy defines cache policy for local clients
|
||||
|
||||
@@ -34,7 +34,12 @@ type WebauthnLoginFunc func(ctx context.Context, origin string, assertion *wanty
|
||||
// NewMFAPrompt creates a new MFA prompt from client settings.
|
||||
func (tc *TeleportClient) NewMFAPrompt(opts ...mfa.PromptOpt) mfa.Prompt {
|
||||
cfg := tc.newPromptConfig(opts...)
|
||||
|
||||
var prompt mfa.Prompt = libmfa.NewCLIPrompt(cfg, tc.Stderr)
|
||||
if tc.MFAPromptConstructor != nil {
|
||||
prompt = tc.MFAPromptConstructor(cfg)
|
||||
}
|
||||
|
||||
return prompt
|
||||
}
|
||||
|
||||
|
||||
+43
-83
@@ -20,7 +20,6 @@ package mfa
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
@@ -54,95 +53,56 @@ func (c *CLIPrompt) Run(ctx context.Context, chal *proto.MFAAuthenticateChalleng
|
||||
fmt.Fprintln(c.writer, c.cfg.PromptReason)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
runOpts, err := c.cfg.getRunOptions(ctx, chal)
|
||||
runOpts, err := c.cfg.GetRunOptions(ctx, chal)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
kind string
|
||||
resp *proto.MFAAuthenticateResponse
|
||||
err error
|
||||
}
|
||||
respC := make(chan response, 2)
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer func() {
|
||||
cancel()
|
||||
// Wait for all goroutines to complete to ensure there are no leaks.
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
// Use variables below to cancel OTP reads and make sure the goroutine exited.
|
||||
otpCtx, otpCancel := context.WithCancel(ctx)
|
||||
defer otpCancel()
|
||||
otpDone := make(chan struct{})
|
||||
otpCancelAndWait := func() {
|
||||
otpCancel()
|
||||
<-otpDone
|
||||
}
|
||||
|
||||
// Fire TOTP goroutine.
|
||||
if runOpts.promptTOTP {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer close(otpDone)
|
||||
|
||||
// Let Webauthn take the prompt below if applicable.
|
||||
quiet := c.cfg.Quiet || runOpts.promptWebauthn
|
||||
|
||||
resp, err := c.promptTOTP(otpCtx, chal, quiet)
|
||||
respC <- response{kind: "TOTP", resp: resp, err: err}
|
||||
}()
|
||||
}
|
||||
|
||||
// Fire Webauthn goroutine.
|
||||
if runOpts.promptWebauthn {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
// get webauthn prompt and wrap with otp context handler.
|
||||
prompt := &webauthnPromptWithOTP{
|
||||
LoginPrompt: c.getWebauthnPrompt(ctx, runOpts.promptTOTP),
|
||||
otpCancelAndWait: otpCancelAndWait,
|
||||
}
|
||||
|
||||
resp, err := c.promptWebauthn(ctx, chal, prompt)
|
||||
respC <- response{kind: "WEBAUTHN", resp: resp, err: err}
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for the 1-2 authn goroutines above to complete, then close respC.
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(respC)
|
||||
}()
|
||||
|
||||
// Wait for a successful response, or terminating error, from the 1-2 authn goroutines.
|
||||
// The goroutine above will ensure the response channel is closed once all goroutines are done.
|
||||
for resp := range respC {
|
||||
switch err := resp.err; {
|
||||
case errors.Is(err, wancli.ErrUsingNonRegisteredDevice):
|
||||
// Surface error immediately.
|
||||
return nil, trace.Wrap(resp.err)
|
||||
case err != nil:
|
||||
c.cfg.Log.WithError(err).Debugf("%s authentication failed", resp.kind)
|
||||
// Continue to give the other authn goroutine a chance to succeed.
|
||||
// If both have failed, this will exit the loop.
|
||||
continue
|
||||
// Depending on the run opts, we may spawn a TOTP goroutine, webauth goroutine, or both.
|
||||
spawnGoroutines := func(ctx context.Context, wg *sync.WaitGroup, respC chan<- MFAGoroutineResponse) {
|
||||
// Use variables below to cancel OTP reads and make sure the goroutine exited.
|
||||
otpCtx, otpCancel := context.WithCancel(ctx)
|
||||
defer otpCancel()
|
||||
otpDone := make(chan struct{})
|
||||
otpCancelAndWait := func() {
|
||||
otpCancel()
|
||||
<-otpDone
|
||||
}
|
||||
|
||||
// Return successful response.
|
||||
return resp.resp, nil
|
||||
// Fire TOTP goroutine.
|
||||
if runOpts.PromptTOTP {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer close(otpDone)
|
||||
|
||||
// Let Webauthn take the prompt below if applicable.
|
||||
quiet := c.cfg.Quiet || runOpts.PromptWebauthn
|
||||
|
||||
resp, err := c.promptTOTP(otpCtx, chal, quiet)
|
||||
respC <- MFAGoroutineResponse{Resp: resp, Err: trace.Wrap(err, "TOTP authentication failed")}
|
||||
}()
|
||||
}
|
||||
|
||||
// Fire Webauthn goroutine.
|
||||
if runOpts.PromptWebauthn {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
// Get webauthn prompt and wrap with otp context handler.
|
||||
prompt := &webauthnPromptWithOTP{
|
||||
LoginPrompt: c.getWebauthnPrompt(ctx, runOpts.PromptTOTP),
|
||||
otpCancelAndWait: otpCancelAndWait,
|
||||
}
|
||||
|
||||
resp, err := c.promptWebauthn(ctx, chal, prompt)
|
||||
respC <- MFAGoroutineResponse{Resp: resp, Err: trace.Wrap(err, "Webauthn authentication failed")}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// If no successful response is returned, this means the authn goroutines were unsuccessful.
|
||||
// This usually occurs when the prompt times out or no devices are available to prompt.
|
||||
// Return a user readable error message.
|
||||
return nil, trace.BadParameter("failed to authenticate using available MFA devices, rerun the command with '-d' to see error details for each device")
|
||||
return HandleMFAPromptGoroutines(ctx, spawnGoroutines)
|
||||
}
|
||||
|
||||
func (c *CLIPrompt) promptTOTP(ctx context.Context, chal *proto.MFAAuthenticateChallenge, quiet bool) (*proto.MFAAuthenticateResponse, error) {
|
||||
@@ -187,7 +147,7 @@ func (c *CLIPrompt) getWebauthnPrompt(ctx context.Context, withTOTP bool) wancli
|
||||
|
||||
func (c *CLIPrompt) promptWebauthn(ctx context.Context, chal *proto.MFAAuthenticateChallenge, prompt wancli.LoginPrompt) (*proto.MFAAuthenticateResponse, error) {
|
||||
opts := &wancli.LoginOpts{AuthenticatorAttachment: c.cfg.AuthenticatorAttachment}
|
||||
resp, _, err := c.cfg.WebauthnLoginFunc(ctx, c.cfg.getWebauthnOrigin(), wantypes.CredentialAssertionFromProto(chal.WebauthnChallenge), prompt, opts)
|
||||
resp, _, err := c.cfg.WebauthnLoginFunc(ctx, c.cfg.GetWebauthnOrigin(), wantypes.CredentialAssertionFromProto(chal.WebauthnChallenge), prompt, opts)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
+61
-17
@@ -20,12 +20,12 @@ package mfa
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
"github.com/gravitational/teleport/api/mfa"
|
||||
wancli "github.com/gravitational/teleport/lib/auth/webauthncli"
|
||||
@@ -52,8 +52,6 @@ type PromptConfig struct {
|
||||
PreferOTP bool
|
||||
// WebauthnSupported indicates whether Webauthn is supported.
|
||||
WebauthnSupported bool
|
||||
// Log is a logging entry.
|
||||
Log *logrus.Entry
|
||||
}
|
||||
|
||||
// NewPromptConfig returns a prompt config that will induce default behavior.
|
||||
@@ -62,9 +60,6 @@ func NewPromptConfig(proxyAddr string, opts ...mfa.PromptOpt) *PromptConfig {
|
||||
ProxyAddress: proxyAddr,
|
||||
WebauthnLoginFunc: wancli.Login,
|
||||
WebauthnSupported: wancli.HasPlatformSupport(),
|
||||
Log: logrus.WithFields(logrus.Fields{
|
||||
trace.Component: teleport.ComponentClient,
|
||||
}),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
@@ -74,25 +69,25 @@ func NewPromptConfig(proxyAddr string, opts ...mfa.PromptOpt) *PromptConfig {
|
||||
return cfg
|
||||
}
|
||||
|
||||
// runOpts are mfa prompt run options.
|
||||
type runOpts struct {
|
||||
promptTOTP bool
|
||||
promptWebauthn bool
|
||||
// RunOpts are mfa prompt run options.
|
||||
type RunOpts struct {
|
||||
PromptTOTP bool
|
||||
PromptWebauthn bool
|
||||
}
|
||||
|
||||
// getRunOptions gets mfa prompt run options by cross referencing the mfa challenge with prompt configuration.
|
||||
func (c PromptConfig) getRunOptions(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (runOpts, error) {
|
||||
// GetRunOptions gets mfa prompt run options by cross referencing the mfa challenge with prompt configuration.
|
||||
func (c PromptConfig) GetRunOptions(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (RunOpts, error) {
|
||||
promptTOTP := chal.TOTP != nil
|
||||
promptWebauthn := chal.WebauthnChallenge != nil
|
||||
|
||||
if !promptTOTP && !promptWebauthn {
|
||||
return runOpts{}, trace.BadParameter("mfa challenge is empty")
|
||||
return RunOpts{}, trace.BadParameter("mfa challenge is empty")
|
||||
}
|
||||
|
||||
// Does the current platform support hardware MFA? Adjust accordingly.
|
||||
switch {
|
||||
case !promptTOTP && !c.WebauthnSupported:
|
||||
return runOpts{}, trace.BadParameter("hardware device MFA not supported by your platform, please register an OTP device")
|
||||
return RunOpts{}, trace.BadParameter("hardware device MFA not supported by your platform, please register an OTP device")
|
||||
case !c.WebauthnSupported:
|
||||
// Do not prompt for hardware devices, it won't work.
|
||||
promptWebauthn = false
|
||||
@@ -110,12 +105,61 @@ func (c PromptConfig) getRunOptions(ctx context.Context, chal *proto.MFAAuthenti
|
||||
promptTOTP = false
|
||||
}
|
||||
|
||||
return runOpts{promptTOTP, promptWebauthn}, nil
|
||||
return RunOpts{promptTOTP, promptWebauthn}, nil
|
||||
}
|
||||
|
||||
func (c PromptConfig) getWebauthnOrigin() string {
|
||||
func (c PromptConfig) GetWebauthnOrigin() string {
|
||||
if !strings.HasPrefix(c.ProxyAddress, "https://") {
|
||||
return "https://" + c.ProxyAddress
|
||||
}
|
||||
return c.ProxyAddress
|
||||
}
|
||||
|
||||
// MFAGoroutineResponse is an MFA goroutine response.
|
||||
type MFAGoroutineResponse struct {
|
||||
Resp *proto.MFAAuthenticateResponse
|
||||
Err error
|
||||
}
|
||||
|
||||
// HandleMFAPromptGoroutines spawns MFA prompt goroutines and returns the first successful response,
|
||||
// terminating error, or an aggregated error if they all fail.
|
||||
func HandleMFAPromptGoroutines(ctx context.Context, startGoroutines func(context.Context, *sync.WaitGroup, chan<- MFAGoroutineResponse)) (*proto.MFAAuthenticateResponse, error) {
|
||||
respC := make(chan MFAGoroutineResponse, 2)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer func() {
|
||||
cancel()
|
||||
// wait for all goroutines to complete to ensure there are no leaks.
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
startGoroutines(ctx, &wg, respC)
|
||||
|
||||
// Wait for spawned goroutines above to complete, then close respC.
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(respC)
|
||||
}()
|
||||
|
||||
// Wait for a successful response, or terminating error, from the spawned goroutines.
|
||||
// The goroutine above will ensure the response channel is closed once all goroutines are done.
|
||||
var errs []error
|
||||
for resp := range respC {
|
||||
switch err := resp.Err; {
|
||||
case errors.Is(err, wancli.ErrUsingNonRegisteredDevice):
|
||||
// Surface error immediately.
|
||||
return nil, trace.Wrap(resp.Err)
|
||||
case err != nil:
|
||||
errs = append(errs, err)
|
||||
// Continue to give the other authn goroutine a chance to succeed.
|
||||
// If both have failed, this will exit the loop.
|
||||
continue
|
||||
}
|
||||
|
||||
// Return successful response.
|
||||
return resp.Resp, nil
|
||||
}
|
||||
|
||||
return nil, trace.Wrap(trace.NewAggregate(errs...), "failed to authenticate using available MFA devices")
|
||||
}
|
||||
|
||||
@@ -220,7 +220,12 @@ func (s *Service) ResolveCluster(path string) (*clusters.Cluster, *client.Telepo
|
||||
// worry about parsing URIs and can assume they are correct.
|
||||
func (s *Service) ResolveClusterURI(uri uri.ResourceURI) (*clusters.Cluster, *client.TeleportClient, error) {
|
||||
cluster, clusterClient, err := s.cfg.Storage.GetByResourceURI(uri)
|
||||
return cluster, clusterClient, trace.Wrap(err)
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
clusterClient.MFAPromptConstructor = s.NewMFAPromptConstructor(cluster.URI.String())
|
||||
return cluster, clusterClient, nil
|
||||
}
|
||||
|
||||
// ResolveClusterWithDetails returns fully detailed cluster information. It makes requests to the auth server and includes
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// 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 daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/gravitational/trace/trail"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
"github.com/gravitational/teleport/api/mfa"
|
||||
api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1"
|
||||
wancli "github.com/gravitational/teleport/lib/auth/webauthncli"
|
||||
wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes"
|
||||
libmfa "github.com/gravitational/teleport/lib/client/mfa"
|
||||
)
|
||||
|
||||
// mfaPrompt is a tshd implementation of mfa.Prompt that uses the
|
||||
// tshdEventsClient to propagate mfa prompts to the Electron App.
|
||||
type mfaPrompt struct {
|
||||
cfg libmfa.PromptConfig
|
||||
clusterURI string
|
||||
promptAppMFA func(ctx context.Context, in *api.PromptMFARequest) (*api.PromptMFAResponse, error)
|
||||
}
|
||||
|
||||
// NewMFAPromptConstructor returns a new MFA prompt constructor
|
||||
// for this service and the given cluster.
|
||||
func (s *Service) NewMFAPromptConstructor(clusterURI string) func(cfg *libmfa.PromptConfig) mfa.Prompt {
|
||||
return func(cfg *libmfa.PromptConfig) mfa.Prompt {
|
||||
return s.NewMFAPrompt(clusterURI, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
// NewMFAPrompt returns a new MFA prompt for this service and the given cluster.
|
||||
func (s *Service) NewMFAPrompt(clusterURI string, cfg *libmfa.PromptConfig) *mfaPrompt {
|
||||
return &mfaPrompt{
|
||||
cfg: *cfg,
|
||||
clusterURI: clusterURI,
|
||||
promptAppMFA: s.promptAppMFA,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) promptAppMFA(ctx context.Context, in *api.PromptMFARequest) (*api.PromptMFAResponse, error) {
|
||||
if err := s.importantModalSemaphore.Acquire(ctx); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
defer s.importantModalSemaphore.Release()
|
||||
|
||||
return s.tshdEventsClient.PromptMFA(ctx, in)
|
||||
}
|
||||
|
||||
// Run prompts the user to complete an MFA authentication challenge.
|
||||
func (p *mfaPrompt) Run(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) {
|
||||
runOpts, err := p.cfg.GetRunOptions(ctx, chal)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Depending on the run opts, we may spawn a TOTP goroutine, webauth goroutine, or both.
|
||||
spawnGoroutines := func(ctx context.Context, wg *sync.WaitGroup, respC chan<- libmfa.MFAGoroutineResponse) {
|
||||
// Fire App goroutine (TOTP).
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
resp, err := p.promptMFA(ctx, chal, runOpts)
|
||||
respC <- libmfa.MFAGoroutineResponse{Resp: resp, Err: err}
|
||||
}()
|
||||
|
||||
// Fire Webauthn goroutine.
|
||||
if runOpts.PromptWebauthn {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
resp, err := p.promptWebauthn(ctx, chal)
|
||||
respC <- libmfa.MFAGoroutineResponse{Resp: resp, Err: trace.Wrap(err, "Webauthn authentication failed")}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
return libmfa.HandleMFAPromptGoroutines(ctx, spawnGoroutines)
|
||||
}
|
||||
|
||||
func (p *mfaPrompt) promptWebauthn(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) {
|
||||
prompt := wancli.NewDefaultPrompt(ctx, io.Discard)
|
||||
opts := &wancli.LoginOpts{AuthenticatorAttachment: p.cfg.AuthenticatorAttachment}
|
||||
resp, _, err := p.cfg.WebauthnLoginFunc(ctx, p.cfg.GetWebauthnOrigin(), wantypes.CredentialAssertionFromProto(chal.WebauthnChallenge), prompt, opts)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *mfaPrompt) promptMFA(ctx context.Context, chal *proto.MFAAuthenticateChallenge, runOpts libmfa.RunOpts) (*proto.MFAAuthenticateResponse, error) {
|
||||
resp, err := p.promptAppMFA(ctx, &api.PromptMFARequest{
|
||||
RootClusterUri: p.clusterURI,
|
||||
Reason: p.cfg.PromptReason,
|
||||
Totp: runOpts.PromptTOTP,
|
||||
Webauthn: runOpts.PromptWebauthn,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trail.FromGRPC(err)
|
||||
}
|
||||
return &proto.MFAAuthenticateResponse{
|
||||
Response: &proto.MFAAuthenticateResponse_TOTP{
|
||||
TOTP: &proto.TOTPResponse{Code: resp.TotpCode},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -35,6 +35,8 @@ service TshdEventsService {
|
||||
// SendPendingHeadlessAuthentication notifies the Electron app of a pending headless authentication,
|
||||
// which it can use to initiate headless authentication resolution in the UI.
|
||||
rpc SendPendingHeadlessAuthentication(SendPendingHeadlessAuthenticationRequest) returns (SendPendingHeadlessAuthenticationResponse);
|
||||
// PromptMFA notifies the Electron app that the daemon is waiting for the user to answer an MFA prompt.
|
||||
rpc PromptMFA(PromptMFARequest) returns (PromptMFAResponse);
|
||||
}
|
||||
|
||||
// Relogin
|
||||
@@ -88,3 +90,16 @@ message SendPendingHeadlessAuthenticationRequest {
|
||||
}
|
||||
|
||||
message SendPendingHeadlessAuthenticationResponse {}
|
||||
|
||||
// PromptMFA
|
||||
|
||||
message PromptMFARequest {
|
||||
string root_cluster_uri = 1;
|
||||
string reason = 2;
|
||||
bool totp = 3;
|
||||
bool webauthn = 4;
|
||||
}
|
||||
|
||||
message PromptMFAResponse {
|
||||
string totp_code = 1;
|
||||
}
|
||||
|
||||
@@ -207,6 +207,10 @@ function createService(logger: Logger): {
|
||||
}
|
||||
);
|
||||
},
|
||||
promptMFA: () => {
|
||||
// TODO (joerger): Handle MFA prompt with totp/webauthn modal.
|
||||
logger.info('Received prompt mfa request');
|
||||
},
|
||||
};
|
||||
|
||||
return { service, subscribeToTshdEvent };
|
||||
|
||||
Reference in New Issue
Block a user