[Browser MFA] Add Browser MFA to challenge request flow#63936
Conversation
f9d5208 to
9bd9b9e
Compare
e8d3f57 to
66deea0
Compare
68a5f0c to
7ac607e
Compare
3e63a80 to
09a1356
Compare
| BrowserMFATSHRedirectURL string | ||
| ProxyAddress string | ||
| Ext *mfav1.ChallengeExtensions | ||
| SIP *mfav1.SessionIdentifyingPayload |
There was a problem hiding this comment.
Just to clarify if I understand the purpose correctly: does this field have any purpose outside of per-session MFA?
There was a problem hiding this comment.
Yes, this field is only for in-band per-session MFA
| // If the user has a WebAuthn device and no SSO MFA configured, return a Browser | ||
| // MFA challenge. This challenge is useful in cases where a user only has a | ||
| // browser-associated WebAuthn device, but is trying to MFA via a CLI tool (tsh, tctl etc.) | ||
| if groupedDevs.Browser != nil && browserMFATSHRedirectURL != "" { |
There was a problem hiding this comment.
Is this feature unconditionally turned on? I'm asking because the previous conditional has enableSSO as a part of the condition.
There was a problem hiding this comment.
It isn't unconditionally enabled, I checked if it was enabled inside this if statement because I didn't want to query the auth preferences if the MFA device or redirect URL wasn't set. However, I realise that authPrefs are checked further up and I can just reuse that response, so I've modified this to match the other MFA methods
| return nil, trace.Wrap(err, InvalidClientRedirectErrorMessage) | ||
| } | ||
|
|
||
| proxyAddr := params.ProxyAddress |
There was a problem hiding this comment.
So ProxyAddress is expected to be filled by the proxy service, and it's not a user-provided value, right? Can you explain in which case this value will be empty and will need to be filled here?
There was a problem hiding this comment.
The SSO MFA challenge request flow, which this is heavily inspired by, passes the proxy address and a redirect URL. Browser MFA just has the client send the redirect URL. So, unless some large changes are made to SSO MFA, the proxy address is always going to be present because it is passed as a param to the mfaAuthChallenge function that calls either BeginSSOMFAChallenge or BeginBrowserMFAChallenge. Just in case changes are made, I have a fallback here to get the proxy address. I'll add a comment to explain that.
| // TargetCluster is the optional cluster where the authentication is targeted. | ||
| TargetCluster string `json:"target_cluster,omitempty"` | ||
| // TshRedirectURL is the redirect URL used to return a WebAuthn response back to tsh | ||
| TshRedirectURL string `json:"tsh_redirect_url,omitempty"` |
There was a problem hiding this comment.
This should be TSHRedirectURL to conform to the naming conventions. Also: I've seen this field written to, but I don't think I've seen it being actually used anywhere. Will it be used in a future PR?
There was a problem hiding this comment.
Renamed that. Yeah, there are other PRs that will read this value
| Scope: mfav1.ChallengeScope_CHALLENGE_SCOPE_LOGIN, | ||
| } | ||
|
|
||
| if req.BrowserMFATSHRedirectURL != "" { |
There was a problem hiding this comment.
I'd argue that this conditional is unnecessary, as the URL will be initialized to an empty string anyway.
There was a problem hiding this comment.
Makes it look cleaner 👍
| } | ||
|
|
||
| // BrowserMFAChallenge contains browser challenge details. | ||
| message BrowserMFAChallenge { |
There was a problem hiding this comment.
Will this message be used in a future PR? I don't see it used here.
There was a problem hiding this comment.
Apologies, that commit snuck in to this branch, I've removed it now
adae9ae to
2ce5b66
Compare
acc34c1 to
655a559
Compare
6e6e08b to
80601ac
Compare
Joerger
left a comment
There was a problem hiding this comment.
LGTM, just a small test request
| }, | ||
| }, | ||
| { | ||
| name: "NOK SSO MFA user should not get Browser MFA", |
There was a problem hiding this comment.
Let's add another test case for an SSO MFA user w/ a webauthn device getting both challenges.
| @@ -4459,7 +4444,7 @@ func (a *Server) CreateAuthenticateChallenge(ctx context.Context, req *proto.Cre | |||
| } | |||
| } | |||
|
|
|||
| challenges, err := a.mfaAuthChallenge(ctx, username, req.SSOClientRedirectURL, req.ProxyAddress, challengeExtensions) | |||
| challenges, err := a.mfaAuthChallenge(ctx, username, req.SSOClientRedirectURL, req.BrowserMFATSHRedirectURL, req.ProxyAddress, challengeExtensions) | |||
There was a problem hiding this comment.
Yeah that's exactly what I was thinking.
I'm not sure if we'll end up liking the change or not. I guess it depends how big of a change it is and how clear the final code is, but give it a shot and see if you like it better with a single redirect URL.
| Webauthn: &types.Webauthn{ | ||
| RPID: "localhost", | ||
| }, | ||
| AllowBrowserAuthentication: types.NewBoolOption(true), |
There was a problem hiding this comment.
Is this the new option that enables browser MFA?
If so, I think the name should mention "MFA" - we don't want people to think this is some sort of setting for disabling regular web UI login.
There was a problem hiding this comment.
Yes it is, and I agree we should change the name. However, the change to types.proto has already been merged to master with this name. Is there any way we can change this field?
6784a31 to
6143668
Compare
6143668 to
c039f40
Compare
|
@danielashare See the table below for backport results.
|
This PR adds Browser MFA fields to the
/webapi/login/mfa/beginflow. The RFD for this addition can be found here. Needs to be merged after #63831.These changes address this part of the flow from the above RFD:
sequenceDiagram participant tsh participant proxy as Proxy participant auth as Auth tsh->>proxy: POST /webapi/mfa/login/begin<br/>w/ redirect /callback?secret_key=xxx proxy->>auth: Forward login request auth->>auth: Generate request_id<br/>Upsert SSOMFASession auth-->>proxy: MFA Challenge proxy-->>tsh: Return MFA ChallengeManual tests:
tshclient receives Browser MFA challenge