diff --git a/api/gen/proto/go/teleport/mfa/v2/challenge.pb.go b/api/gen/proto/go/teleport/mfa/v2/challenge.pb.go new file mode 100644 index 00000000000..62095e3a0d0 --- /dev/null +++ b/api/gen/proto/go/teleport/mfa/v2/challenge.pb.go @@ -0,0 +1,919 @@ +// Copyright 2026 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: teleport/mfa/v2/challenge.proto + +package mfav2 + +import ( + v2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/webauthn/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// AuthenticateChallenge is a challenge for all MFA devices registered for a user. +type AuthenticateChallenge struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Name string `protobuf:"bytes,1,opt,name=name,proto3"` + xxx_hidden_WebauthnChallenge *v2.CredentialAssertion `protobuf:"bytes,2,opt,name=webauthn_challenge,json=webauthnChallenge,proto3"` + xxx_hidden_SsoChallenge *SSOChallenge `protobuf:"bytes,3,opt,name=sso_challenge,json=ssoChallenge,proto3"` + xxx_hidden_BrowserChallenge *BrowserMFAChallenge `protobuf:"bytes,4,opt,name=browser_challenge,json=browserChallenge,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthenticateChallenge) Reset() { + *x = AuthenticateChallenge{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthenticateChallenge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthenticateChallenge) ProtoMessage() {} + +func (x *AuthenticateChallenge) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *AuthenticateChallenge) GetName() string { + if x != nil { + return x.xxx_hidden_Name + } + return "" +} + +func (x *AuthenticateChallenge) GetWebauthnChallenge() *v2.CredentialAssertion { + if x != nil { + return x.xxx_hidden_WebauthnChallenge + } + return nil +} + +func (x *AuthenticateChallenge) GetSsoChallenge() *SSOChallenge { + if x != nil { + return x.xxx_hidden_SsoChallenge + } + return nil +} + +func (x *AuthenticateChallenge) GetBrowserChallenge() *BrowserMFAChallenge { + if x != nil { + return x.xxx_hidden_BrowserChallenge + } + return nil +} + +func (x *AuthenticateChallenge) SetName(v string) { + x.xxx_hidden_Name = v +} + +func (x *AuthenticateChallenge) SetWebauthnChallenge(v *v2.CredentialAssertion) { + x.xxx_hidden_WebauthnChallenge = v +} + +func (x *AuthenticateChallenge) SetSsoChallenge(v *SSOChallenge) { + x.xxx_hidden_SsoChallenge = v +} + +func (x *AuthenticateChallenge) SetBrowserChallenge(v *BrowserMFAChallenge) { + x.xxx_hidden_BrowserChallenge = v +} + +func (x *AuthenticateChallenge) HasWebauthnChallenge() bool { + if x == nil { + return false + } + return x.xxx_hidden_WebauthnChallenge != nil +} + +func (x *AuthenticateChallenge) HasSsoChallenge() bool { + if x == nil { + return false + } + return x.xxx_hidden_SsoChallenge != nil +} + +func (x *AuthenticateChallenge) HasBrowserChallenge() bool { + if x == nil { + return false + } + return x.xxx_hidden_BrowserChallenge != nil +} + +func (x *AuthenticateChallenge) ClearWebauthnChallenge() { + x.xxx_hidden_WebauthnChallenge = nil +} + +func (x *AuthenticateChallenge) ClearSsoChallenge() { + x.xxx_hidden_SsoChallenge = nil +} + +func (x *AuthenticateChallenge) ClearBrowserChallenge() { + x.xxx_hidden_BrowserChallenge = nil +} + +type AuthenticateChallenge_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Unique resource name for the issued challenge generated by the server. Should be treated as an opaque identifier + // and used as-is in subsequent API calls. + Name string + // Webauthn credential assertion used for login/authentication ceremonies. Holds a list of allowed credentials (one + // for each U2F or Webauthn device registered by the user). + WebauthnChallenge *v2.CredentialAssertion + // SSO MFA challenge. If set, the client can go to the IdP redirect URL to perform an MFA check and obtain an MFA + // token. This token paired with the request id can be used for verification. + SsoChallenge *SSOChallenge + // Browser challenge allows a user to MFA in the browser, to get a WebAuthn + // response that is returned to the client to be used for verification. + BrowserChallenge *BrowserMFAChallenge +} + +func (b0 AuthenticateChallenge_builder) Build() *AuthenticateChallenge { + m0 := &AuthenticateChallenge{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Name = b.Name + x.xxx_hidden_WebauthnChallenge = b.WebauthnChallenge + x.xxx_hidden_SsoChallenge = b.SsoChallenge + x.xxx_hidden_BrowserChallenge = b.BrowserChallenge + return m0 +} + +// AuthenticateResponse is a response to AuthenticateChallenge using one of the MFA devices registered for a user. +type AuthenticateResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Name string `protobuf:"bytes,1,opt,name=name,proto3"` + xxx_hidden_Response isAuthenticateResponse_Response `protobuf_oneof:"response"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthenticateResponse) Reset() { + *x = AuthenticateResponse{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthenticateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthenticateResponse) ProtoMessage() {} + +func (x *AuthenticateResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *AuthenticateResponse) GetName() string { + if x != nil { + return x.xxx_hidden_Name + } + return "" +} + +func (x *AuthenticateResponse) GetWebauthn() *v2.CredentialAssertionResponse { + if x != nil { + if x, ok := x.xxx_hidden_Response.(*authenticateResponse_Webauthn); ok { + return x.Webauthn + } + } + return nil +} + +func (x *AuthenticateResponse) GetSso() *SSOChallengeResponse { + if x != nil { + if x, ok := x.xxx_hidden_Response.(*authenticateResponse_Sso); ok { + return x.Sso + } + } + return nil +} + +func (x *AuthenticateResponse) GetBrowser() *BrowserMFAResponse { + if x != nil { + if x, ok := x.xxx_hidden_Response.(*authenticateResponse_Browser); ok { + return x.Browser + } + } + return nil +} + +func (x *AuthenticateResponse) SetName(v string) { + x.xxx_hidden_Name = v +} + +func (x *AuthenticateResponse) SetWebauthn(v *v2.CredentialAssertionResponse) { + if v == nil { + x.xxx_hidden_Response = nil + return + } + x.xxx_hidden_Response = &authenticateResponse_Webauthn{v} +} + +func (x *AuthenticateResponse) SetSso(v *SSOChallengeResponse) { + if v == nil { + x.xxx_hidden_Response = nil + return + } + x.xxx_hidden_Response = &authenticateResponse_Sso{v} +} + +func (x *AuthenticateResponse) SetBrowser(v *BrowserMFAResponse) { + if v == nil { + x.xxx_hidden_Response = nil + return + } + x.xxx_hidden_Response = &authenticateResponse_Browser{v} +} + +func (x *AuthenticateResponse) HasResponse() bool { + if x == nil { + return false + } + return x.xxx_hidden_Response != nil +} + +func (x *AuthenticateResponse) HasWebauthn() bool { + if x == nil { + return false + } + _, ok := x.xxx_hidden_Response.(*authenticateResponse_Webauthn) + return ok +} + +func (x *AuthenticateResponse) HasSso() bool { + if x == nil { + return false + } + _, ok := x.xxx_hidden_Response.(*authenticateResponse_Sso) + return ok +} + +func (x *AuthenticateResponse) HasBrowser() bool { + if x == nil { + return false + } + _, ok := x.xxx_hidden_Response.(*authenticateResponse_Browser) + return ok +} + +func (x *AuthenticateResponse) ClearResponse() { + x.xxx_hidden_Response = nil +} + +func (x *AuthenticateResponse) ClearWebauthn() { + if _, ok := x.xxx_hidden_Response.(*authenticateResponse_Webauthn); ok { + x.xxx_hidden_Response = nil + } +} + +func (x *AuthenticateResponse) ClearSso() { + if _, ok := x.xxx_hidden_Response.(*authenticateResponse_Sso); ok { + x.xxx_hidden_Response = nil + } +} + +func (x *AuthenticateResponse) ClearBrowser() { + if _, ok := x.xxx_hidden_Response.(*authenticateResponse_Browser); ok { + x.xxx_hidden_Response = nil + } +} + +const AuthenticateResponse_Response_not_set_case case_AuthenticateResponse_Response = 0 +const AuthenticateResponse_Webauthn_case case_AuthenticateResponse_Response = 2 +const AuthenticateResponse_Sso_case case_AuthenticateResponse_Response = 3 +const AuthenticateResponse_Browser_case case_AuthenticateResponse_Response = 4 + +func (x *AuthenticateResponse) WhichResponse() case_AuthenticateResponse_Response { + if x == nil { + return AuthenticateResponse_Response_not_set_case + } + switch x.xxx_hidden_Response.(type) { + case *authenticateResponse_Webauthn: + return AuthenticateResponse_Webauthn_case + case *authenticateResponse_Sso: + return AuthenticateResponse_Sso_case + case *authenticateResponse_Browser: + return AuthenticateResponse_Browser_case + default: + return AuthenticateResponse_Response_not_set_case + } +} + +type AuthenticateResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Unique resource name for the issued challenge generated by the server. Should be treated as an opaque identifier + // and used as-is in subsequent API calls. + Name string + // Response to the challenge using one of the MFA devices. + + // Fields of oneof xxx_hidden_Response: + // Response to a Webauthn challenge. + Webauthn *v2.CredentialAssertionResponse + // Response to an SSO challenge. + Sso *SSOChallengeResponse + // Response to a browser challenge. + Browser *BrowserMFAResponse + // -- end of xxx_hidden_Response +} + +func (b0 AuthenticateResponse_builder) Build() *AuthenticateResponse { + m0 := &AuthenticateResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Name = b.Name + if b.Webauthn != nil { + x.xxx_hidden_Response = &authenticateResponse_Webauthn{b.Webauthn} + } + if b.Sso != nil { + x.xxx_hidden_Response = &authenticateResponse_Sso{b.Sso} + } + if b.Browser != nil { + x.xxx_hidden_Response = &authenticateResponse_Browser{b.Browser} + } + return m0 +} + +type case_AuthenticateResponse_Response protoreflect.FieldNumber + +func (x case_AuthenticateResponse_Response) String() string { + md := file_teleport_mfa_v2_challenge_proto_msgTypes[1].Descriptor() + if x == 0 { + return "not set" + } + return protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x)) +} + +type isAuthenticateResponse_Response interface { + isAuthenticateResponse_Response() +} + +type authenticateResponse_Webauthn struct { + // Response to a Webauthn challenge. + Webauthn *v2.CredentialAssertionResponse `protobuf:"bytes,2,opt,name=webauthn,proto3,oneof"` +} + +type authenticateResponse_Sso struct { + // Response to an SSO challenge. + Sso *SSOChallengeResponse `protobuf:"bytes,3,opt,name=sso,proto3,oneof"` +} + +type authenticateResponse_Browser struct { + // Response to a browser challenge. + Browser *BrowserMFAResponse `protobuf:"bytes,4,opt,name=browser,proto3,oneof"` +} + +func (*authenticateResponse_Webauthn) isAuthenticateResponse_Response() {} + +func (*authenticateResponse_Sso) isAuthenticateResponse_Response() {} + +func (*authenticateResponse_Browser) isAuthenticateResponse_Response() {} + +// SSOChallenge contains SSO auth request details to perform an SSO MFA check. +type SSOChallenge struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3"` + xxx_hidden_RedirectUrl string `protobuf:"bytes,2,opt,name=redirect_url,json=redirectUrl,proto3"` + xxx_hidden_Device *SSOMFADevice `protobuf:"bytes,3,opt,name=device,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SSOChallenge) Reset() { + *x = SSOChallenge{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SSOChallenge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SSOChallenge) ProtoMessage() {} + +func (x *SSOChallenge) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *SSOChallenge) GetRequestId() string { + if x != nil { + return x.xxx_hidden_RequestId + } + return "" +} + +func (x *SSOChallenge) GetRedirectUrl() string { + if x != nil { + return x.xxx_hidden_RedirectUrl + } + return "" +} + +func (x *SSOChallenge) GetDevice() *SSOMFADevice { + if x != nil { + return x.xxx_hidden_Device + } + return nil +} + +func (x *SSOChallenge) SetRequestId(v string) { + x.xxx_hidden_RequestId = v +} + +func (x *SSOChallenge) SetRedirectUrl(v string) { + x.xxx_hidden_RedirectUrl = v +} + +func (x *SSOChallenge) SetDevice(v *SSOMFADevice) { + x.xxx_hidden_Device = v +} + +func (x *SSOChallenge) HasDevice() bool { + if x == nil { + return false + } + return x.xxx_hidden_Device != nil +} + +func (x *SSOChallenge) ClearDevice() { + x.xxx_hidden_Device = nil +} + +type SSOChallenge_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // ID of an SSO auth request. + RequestId string + // IdP redirect URL to initiate the SSO MFA flow. + RedirectUrl string + // SSO device corresponding to the challenge. + Device *SSOMFADevice +} + +func (b0 SSOChallenge_builder) Build() *SSOChallenge { + m0 := &SSOChallenge{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_RequestId = b.RequestId + x.xxx_hidden_RedirectUrl = b.RedirectUrl + x.xxx_hidden_Device = b.Device + return m0 +} + +// SSOMFADevice contains details of an SSO MFA method. +type SSOMFADevice struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_ConnectorId string `protobuf:"bytes,1,opt,name=connector_id,json=connectorId,proto3"` + xxx_hidden_ConnectorType string `protobuf:"bytes,2,opt,name=connector_type,json=connectorType,proto3"` + xxx_hidden_DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SSOMFADevice) Reset() { + *x = SSOMFADevice{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SSOMFADevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SSOMFADevice) ProtoMessage() {} + +func (x *SSOMFADevice) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *SSOMFADevice) GetConnectorId() string { + if x != nil { + return x.xxx_hidden_ConnectorId + } + return "" +} + +func (x *SSOMFADevice) GetConnectorType() string { + if x != nil { + return x.xxx_hidden_ConnectorType + } + return "" +} + +func (x *SSOMFADevice) GetDisplayName() string { + if x != nil { + return x.xxx_hidden_DisplayName + } + return "" +} + +func (x *SSOMFADevice) SetConnectorId(v string) { + x.xxx_hidden_ConnectorId = v +} + +func (x *SSOMFADevice) SetConnectorType(v string) { + x.xxx_hidden_ConnectorType = v +} + +func (x *SSOMFADevice) SetDisplayName(v string) { + x.xxx_hidden_DisplayName = v +} + +type SSOMFADevice_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // connector_id is the ID of the SSO connector. + ConnectorId string + // connector_type is the type of the SSO connector. + ConnectorType string + // display_name is the display name of the SSO connector + DisplayName string +} + +func (b0 SSOMFADevice_builder) Build() *SSOMFADevice { + m0 := &SSOMFADevice{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_ConnectorId = b.ConnectorId + x.xxx_hidden_ConnectorType = b.ConnectorType + x.xxx_hidden_DisplayName = b.DisplayName + return m0 +} + +// SSOChallengeResponse is a response to an SSOChallenge. +type SSOChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3"` + xxx_hidden_Token string `protobuf:"bytes,2,opt,name=token,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SSOChallengeResponse) Reset() { + *x = SSOChallengeResponse{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SSOChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SSOChallengeResponse) ProtoMessage() {} + +func (x *SSOChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *SSOChallengeResponse) GetRequestId() string { + if x != nil { + return x.xxx_hidden_RequestId + } + return "" +} + +func (x *SSOChallengeResponse) GetToken() string { + if x != nil { + return x.xxx_hidden_Token + } + return "" +} + +func (x *SSOChallengeResponse) SetRequestId(v string) { + x.xxx_hidden_RequestId = v +} + +func (x *SSOChallengeResponse) SetToken(v string) { + x.xxx_hidden_Token = v +} + +type SSOChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // ID of an SSO auth request. + RequestId string + // Secret token used to verify the user's SSO MFA session. + Token string +} + +func (b0 SSOChallengeResponse_builder) Build() *SSOChallengeResponse { + m0 := &SSOChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_RequestId = b.RequestId + x.xxx_hidden_Token = b.Token + return m0 +} + +// BrowserMFAChallenge contains browser MFA request details to perform a browser MFA check. +type BrowserMFAChallenge struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BrowserMFAChallenge) Reset() { + *x = BrowserMFAChallenge{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BrowserMFAChallenge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BrowserMFAChallenge) ProtoMessage() {} + +func (x *BrowserMFAChallenge) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *BrowserMFAChallenge) GetRequestId() string { + if x != nil { + return x.xxx_hidden_RequestId + } + return "" +} + +func (x *BrowserMFAChallenge) SetRequestId(v string) { + x.xxx_hidden_RequestId = v +} + +type BrowserMFAChallenge_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // RequestId is the ID of a browser MFA request. + RequestId string +} + +func (b0 BrowserMFAChallenge_builder) Build() *BrowserMFAChallenge { + m0 := &BrowserMFAChallenge{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_RequestId = b.RequestId + return m0 +} + +// BrowserMFAResponse is a response to BrowserMFAChallenge. +type BrowserMFAResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3"` + xxx_hidden_WebauthnResponse *v2.CredentialAssertionResponse `protobuf:"bytes,2,opt,name=webauthn_response,json=webauthnResponse,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *BrowserMFAResponse) Reset() { + *x = BrowserMFAResponse{} + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *BrowserMFAResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BrowserMFAResponse) ProtoMessage() {} + +func (x *BrowserMFAResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_challenge_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *BrowserMFAResponse) GetRequestId() string { + if x != nil { + return x.xxx_hidden_RequestId + } + return "" +} + +func (x *BrowserMFAResponse) GetWebauthnResponse() *v2.CredentialAssertionResponse { + if x != nil { + return x.xxx_hidden_WebauthnResponse + } + return nil +} + +func (x *BrowserMFAResponse) SetRequestId(v string) { + x.xxx_hidden_RequestId = v +} + +func (x *BrowserMFAResponse) SetWebauthnResponse(v *v2.CredentialAssertionResponse) { + x.xxx_hidden_WebauthnResponse = v +} + +func (x *BrowserMFAResponse) HasWebauthnResponse() bool { + if x == nil { + return false + } + return x.xxx_hidden_WebauthnResponse != nil +} + +func (x *BrowserMFAResponse) ClearWebauthnResponse() { + x.xxx_hidden_WebauthnResponse = nil +} + +type BrowserMFAResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // RequestId is the ID of a browser MFA request. + RequestId string + // WebauthnResponse is the WebAuthn credential assertion response from the browser MFA flow. + WebauthnResponse *v2.CredentialAssertionResponse +} + +func (b0 BrowserMFAResponse_builder) Build() *BrowserMFAResponse { + m0 := &BrowserMFAResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_RequestId = b.RequestId + x.xxx_hidden_WebauthnResponse = b.WebauthnResponse + return m0 +} + +var File_teleport_mfa_v2_challenge_proto protoreflect.FileDescriptor + +const file_teleport_mfa_v2_challenge_proto_rawDesc = "" + + "\n" + + "\x1fteleport/mfa/v2/challenge.proto\x12\x0fteleport.mfa.v2\x1a#teleport/webauthn/v2/webauthn.proto\"\x9c\x02\n" + + "\x15AuthenticateChallenge\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12X\n" + + "\x12webauthn_challenge\x18\x02 \x01(\v2).teleport.webauthn.v2.CredentialAssertionR\x11webauthnChallenge\x12B\n" + + "\rsso_challenge\x18\x03 \x01(\v2\x1d.teleport.mfa.v2.SSOChallengeR\fssoChallenge\x12Q\n" + + "\x11browser_challenge\x18\x04 \x01(\v2$.teleport.mfa.v2.BrowserMFAChallengeR\x10browserChallenge\"\x83\x02\n" + + "\x14AuthenticateResponse\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12O\n" + + "\bwebauthn\x18\x02 \x01(\v21.teleport.webauthn.v2.CredentialAssertionResponseH\x00R\bwebauthn\x129\n" + + "\x03sso\x18\x03 \x01(\v2%.teleport.mfa.v2.SSOChallengeResponseH\x00R\x03sso\x12?\n" + + "\abrowser\x18\x04 \x01(\v2#.teleport.mfa.v2.BrowserMFAResponseH\x00R\abrowserB\n" + + "\n" + + "\bresponse\"\x87\x01\n" + + "\fSSOChallenge\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x12!\n" + + "\fredirect_url\x18\x02 \x01(\tR\vredirectUrl\x125\n" + + "\x06device\x18\x03 \x01(\v2\x1d.teleport.mfa.v2.SSOMFADeviceR\x06device\"{\n" + + "\fSSOMFADevice\x12!\n" + + "\fconnector_id\x18\x01 \x01(\tR\vconnectorId\x12%\n" + + "\x0econnector_type\x18\x02 \x01(\tR\rconnectorType\x12!\n" + + "\fdisplay_name\x18\x03 \x01(\tR\vdisplayName\"K\n" + + "\x14SSOChallengeResponse\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x12\x14\n" + + "\x05token\x18\x02 \x01(\tR\x05token\"4\n" + + "\x13BrowserMFAChallenge\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\"\x93\x01\n" + + "\x12BrowserMFAResponse\x12\x1d\n" + + "\n" + + "request_id\x18\x01 \x01(\tR\trequestId\x12^\n" + + "\x11webauthn_response\x18\x02 \x01(\v21.teleport.webauthn.v2.CredentialAssertionResponseR\x10webauthnResponseBJZHgithub.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2b\x06proto3" + +var file_teleport_mfa_v2_challenge_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_teleport_mfa_v2_challenge_proto_goTypes = []any{ + (*AuthenticateChallenge)(nil), // 0: teleport.mfa.v2.AuthenticateChallenge + (*AuthenticateResponse)(nil), // 1: teleport.mfa.v2.AuthenticateResponse + (*SSOChallenge)(nil), // 2: teleport.mfa.v2.SSOChallenge + (*SSOMFADevice)(nil), // 3: teleport.mfa.v2.SSOMFADevice + (*SSOChallengeResponse)(nil), // 4: teleport.mfa.v2.SSOChallengeResponse + (*BrowserMFAChallenge)(nil), // 5: teleport.mfa.v2.BrowserMFAChallenge + (*BrowserMFAResponse)(nil), // 6: teleport.mfa.v2.BrowserMFAResponse + (*v2.CredentialAssertion)(nil), // 7: teleport.webauthn.v2.CredentialAssertion + (*v2.CredentialAssertionResponse)(nil), // 8: teleport.webauthn.v2.CredentialAssertionResponse +} +var file_teleport_mfa_v2_challenge_proto_depIdxs = []int32{ + 7, // 0: teleport.mfa.v2.AuthenticateChallenge.webauthn_challenge:type_name -> teleport.webauthn.v2.CredentialAssertion + 2, // 1: teleport.mfa.v2.AuthenticateChallenge.sso_challenge:type_name -> teleport.mfa.v2.SSOChallenge + 5, // 2: teleport.mfa.v2.AuthenticateChallenge.browser_challenge:type_name -> teleport.mfa.v2.BrowserMFAChallenge + 8, // 3: teleport.mfa.v2.AuthenticateResponse.webauthn:type_name -> teleport.webauthn.v2.CredentialAssertionResponse + 4, // 4: teleport.mfa.v2.AuthenticateResponse.sso:type_name -> teleport.mfa.v2.SSOChallengeResponse + 6, // 5: teleport.mfa.v2.AuthenticateResponse.browser:type_name -> teleport.mfa.v2.BrowserMFAResponse + 3, // 6: teleport.mfa.v2.SSOChallenge.device:type_name -> teleport.mfa.v2.SSOMFADevice + 8, // 7: teleport.mfa.v2.BrowserMFAResponse.webauthn_response:type_name -> teleport.webauthn.v2.CredentialAssertionResponse + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_teleport_mfa_v2_challenge_proto_init() } +func file_teleport_mfa_v2_challenge_proto_init() { + if File_teleport_mfa_v2_challenge_proto != nil { + return + } + file_teleport_mfa_v2_challenge_proto_msgTypes[1].OneofWrappers = []any{ + (*authenticateResponse_Webauthn)(nil), + (*authenticateResponse_Sso)(nil), + (*authenticateResponse_Browser)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_mfa_v2_challenge_proto_rawDesc), len(file_teleport_mfa_v2_challenge_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_mfa_v2_challenge_proto_goTypes, + DependencyIndexes: file_teleport_mfa_v2_challenge_proto_depIdxs, + MessageInfos: file_teleport_mfa_v2_challenge_proto_msgTypes, + }.Build() + File_teleport_mfa_v2_challenge_proto = out.File + file_teleport_mfa_v2_challenge_proto_goTypes = nil + file_teleport_mfa_v2_challenge_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/mfa/v2/service.pb.go b/api/gen/proto/go/teleport/mfa/v2/service.pb.go new file mode 100644 index 00000000000..abb3251f134 --- /dev/null +++ b/api/gen/proto/go/teleport/mfa/v2/service.pb.go @@ -0,0 +1,1246 @@ +// Copyright 2026 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: teleport/mfa/v2/service.proto + +package mfav2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// CreateSessionChallengeRequest is the request message for CreateSessionChallenge. +type CreateSessionChallengeRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Payload *SessionIdentifyingPayload `protobuf:"bytes,1,opt,name=payload,proto3"` + xxx_hidden_TargetCluster string `protobuf:"bytes,2,opt,name=target_cluster,json=targetCluster,proto3"` + xxx_hidden_SsoClientRedirectUrl string `protobuf:"bytes,3,opt,name=sso_client_redirect_url,json=ssoClientRedirectUrl,proto3"` + xxx_hidden_ProxyAddressForSso string `protobuf:"bytes,4,opt,name=proxy_address_for_sso,json=proxyAddressForSso,proto3"` + xxx_hidden_BrowserMfaTshRedirectUrl string `protobuf:"bytes,5,opt,name=browser_mfa_tsh_redirect_url,json=browserMfaTshRedirectUrl,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSessionChallengeRequest) Reset() { + *x = CreateSessionChallengeRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSessionChallengeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSessionChallengeRequest) ProtoMessage() {} + +func (x *CreateSessionChallengeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CreateSessionChallengeRequest) GetPayload() *SessionIdentifyingPayload { + if x != nil { + return x.xxx_hidden_Payload + } + return nil +} + +func (x *CreateSessionChallengeRequest) GetTargetCluster() string { + if x != nil { + return x.xxx_hidden_TargetCluster + } + return "" +} + +func (x *CreateSessionChallengeRequest) GetSsoClientRedirectUrl() string { + if x != nil { + return x.xxx_hidden_SsoClientRedirectUrl + } + return "" +} + +func (x *CreateSessionChallengeRequest) GetProxyAddressForSso() string { + if x != nil { + return x.xxx_hidden_ProxyAddressForSso + } + return "" +} + +func (x *CreateSessionChallengeRequest) GetBrowserMfaTshRedirectUrl() string { + if x != nil { + return x.xxx_hidden_BrowserMfaTshRedirectUrl + } + return "" +} + +func (x *CreateSessionChallengeRequest) SetPayload(v *SessionIdentifyingPayload) { + x.xxx_hidden_Payload = v +} + +func (x *CreateSessionChallengeRequest) SetTargetCluster(v string) { + x.xxx_hidden_TargetCluster = v +} + +func (x *CreateSessionChallengeRequest) SetSsoClientRedirectUrl(v string) { + x.xxx_hidden_SsoClientRedirectUrl = v +} + +func (x *CreateSessionChallengeRequest) SetProxyAddressForSso(v string) { + x.xxx_hidden_ProxyAddressForSso = v +} + +func (x *CreateSessionChallengeRequest) SetBrowserMfaTshRedirectUrl(v string) { + x.xxx_hidden_BrowserMfaTshRedirectUrl = v +} + +func (x *CreateSessionChallengeRequest) HasPayload() bool { + if x == nil { + return false + } + return x.xxx_hidden_Payload != nil +} + +func (x *CreateSessionChallengeRequest) ClearPayload() { + x.xxx_hidden_Payload = nil +} + +type CreateSessionChallengeRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Value that uniquely identifies the user's session. When VerifyValidatedMFAChallenge is called, the server will + // verify it matches the payload supplied to CreateSessionChallengeRequest. + Payload *SessionIdentifyingPayload + // Name of the target cluster where the SSH session is being established. If unset, the server assumes the challenge + // is for the local cluster. Used to determine where the validated challenge should be replicated for leaf clusters. + // Required when the SSH session is being established in a leaf cluster. + TargetCluster string + // Used to construct the IdP redirect URL in SSO MFA challenges. If the client does not support SSO MFA, this field + // may be left unset and no SSO challenge will be included in the response. If set, the server will include SSO + // challenges in the response. + SsoClientRedirectUrl string + // Proxy address the user is using to connect to the Proxy. Required for SSO MFA to determine which URL to redirect + // the user to when there are multiple options. + ProxyAddressForSso string + // Used to construct the redirect URL for browser-based MFA flows. If the client supports browser MFA, this field + // should be set to the URL where the browser should redirect to tsh after completing the MFA challenge. + // Format: http://127.0.0.1:[random_port]/callback?response={encrypted_webauthn_response} + BrowserMfaTshRedirectUrl string +} + +func (b0 CreateSessionChallengeRequest_builder) Build() *CreateSessionChallengeRequest { + m0 := &CreateSessionChallengeRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Payload = b.Payload + x.xxx_hidden_TargetCluster = b.TargetCluster + x.xxx_hidden_SsoClientRedirectUrl = b.SsoClientRedirectUrl + x.xxx_hidden_ProxyAddressForSso = b.ProxyAddressForSso + x.xxx_hidden_BrowserMfaTshRedirectUrl = b.BrowserMfaTshRedirectUrl + return m0 +} + +// CreateSessionChallengeResponse is the response message for CreateSessionChallenge. +type CreateSessionChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_MfaChallenge *AuthenticateChallenge `protobuf:"bytes,1,opt,name=mfa_challenge,json=mfaChallenge,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSessionChallengeResponse) Reset() { + *x = CreateSessionChallengeResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSessionChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSessionChallengeResponse) ProtoMessage() {} + +func (x *CreateSessionChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CreateSessionChallengeResponse) GetMfaChallenge() *AuthenticateChallenge { + if x != nil { + return x.xxx_hidden_MfaChallenge + } + return nil +} + +func (x *CreateSessionChallengeResponse) SetMfaChallenge(v *AuthenticateChallenge) { + x.xxx_hidden_MfaChallenge = v +} + +func (x *CreateSessionChallengeResponse) HasMfaChallenge() bool { + if x == nil { + return false + } + return x.xxx_hidden_MfaChallenge != nil +} + +func (x *CreateSessionChallengeResponse) ClearMfaChallenge() { + x.xxx_hidden_MfaChallenge = nil +} + +type CreateSessionChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // MFA challenge that the user must respond to. + MfaChallenge *AuthenticateChallenge +} + +func (b0 CreateSessionChallengeResponse_builder) Build() *CreateSessionChallengeResponse { + m0 := &CreateSessionChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_MfaChallenge = b.MfaChallenge + return m0 +} + +// ValidateSessionChallengeRequest is the request message for ValidateSessionChallenge. +type ValidateSessionChallengeRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_MfaResponse *AuthenticateResponse `protobuf:"bytes,1,opt,name=mfa_response,json=mfaResponse,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidateSessionChallengeRequest) Reset() { + *x = ValidateSessionChallengeRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidateSessionChallengeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateSessionChallengeRequest) ProtoMessage() {} + +func (x *ValidateSessionChallengeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ValidateSessionChallengeRequest) GetMfaResponse() *AuthenticateResponse { + if x != nil { + return x.xxx_hidden_MfaResponse + } + return nil +} + +func (x *ValidateSessionChallengeRequest) SetMfaResponse(v *AuthenticateResponse) { + x.xxx_hidden_MfaResponse = v +} + +func (x *ValidateSessionChallengeRequest) HasMfaResponse() bool { + if x == nil { + return false + } + return x.xxx_hidden_MfaResponse != nil +} + +func (x *ValidateSessionChallengeRequest) ClearMfaResponse() { + x.xxx_hidden_MfaResponse = nil +} + +type ValidateSessionChallengeRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // MFA challenge response provided by the user. + MfaResponse *AuthenticateResponse +} + +func (b0 ValidateSessionChallengeRequest_builder) Build() *ValidateSessionChallengeRequest { + m0 := &ValidateSessionChallengeRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_MfaResponse = b.MfaResponse + return m0 +} + +// ValidateSessionChallengeResponse is the response message for ValidateSessionChallenge. +type ValidateSessionChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidateSessionChallengeResponse) Reset() { + *x = ValidateSessionChallengeResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidateSessionChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateSessionChallengeResponse) ProtoMessage() {} + +func (x *ValidateSessionChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +type ValidateSessionChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + +} + +func (b0 ValidateSessionChallengeResponse_builder) Build() *ValidateSessionChallengeResponse { + m0 := &ValidateSessionChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + return m0 +} + +// ListValidatedMFAChallengesFilter is used to filter validated MFA challenges in ListValidatedMFAChallengesRequest. +type ListValidatedMFAChallengesFilter struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_TargetCluster *string `protobuf:"bytes,1,opt,name=target_cluster,json=targetCluster,proto3,oneof"` + XXX_raceDetectHookData protoimpl.RaceDetectHookData + XXX_presence [1]uint32 + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListValidatedMFAChallengesFilter) Reset() { + *x = ListValidatedMFAChallengesFilter{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListValidatedMFAChallengesFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListValidatedMFAChallengesFilter) ProtoMessage() {} + +func (x *ListValidatedMFAChallengesFilter) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ListValidatedMFAChallengesFilter) GetTargetCluster() string { + if x != nil { + if x.xxx_hidden_TargetCluster != nil { + return *x.xxx_hidden_TargetCluster + } + return "" + } + return "" +} + +func (x *ListValidatedMFAChallengesFilter) SetTargetCluster(v string) { + x.xxx_hidden_TargetCluster = &v + protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 1) +} + +func (x *ListValidatedMFAChallengesFilter) HasTargetCluster() bool { + if x == nil { + return false + } + return protoimpl.X.Present(&(x.XXX_presence[0]), 0) +} + +func (x *ListValidatedMFAChallengesFilter) ClearTargetCluster() { + protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0) + x.xxx_hidden_TargetCluster = nil +} + +type ListValidatedMFAChallengesFilter_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // If set, only return validated MFA challenges for the specified target cluster. + TargetCluster *string +} + +func (b0 ListValidatedMFAChallengesFilter_builder) Build() *ListValidatedMFAChallengesFilter { + m0 := &ListValidatedMFAChallengesFilter{} + b, x := &b0, m0 + _, _ = b, x + if b.TargetCluster != nil { + protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 1) + x.xxx_hidden_TargetCluster = b.TargetCluster + } + return m0 +} + +// ListValidatedMFAChallengesRequest is the request message for ListValidatedMFAChallenges. +type ListValidatedMFAChallengesRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3"` + xxx_hidden_PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3"` + xxx_hidden_Filter *ListValidatedMFAChallengesFilter `protobuf:"bytes,3,opt,name=filter,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListValidatedMFAChallengesRequest) Reset() { + *x = ListValidatedMFAChallengesRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListValidatedMFAChallengesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListValidatedMFAChallengesRequest) ProtoMessage() {} + +func (x *ListValidatedMFAChallengesRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ListValidatedMFAChallengesRequest) GetPageSize() int32 { + if x != nil { + return x.xxx_hidden_PageSize + } + return 0 +} + +func (x *ListValidatedMFAChallengesRequest) GetPageToken() string { + if x != nil { + return x.xxx_hidden_PageToken + } + return "" +} + +func (x *ListValidatedMFAChallengesRequest) GetFilter() *ListValidatedMFAChallengesFilter { + if x != nil { + return x.xxx_hidden_Filter + } + return nil +} + +func (x *ListValidatedMFAChallengesRequest) SetPageSize(v int32) { + x.xxx_hidden_PageSize = v +} + +func (x *ListValidatedMFAChallengesRequest) SetPageToken(v string) { + x.xxx_hidden_PageToken = v +} + +func (x *ListValidatedMFAChallengesRequest) SetFilter(v *ListValidatedMFAChallengesFilter) { + x.xxx_hidden_Filter = v +} + +func (x *ListValidatedMFAChallengesRequest) HasFilter() bool { + if x == nil { + return false + } + return x.xxx_hidden_Filter != nil +} + +func (x *ListValidatedMFAChallengesRequest) ClearFilter() { + x.xxx_hidden_Filter = nil +} + +type ListValidatedMFAChallengesRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // The maximum number of items to return. The server may impose a different page size at its discretion. + PageSize int32 + // The next_page_token value returned from a previous List request, if any. + PageToken string + // Collection of fields to filter challenges by. Challenges must match all filter fields to be included in the + // results. If unset, no filtering is performed and all validated MFA challenges are returned (up to the page size + // limit). + Filter *ListValidatedMFAChallengesFilter +} + +func (b0 ListValidatedMFAChallengesRequest_builder) Build() *ListValidatedMFAChallengesRequest { + m0 := &ListValidatedMFAChallengesRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_PageSize = b.PageSize + x.xxx_hidden_PageToken = b.PageToken + x.xxx_hidden_Filter = b.Filter + return m0 +} + +// ListValidatedMFAChallengesResponse is the response message for ListValidatedMFAChallenges. +type ListValidatedMFAChallengesResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_ValidatedChallenges *[]*ValidatedMFAChallenge `protobuf:"bytes,1,rep,name=validated_challenges,json=validatedChallenges,proto3"` + xxx_hidden_NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListValidatedMFAChallengesResponse) Reset() { + *x = ListValidatedMFAChallengesResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListValidatedMFAChallengesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListValidatedMFAChallengesResponse) ProtoMessage() {} + +func (x *ListValidatedMFAChallengesResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ListValidatedMFAChallengesResponse) GetValidatedChallenges() []*ValidatedMFAChallenge { + if x != nil { + if x.xxx_hidden_ValidatedChallenges != nil { + return *x.xxx_hidden_ValidatedChallenges + } + } + return nil +} + +func (x *ListValidatedMFAChallengesResponse) GetNextPageToken() string { + if x != nil { + return x.xxx_hidden_NextPageToken + } + return "" +} + +func (x *ListValidatedMFAChallengesResponse) SetValidatedChallenges(v []*ValidatedMFAChallenge) { + x.xxx_hidden_ValidatedChallenges = &v +} + +func (x *ListValidatedMFAChallengesResponse) SetNextPageToken(v string) { + x.xxx_hidden_NextPageToken = v +} + +type ListValidatedMFAChallengesResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // List of validated MFA challenges that have been created for user sessions. + ValidatedChallenges []*ValidatedMFAChallenge + // Token to retrieve the next page of results, or empty if there are no more results exist. + NextPageToken string +} + +func (b0 ListValidatedMFAChallengesResponse_builder) Build() *ListValidatedMFAChallengesResponse { + m0 := &ListValidatedMFAChallengesResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_ValidatedChallenges = &b.ValidatedChallenges + x.xxx_hidden_NextPageToken = b.NextPageToken + return m0 +} + +// ReplicateValidatedMFAChallengeRequest is the request message for ReplicateValidatedMFAChallenge. +type ReplicateValidatedMFAChallengeRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Name string `protobuf:"bytes,1,opt,name=name,proto3"` + xxx_hidden_Payload *SessionIdentifyingPayload `protobuf:"bytes,2,opt,name=payload,proto3"` + xxx_hidden_SourceCluster string `protobuf:"bytes,3,opt,name=source_cluster,json=sourceCluster,proto3"` + xxx_hidden_TargetCluster string `protobuf:"bytes,4,opt,name=target_cluster,json=targetCluster,proto3"` + xxx_hidden_Username string `protobuf:"bytes,5,opt,name=username,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReplicateValidatedMFAChallengeRequest) Reset() { + *x = ReplicateValidatedMFAChallengeRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReplicateValidatedMFAChallengeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicateValidatedMFAChallengeRequest) ProtoMessage() {} + +func (x *ReplicateValidatedMFAChallengeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ReplicateValidatedMFAChallengeRequest) GetName() string { + if x != nil { + return x.xxx_hidden_Name + } + return "" +} + +func (x *ReplicateValidatedMFAChallengeRequest) GetPayload() *SessionIdentifyingPayload { + if x != nil { + return x.xxx_hidden_Payload + } + return nil +} + +func (x *ReplicateValidatedMFAChallengeRequest) GetSourceCluster() string { + if x != nil { + return x.xxx_hidden_SourceCluster + } + return "" +} + +func (x *ReplicateValidatedMFAChallengeRequest) GetTargetCluster() string { + if x != nil { + return x.xxx_hidden_TargetCluster + } + return "" +} + +func (x *ReplicateValidatedMFAChallengeRequest) GetUsername() string { + if x != nil { + return x.xxx_hidden_Username + } + return "" +} + +func (x *ReplicateValidatedMFAChallengeRequest) SetName(v string) { + x.xxx_hidden_Name = v +} + +func (x *ReplicateValidatedMFAChallengeRequest) SetPayload(v *SessionIdentifyingPayload) { + x.xxx_hidden_Payload = v +} + +func (x *ReplicateValidatedMFAChallengeRequest) SetSourceCluster(v string) { + x.xxx_hidden_SourceCluster = v +} + +func (x *ReplicateValidatedMFAChallengeRequest) SetTargetCluster(v string) { + x.xxx_hidden_TargetCluster = v +} + +func (x *ReplicateValidatedMFAChallengeRequest) SetUsername(v string) { + x.xxx_hidden_Username = v +} + +func (x *ReplicateValidatedMFAChallengeRequest) HasPayload() bool { + if x == nil { + return false + } + return x.xxx_hidden_Payload != nil +} + +func (x *ReplicateValidatedMFAChallengeRequest) ClearPayload() { + x.xxx_hidden_Payload = nil +} + +type ReplicateValidatedMFAChallengeRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Resource name for the issued challenge. Must match the AuthenticateChallenge.name in order to find the correct + // challenge. + Name string + // Value that uniquely identifies the user's session. Must match the payload in CreateSessionChallengeRequest. + Payload *SessionIdentifyingPayload + // Name of the source cluster where the validated challenge originated. Required in order to match the validated + // challenge to the correct session. + SourceCluster string + // Name of the target cluster where the SSH session is being established. Required in order to match the validated + // challenge to the correct session. + TargetCluster string + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified by source_cluster. + Username string +} + +func (b0 ReplicateValidatedMFAChallengeRequest_builder) Build() *ReplicateValidatedMFAChallengeRequest { + m0 := &ReplicateValidatedMFAChallengeRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Name = b.Name + x.xxx_hidden_Payload = b.Payload + x.xxx_hidden_SourceCluster = b.SourceCluster + x.xxx_hidden_TargetCluster = b.TargetCluster + x.xxx_hidden_Username = b.Username + return m0 +} + +// ReplicateValidatedMFAChallengeResponse is the response message for ReplicateValidatedMFAChallenge. +type ReplicateValidatedMFAChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_ReplicatedChallenge *ValidatedMFAChallenge `protobuf:"bytes,1,opt,name=replicated_challenge,json=replicatedChallenge,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReplicateValidatedMFAChallengeResponse) Reset() { + *x = ReplicateValidatedMFAChallengeResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReplicateValidatedMFAChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicateValidatedMFAChallengeResponse) ProtoMessage() {} + +func (x *ReplicateValidatedMFAChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ReplicateValidatedMFAChallengeResponse) GetReplicatedChallenge() *ValidatedMFAChallenge { + if x != nil { + return x.xxx_hidden_ReplicatedChallenge + } + return nil +} + +func (x *ReplicateValidatedMFAChallengeResponse) SetReplicatedChallenge(v *ValidatedMFAChallenge) { + x.xxx_hidden_ReplicatedChallenge = v +} + +func (x *ReplicateValidatedMFAChallengeResponse) HasReplicatedChallenge() bool { + if x == nil { + return false + } + return x.xxx_hidden_ReplicatedChallenge != nil +} + +func (x *ReplicateValidatedMFAChallengeResponse) ClearReplicatedChallenge() { + x.xxx_hidden_ReplicatedChallenge = nil +} + +type ReplicateValidatedMFAChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Validated MFA challenge that was replicated. + ReplicatedChallenge *ValidatedMFAChallenge +} + +func (b0 ReplicateValidatedMFAChallengeResponse_builder) Build() *ReplicateValidatedMFAChallengeResponse { + m0 := &ReplicateValidatedMFAChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_ReplicatedChallenge = b.ReplicatedChallenge + return m0 +} + +// VerifyValidatedMFAChallengeRequest is the request message for VerifyValidatedMFAChallenge. +type VerifyValidatedMFAChallengeRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Name string `protobuf:"bytes,1,opt,name=name,proto3"` + xxx_hidden_Payload *SessionIdentifyingPayload `protobuf:"bytes,2,opt,name=payload,proto3"` + xxx_hidden_SourceCluster string `protobuf:"bytes,3,opt,name=source_cluster,json=sourceCluster,proto3"` + xxx_hidden_Username string `protobuf:"bytes,4,opt,name=username,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyValidatedMFAChallengeRequest) Reset() { + *x = VerifyValidatedMFAChallengeRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyValidatedMFAChallengeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyValidatedMFAChallengeRequest) ProtoMessage() {} + +func (x *VerifyValidatedMFAChallengeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *VerifyValidatedMFAChallengeRequest) GetName() string { + if x != nil { + return x.xxx_hidden_Name + } + return "" +} + +func (x *VerifyValidatedMFAChallengeRequest) GetPayload() *SessionIdentifyingPayload { + if x != nil { + return x.xxx_hidden_Payload + } + return nil +} + +func (x *VerifyValidatedMFAChallengeRequest) GetSourceCluster() string { + if x != nil { + return x.xxx_hidden_SourceCluster + } + return "" +} + +func (x *VerifyValidatedMFAChallengeRequest) GetUsername() string { + if x != nil { + return x.xxx_hidden_Username + } + return "" +} + +func (x *VerifyValidatedMFAChallengeRequest) SetName(v string) { + x.xxx_hidden_Name = v +} + +func (x *VerifyValidatedMFAChallengeRequest) SetPayload(v *SessionIdentifyingPayload) { + x.xxx_hidden_Payload = v +} + +func (x *VerifyValidatedMFAChallengeRequest) SetSourceCluster(v string) { + x.xxx_hidden_SourceCluster = v +} + +func (x *VerifyValidatedMFAChallengeRequest) SetUsername(v string) { + x.xxx_hidden_Username = v +} + +func (x *VerifyValidatedMFAChallengeRequest) HasPayload() bool { + if x == nil { + return false + } + return x.xxx_hidden_Payload != nil +} + +func (x *VerifyValidatedMFAChallengeRequest) ClearPayload() { + x.xxx_hidden_Payload = nil +} + +type VerifyValidatedMFAChallengeRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Resource name for the issued challenge. Must match the AuthenticateChallenge.name in order to find the correct + // challenge. + Name string + // Value that uniquely identifies the user's session. The client MUST independently compute this value from session + // state. The server will verify it matches the payload supplied in CreateSessionChallengeRequest to ensure the + // challenge is tied to the correct session. + Payload *SessionIdentifyingPayload + // Name of the cluster where the validated challenge originated. + SourceCluster string + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified by source_cluster. The client MUST determine this + // value by authenticating the Teleport user before calling this method. The server will verify that it matches the + // Teleport user associated with the validated challenge to ensure the challenge is tied to the correct user. + Username string +} + +func (b0 VerifyValidatedMFAChallengeRequest_builder) Build() *VerifyValidatedMFAChallengeRequest { + m0 := &VerifyValidatedMFAChallengeRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Name = b.Name + x.xxx_hidden_Payload = b.Payload + x.xxx_hidden_SourceCluster = b.SourceCluster + x.xxx_hidden_Username = b.Username + return m0 +} + +// VerifyValidatedMFAChallengeResponse is the response message for VerifyValidatedMFAChallenge. +type VerifyValidatedMFAChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VerifyValidatedMFAChallengeResponse) Reset() { + *x = VerifyValidatedMFAChallengeResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VerifyValidatedMFAChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyValidatedMFAChallengeResponse) ProtoMessage() {} + +func (x *VerifyValidatedMFAChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +type VerifyValidatedMFAChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + +} + +func (b0 VerifyValidatedMFAChallengeResponse_builder) Build() *VerifyValidatedMFAChallengeResponse { + m0 := &VerifyValidatedMFAChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + return m0 +} + +// CompleteBrowserMFAChallengeRequest is used to complete an MFA response +// during a browser-based MFA authentication flow. +type CompleteBrowserMFAChallengeRequest struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_BrowserMfaResponse *BrowserMFAResponse `protobuf:"bytes,1,opt,name=browser_mfa_response,json=browserMfaResponse,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompleteBrowserMFAChallengeRequest) Reset() { + *x = CompleteBrowserMFAChallengeRequest{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompleteBrowserMFAChallengeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompleteBrowserMFAChallengeRequest) ProtoMessage() {} + +func (x *CompleteBrowserMFAChallengeRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CompleteBrowserMFAChallengeRequest) GetBrowserMfaResponse() *BrowserMFAResponse { + if x != nil { + return x.xxx_hidden_BrowserMfaResponse + } + return nil +} + +func (x *CompleteBrowserMFAChallengeRequest) SetBrowserMfaResponse(v *BrowserMFAResponse) { + x.xxx_hidden_BrowserMfaResponse = v +} + +func (x *CompleteBrowserMFAChallengeRequest) HasBrowserMfaResponse() bool { + if x == nil { + return false + } + return x.xxx_hidden_BrowserMfaResponse != nil +} + +func (x *CompleteBrowserMFAChallengeRequest) ClearBrowserMfaResponse() { + x.xxx_hidden_BrowserMfaResponse = nil +} + +type CompleteBrowserMFAChallengeRequest_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + BrowserMfaResponse *BrowserMFAResponse +} + +func (b0 CompleteBrowserMFAChallengeRequest_builder) Build() *CompleteBrowserMFAChallengeRequest { + m0 := &CompleteBrowserMFAChallengeRequest{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_BrowserMfaResponse = b.BrowserMfaResponse + return m0 +} + +// CompleteBrowserMFAChallengeResponse contains the redirect URL to send +// the user back to after successfully completing browser-based MFA authentication. +type CompleteBrowserMFAChallengeResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_TshRedirectUrl string `protobuf:"bytes,1,opt,name=tsh_redirect_url,json=tshRedirectUrl,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompleteBrowserMFAChallengeResponse) Reset() { + *x = CompleteBrowserMFAChallengeResponse{} + mi := &file_teleport_mfa_v2_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompleteBrowserMFAChallengeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompleteBrowserMFAChallengeResponse) ProtoMessage() {} + +func (x *CompleteBrowserMFAChallengeResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CompleteBrowserMFAChallengeResponse) GetTshRedirectUrl() string { + if x != nil { + return x.xxx_hidden_TshRedirectUrl + } + return "" +} + +func (x *CompleteBrowserMFAChallengeResponse) SetTshRedirectUrl(v string) { + x.xxx_hidden_TshRedirectUrl = v +} + +type CompleteBrowserMFAChallengeResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // tsh_redirect_url is the callback URL to tsh's local HTTP server with the encrypted WebAuthn response. + // Format: http://127.0.0.1:[random_port]/callback?response={encrypted_webauthn_response} + TshRedirectUrl string +} + +func (b0 CompleteBrowserMFAChallengeResponse_builder) Build() *CompleteBrowserMFAChallengeResponse { + m0 := &CompleteBrowserMFAChallengeResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_TshRedirectUrl = b.TshRedirectUrl + return m0 +} + +var File_teleport_mfa_v2_service_proto protoreflect.FileDescriptor + +const file_teleport_mfa_v2_service_proto_rawDesc = "" + + "\n" + + "\x1dteleport/mfa/v2/service.proto\x12\x0fteleport.mfa.v2\x1a\x1fteleport/mfa/v2/challenge.proto\x1a)teleport/mfa/v2/validated_challenge.proto\"\xb6\x02\n" + + "\x1dCreateSessionChallengeRequest\x12D\n" + + "\apayload\x18\x01 \x01(\v2*.teleport.mfa.v2.SessionIdentifyingPayloadR\apayload\x12%\n" + + "\x0etarget_cluster\x18\x02 \x01(\tR\rtargetCluster\x125\n" + + "\x17sso_client_redirect_url\x18\x03 \x01(\tR\x14ssoClientRedirectUrl\x121\n" + + "\x15proxy_address_for_sso\x18\x04 \x01(\tR\x12proxyAddressForSso\x12>\n" + + "\x1cbrowser_mfa_tsh_redirect_url\x18\x05 \x01(\tR\x18browserMfaTshRedirectUrl\"m\n" + + "\x1eCreateSessionChallengeResponse\x12K\n" + + "\rmfa_challenge\x18\x01 \x01(\v2&.teleport.mfa.v2.AuthenticateChallengeR\fmfaChallenge\"k\n" + + "\x1fValidateSessionChallengeRequest\x12H\n" + + "\fmfa_response\x18\x01 \x01(\v2%.teleport.mfa.v2.AuthenticateResponseR\vmfaResponse\"\"\n" + + " ValidateSessionChallengeResponse\"a\n" + + " ListValidatedMFAChallengesFilter\x12*\n" + + "\x0etarget_cluster\x18\x01 \x01(\tH\x00R\rtargetCluster\x88\x01\x01B\x11\n" + + "\x0f_target_cluster\"\xaa\x01\n" + + "!ListValidatedMFAChallengesRequest\x12\x1b\n" + + "\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x02 \x01(\tR\tpageToken\x12I\n" + + "\x06filter\x18\x03 \x01(\v21.teleport.mfa.v2.ListValidatedMFAChallengesFilterR\x06filter\"\xa7\x01\n" + + "\"ListValidatedMFAChallengesResponse\x12Y\n" + + "\x14validated_challenges\x18\x01 \x03(\v2&.teleport.mfa.v2.ValidatedMFAChallengeR\x13validatedChallenges\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"\xeb\x01\n" + + "%ReplicateValidatedMFAChallengeRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12D\n" + + "\apayload\x18\x02 \x01(\v2*.teleport.mfa.v2.SessionIdentifyingPayloadR\apayload\x12%\n" + + "\x0esource_cluster\x18\x03 \x01(\tR\rsourceCluster\x12%\n" + + "\x0etarget_cluster\x18\x04 \x01(\tR\rtargetCluster\x12\x1a\n" + + "\busername\x18\x05 \x01(\tR\busername\"\x83\x01\n" + + "&ReplicateValidatedMFAChallengeResponse\x12Y\n" + + "\x14replicated_challenge\x18\x01 \x01(\v2&.teleport.mfa.v2.ValidatedMFAChallengeR\x13replicatedChallenge\"\xc1\x01\n" + + "\"VerifyValidatedMFAChallengeRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12D\n" + + "\apayload\x18\x02 \x01(\v2*.teleport.mfa.v2.SessionIdentifyingPayloadR\apayload\x12%\n" + + "\x0esource_cluster\x18\x03 \x01(\tR\rsourceCluster\x12\x1a\n" + + "\busername\x18\x04 \x01(\tR\busername\"%\n" + + "#VerifyValidatedMFAChallengeResponse\"{\n" + + "\"CompleteBrowserMFAChallengeRequest\x12U\n" + + "\x14browser_mfa_response\x18\x01 \x01(\v2#.teleport.mfa.v2.BrowserMFAResponseR\x12browserMfaResponse\"O\n" + + "#CompleteBrowserMFAChallengeResponse\x12(\n" + + "\x10tsh_redirect_url\x18\x01 \x01(\tR\x0etshRedirectUrl2\xba\x06\n" + + "\n" + + "MFAService\x12y\n" + + "\x16CreateSessionChallenge\x12..teleport.mfa.v2.CreateSessionChallengeRequest\x1a/.teleport.mfa.v2.CreateSessionChallengeResponse\x12\x7f\n" + + "\x18ValidateSessionChallenge\x120.teleport.mfa.v2.ValidateSessionChallengeRequest\x1a1.teleport.mfa.v2.ValidateSessionChallengeResponse\x12\x85\x01\n" + + "\x1aListValidatedMFAChallenges\x122.teleport.mfa.v2.ListValidatedMFAChallengesRequest\x1a3.teleport.mfa.v2.ListValidatedMFAChallengesResponse\x12\x91\x01\n" + + "\x1eReplicateValidatedMFAChallenge\x126.teleport.mfa.v2.ReplicateValidatedMFAChallengeRequest\x1a7.teleport.mfa.v2.ReplicateValidatedMFAChallengeResponse\x12\x88\x01\n" + + "\x1bVerifyValidatedMFAChallenge\x123.teleport.mfa.v2.VerifyValidatedMFAChallengeRequest\x1a4.teleport.mfa.v2.VerifyValidatedMFAChallengeResponse\x12\x88\x01\n" + + "\x1bCompleteBrowserMFAChallenge\x123.teleport.mfa.v2.CompleteBrowserMFAChallengeRequest\x1a4.teleport.mfa.v2.CompleteBrowserMFAChallengeResponseBJZHgithub.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2b\x06proto3" + +var file_teleport_mfa_v2_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_teleport_mfa_v2_service_proto_goTypes = []any{ + (*CreateSessionChallengeRequest)(nil), // 0: teleport.mfa.v2.CreateSessionChallengeRequest + (*CreateSessionChallengeResponse)(nil), // 1: teleport.mfa.v2.CreateSessionChallengeResponse + (*ValidateSessionChallengeRequest)(nil), // 2: teleport.mfa.v2.ValidateSessionChallengeRequest + (*ValidateSessionChallengeResponse)(nil), // 3: teleport.mfa.v2.ValidateSessionChallengeResponse + (*ListValidatedMFAChallengesFilter)(nil), // 4: teleport.mfa.v2.ListValidatedMFAChallengesFilter + (*ListValidatedMFAChallengesRequest)(nil), // 5: teleport.mfa.v2.ListValidatedMFAChallengesRequest + (*ListValidatedMFAChallengesResponse)(nil), // 6: teleport.mfa.v2.ListValidatedMFAChallengesResponse + (*ReplicateValidatedMFAChallengeRequest)(nil), // 7: teleport.mfa.v2.ReplicateValidatedMFAChallengeRequest + (*ReplicateValidatedMFAChallengeResponse)(nil), // 8: teleport.mfa.v2.ReplicateValidatedMFAChallengeResponse + (*VerifyValidatedMFAChallengeRequest)(nil), // 9: teleport.mfa.v2.VerifyValidatedMFAChallengeRequest + (*VerifyValidatedMFAChallengeResponse)(nil), // 10: teleport.mfa.v2.VerifyValidatedMFAChallengeResponse + (*CompleteBrowserMFAChallengeRequest)(nil), // 11: teleport.mfa.v2.CompleteBrowserMFAChallengeRequest + (*CompleteBrowserMFAChallengeResponse)(nil), // 12: teleport.mfa.v2.CompleteBrowserMFAChallengeResponse + (*SessionIdentifyingPayload)(nil), // 13: teleport.mfa.v2.SessionIdentifyingPayload + (*AuthenticateChallenge)(nil), // 14: teleport.mfa.v2.AuthenticateChallenge + (*AuthenticateResponse)(nil), // 15: teleport.mfa.v2.AuthenticateResponse + (*ValidatedMFAChallenge)(nil), // 16: teleport.mfa.v2.ValidatedMFAChallenge + (*BrowserMFAResponse)(nil), // 17: teleport.mfa.v2.BrowserMFAResponse +} +var file_teleport_mfa_v2_service_proto_depIdxs = []int32{ + 13, // 0: teleport.mfa.v2.CreateSessionChallengeRequest.payload:type_name -> teleport.mfa.v2.SessionIdentifyingPayload + 14, // 1: teleport.mfa.v2.CreateSessionChallengeResponse.mfa_challenge:type_name -> teleport.mfa.v2.AuthenticateChallenge + 15, // 2: teleport.mfa.v2.ValidateSessionChallengeRequest.mfa_response:type_name -> teleport.mfa.v2.AuthenticateResponse + 4, // 3: teleport.mfa.v2.ListValidatedMFAChallengesRequest.filter:type_name -> teleport.mfa.v2.ListValidatedMFAChallengesFilter + 16, // 4: teleport.mfa.v2.ListValidatedMFAChallengesResponse.validated_challenges:type_name -> teleport.mfa.v2.ValidatedMFAChallenge + 13, // 5: teleport.mfa.v2.ReplicateValidatedMFAChallengeRequest.payload:type_name -> teleport.mfa.v2.SessionIdentifyingPayload + 16, // 6: teleport.mfa.v2.ReplicateValidatedMFAChallengeResponse.replicated_challenge:type_name -> teleport.mfa.v2.ValidatedMFAChallenge + 13, // 7: teleport.mfa.v2.VerifyValidatedMFAChallengeRequest.payload:type_name -> teleport.mfa.v2.SessionIdentifyingPayload + 17, // 8: teleport.mfa.v2.CompleteBrowserMFAChallengeRequest.browser_mfa_response:type_name -> teleport.mfa.v2.BrowserMFAResponse + 0, // 9: teleport.mfa.v2.MFAService.CreateSessionChallenge:input_type -> teleport.mfa.v2.CreateSessionChallengeRequest + 2, // 10: teleport.mfa.v2.MFAService.ValidateSessionChallenge:input_type -> teleport.mfa.v2.ValidateSessionChallengeRequest + 5, // 11: teleport.mfa.v2.MFAService.ListValidatedMFAChallenges:input_type -> teleport.mfa.v2.ListValidatedMFAChallengesRequest + 7, // 12: teleport.mfa.v2.MFAService.ReplicateValidatedMFAChallenge:input_type -> teleport.mfa.v2.ReplicateValidatedMFAChallengeRequest + 9, // 13: teleport.mfa.v2.MFAService.VerifyValidatedMFAChallenge:input_type -> teleport.mfa.v2.VerifyValidatedMFAChallengeRequest + 11, // 14: teleport.mfa.v2.MFAService.CompleteBrowserMFAChallenge:input_type -> teleport.mfa.v2.CompleteBrowserMFAChallengeRequest + 1, // 15: teleport.mfa.v2.MFAService.CreateSessionChallenge:output_type -> teleport.mfa.v2.CreateSessionChallengeResponse + 3, // 16: teleport.mfa.v2.MFAService.ValidateSessionChallenge:output_type -> teleport.mfa.v2.ValidateSessionChallengeResponse + 6, // 17: teleport.mfa.v2.MFAService.ListValidatedMFAChallenges:output_type -> teleport.mfa.v2.ListValidatedMFAChallengesResponse + 8, // 18: teleport.mfa.v2.MFAService.ReplicateValidatedMFAChallenge:output_type -> teleport.mfa.v2.ReplicateValidatedMFAChallengeResponse + 10, // 19: teleport.mfa.v2.MFAService.VerifyValidatedMFAChallenge:output_type -> teleport.mfa.v2.VerifyValidatedMFAChallengeResponse + 12, // 20: teleport.mfa.v2.MFAService.CompleteBrowserMFAChallenge:output_type -> teleport.mfa.v2.CompleteBrowserMFAChallengeResponse + 15, // [15:21] is the sub-list for method output_type + 9, // [9:15] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_teleport_mfa_v2_service_proto_init() } +func file_teleport_mfa_v2_service_proto_init() { + if File_teleport_mfa_v2_service_proto != nil { + return + } + file_teleport_mfa_v2_challenge_proto_init() + file_teleport_mfa_v2_validated_challenge_proto_init() + file_teleport_mfa_v2_service_proto_msgTypes[4].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_mfa_v2_service_proto_rawDesc), len(file_teleport_mfa_v2_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_teleport_mfa_v2_service_proto_goTypes, + DependencyIndexes: file_teleport_mfa_v2_service_proto_depIdxs, + MessageInfos: file_teleport_mfa_v2_service_proto_msgTypes, + }.Build() + File_teleport_mfa_v2_service_proto = out.File + file_teleport_mfa_v2_service_proto_goTypes = nil + file_teleport_mfa_v2_service_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/mfa/v2/service_grpc.pb.go b/api/gen/proto/go/teleport/mfa/v2/service_grpc.pb.go new file mode 100644 index 00000000000..c2b6a7a4d33 --- /dev/null +++ b/api/gen/proto/go/teleport/mfa/v2/service_grpc.pb.go @@ -0,0 +1,373 @@ +// Copyright 2026 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. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: teleport/mfa/v2/service.proto + +package mfav2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + MFAService_CreateSessionChallenge_FullMethodName = "/teleport.mfa.v2.MFAService/CreateSessionChallenge" + MFAService_ValidateSessionChallenge_FullMethodName = "/teleport.mfa.v2.MFAService/ValidateSessionChallenge" + MFAService_ListValidatedMFAChallenges_FullMethodName = "/teleport.mfa.v2.MFAService/ListValidatedMFAChallenges" + MFAService_ReplicateValidatedMFAChallenge_FullMethodName = "/teleport.mfa.v2.MFAService/ReplicateValidatedMFAChallenge" + MFAService_VerifyValidatedMFAChallenge_FullMethodName = "/teleport.mfa.v2.MFAService/VerifyValidatedMFAChallenge" + MFAService_CompleteBrowserMFAChallenge_FullMethodName = "/teleport.mfa.v2.MFAService/CompleteBrowserMFAChallenge" +) + +// MFAServiceClient is the client API for MFAService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// MFAService defines the Multi-Factor Authentication (MFA) service. While this service is currently focused on user +// sessions, new MFA related RPCs should be added here instead of the AuthService, to maintain a clear separation of +// concerns instead of further bloating the AuthService. +type MFAServiceClient interface { + // CreateSessionChallenge creates an MFA challenge that is tied to a user session. + CreateSessionChallenge(ctx context.Context, in *CreateSessionChallengeRequest, opts ...grpc.CallOption) (*CreateSessionChallengeResponse, error) + // ValidateSessionChallenge validates the MFA challenge response for a user session and stores the validated response + // in the backend. + ValidateSessionChallenge(ctx context.Context, in *ValidateSessionChallengeRequest, opts ...grpc.CallOption) (*ValidateSessionChallengeResponse, error) + // ListValidatedMFAChallenges lists validated MFA challenges that have been created for all user sessions. This is + // intended to be used by the reverse tunnel server to watch for new validated challenges that need to be replicated + // for SSH session establishment in leaf clusters. + ListValidatedMFAChallenges(ctx context.Context, in *ListValidatedMFAChallengesRequest, opts ...grpc.CallOption) (*ListValidatedMFAChallengesResponse, error) + // ReplicateValidatedMFAChallenge replicates a validated MFA challenge from root cluster to leaf cluster for + // verification during SSH session establishment. The reverse tunnel server watches for validated challenges in the + // root cluster and invokes this RPC on the leaf cluster. This is a NOOP when invoked in the root cluster. + ReplicateValidatedMFAChallenge(ctx context.Context, in *ReplicateValidatedMFAChallengeRequest, opts ...grpc.CallOption) (*ReplicateValidatedMFAChallengeResponse, error) + // VerifyValidatedMFAChallenge verifies a previously validated MFA challenge response for a user session. If the + // challenge does not yet exist, this method will block until the resource appears or until the timeout is reached. + // The payload is used to verify the challenge is tied to the correct user session. If the verification fails, an + // error is returned. + VerifyValidatedMFAChallenge(ctx context.Context, in *VerifyValidatedMFAChallengeRequest, opts ...grpc.CallOption) (*VerifyValidatedMFAChallengeResponse, error) + // CompleteBrowserMFAChallenge completes a browser MFA challenge request by encrypting + // it and returning it to the browser. + // This is called when a user has been sent to the browser to solve an MFA challenge + // that was triggered by tsh or tctl. When the user solves the MFA challenge, the + // response is sent to this RPC. CompleteBrowserMFAChallenge receives the MFA + // response, encrypts it, appends it to tsh/tctl's callback URL and returns it to the browser. + // More info: https://github.com/gravitational/teleport/blob/master/rfd/0233-tsh-browser-mfa.md + CompleteBrowserMFAChallenge(ctx context.Context, in *CompleteBrowserMFAChallengeRequest, opts ...grpc.CallOption) (*CompleteBrowserMFAChallengeResponse, error) +} + +type mFAServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewMFAServiceClient(cc grpc.ClientConnInterface) MFAServiceClient { + return &mFAServiceClient{cc} +} + +func (c *mFAServiceClient) CreateSessionChallenge(ctx context.Context, in *CreateSessionChallengeRequest, opts ...grpc.CallOption) (*CreateSessionChallengeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateSessionChallengeResponse) + err := c.cc.Invoke(ctx, MFAService_CreateSessionChallenge_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mFAServiceClient) ValidateSessionChallenge(ctx context.Context, in *ValidateSessionChallengeRequest, opts ...grpc.CallOption) (*ValidateSessionChallengeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ValidateSessionChallengeResponse) + err := c.cc.Invoke(ctx, MFAService_ValidateSessionChallenge_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mFAServiceClient) ListValidatedMFAChallenges(ctx context.Context, in *ListValidatedMFAChallengesRequest, opts ...grpc.CallOption) (*ListValidatedMFAChallengesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListValidatedMFAChallengesResponse) + err := c.cc.Invoke(ctx, MFAService_ListValidatedMFAChallenges_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mFAServiceClient) ReplicateValidatedMFAChallenge(ctx context.Context, in *ReplicateValidatedMFAChallengeRequest, opts ...grpc.CallOption) (*ReplicateValidatedMFAChallengeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ReplicateValidatedMFAChallengeResponse) + err := c.cc.Invoke(ctx, MFAService_ReplicateValidatedMFAChallenge_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mFAServiceClient) VerifyValidatedMFAChallenge(ctx context.Context, in *VerifyValidatedMFAChallengeRequest, opts ...grpc.CallOption) (*VerifyValidatedMFAChallengeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(VerifyValidatedMFAChallengeResponse) + err := c.cc.Invoke(ctx, MFAService_VerifyValidatedMFAChallenge_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *mFAServiceClient) CompleteBrowserMFAChallenge(ctx context.Context, in *CompleteBrowserMFAChallengeRequest, opts ...grpc.CallOption) (*CompleteBrowserMFAChallengeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CompleteBrowserMFAChallengeResponse) + err := c.cc.Invoke(ctx, MFAService_CompleteBrowserMFAChallenge_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MFAServiceServer is the server API for MFAService service. +// All implementations must embed UnimplementedMFAServiceServer +// for forward compatibility. +// +// MFAService defines the Multi-Factor Authentication (MFA) service. While this service is currently focused on user +// sessions, new MFA related RPCs should be added here instead of the AuthService, to maintain a clear separation of +// concerns instead of further bloating the AuthService. +type MFAServiceServer interface { + // CreateSessionChallenge creates an MFA challenge that is tied to a user session. + CreateSessionChallenge(context.Context, *CreateSessionChallengeRequest) (*CreateSessionChallengeResponse, error) + // ValidateSessionChallenge validates the MFA challenge response for a user session and stores the validated response + // in the backend. + ValidateSessionChallenge(context.Context, *ValidateSessionChallengeRequest) (*ValidateSessionChallengeResponse, error) + // ListValidatedMFAChallenges lists validated MFA challenges that have been created for all user sessions. This is + // intended to be used by the reverse tunnel server to watch for new validated challenges that need to be replicated + // for SSH session establishment in leaf clusters. + ListValidatedMFAChallenges(context.Context, *ListValidatedMFAChallengesRequest) (*ListValidatedMFAChallengesResponse, error) + // ReplicateValidatedMFAChallenge replicates a validated MFA challenge from root cluster to leaf cluster for + // verification during SSH session establishment. The reverse tunnel server watches for validated challenges in the + // root cluster and invokes this RPC on the leaf cluster. This is a NOOP when invoked in the root cluster. + ReplicateValidatedMFAChallenge(context.Context, *ReplicateValidatedMFAChallengeRequest) (*ReplicateValidatedMFAChallengeResponse, error) + // VerifyValidatedMFAChallenge verifies a previously validated MFA challenge response for a user session. If the + // challenge does not yet exist, this method will block until the resource appears or until the timeout is reached. + // The payload is used to verify the challenge is tied to the correct user session. If the verification fails, an + // error is returned. + VerifyValidatedMFAChallenge(context.Context, *VerifyValidatedMFAChallengeRequest) (*VerifyValidatedMFAChallengeResponse, error) + // CompleteBrowserMFAChallenge completes a browser MFA challenge request by encrypting + // it and returning it to the browser. + // This is called when a user has been sent to the browser to solve an MFA challenge + // that was triggered by tsh or tctl. When the user solves the MFA challenge, the + // response is sent to this RPC. CompleteBrowserMFAChallenge receives the MFA + // response, encrypts it, appends it to tsh/tctl's callback URL and returns it to the browser. + // More info: https://github.com/gravitational/teleport/blob/master/rfd/0233-tsh-browser-mfa.md + CompleteBrowserMFAChallenge(context.Context, *CompleteBrowserMFAChallengeRequest) (*CompleteBrowserMFAChallengeResponse, error) + mustEmbedUnimplementedMFAServiceServer() +} + +// UnimplementedMFAServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedMFAServiceServer struct{} + +func (UnimplementedMFAServiceServer) CreateSessionChallenge(context.Context, *CreateSessionChallengeRequest) (*CreateSessionChallengeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateSessionChallenge not implemented") +} +func (UnimplementedMFAServiceServer) ValidateSessionChallenge(context.Context, *ValidateSessionChallengeRequest) (*ValidateSessionChallengeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidateSessionChallenge not implemented") +} +func (UnimplementedMFAServiceServer) ListValidatedMFAChallenges(context.Context, *ListValidatedMFAChallengesRequest) (*ListValidatedMFAChallengesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListValidatedMFAChallenges not implemented") +} +func (UnimplementedMFAServiceServer) ReplicateValidatedMFAChallenge(context.Context, *ReplicateValidatedMFAChallengeRequest) (*ReplicateValidatedMFAChallengeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReplicateValidatedMFAChallenge not implemented") +} +func (UnimplementedMFAServiceServer) VerifyValidatedMFAChallenge(context.Context, *VerifyValidatedMFAChallengeRequest) (*VerifyValidatedMFAChallengeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyValidatedMFAChallenge not implemented") +} +func (UnimplementedMFAServiceServer) CompleteBrowserMFAChallenge(context.Context, *CompleteBrowserMFAChallengeRequest) (*CompleteBrowserMFAChallengeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CompleteBrowserMFAChallenge not implemented") +} +func (UnimplementedMFAServiceServer) mustEmbedUnimplementedMFAServiceServer() {} +func (UnimplementedMFAServiceServer) testEmbeddedByValue() {} + +// UnsafeMFAServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to MFAServiceServer will +// result in compilation errors. +type UnsafeMFAServiceServer interface { + mustEmbedUnimplementedMFAServiceServer() +} + +func RegisterMFAServiceServer(s grpc.ServiceRegistrar, srv MFAServiceServer) { + // If the following call pancis, it indicates UnimplementedMFAServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&MFAService_ServiceDesc, srv) +} + +func _MFAService_CreateSessionChallenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSessionChallengeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).CreateSessionChallenge(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_CreateSessionChallenge_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).CreateSessionChallenge(ctx, req.(*CreateSessionChallengeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MFAService_ValidateSessionChallenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateSessionChallengeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).ValidateSessionChallenge(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_ValidateSessionChallenge_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).ValidateSessionChallenge(ctx, req.(*ValidateSessionChallengeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MFAService_ListValidatedMFAChallenges_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListValidatedMFAChallengesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).ListValidatedMFAChallenges(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_ListValidatedMFAChallenges_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).ListValidatedMFAChallenges(ctx, req.(*ListValidatedMFAChallengesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MFAService_ReplicateValidatedMFAChallenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ReplicateValidatedMFAChallengeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).ReplicateValidatedMFAChallenge(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_ReplicateValidatedMFAChallenge_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).ReplicateValidatedMFAChallenge(ctx, req.(*ReplicateValidatedMFAChallengeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MFAService_VerifyValidatedMFAChallenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VerifyValidatedMFAChallengeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).VerifyValidatedMFAChallenge(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_VerifyValidatedMFAChallenge_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).VerifyValidatedMFAChallenge(ctx, req.(*VerifyValidatedMFAChallengeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _MFAService_CompleteBrowserMFAChallenge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CompleteBrowserMFAChallengeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MFAServiceServer).CompleteBrowserMFAChallenge(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MFAService_CompleteBrowserMFAChallenge_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MFAServiceServer).CompleteBrowserMFAChallenge(ctx, req.(*CompleteBrowserMFAChallengeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// MFAService_ServiceDesc is the grpc.ServiceDesc for MFAService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var MFAService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "teleport.mfa.v2.MFAService", + HandlerType: (*MFAServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateSessionChallenge", + Handler: _MFAService_CreateSessionChallenge_Handler, + }, + { + MethodName: "ValidateSessionChallenge", + Handler: _MFAService_ValidateSessionChallenge_Handler, + }, + { + MethodName: "ListValidatedMFAChallenges", + Handler: _MFAService_ListValidatedMFAChallenges_Handler, + }, + { + MethodName: "ReplicateValidatedMFAChallenge", + Handler: _MFAService_ReplicateValidatedMFAChallenge_Handler, + }, + { + MethodName: "VerifyValidatedMFAChallenge", + Handler: _MFAService_VerifyValidatedMFAChallenge_Handler, + }, + { + MethodName: "CompleteBrowserMFAChallenge", + Handler: _MFAService_CompleteBrowserMFAChallenge_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "teleport/mfa/v2/service.proto", +} diff --git a/api/gen/proto/go/teleport/mfa/v2/validated_challenge.pb.go b/api/gen/proto/go/teleport/mfa/v2/validated_challenge.pb.go new file mode 100644 index 00000000000..1bc38cade0c --- /dev/null +++ b/api/gen/proto/go/teleport/mfa/v2/validated_challenge.pb.go @@ -0,0 +1,490 @@ +// Copyright 2026 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: teleport/mfa/v2/validated_challenge.proto + +package mfav2 + +import ( + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// ValidatedMFAChallenge represents a validated MFA challenge tied to a user session. +type ValidatedMFAChallenge struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Kind string `protobuf:"bytes,1,opt,name=kind,proto3"` + xxx_hidden_SubKind string `protobuf:"bytes,2,opt,name=sub_kind,json=subKind,proto3"` + xxx_hidden_Version string `protobuf:"bytes,3,opt,name=version,proto3"` + xxx_hidden_Metadata *v1.Metadata `protobuf:"bytes,4,opt,name=metadata,proto3"` + xxx_hidden_Spec *ValidatedMFAChallengeSpec `protobuf:"bytes,5,opt,name=spec,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidatedMFAChallenge) Reset() { + *x = ValidatedMFAChallenge{} + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidatedMFAChallenge) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatedMFAChallenge) ProtoMessage() {} + +func (x *ValidatedMFAChallenge) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ValidatedMFAChallenge) GetKind() string { + if x != nil { + return x.xxx_hidden_Kind + } + return "" +} + +func (x *ValidatedMFAChallenge) GetSubKind() string { + if x != nil { + return x.xxx_hidden_SubKind + } + return "" +} + +func (x *ValidatedMFAChallenge) GetVersion() string { + if x != nil { + return x.xxx_hidden_Version + } + return "" +} + +func (x *ValidatedMFAChallenge) GetMetadata() *v1.Metadata { + if x != nil { + return x.xxx_hidden_Metadata + } + return nil +} + +func (x *ValidatedMFAChallenge) GetSpec() *ValidatedMFAChallengeSpec { + if x != nil { + return x.xxx_hidden_Spec + } + return nil +} + +func (x *ValidatedMFAChallenge) SetKind(v string) { + x.xxx_hidden_Kind = v +} + +func (x *ValidatedMFAChallenge) SetSubKind(v string) { + x.xxx_hidden_SubKind = v +} + +func (x *ValidatedMFAChallenge) SetVersion(v string) { + x.xxx_hidden_Version = v +} + +func (x *ValidatedMFAChallenge) SetMetadata(v *v1.Metadata) { + x.xxx_hidden_Metadata = v +} + +func (x *ValidatedMFAChallenge) SetSpec(v *ValidatedMFAChallengeSpec) { + x.xxx_hidden_Spec = v +} + +func (x *ValidatedMFAChallenge) HasMetadata() bool { + if x == nil { + return false + } + return x.xxx_hidden_Metadata != nil +} + +func (x *ValidatedMFAChallenge) HasSpec() bool { + if x == nil { + return false + } + return x.xxx_hidden_Spec != nil +} + +func (x *ValidatedMFAChallenge) ClearMetadata() { + x.xxx_hidden_Metadata = nil +} + +func (x *ValidatedMFAChallenge) ClearSpec() { + x.xxx_hidden_Spec = nil +} + +type ValidatedMFAChallenge_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Resource kind, always 'validated_mfa_challenge'. + Kind string + // No sub-kinds are currently defined and can be empty. Reserved for future use. + SubKind string + // Currently only 'v1' is supported. + Version string + // Common metadata for the resource. + Metadata *v1.Metadata + // Validated challenge specification. + Spec *ValidatedMFAChallengeSpec +} + +func (b0 ValidatedMFAChallenge_builder) Build() *ValidatedMFAChallenge { + m0 := &ValidatedMFAChallenge{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Kind = b.Kind + x.xxx_hidden_SubKind = b.SubKind + x.xxx_hidden_Version = b.Version + x.xxx_hidden_Metadata = b.Metadata + x.xxx_hidden_Spec = b.Spec + return m0 +} + +// ValidatedMFAChallengeSpec contains the validated challenge data that is set once during creation and never modified. +type ValidatedMFAChallengeSpec struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Payload *SessionIdentifyingPayload `protobuf:"bytes,1,opt,name=payload,proto3"` + xxx_hidden_SourceCluster string `protobuf:"bytes,2,opt,name=source_cluster,json=sourceCluster,proto3"` + xxx_hidden_TargetCluster string `protobuf:"bytes,3,opt,name=target_cluster,json=targetCluster,proto3"` + xxx_hidden_Username string `protobuf:"bytes,4,opt,name=username,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidatedMFAChallengeSpec) Reset() { + *x = ValidatedMFAChallengeSpec{} + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidatedMFAChallengeSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidatedMFAChallengeSpec) ProtoMessage() {} + +func (x *ValidatedMFAChallengeSpec) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *ValidatedMFAChallengeSpec) GetPayload() *SessionIdentifyingPayload { + if x != nil { + return x.xxx_hidden_Payload + } + return nil +} + +func (x *ValidatedMFAChallengeSpec) GetSourceCluster() string { + if x != nil { + return x.xxx_hidden_SourceCluster + } + return "" +} + +func (x *ValidatedMFAChallengeSpec) GetTargetCluster() string { + if x != nil { + return x.xxx_hidden_TargetCluster + } + return "" +} + +func (x *ValidatedMFAChallengeSpec) GetUsername() string { + if x != nil { + return x.xxx_hidden_Username + } + return "" +} + +func (x *ValidatedMFAChallengeSpec) SetPayload(v *SessionIdentifyingPayload) { + x.xxx_hidden_Payload = v +} + +func (x *ValidatedMFAChallengeSpec) SetSourceCluster(v string) { + x.xxx_hidden_SourceCluster = v +} + +func (x *ValidatedMFAChallengeSpec) SetTargetCluster(v string) { + x.xxx_hidden_TargetCluster = v +} + +func (x *ValidatedMFAChallengeSpec) SetUsername(v string) { + x.xxx_hidden_Username = v +} + +func (x *ValidatedMFAChallengeSpec) HasPayload() bool { + if x == nil { + return false + } + return x.xxx_hidden_Payload != nil +} + +func (x *ValidatedMFAChallengeSpec) ClearPayload() { + x.xxx_hidden_Payload = nil +} + +type ValidatedMFAChallengeSpec_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Value that uniquely identifies the user's session. Supplied in CreateSessionChallengeRequest. + Payload *SessionIdentifyingPayload + // Name of the cluster where the validated challenge originated. + SourceCluster string + // Name of the cluster where the SSH session is being established and this resource is intended for. + TargetCluster string + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified to source_cluster. + Username string +} + +func (b0 ValidatedMFAChallengeSpec_builder) Build() *ValidatedMFAChallengeSpec { + m0 := &ValidatedMFAChallengeSpec{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Payload = b.Payload + x.xxx_hidden_SourceCluster = b.SourceCluster + x.xxx_hidden_TargetCluster = b.TargetCluster + x.xxx_hidden_Username = b.Username + return m0 +} + +// SessionIdentifyingPayload contains a value that uniquely identifies a user's session. It must be computed by the +// client from session state and is used to bind MFA challenges to specific sessions. +type SessionIdentifyingPayload struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Payload isSessionIdentifyingPayload_Payload `protobuf_oneof:"payload"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SessionIdentifyingPayload) Reset() { + *x = SessionIdentifyingPayload{} + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionIdentifyingPayload) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionIdentifyingPayload) ProtoMessage() {} + +func (x *SessionIdentifyingPayload) ProtoReflect() protoreflect.Message { + mi := &file_teleport_mfa_v2_validated_challenge_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *SessionIdentifyingPayload) GetSshSessionId() []byte { + if x != nil { + if x, ok := x.xxx_hidden_Payload.(*sessionIdentifyingPayload_SshSessionId); ok { + return x.SshSessionId + } + } + return nil +} + +func (x *SessionIdentifyingPayload) SetSshSessionId(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_Payload = &sessionIdentifyingPayload_SshSessionId{v} +} + +func (x *SessionIdentifyingPayload) HasPayload() bool { + if x == nil { + return false + } + return x.xxx_hidden_Payload != nil +} + +func (x *SessionIdentifyingPayload) HasSshSessionId() bool { + if x == nil { + return false + } + _, ok := x.xxx_hidden_Payload.(*sessionIdentifyingPayload_SshSessionId) + return ok +} + +func (x *SessionIdentifyingPayload) ClearPayload() { + x.xxx_hidden_Payload = nil +} + +func (x *SessionIdentifyingPayload) ClearSshSessionId() { + if _, ok := x.xxx_hidden_Payload.(*sessionIdentifyingPayload_SshSessionId); ok { + x.xxx_hidden_Payload = nil + } +} + +const SessionIdentifyingPayload_Payload_not_set_case case_SessionIdentifyingPayload_Payload = 0 +const SessionIdentifyingPayload_SshSessionId_case case_SessionIdentifyingPayload_Payload = 1 + +func (x *SessionIdentifyingPayload) WhichPayload() case_SessionIdentifyingPayload_Payload { + if x == nil { + return SessionIdentifyingPayload_Payload_not_set_case + } + switch x.xxx_hidden_Payload.(type) { + case *sessionIdentifyingPayload_SshSessionId: + return SessionIdentifyingPayload_SshSessionId_case + default: + return SessionIdentifyingPayload_Payload_not_set_case + } +} + +type SessionIdentifyingPayload_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Fields of oneof xxx_hidden_Payload: + // SSH session hash computed from session state. For example, in Go this is the value from + // crypto/ssh#ConnMetadata.SessionID(). + SshSessionId []byte + // -- end of xxx_hidden_Payload +} + +func (b0 SessionIdentifyingPayload_builder) Build() *SessionIdentifyingPayload { + m0 := &SessionIdentifyingPayload{} + b, x := &b0, m0 + _, _ = b, x + if b.SshSessionId != nil { + x.xxx_hidden_Payload = &sessionIdentifyingPayload_SshSessionId{b.SshSessionId} + } + return m0 +} + +type case_SessionIdentifyingPayload_Payload protoreflect.FieldNumber + +func (x case_SessionIdentifyingPayload_Payload) String() string { + md := file_teleport_mfa_v2_validated_challenge_proto_msgTypes[2].Descriptor() + if x == 0 { + return "not set" + } + return protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x)) +} + +type isSessionIdentifyingPayload_Payload interface { + isSessionIdentifyingPayload_Payload() +} + +type sessionIdentifyingPayload_SshSessionId struct { + // SSH session hash computed from session state. For example, in Go this is the value from + // crypto/ssh#ConnMetadata.SessionID(). + SshSessionId []byte `protobuf:"bytes,1,opt,name=ssh_session_id,json=sshSessionId,proto3,oneof"` +} + +func (*sessionIdentifyingPayload_SshSessionId) isSessionIdentifyingPayload_Payload() {} + +var File_teleport_mfa_v2_validated_challenge_proto protoreflect.FileDescriptor + +const file_teleport_mfa_v2_validated_challenge_proto_rawDesc = "" + + "\n" + + ")teleport/mfa/v2/validated_challenge.proto\x12\x0fteleport.mfa.v2\x1a!teleport/header/v1/metadata.proto\"\xda\x01\n" + + "\x15ValidatedMFAChallenge\x12\x12\n" + + "\x04kind\x18\x01 \x01(\tR\x04kind\x12\x19\n" + + "\bsub_kind\x18\x02 \x01(\tR\asubKind\x12\x18\n" + + "\aversion\x18\x03 \x01(\tR\aversion\x128\n" + + "\bmetadata\x18\x04 \x01(\v2\x1c.teleport.header.v1.MetadataR\bmetadata\x12>\n" + + "\x04spec\x18\x05 \x01(\v2*.teleport.mfa.v2.ValidatedMFAChallengeSpecR\x04spec\"\xcb\x01\n" + + "\x19ValidatedMFAChallengeSpec\x12D\n" + + "\apayload\x18\x01 \x01(\v2*.teleport.mfa.v2.SessionIdentifyingPayloadR\apayload\x12%\n" + + "\x0esource_cluster\x18\x02 \x01(\tR\rsourceCluster\x12%\n" + + "\x0etarget_cluster\x18\x03 \x01(\tR\rtargetCluster\x12\x1a\n" + + "\busername\x18\x04 \x01(\tR\busername\"N\n" + + "\x19SessionIdentifyingPayload\x12&\n" + + "\x0essh_session_id\x18\x01 \x01(\fH\x00R\fsshSessionIdB\t\n" + + "\apayloadBJZHgithub.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2b\x06proto3" + +var file_teleport_mfa_v2_validated_challenge_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_teleport_mfa_v2_validated_challenge_proto_goTypes = []any{ + (*ValidatedMFAChallenge)(nil), // 0: teleport.mfa.v2.ValidatedMFAChallenge + (*ValidatedMFAChallengeSpec)(nil), // 1: teleport.mfa.v2.ValidatedMFAChallengeSpec + (*SessionIdentifyingPayload)(nil), // 2: teleport.mfa.v2.SessionIdentifyingPayload + (*v1.Metadata)(nil), // 3: teleport.header.v1.Metadata +} +var file_teleport_mfa_v2_validated_challenge_proto_depIdxs = []int32{ + 3, // 0: teleport.mfa.v2.ValidatedMFAChallenge.metadata:type_name -> teleport.header.v1.Metadata + 1, // 1: teleport.mfa.v2.ValidatedMFAChallenge.spec:type_name -> teleport.mfa.v2.ValidatedMFAChallengeSpec + 2, // 2: teleport.mfa.v2.ValidatedMFAChallengeSpec.payload:type_name -> teleport.mfa.v2.SessionIdentifyingPayload + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_teleport_mfa_v2_validated_challenge_proto_init() } +func file_teleport_mfa_v2_validated_challenge_proto_init() { + if File_teleport_mfa_v2_validated_challenge_proto != nil { + return + } + file_teleport_mfa_v2_validated_challenge_proto_msgTypes[2].OneofWrappers = []any{ + (*sessionIdentifyingPayload_SshSessionId)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_mfa_v2_validated_challenge_proto_rawDesc), len(file_teleport_mfa_v2_validated_challenge_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_mfa_v2_validated_challenge_proto_goTypes, + DependencyIndexes: file_teleport_mfa_v2_validated_challenge_proto_depIdxs, + MessageInfos: file_teleport_mfa_v2_validated_challenge_proto_msgTypes, + }.Build() + File_teleport_mfa_v2_validated_challenge_proto = out.File + file_teleport_mfa_v2_validated_challenge_proto_goTypes = nil + file_teleport_mfa_v2_validated_challenge_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/webauthn/v2/webauthn.pb.go b/api/gen/proto/go/teleport/webauthn/v2/webauthn.pb.go new file mode 100644 index 00000000000..c9fad52c569 --- /dev/null +++ b/api/gen/proto/go/teleport/webauthn/v2/webauthn.pb.go @@ -0,0 +1,908 @@ +// Copyright 2026 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc (unknown) +// source: teleport/webauthn/v2/webauthn.proto + +package webauthnv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Credential assertion used for login ceremonies. +type CredentialAssertion struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_PublicKey *PublicKeyCredentialRequestOptions `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CredentialAssertion) Reset() { + *x = CredentialAssertion{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CredentialAssertion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CredentialAssertion) ProtoMessage() {} + +func (x *CredentialAssertion) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CredentialAssertion) GetPublicKey() *PublicKeyCredentialRequestOptions { + if x != nil { + return x.xxx_hidden_PublicKey + } + return nil +} + +func (x *CredentialAssertion) SetPublicKey(v *PublicKeyCredentialRequestOptions) { + x.xxx_hidden_PublicKey = v +} + +func (x *CredentialAssertion) HasPublicKey() bool { + if x == nil { + return false + } + return x.xxx_hidden_PublicKey != nil +} + +func (x *CredentialAssertion) ClearPublicKey() { + x.xxx_hidden_PublicKey = nil +} + +type CredentialAssertion_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + PublicKey *PublicKeyCredentialRequestOptions +} + +func (b0 CredentialAssertion_builder) Build() *CredentialAssertion { + m0 := &CredentialAssertion{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_PublicKey = b.PublicKey + return m0 +} + +// Request options necessary for credential assertions, aka login ceremonies. +// See https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options or +// refer to navigator.credentials.get in your browser. +type PublicKeyCredentialRequestOptions struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Challenge []byte `protobuf:"bytes,1,opt,name=challenge,proto3"` + xxx_hidden_TimeoutMs int64 `protobuf:"varint,2,opt,name=timeout_ms,json=timeoutMs,proto3"` + xxx_hidden_RpId string `protobuf:"bytes,3,opt,name=rp_id,json=rpId,proto3"` + xxx_hidden_AllowCredentials *[]*CredentialDescriptor `protobuf:"bytes,4,rep,name=allow_credentials,json=allowCredentials,proto3"` + xxx_hidden_Extensions *AuthenticationExtensionsClientInputs `protobuf:"bytes,5,opt,name=extensions,proto3"` + xxx_hidden_UserVerification string `protobuf:"bytes,6,opt,name=user_verification,json=userVerification,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PublicKeyCredentialRequestOptions) Reset() { + *x = PublicKeyCredentialRequestOptions{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PublicKeyCredentialRequestOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PublicKeyCredentialRequestOptions) ProtoMessage() {} + +func (x *PublicKeyCredentialRequestOptions) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *PublicKeyCredentialRequestOptions) GetChallenge() []byte { + if x != nil { + return x.xxx_hidden_Challenge + } + return nil +} + +func (x *PublicKeyCredentialRequestOptions) GetTimeoutMs() int64 { + if x != nil { + return x.xxx_hidden_TimeoutMs + } + return 0 +} + +func (x *PublicKeyCredentialRequestOptions) GetRpId() string { + if x != nil { + return x.xxx_hidden_RpId + } + return "" +} + +func (x *PublicKeyCredentialRequestOptions) GetAllowCredentials() []*CredentialDescriptor { + if x != nil { + if x.xxx_hidden_AllowCredentials != nil { + return *x.xxx_hidden_AllowCredentials + } + } + return nil +} + +func (x *PublicKeyCredentialRequestOptions) GetExtensions() *AuthenticationExtensionsClientInputs { + if x != nil { + return x.xxx_hidden_Extensions + } + return nil +} + +func (x *PublicKeyCredentialRequestOptions) GetUserVerification() string { + if x != nil { + return x.xxx_hidden_UserVerification + } + return "" +} + +func (x *PublicKeyCredentialRequestOptions) SetChallenge(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_Challenge = v +} + +func (x *PublicKeyCredentialRequestOptions) SetTimeoutMs(v int64) { + x.xxx_hidden_TimeoutMs = v +} + +func (x *PublicKeyCredentialRequestOptions) SetRpId(v string) { + x.xxx_hidden_RpId = v +} + +func (x *PublicKeyCredentialRequestOptions) SetAllowCredentials(v []*CredentialDescriptor) { + x.xxx_hidden_AllowCredentials = &v +} + +func (x *PublicKeyCredentialRequestOptions) SetExtensions(v *AuthenticationExtensionsClientInputs) { + x.xxx_hidden_Extensions = v +} + +func (x *PublicKeyCredentialRequestOptions) SetUserVerification(v string) { + x.xxx_hidden_UserVerification = v +} + +func (x *PublicKeyCredentialRequestOptions) HasExtensions() bool { + if x == nil { + return false + } + return x.xxx_hidden_Extensions != nil +} + +func (x *PublicKeyCredentialRequestOptions) ClearExtensions() { + x.xxx_hidden_Extensions = nil +} + +type PublicKeyCredentialRequestOptions_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Raw challenge used for assertion. + Challenge []byte + // Timeout in milliseconds. + TimeoutMs int64 + // Relying Party ID. + RpId string + // Allowed credentials for assertion. + AllowCredentials []*CredentialDescriptor + // Extensions supplied by the Relying Party. + Extensions *AuthenticationExtensionsClientInputs + // User verification requirement. + UserVerification string +} + +func (b0 PublicKeyCredentialRequestOptions_builder) Build() *PublicKeyCredentialRequestOptions { + m0 := &PublicKeyCredentialRequestOptions{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Challenge = b.Challenge + x.xxx_hidden_TimeoutMs = b.TimeoutMs + x.xxx_hidden_RpId = b.RpId + x.xxx_hidden_AllowCredentials = &b.AllowCredentials + x.xxx_hidden_Extensions = b.Extensions + x.xxx_hidden_UserVerification = b.UserVerification + return m0 +} + +// Assertion response returned by the authenticator. +// Refer to navigator.credentials.get in your browser. +type CredentialAssertionResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Type string `protobuf:"bytes,1,opt,name=type,proto3"` + xxx_hidden_RawId []byte `protobuf:"bytes,2,opt,name=raw_id,json=rawId,proto3"` + xxx_hidden_Response *AuthenticatorAssertionResponse `protobuf:"bytes,3,opt,name=response,proto3"` + xxx_hidden_Extensions *AuthenticationExtensionsClientOutputs `protobuf:"bytes,4,opt,name=extensions,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CredentialAssertionResponse) Reset() { + *x = CredentialAssertionResponse{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CredentialAssertionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CredentialAssertionResponse) ProtoMessage() {} + +func (x *CredentialAssertionResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CredentialAssertionResponse) GetType() string { + if x != nil { + return x.xxx_hidden_Type + } + return "" +} + +func (x *CredentialAssertionResponse) GetRawId() []byte { + if x != nil { + return x.xxx_hidden_RawId + } + return nil +} + +func (x *CredentialAssertionResponse) GetResponse() *AuthenticatorAssertionResponse { + if x != nil { + return x.xxx_hidden_Response + } + return nil +} + +func (x *CredentialAssertionResponse) GetExtensions() *AuthenticationExtensionsClientOutputs { + if x != nil { + return x.xxx_hidden_Extensions + } + return nil +} + +func (x *CredentialAssertionResponse) SetType(v string) { + x.xxx_hidden_Type = v +} + +func (x *CredentialAssertionResponse) SetRawId(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_RawId = v +} + +func (x *CredentialAssertionResponse) SetResponse(v *AuthenticatorAssertionResponse) { + x.xxx_hidden_Response = v +} + +func (x *CredentialAssertionResponse) SetExtensions(v *AuthenticationExtensionsClientOutputs) { + x.xxx_hidden_Extensions = v +} + +func (x *CredentialAssertionResponse) HasResponse() bool { + if x == nil { + return false + } + return x.xxx_hidden_Response != nil +} + +func (x *CredentialAssertionResponse) HasExtensions() bool { + if x == nil { + return false + } + return x.xxx_hidden_Extensions != nil +} + +func (x *CredentialAssertionResponse) ClearResponse() { + x.xxx_hidden_Response = nil +} + +func (x *CredentialAssertionResponse) ClearExtensions() { + x.xxx_hidden_Extensions = nil +} + +type CredentialAssertionResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Type of the credential, usually "public-key". + Type string + // Raw Credential ID. + RawId []byte + // Assertion response from the authenticator. + Response *AuthenticatorAssertionResponse + // Extensions supplied by the authenticator. + Extensions *AuthenticationExtensionsClientOutputs +} + +func (b0 CredentialAssertionResponse_builder) Build() *CredentialAssertionResponse { + m0 := &CredentialAssertionResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Type = b.Type + x.xxx_hidden_RawId = b.RawId + x.xxx_hidden_Response = b.Response + x.xxx_hidden_Extensions = b.Extensions + return m0 +} + +// Authenticator assertion response. +// https://www.w3.org/TR/webauthn-2/#authenticatorassertionresponse +type AuthenticatorAssertionResponse struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_ClientDataJson []byte `protobuf:"bytes,1,opt,name=client_data_json,json=clientDataJson,proto3"` + xxx_hidden_AuthenticatorData []byte `protobuf:"bytes,2,opt,name=authenticator_data,json=authenticatorData,proto3"` + xxx_hidden_Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3"` + xxx_hidden_UserHandle []byte `protobuf:"bytes,4,opt,name=user_handle,json=userHandle,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthenticatorAssertionResponse) Reset() { + *x = AuthenticatorAssertionResponse{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthenticatorAssertionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthenticatorAssertionResponse) ProtoMessage() {} + +func (x *AuthenticatorAssertionResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *AuthenticatorAssertionResponse) GetClientDataJson() []byte { + if x != nil { + return x.xxx_hidden_ClientDataJson + } + return nil +} + +func (x *AuthenticatorAssertionResponse) GetAuthenticatorData() []byte { + if x != nil { + return x.xxx_hidden_AuthenticatorData + } + return nil +} + +func (x *AuthenticatorAssertionResponse) GetSignature() []byte { + if x != nil { + return x.xxx_hidden_Signature + } + return nil +} + +func (x *AuthenticatorAssertionResponse) GetUserHandle() []byte { + if x != nil { + return x.xxx_hidden_UserHandle + } + return nil +} + +func (x *AuthenticatorAssertionResponse) SetClientDataJson(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_ClientDataJson = v +} + +func (x *AuthenticatorAssertionResponse) SetAuthenticatorData(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_AuthenticatorData = v +} + +func (x *AuthenticatorAssertionResponse) SetSignature(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_Signature = v +} + +func (x *AuthenticatorAssertionResponse) SetUserHandle(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_UserHandle = v +} + +type AuthenticatorAssertionResponse_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Raw client data JSON, exactly as signed by the authenticator. + // https://www.w3.org/TR/webauthn-2/#dictdef-collectedclientdata. + ClientDataJson []byte + // Raw authenticator data, exactly as signed by the authenticator. + // https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data. + AuthenticatorData []byte + // Raw assertion signature performed authenticatorData|clientDataJSON. + // https://www.w3.org/TR/webauthn-2/#assertion-signature. + Signature []byte + // Raw user handle returned by the authenticator, if any. + UserHandle []byte +} + +func (b0 AuthenticatorAssertionResponse_builder) Build() *AuthenticatorAssertionResponse { + m0 := &AuthenticatorAssertionResponse{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_ClientDataJson = b.ClientDataJson + x.xxx_hidden_AuthenticatorData = b.AuthenticatorData + x.xxx_hidden_Signature = b.Signature + x.xxx_hidden_UserHandle = b.UserHandle + return m0 +} + +// Extensions supplied by the Relying Party during credential assertion or +// creation. +// https://www.w3.org/TR/webauthn-2/#client-extension-input +type AuthenticationExtensionsClientInputs struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3"` + xxx_hidden_CredProps bool `protobuf:"varint,2,opt,name=cred_props,json=credProps,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthenticationExtensionsClientInputs) Reset() { + *x = AuthenticationExtensionsClientInputs{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthenticationExtensionsClientInputs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthenticationExtensionsClientInputs) ProtoMessage() {} + +func (x *AuthenticationExtensionsClientInputs) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *AuthenticationExtensionsClientInputs) GetAppId() string { + if x != nil { + return x.xxx_hidden_AppId + } + return "" +} + +func (x *AuthenticationExtensionsClientInputs) GetCredProps() bool { + if x != nil { + return x.xxx_hidden_CredProps + } + return false +} + +func (x *AuthenticationExtensionsClientInputs) SetAppId(v string) { + x.xxx_hidden_AppId = v +} + +func (x *AuthenticationExtensionsClientInputs) SetCredProps(v bool) { + x.xxx_hidden_CredProps = v +} + +type AuthenticationExtensionsClientInputs_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // U2F application ID to be used by the authenticator, if any. + // Only available if using U2F compatibility mode. + // https://www.w3.org/TR/webauthn-2/#sctn-appid-extension. + AppId string + // Enables the credProps extension. + // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension + CredProps bool +} + +func (b0 AuthenticationExtensionsClientInputs_builder) Build() *AuthenticationExtensionsClientInputs { + m0 := &AuthenticationExtensionsClientInputs{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_AppId = b.AppId + x.xxx_hidden_CredProps = b.CredProps + return m0 +} + +// Extensions supplied by the authenticator to the Relying Party, during +// credential assertion or creation. +// https://www.w3.org/TR/webauthn-2/#client-extension-output. +type AuthenticationExtensionsClientOutputs struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_AppId bool `protobuf:"varint,1,opt,name=app_id,json=appId,proto3"` + xxx_hidden_CredProps *CredentialPropertiesOutput `protobuf:"bytes,2,opt,name=cred_props,json=credProps,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AuthenticationExtensionsClientOutputs) Reset() { + *x = AuthenticationExtensionsClientOutputs{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AuthenticationExtensionsClientOutputs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthenticationExtensionsClientOutputs) ProtoMessage() {} + +func (x *AuthenticationExtensionsClientOutputs) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *AuthenticationExtensionsClientOutputs) GetAppId() bool { + if x != nil { + return x.xxx_hidden_AppId + } + return false +} + +func (x *AuthenticationExtensionsClientOutputs) GetCredProps() *CredentialPropertiesOutput { + if x != nil { + return x.xxx_hidden_CredProps + } + return nil +} + +func (x *AuthenticationExtensionsClientOutputs) SetAppId(v bool) { + x.xxx_hidden_AppId = v +} + +func (x *AuthenticationExtensionsClientOutputs) SetCredProps(v *CredentialPropertiesOutput) { + x.xxx_hidden_CredProps = v +} + +func (x *AuthenticationExtensionsClientOutputs) HasCredProps() bool { + if x == nil { + return false + } + return x.xxx_hidden_CredProps != nil +} + +func (x *AuthenticationExtensionsClientOutputs) ClearCredProps() { + x.xxx_hidden_CredProps = nil +} + +type AuthenticationExtensionsClientOutputs_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // If true, the AppID extension was used by the authenticator, which changes + // the rpIdHash accordingly. + // https://www.w3.org/TR/webauthn-2/#sctn-appid-extension. + AppId bool + // Credential properties per credProps extension. + // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension. + CredProps *CredentialPropertiesOutput +} + +func (b0 AuthenticationExtensionsClientOutputs_builder) Build() *AuthenticationExtensionsClientOutputs { + m0 := &AuthenticationExtensionsClientOutputs{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_AppId = b.AppId + x.xxx_hidden_CredProps = b.CredProps + return m0 +} + +// CredentialPropertiesOutput is the output of the credProps extension. +type CredentialPropertiesOutput struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Rk bool `protobuf:"varint,1,opt,name=rk,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CredentialPropertiesOutput) Reset() { + *x = CredentialPropertiesOutput{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CredentialPropertiesOutput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CredentialPropertiesOutput) ProtoMessage() {} + +func (x *CredentialPropertiesOutput) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CredentialPropertiesOutput) GetRk() bool { + if x != nil { + return x.xxx_hidden_Rk + } + return false +} + +func (x *CredentialPropertiesOutput) SetRk(v bool) { + x.xxx_hidden_Rk = v +} + +type CredentialPropertiesOutput_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // If true, the created credential is a resident key (regardless of the + // AuthenticatorSelection.require_resident_key value). + // OPTIONAL by specification. + Rk bool +} + +func (b0 CredentialPropertiesOutput_builder) Build() *CredentialPropertiesOutput { + m0 := &CredentialPropertiesOutput{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Rk = b.Rk + return m0 +} + +// Public key credential descriptor. +// https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialdescriptor. +type CredentialDescriptor struct { + state protoimpl.MessageState `protogen:"opaque.v1"` + xxx_hidden_Type string `protobuf:"bytes,1,opt,name=type,proto3"` + xxx_hidden_Id []byte `protobuf:"bytes,2,opt,name=id,proto3"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CredentialDescriptor) Reset() { + *x = CredentialDescriptor{} + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CredentialDescriptor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CredentialDescriptor) ProtoMessage() {} + +func (x *CredentialDescriptor) ProtoReflect() protoreflect.Message { + mi := &file_teleport_webauthn_v2_webauthn_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +func (x *CredentialDescriptor) GetType() string { + if x != nil { + return x.xxx_hidden_Type + } + return "" +} + +func (x *CredentialDescriptor) GetId() []byte { + if x != nil { + return x.xxx_hidden_Id + } + return nil +} + +func (x *CredentialDescriptor) SetType(v string) { + x.xxx_hidden_Type = v +} + +func (x *CredentialDescriptor) SetId(v []byte) { + if v == nil { + v = []byte{} + } + x.xxx_hidden_Id = v +} + +type CredentialDescriptor_builder struct { + _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. + + // Type of the credential, usually "public-key". + Type string + // Raw Credential ID. + Id []byte +} + +func (b0 CredentialDescriptor_builder) Build() *CredentialDescriptor { + m0 := &CredentialDescriptor{} + b, x := &b0, m0 + _, _ = b, x + x.xxx_hidden_Type = b.Type + x.xxx_hidden_Id = b.Id + return m0 +} + +var File_teleport_webauthn_v2_webauthn_proto protoreflect.FileDescriptor + +const file_teleport_webauthn_v2_webauthn_proto_rawDesc = "" + + "\n" + + "#teleport/webauthn/v2/webauthn.proto\x12\x14teleport.webauthn.v2\"m\n" + + "\x13CredentialAssertion\x12V\n" + + "\n" + + "public_key\x18\x01 \x01(\v27.teleport.webauthn.v2.PublicKeyCredentialRequestOptionsR\tpublicKey\"\xd7\x02\n" + + "!PublicKeyCredentialRequestOptions\x12\x1c\n" + + "\tchallenge\x18\x01 \x01(\fR\tchallenge\x12\x1d\n" + + "\n" + + "timeout_ms\x18\x02 \x01(\x03R\ttimeoutMs\x12\x13\n" + + "\x05rp_id\x18\x03 \x01(\tR\x04rpId\x12W\n" + + "\x11allow_credentials\x18\x04 \x03(\v2*.teleport.webauthn.v2.CredentialDescriptorR\x10allowCredentials\x12Z\n" + + "\n" + + "extensions\x18\x05 \x01(\v2:.teleport.webauthn.v2.AuthenticationExtensionsClientInputsR\n" + + "extensions\x12+\n" + + "\x11user_verification\x18\x06 \x01(\tR\x10userVerification\"\xf7\x01\n" + + "\x1bCredentialAssertionResponse\x12\x12\n" + + "\x04type\x18\x01 \x01(\tR\x04type\x12\x15\n" + + "\x06raw_id\x18\x02 \x01(\fR\x05rawId\x12P\n" + + "\bresponse\x18\x03 \x01(\v24.teleport.webauthn.v2.AuthenticatorAssertionResponseR\bresponse\x12[\n" + + "\n" + + "extensions\x18\x04 \x01(\v2;.teleport.webauthn.v2.AuthenticationExtensionsClientOutputsR\n" + + "extensions\"\xb8\x01\n" + + "\x1eAuthenticatorAssertionResponse\x12(\n" + + "\x10client_data_json\x18\x01 \x01(\fR\x0eclientDataJson\x12-\n" + + "\x12authenticator_data\x18\x02 \x01(\fR\x11authenticatorData\x12\x1c\n" + + "\tsignature\x18\x03 \x01(\fR\tsignature\x12\x1f\n" + + "\vuser_handle\x18\x04 \x01(\fR\n" + + "userHandle\"\\\n" + + "$AuthenticationExtensionsClientInputs\x12\x15\n" + + "\x06app_id\x18\x01 \x01(\tR\x05appId\x12\x1d\n" + + "\n" + + "cred_props\x18\x02 \x01(\bR\tcredProps\"\x8f\x01\n" + + "%AuthenticationExtensionsClientOutputs\x12\x15\n" + + "\x06app_id\x18\x01 \x01(\bR\x05appId\x12O\n" + + "\n" + + "cred_props\x18\x02 \x01(\v20.teleport.webauthn.v2.CredentialPropertiesOutputR\tcredProps\",\n" + + "\x1aCredentialPropertiesOutput\x12\x0e\n" + + "\x02rk\x18\x01 \x01(\bR\x02rk\":\n" + + "\x14CredentialDescriptor\x12\x12\n" + + "\x04type\x18\x01 \x01(\tR\x04type\x12\x0e\n" + + "\x02id\x18\x02 \x01(\fR\x02idBTZRgithub.com/gravitational/teleport/api/gen/proto/go/teleport/webauthn/v2;webauthnv2b\x06proto3" + +var file_teleport_webauthn_v2_webauthn_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_teleport_webauthn_v2_webauthn_proto_goTypes = []any{ + (*CredentialAssertion)(nil), // 0: teleport.webauthn.v2.CredentialAssertion + (*PublicKeyCredentialRequestOptions)(nil), // 1: teleport.webauthn.v2.PublicKeyCredentialRequestOptions + (*CredentialAssertionResponse)(nil), // 2: teleport.webauthn.v2.CredentialAssertionResponse + (*AuthenticatorAssertionResponse)(nil), // 3: teleport.webauthn.v2.AuthenticatorAssertionResponse + (*AuthenticationExtensionsClientInputs)(nil), // 4: teleport.webauthn.v2.AuthenticationExtensionsClientInputs + (*AuthenticationExtensionsClientOutputs)(nil), // 5: teleport.webauthn.v2.AuthenticationExtensionsClientOutputs + (*CredentialPropertiesOutput)(nil), // 6: teleport.webauthn.v2.CredentialPropertiesOutput + (*CredentialDescriptor)(nil), // 7: teleport.webauthn.v2.CredentialDescriptor +} +var file_teleport_webauthn_v2_webauthn_proto_depIdxs = []int32{ + 1, // 0: teleport.webauthn.v2.CredentialAssertion.public_key:type_name -> teleport.webauthn.v2.PublicKeyCredentialRequestOptions + 7, // 1: teleport.webauthn.v2.PublicKeyCredentialRequestOptions.allow_credentials:type_name -> teleport.webauthn.v2.CredentialDescriptor + 4, // 2: teleport.webauthn.v2.PublicKeyCredentialRequestOptions.extensions:type_name -> teleport.webauthn.v2.AuthenticationExtensionsClientInputs + 3, // 3: teleport.webauthn.v2.CredentialAssertionResponse.response:type_name -> teleport.webauthn.v2.AuthenticatorAssertionResponse + 5, // 4: teleport.webauthn.v2.CredentialAssertionResponse.extensions:type_name -> teleport.webauthn.v2.AuthenticationExtensionsClientOutputs + 6, // 5: teleport.webauthn.v2.AuthenticationExtensionsClientOutputs.cred_props:type_name -> teleport.webauthn.v2.CredentialPropertiesOutput + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_teleport_webauthn_v2_webauthn_proto_init() } +func file_teleport_webauthn_v2_webauthn_proto_init() { + if File_teleport_webauthn_v2_webauthn_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_webauthn_v2_webauthn_proto_rawDesc), len(file_teleport_webauthn_v2_webauthn_proto_rawDesc)), + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_webauthn_v2_webauthn_proto_goTypes, + DependencyIndexes: file_teleport_webauthn_v2_webauthn_proto_depIdxs, + MessageInfos: file_teleport_webauthn_v2_webauthn_proto_msgTypes, + }.Build() + File_teleport_webauthn_v2_webauthn_proto = out.File + file_teleport_webauthn_v2_webauthn_proto_goTypes = nil + file_teleport_webauthn_v2_webauthn_proto_depIdxs = nil +} diff --git a/api/proto/teleport/legacy/types/webauthn/webauthn.proto b/api/proto/teleport/legacy/types/webauthn/webauthn.proto index 488f57c438f..8404050fad7 100644 --- a/api/proto/teleport/legacy/types/webauthn/webauthn.proto +++ b/api/proto/teleport/legacy/types/webauthn/webauthn.proto @@ -37,6 +37,12 @@ option go_package = "github.com/gravitational/teleport/api/types/webauthn;webaut option (gogoproto.marshaler_all) = true; option (gogoproto.unmarshaler_all) = true; +// A partial, non-gogoproto copy of this package is defined in +// teleport/webauthn/v2/webauthn.proto. Only a subset of this legacy WebAuthn +// package is defined there (namely, assertion messages.) Messages that are +// present in both packages must be kept in sync. Registration messages and any +// other absent WebAuthn messages may be copied over lazily, if necessary. + // ----------------------------------------------------------------------------- // Assertion (aka login). // ----------------------------------------------------------------------------- diff --git a/api/proto/teleport/mfa/v2/challenge.proto b/api/proto/teleport/mfa/v2/challenge.proto new file mode 100644 index 00000000000..e15a3a96fb7 --- /dev/null +++ b/api/proto/teleport/mfa/v2/challenge.proto @@ -0,0 +1,95 @@ +// Copyright 2026 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. + +syntax = "proto3"; + +package teleport.mfa.v2; + +import "teleport/webauthn/v2/webauthn.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2"; + +// AuthenticateChallenge is a challenge for all MFA devices registered for a user. +message AuthenticateChallenge { + // Unique resource name for the issued challenge generated by the server. Should be treated as an opaque identifier + // and used as-is in subsequent API calls. + string name = 1; + // Webauthn credential assertion used for login/authentication ceremonies. Holds a list of allowed credentials (one + // for each U2F or Webauthn device registered by the user). + teleport.webauthn.v2.CredentialAssertion webauthn_challenge = 2; + // SSO MFA challenge. If set, the client can go to the IdP redirect URL to perform an MFA check and obtain an MFA + // token. This token paired with the request id can be used for verification. + SSOChallenge sso_challenge = 3; + // Browser challenge allows a user to MFA in the browser, to get a WebAuthn + // response that is returned to the client to be used for verification. + BrowserMFAChallenge browser_challenge = 4; +} + +// AuthenticateResponse is a response to AuthenticateChallenge using one of the MFA devices registered for a user. +message AuthenticateResponse { + // Unique resource name for the issued challenge generated by the server. Should be treated as an opaque identifier + // and used as-is in subsequent API calls. + string name = 1; + // Response to the challenge using one of the MFA devices. + oneof response { + // Response to a Webauthn challenge. + teleport.webauthn.v2.CredentialAssertionResponse webauthn = 2; + // Response to an SSO challenge. + SSOChallengeResponse sso = 3; + // Response to a browser challenge. + BrowserMFAResponse browser = 4; + } +} + +// SSOChallenge contains SSO auth request details to perform an SSO MFA check. +message SSOChallenge { + // ID of an SSO auth request. + string request_id = 1; + // IdP redirect URL to initiate the SSO MFA flow. + string redirect_url = 2; + // SSO device corresponding to the challenge. + SSOMFADevice device = 3; +} + +// SSOMFADevice contains details of an SSO MFA method. +message SSOMFADevice { + // connector_id is the ID of the SSO connector. + string connector_id = 1; + // connector_type is the type of the SSO connector. + string connector_type = 2; + // display_name is the display name of the SSO connector + string display_name = 3; +} + +// SSOChallengeResponse is a response to an SSOChallenge. +message SSOChallengeResponse { + // ID of an SSO auth request. + string request_id = 1; + // Secret token used to verify the user's SSO MFA session. + string token = 2; +} + +// BrowserMFAChallenge contains browser MFA request details to perform a browser MFA check. +message BrowserMFAChallenge { + // RequestId is the ID of a browser MFA request. + string request_id = 1; +} + +// BrowserMFAResponse is a response to BrowserMFAChallenge. +message BrowserMFAResponse { + // RequestId is the ID of a browser MFA request. + string request_id = 1; + // WebauthnResponse is the WebAuthn credential assertion response from the browser MFA flow. + teleport.webauthn.v2.CredentialAssertionResponse webauthn_response = 2; +} diff --git a/api/proto/teleport/mfa/v2/service.proto b/api/proto/teleport/mfa/v2/service.proto new file mode 100644 index 00000000000..66a5a65a6e5 --- /dev/null +++ b/api/proto/teleport/mfa/v2/service.proto @@ -0,0 +1,176 @@ +// Copyright 2026 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. + +syntax = "proto3"; + +package teleport.mfa.v2; + +import "teleport/mfa/v2/challenge.proto"; +import "teleport/mfa/v2/validated_challenge.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2"; + +// MFAService defines the Multi-Factor Authentication (MFA) service. While this service is currently focused on user +// sessions, new MFA related RPCs should be added here instead of the AuthService, to maintain a clear separation of +// concerns instead of further bloating the AuthService. +service MFAService { + // CreateSessionChallenge creates an MFA challenge that is tied to a user session. + rpc CreateSessionChallenge(CreateSessionChallengeRequest) returns (CreateSessionChallengeResponse); + // ValidateSessionChallenge validates the MFA challenge response for a user session and stores the validated response + // in the backend. + rpc ValidateSessionChallenge(ValidateSessionChallengeRequest) returns (ValidateSessionChallengeResponse); + // ListValidatedMFAChallenges lists validated MFA challenges that have been created for all user sessions. This is + // intended to be used by the reverse tunnel server to watch for new validated challenges that need to be replicated + // for SSH session establishment in leaf clusters. + rpc ListValidatedMFAChallenges(ListValidatedMFAChallengesRequest) returns (ListValidatedMFAChallengesResponse); + // ReplicateValidatedMFAChallenge replicates a validated MFA challenge from root cluster to leaf cluster for + // verification during SSH session establishment. The reverse tunnel server watches for validated challenges in the + // root cluster and invokes this RPC on the leaf cluster. This is a NOOP when invoked in the root cluster. + rpc ReplicateValidatedMFAChallenge(ReplicateValidatedMFAChallengeRequest) returns (ReplicateValidatedMFAChallengeResponse); + // VerifyValidatedMFAChallenge verifies a previously validated MFA challenge response for a user session. If the + // challenge does not yet exist, this method will block until the resource appears or until the timeout is reached. + // The payload is used to verify the challenge is tied to the correct user session. If the verification fails, an + // error is returned. + rpc VerifyValidatedMFAChallenge(VerifyValidatedMFAChallengeRequest) returns (VerifyValidatedMFAChallengeResponse); + // CompleteBrowserMFAChallenge completes a browser MFA challenge request by encrypting + // it and returning it to the browser. + // This is called when a user has been sent to the browser to solve an MFA challenge + // that was triggered by tsh or tctl. When the user solves the MFA challenge, the + // response is sent to this RPC. CompleteBrowserMFAChallenge receives the MFA + // response, encrypts it, appends it to tsh/tctl's callback URL and returns it to the browser. + // More info: https://github.com/gravitational/teleport/blob/master/rfd/0233-tsh-browser-mfa.md + rpc CompleteBrowserMFAChallenge(CompleteBrowserMFAChallengeRequest) returns (CompleteBrowserMFAChallengeResponse); +} + +// CreateSessionChallengeRequest is the request message for CreateSessionChallenge. +message CreateSessionChallengeRequest { + // Value that uniquely identifies the user's session. When VerifyValidatedMFAChallenge is called, the server will + // verify it matches the payload supplied to CreateSessionChallengeRequest. + SessionIdentifyingPayload payload = 1; + // Name of the target cluster where the SSH session is being established. If unset, the server assumes the challenge + // is for the local cluster. Used to determine where the validated challenge should be replicated for leaf clusters. + // Required when the SSH session is being established in a leaf cluster. + string target_cluster = 2; + // Used to construct the IdP redirect URL in SSO MFA challenges. If the client does not support SSO MFA, this field + // may be left unset and no SSO challenge will be included in the response. If set, the server will include SSO + // challenges in the response. + string sso_client_redirect_url = 3; + // Proxy address the user is using to connect to the Proxy. Required for SSO MFA to determine which URL to redirect + // the user to when there are multiple options. + string proxy_address_for_sso = 4; + // Used to construct the redirect URL for browser-based MFA flows. If the client supports browser MFA, this field + // should be set to the URL where the browser should redirect to tsh after completing the MFA challenge. + // Format: http://127.0.0.1:[random_port]/callback?response={encrypted_webauthn_response} + string browser_mfa_tsh_redirect_url = 5; +} + +// CreateSessionChallengeResponse is the response message for CreateSessionChallenge. +message CreateSessionChallengeResponse { + // MFA challenge that the user must respond to. + AuthenticateChallenge mfa_challenge = 1; +} + +// ValidateSessionChallengeRequest is the request message for ValidateSessionChallenge. +message ValidateSessionChallengeRequest { + // MFA challenge response provided by the user. + AuthenticateResponse mfa_response = 1; +} + +// ValidateSessionChallengeResponse is the response message for ValidateSessionChallenge. +message ValidateSessionChallengeResponse {} + +// ListValidatedMFAChallengesFilter is used to filter validated MFA challenges in ListValidatedMFAChallengesRequest. +message ListValidatedMFAChallengesFilter { + // If set, only return validated MFA challenges for the specified target cluster. + optional string target_cluster = 1; +} + +// ListValidatedMFAChallengesRequest is the request message for ListValidatedMFAChallenges. +message ListValidatedMFAChallengesRequest { + // The maximum number of items to return. The server may impose a different page size at its discretion. + int32 page_size = 1; + // The next_page_token value returned from a previous List request, if any. + string page_token = 2; + // Collection of fields to filter challenges by. Challenges must match all filter fields to be included in the + // results. If unset, no filtering is performed and all validated MFA challenges are returned (up to the page size + // limit). + ListValidatedMFAChallengesFilter filter = 3; +} + +// ListValidatedMFAChallengesResponse is the response message for ListValidatedMFAChallenges. +message ListValidatedMFAChallengesResponse { + // List of validated MFA challenges that have been created for user sessions. + repeated ValidatedMFAChallenge validated_challenges = 1; + // Token to retrieve the next page of results, or empty if there are no more results exist. + string next_page_token = 2; +} + +// ReplicateValidatedMFAChallengeRequest is the request message for ReplicateValidatedMFAChallenge. +message ReplicateValidatedMFAChallengeRequest { + // Resource name for the issued challenge. Must match the AuthenticateChallenge.name in order to find the correct + // challenge. + string name = 1; + // Value that uniquely identifies the user's session. Must match the payload in CreateSessionChallengeRequest. + SessionIdentifyingPayload payload = 2; + // Name of the source cluster where the validated challenge originated. Required in order to match the validated + // challenge to the correct session. + string source_cluster = 3; + // Name of the target cluster where the SSH session is being established. Required in order to match the validated + // challenge to the correct session. + string target_cluster = 4; + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified by source_cluster. + string username = 5; +} + +// ReplicateValidatedMFAChallengeResponse is the response message for ReplicateValidatedMFAChallenge. +message ReplicateValidatedMFAChallengeResponse { + // Validated MFA challenge that was replicated. + ValidatedMFAChallenge replicated_challenge = 1; +} + +// VerifyValidatedMFAChallengeRequest is the request message for VerifyValidatedMFAChallenge. +message VerifyValidatedMFAChallengeRequest { + // Resource name for the issued challenge. Must match the AuthenticateChallenge.name in order to find the correct + // challenge. + string name = 1; + // Value that uniquely identifies the user's session. The client MUST independently compute this value from session + // state. The server will verify it matches the payload supplied in CreateSessionChallengeRequest to ensure the + // challenge is tied to the correct session. + SessionIdentifyingPayload payload = 2; + // Name of the cluster where the validated challenge originated. + string source_cluster = 3; + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified by source_cluster. The client MUST determine this + // value by authenticating the Teleport user before calling this method. The server will verify that it matches the + // Teleport user associated with the validated challenge to ensure the challenge is tied to the correct user. + string username = 4; +} + +// VerifyValidatedMFAChallengeResponse is the response message for VerifyValidatedMFAChallenge. +message VerifyValidatedMFAChallengeResponse {} + +// CompleteBrowserMFAChallengeRequest is used to complete an MFA response +// during a browser-based MFA authentication flow. +message CompleteBrowserMFAChallengeRequest { + BrowserMFAResponse browser_mfa_response = 1; +} + +// CompleteBrowserMFAChallengeResponse contains the redirect URL to send +// the user back to after successfully completing browser-based MFA authentication. +message CompleteBrowserMFAChallengeResponse { + // tsh_redirect_url is the callback URL to tsh's local HTTP server with the encrypted WebAuthn response. + // Format: http://127.0.0.1:[random_port]/callback?response={encrypted_webauthn_response} + string tsh_redirect_url = 1; +} diff --git a/api/proto/teleport/mfa/v2/validated_challenge.proto b/api/proto/teleport/mfa/v2/validated_challenge.proto new file mode 100644 index 00000000000..e8e7e6dc802 --- /dev/null +++ b/api/proto/teleport/mfa/v2/validated_challenge.proto @@ -0,0 +1,58 @@ +// Copyright 2026 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. + +syntax = "proto3"; + +package teleport.mfa.v2; + +import "teleport/header/v1/metadata.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v2;mfav2"; + +// ValidatedMFAChallenge represents a validated MFA challenge tied to a user session. +message ValidatedMFAChallenge { + // Resource kind, always 'validated_mfa_challenge'. + string kind = 1; + // No sub-kinds are currently defined and can be empty. Reserved for future use. + string sub_kind = 2; + // Currently only 'v1' is supported. + string version = 3; + // Common metadata for the resource. + teleport.header.v1.Metadata metadata = 4; + // Validated challenge specification. + ValidatedMFAChallengeSpec spec = 5; +} + +// ValidatedMFAChallengeSpec contains the validated challenge data that is set once during creation and never modified. +message ValidatedMFAChallengeSpec { + // Value that uniquely identifies the user's session. Supplied in CreateSessionChallengeRequest. + SessionIdentifyingPayload payload = 1; + // Name of the cluster where the validated challenge originated. + string source_cluster = 2; + // Name of the cluster where the SSH session is being established and this resource is intended for. + string target_cluster = 3; + // Username of the Teleport user for whom the challenge was issued. This should be the Teleport username (not the SSH + // login name) and must correspond to a user in the cluster specified to source_cluster. + string username = 4; +} + +// SessionIdentifyingPayload contains a value that uniquely identifies a user's session. It must be computed by the +// client from session state and is used to bind MFA challenges to specific sessions. +message SessionIdentifyingPayload { + oneof payload { + // SSH session hash computed from session state. For example, in Go this is the value from + // crypto/ssh#ConnMetadata.SessionID(). + bytes ssh_session_id = 1; + } +} diff --git a/api/proto/teleport/webauthn/v2/webauthn.proto b/api/proto/teleport/webauthn/v2/webauthn.proto new file mode 100644 index 00000000000..e7c7e446524 --- /dev/null +++ b/api/proto/teleport/webauthn/v2/webauthn.proto @@ -0,0 +1,138 @@ +// Copyright 2026 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. + +syntax = "proto3"; + +package teleport.webauthn.v2; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/webauthn/v2;webauthnv2"; + +// This package is a partial, non-gogoproto copy of +// teleport/legacy/types/webauthn/webauthn.proto, which uses gogoproto. +// Only a subset of the legacy WebAuthn package is defined here (namely, +// assertion messages.) +// Messages that are present must be kept in sync with the legacy package. +// Registration messages and any other absent WebAuthn messages may be copied +// over lazily, if necessary. + +// ----------------------------------------------------------------------------- +// Assertion (aka login). +// ----------------------------------------------------------------------------- + +// Credential assertion used for login ceremonies. +message CredentialAssertion { + PublicKeyCredentialRequestOptions public_key = 1; +} + +// Request options necessary for credential assertions, aka login ceremonies. +// See https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options or +// refer to navigator.credentials.get in your browser. +message PublicKeyCredentialRequestOptions { + // Raw challenge used for assertion. + bytes challenge = 1; + // Timeout in milliseconds. + int64 timeout_ms = 2; + // Relying Party ID. + string rp_id = 3; + // Allowed credentials for assertion. + repeated CredentialDescriptor allow_credentials = 4; + // Extensions supplied by the Relying Party. + AuthenticationExtensionsClientInputs extensions = 5; + // User verification requirement. + string user_verification = 6; +} + +// Assertion response returned by the authenticator. +// Refer to navigator.credentials.get in your browser. +message CredentialAssertionResponse { + // Note: assertion responses return both "rawId" and "id" (RawURLEncoding of + // "id"), but it seemed pointless to have both here. + + // Type of the credential, usually "public-key". + string type = 1; + // Raw Credential ID. + bytes raw_id = 2; + // Assertion response from the authenticator. + AuthenticatorAssertionResponse response = 3; + // Extensions supplied by the authenticator. + AuthenticationExtensionsClientOutputs extensions = 4; +} + +// Authenticator assertion response. +// https://www.w3.org/TR/webauthn-2/#authenticatorassertionresponse +message AuthenticatorAssertionResponse { + // Raw client data JSON, exactly as signed by the authenticator. + // https://www.w3.org/TR/webauthn-2/#dictdef-collectedclientdata. + bytes client_data_json = 1; + // Raw authenticator data, exactly as signed by the authenticator. + // https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data. + bytes authenticator_data = 2; + // Raw assertion signature performed authenticatorData|clientDataJSON. + // https://www.w3.org/TR/webauthn-2/#assertion-signature. + bytes signature = 3; + // Raw user handle returned by the authenticator, if any. + bytes user_handle = 4; +} + +// ----------------------------------------------------------------------------- +// Common WebAuthn objects. +// ----------------------------------------------------------------------------- + +// Extensions supplied by the Relying Party during credential assertion or +// creation. +// https://www.w3.org/TR/webauthn-2/#client-extension-input +message AuthenticationExtensionsClientInputs { + // U2F application ID to be used by the authenticator, if any. + // Only available if using U2F compatibility mode. + // https://www.w3.org/TR/webauthn-2/#sctn-appid-extension. + string app_id = 1; + + // Enables the credProps extension. + // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension + bool cred_props = 2; +} + +// Extensions supplied by the authenticator to the Relying Party, during +// credential assertion or creation. +// https://www.w3.org/TR/webauthn-2/#client-extension-output. +message AuthenticationExtensionsClientOutputs { + // If true, the AppID extension was used by the authenticator, which changes + // the rpIdHash accordingly. + // https://www.w3.org/TR/webauthn-2/#sctn-appid-extension. + bool app_id = 1; + + // Credential properties per credProps extension. + // https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension. + CredentialPropertiesOutput cred_props = 2; +} + +// CredentialPropertiesOutput is the output of the credProps extension. +message CredentialPropertiesOutput { + // If true, the created credential is a resident key (regardless of the + // AuthenticatorSelection.require_resident_key value). + // OPTIONAL by specification. + bool rk = 1; +} + +// Public key credential descriptor. +// https://www.w3.org/TR/webauthn-2/#dictdef-publickeycredentialdescriptor. +message CredentialDescriptor { + // Type of the credential, usually "public-key". + string type = 1; + // Raw Credential ID. + bytes id = 2; + + // Notes: + // * Transport hints omitted (assume no restrictions). +} diff --git a/buf-go.gen.yaml b/buf-go.gen.yaml index ea11f5915ed..ae6377dbc7a 100644 --- a/buf-go.gen.yaml +++ b/buf-go.gen.yaml @@ -7,7 +7,7 @@ inputs: - api/proto/teleport/attestation/ - api/proto/teleport/componentfeatures/ - api/proto/teleport/legacy/ - - api/proto/teleport/mfa/ + - api/proto/teleport/mfa/v1/ - api/proto/teleport/usageevents/ - proto/teleport/lib/web/terminal/envelope.proto # generated by buf-connect-go.gen.yaml diff --git a/buf-gogo.gen.yaml b/buf-gogo.gen.yaml index e0e8fd85c93..90871ceb5be 100644 --- a/buf-gogo.gen.yaml +++ b/buf-gogo.gen.yaml @@ -6,7 +6,7 @@ inputs: - api/proto/teleport/attestation/ - api/proto/teleport/componentfeatures/ - api/proto/teleport/legacy/ - - api/proto/teleport/mfa/ + - api/proto/teleport/mfa/v1/ - api/proto/teleport/usageevents/ - proto/teleport/lib/web/terminal/envelope.proto exclude_paths: diff --git a/gen/proto/ts/teleport/legacy/types/webauthn/webauthn_pb.ts b/gen/proto/ts/teleport/legacy/types/webauthn/webauthn_pb.ts index 210bd37449c..8c18e715107 100644 --- a/gen/proto/ts/teleport/legacy/types/webauthn/webauthn_pb.ts +++ b/gen/proto/ts/teleport/legacy/types/webauthn/webauthn_pb.ts @@ -27,6 +27,12 @@ import { UnknownFieldHandler } from "@protobuf-ts/runtime"; import type { PartialMessage } from "@protobuf-ts/runtime"; import { reflectionMergePartial } from "@protobuf-ts/runtime"; import { MessageType } from "@protobuf-ts/runtime"; +// A partial, non-gogoproto copy of this package is defined in +// teleport/webauthn/v2/webauthn.proto. Only a subset of this legacy WebAuthn +// package is defined there (namely, assertion messages.) Messages that are +// present in both packages must be kept in sync. Registration messages and any +// other absent WebAuthn messages may be copied over lazily, if necessary. + // ----------------------------------------------------------------------------- // Assertion (aka login). // -----------------------------------------------------------------------------