-
Notifications
You must be signed in to change notification settings - Fork 2.1k
[Browser MFA] Add BrowserMFARequestID to CreateAuthenticateChallenge #63945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1463,6 +1463,11 @@ type Server struct { | |||||||||
| // normally be fetched from the GitHub API. Used for testing. | ||||||||||
| GithubUserAndTeamsOverride func() (*GithubUserResponse, []GithubTeamResponse, error) | ||||||||||
|
|
||||||||||
| // ObserveBrowserMFAChallengeExtensionsForTesting, if set, is called with the resolved | ||||||||||
| // challenge extensions when a BrowserMFARequestID is provided to | ||||||||||
| // CreateAuthenticateChallenge. Used for testing. | ||||||||||
| ObserveBrowserMFAChallengeExtensionsForTesting func(*mfav1.ChallengeExtensions) | ||||||||||
|
|
||||||||||
| // AWSRolesAnywhereCreateSessionOverride overrides the AWS Roles Anywhere Create Session API wrapper with a mocked one. | ||||||||||
| // Used for testing. | ||||||||||
| AWSRolesAnywhereCreateSessionOverride func(ctx context.Context, req createsession.CreateSessionRequest) (*createsession.CreateSessionResponse, error) | ||||||||||
|
|
@@ -4254,6 +4259,35 @@ func (a *Server) CreateAuthenticateChallenge(ctx context.Context, req *proto.Cre | |||||||||
| return nil | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // If a BrowserMFARequestID is provided, look up the request and apply its challenge extensions. | ||||||||||
| if req.BrowserMFARequestID != "" { | ||||||||||
| if req.ChallengeExtensions != nil { | ||||||||||
| return nil, trace.BadParameter("challenge extensions must not be set when a browser MFA request ID is provided") | ||||||||||
| } | ||||||||||
|
|
||||||||||
| browserMFAReq, err := a.GetSSOMFASession(ctx, req.BrowserMFARequestID) | ||||||||||
|
Joerger marked this conversation as resolved.
|
||||||||||
| if err != nil { | ||||||||||
| a.logger.WarnContext(ctx, "Failed to read MFA session for browser MFA request", "error", err) | ||||||||||
| return nil, trace.AccessDenied("invalid browser MFA request") | ||||||||||
|
danielashare marked this conversation as resolved.
|
||||||||||
| } | ||||||||||
|
|
||||||||||
| chalExts := browserMFAReq.ChallengeExtensions | ||||||||||
| if chalExts == nil { | ||||||||||
| a.logger.WarnContext(ctx, "MFA session for browser MFA recorded with empty challenge extensions", "request_id", req.BrowserMFARequestID) | ||||||||||
| return nil, trace.BadParameter("stored session lacks challenge extensions") | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Replace the challenge extensions with the ones found in the SSO MFA object. | ||||||||||
| // These are the ones from the original tsh request. | ||||||||||
| challengeExtensions = mfatypes.ChallengeExtensionsToProto(chalExts) | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we make sure that SSO MFA sessions record all ChallengeExtensions fields as well? It appears we do not record UserVerificationRequirement: Lines 158 to 161 in 6382ef5
OK if you want to follow up separately.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I'll include this in an upstream PR, thanks
danielashare marked this conversation as resolved.
|
||||||||||
|
|
||||||||||
| // Used for testing. If observer function is set, call it with | ||||||||||
| // challenge extensions from SSO MFA session. | ||||||||||
| if a.ObserveBrowserMFAChallengeExtensionsForTesting != nil { | ||||||||||
| a.ObserveBrowserMFAChallengeExtensionsForTesting(challengeExtensions) | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| switch req.GetRequest().(type) { | ||||||||||
| case *proto.CreateAuthenticateChallengeRequest_UserCredentials: | ||||||||||
| username = req.GetUserCredentials().GetUsername() | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // Teleport | ||
| // Copyright (C) 2026 Gravitational, Inc. | ||
| // | ||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU Affero General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // | ||
| // This program is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU Affero General Public License for more details. | ||
| // | ||
| // You should have received a copy of the GNU Affero General Public License | ||
| // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| package mfatypes | ||
|
|
||
| import mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" | ||
|
|
||
| // ChallengeExtensionsToProto converts a ChallengeExtensions to its protobuf representation. | ||
| func ChallengeExtensionsToProto(chalExts *ChallengeExtensions) *mfav1.ChallengeExtensions { | ||
|
danielashare marked this conversation as resolved.
|
||
| if chalExts == nil { | ||
| return nil | ||
| } | ||
|
|
||
| return &mfav1.ChallengeExtensions{ | ||
| Scope: chalExts.Scope, | ||
| AllowReuse: chalExts.AllowReuse, | ||
| UserVerificationRequirement: chalExts.UserVerificationRequirement, | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.