Add context.Context to AuthenticateWebUser and AuthenticateSSHUser (#14754)

Updates auth.ClientI to require that both methods take a
context.Context as the first argument. Context propogation required
some additional call sites to ensure the proper context is plumbed
down to the auth.ClientI calls.
This commit is contained in:
rosstimothy 2022-07-25 12:05:40 -04:00 committed by GitHub
parent c063a186e1
commit adc37b4ba3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 107 additions and 110 deletions

View file

@ -574,7 +574,7 @@ func (s *APIServer) authenticateWebUser(auth ClientI, w http.ResponseWriter, r *
return nil, trace.Wrap(err)
}
req.Username = p.ByName("user")
sess, err := auth.AuthenticateWebUser(req)
sess, err := auth.AuthenticateWebUser(r.Context(), req)
if err != nil {
return nil, trace.Wrap(err)
}
@ -587,7 +587,7 @@ func (s *APIServer) authenticateSSHUser(auth ClientI, w http.ResponseWriter, r *
return nil, trace.Wrap(err)
}
req.Username = p.ByName("user")
return auth.AuthenticateSSHUser(req)
return auth.AuthenticateSSHUser(r.Context(), req)
}
// changePassword updates users password based on the old password.

View file

@ -19,13 +19,14 @@ import (
"testing"
"time"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/mocku2f"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
wanlib "github.com/gravitational/teleport/lib/auth/webauthn"
)
@ -408,6 +409,7 @@ const sshPubKey = `ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzd
func TestServer_AuthenticateUser_mfaDevices(t *testing.T) {
t.Parallel()
ctx := context.Background()
svr := newTestTLSServer(t)
authServer := svr.Auth()
mfa := configureForMFA(t, svr)
@ -428,7 +430,7 @@ func TestServer_AuthenticateUser_mfaDevices(t *testing.T) {
makeRun := func(authenticate func(*Server, AuthenticateUserRequest) error) func(t *testing.T) {
return func(t *testing.T) {
// 1st step: acquire challenge
challenge, err := authServer.CreateAuthenticateChallenge(context.Background(), &proto.CreateAuthenticateChallengeRequest{
challenge, err := authServer.CreateAuthenticateChallenge(ctx, &proto.CreateAuthenticateChallengeRequest{
Request: &proto.CreateAuthenticateChallengeRequest_UserCredentials{UserCredentials: &proto.UserCredentials{
Username: username,
Password: []byte(password),
@ -460,7 +462,7 @@ func TestServer_AuthenticateUser_mfaDevices(t *testing.T) {
}
}
t.Run(test.name+"/ssh", makeRun(func(s *Server, req AuthenticateUserRequest) error {
_, err := s.AuthenticateSSHUser(AuthenticateSSHRequest{
_, err := s.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: req,
PublicKey: []byte(sshPubKey),
TTL: 24 * time.Hour,
@ -468,7 +470,7 @@ func TestServer_AuthenticateUser_mfaDevices(t *testing.T) {
return err
}))
t.Run(test.name+"/web", makeRun(func(s *Server, req AuthenticateUserRequest) error {
_, err := s.AuthenticateWebUser(req)
_, err := s.AuthenticateWebUser(ctx, req)
return err
}))
}
@ -557,7 +559,7 @@ func TestServer_Authenticate_passwordless(t *testing.T) {
{
name: "ssh",
authenticate: func(t *testing.T, resp *wanlib.CredentialAssertionResponse) {
loginResp, err := proxyClient.AuthenticateSSHUser(AuthenticateSSHRequest{
loginResp, err := proxyClient.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Webauthn: resp,
},
@ -573,7 +575,7 @@ func TestServer_Authenticate_passwordless(t *testing.T) {
{
name: "web",
authenticate: func(t *testing.T, resp *wanlib.CredentialAssertionResponse) {
session, err := proxyClient.AuthenticateWebUser(AuthenticateUserRequest{
session, err := proxyClient.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Webauthn: resp,
})
require.NoError(t, err, "Failed to perform passwordless authentication")
@ -584,7 +586,7 @@ func TestServer_Authenticate_passwordless(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Fail a login attempt so have a non-empty list of attempts.
_, err := proxyClient.AuthenticateSSHUser(AuthenticateSSHRequest{
_, err := proxyClient.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Webauthn: &wanlib.CredentialAssertionResponse{}, // bad response
@ -678,7 +680,7 @@ func TestServer_Authenticate_nonPasswordlessRequiresUsername(t *testing.T) {
}
// SSH.
_, err = proxyClient.AuthenticateSSHUser(AuthenticateSSHRequest{
_, err = proxyClient.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: req,
PublicKey: []byte(sshPubKey),
TTL: 24 * time.Hour,
@ -687,13 +689,13 @@ func TestServer_Authenticate_nonPasswordlessRequiresUsername(t *testing.T) {
require.Contains(t, err.Error(), test.wantErr)
// Web.
_, err = proxyClient.AuthenticateWebUser(req)
_, err = proxyClient.AuthenticateWebUser(ctx, req)
require.Error(t, err, "Web authentication expected fail (missing username)")
require.Contains(t, err.Error(), test.wantErr)
// Get one right so we don't lock the user between tests.
req.Username = username
_, err = proxyClient.AuthenticateWebUser(req)
_, err = proxyClient.AuthenticateWebUser(ctx, req)
require.NoError(t, err, "Web authentication expected to succeed")
})
}

View file

@ -190,7 +190,7 @@ func TestSessions(t *testing.T) {
user := "user1"
pass := []byte("abc123")
_, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
_, err := s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
})
@ -202,7 +202,7 @@ func TestSessions(t *testing.T) {
err = s.a.UpsertPassword(user, pass)
require.NoError(t, err)
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
ws, err := s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
})
@ -242,7 +242,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
pass := []byte("abc123")
// Try to login as an unknown user.
_, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
_, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -267,7 +267,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
// Login to the root cluster.
resp, err := s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err := s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -305,7 +305,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.Equal(t, *gotID, wantID)
// Login to the leaf cluster.
resp, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -349,7 +349,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
// Login specifying a valid kube cluster. It should appear in the TLS cert.
resp, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -380,7 +380,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
// Login without specifying kube cluster. A registered one should be picked
// automatically.
resp, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -424,7 +424,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
// Login specifying a valid kube cluster. It should appear in the TLS cert.
resp, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -455,7 +455,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
// Login without specifying kube cluster. A registered one should be picked
// automatically.
resp, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -487,7 +487,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.Equal(t, *gotID, wantID)
// Login specifying an invalid kube cluster. This should fail.
_, err = s.a.AuthenticateSSHUser(AuthenticateSSHRequest{
_, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{Password: pass},
@ -503,11 +503,12 @@ func TestAuthenticateSSHUser(t *testing.T) {
func TestUserLock(t *testing.T) {
t.Parallel()
s := newAuthSuite(t)
ctx := context.Background()
username := "user1"
pass := []byte("abc123")
_, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
_, err := s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: username,
Pass: &PassCreds{Password: pass},
})
@ -520,7 +521,7 @@ func TestUserLock(t *testing.T) {
require.NoError(t, err)
// successful log in
ws, err := s.a.AuthenticateWebUser(AuthenticateUserRequest{
ws, err := s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: username,
Pass: &PassCreds{Password: pass},
})
@ -531,7 +532,7 @@ func TestUserLock(t *testing.T) {
s.a.SetClock(fakeClock)
for i := 0; i <= defaults.MaxLoginAttempts; i++ {
_, err = s.a.AuthenticateWebUser(AuthenticateUserRequest{
_, err = s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: username,
Pass: &PassCreds{Password: []byte("wrong pass")},
})
@ -545,7 +546,7 @@ func TestUserLock(t *testing.T) {
// advance time and make sure we can login again
fakeClock.Advance(defaults.AccountLockInterval + time.Second)
_, err = s.a.AuthenticateWebUser(AuthenticateUserRequest{
_, err = s.a.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: username,
Pass: &PassCreds{Password: pass},
})

View file

@ -386,24 +386,24 @@ func (a *ServerWithRoles) UpdateSessionTracker(ctx context.Context, req *proto.U
// AuthenticateWebUser authenticates web user, creates and returns a web session
// in case authentication is successful
func (a *ServerWithRoles) AuthenticateWebUser(req AuthenticateUserRequest) (types.WebSession, error) {
func (a *ServerWithRoles) AuthenticateWebUser(ctx context.Context, req AuthenticateUserRequest) (types.WebSession, error) {
// authentication request has it's own authentication, however this limits the requests
// types to proxies to make it harder to break
if !a.hasBuiltinRole(types.RoleProxy) {
return nil, trace.AccessDenied("this request can be only executed by a proxy")
}
return a.authServer.AuthenticateWebUser(req)
return a.authServer.AuthenticateWebUser(ctx, req)
}
// AuthenticateSSHUser authenticates SSH console user, creates and returns a pair of signed TLS and SSH
// short lived certificates as a result
func (a *ServerWithRoles) AuthenticateSSHUser(req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
func (a *ServerWithRoles) AuthenticateSSHUser(ctx context.Context, req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
// authentication request has it's own authentication, however this limits the requests
// types to proxies to make it harder to break
if !a.hasBuiltinRole(types.RoleProxy) {
return nil, trace.AccessDenied("this request can be only executed by a proxy")
}
return a.authServer.AuthenticateSSHUser(req)
return a.authServer.AuthenticateSSHUser(ctx, req)
}
func (a *ServerWithRoles) GetSessions(namespace string) ([]session.Session, error) {

View file

@ -887,9 +887,9 @@ func (c *Client) CreateWebSession(ctx context.Context, user string) (types.WebSe
// AuthenticateWebUser authenticates web user, creates and returns web session
// in case if authentication is successful
func (c *Client) AuthenticateWebUser(req AuthenticateUserRequest) (types.WebSession, error) {
func (c *Client) AuthenticateWebUser(ctx context.Context, req AuthenticateUserRequest) (types.WebSession, error) {
out, err := c.PostJSON(
context.TODO(),
ctx,
c.Endpoint("users", req.Username, "web", "authenticate"),
req,
)
@ -901,9 +901,9 @@ func (c *Client) AuthenticateWebUser(req AuthenticateUserRequest) (types.WebSess
// AuthenticateSSHUser authenticates SSH console user, creates and returns a pair of signed TLS and SSH
// short lived certificates as a result
func (c *Client) AuthenticateSSHUser(req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
func (c *Client) AuthenticateSSHUser(ctx context.Context, req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
out, err := c.PostJSON(
context.TODO(),
ctx,
c.Endpoint("users", req.Username, "ssh", "authenticate"),
req,
)
@ -1716,10 +1716,10 @@ type ClientI interface {
GenerateHostCerts(context.Context, *proto.HostCertsRequest) (*proto.Certs, error)
// AuthenticateWebUser authenticates web user, creates and returns web session
// in case if authentication is successful
AuthenticateWebUser(req AuthenticateUserRequest) (types.WebSession, error)
AuthenticateWebUser(ctx context.Context, req AuthenticateUserRequest) (types.WebSession, error)
// AuthenticateSSHUser authenticates SSH console user, creates and returns a pair of signed TLS and SSH
// short lived certificates as a result
AuthenticateSSHUser(req AuthenticateSSHRequest) (*SSHLoginResponse, error)
// short-lived certificates as a result
AuthenticateSSHUser(ctx context.Context, req AuthenticateSSHRequest) (*SSHLoginResponse, error)
// ProcessKubeCSR processes CSR request against Kubernetes CA, returns
// signed certificate if successful.

View file

@ -21,6 +21,9 @@ import (
"errors"
"time"
"github.com/gravitational/trace"
"golang.org/x/crypto/ssh"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/api/types"
@ -29,8 +32,6 @@ import (
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/utils"
"github.com/gravitational/trace"
"golang.org/x/crypto/ssh"
)
// AuthenticateUserRequest is a request to authenticate interactive user
@ -294,10 +295,9 @@ func (s *Server) authenticatePasswordless(ctx context.Context, req AuthenticateU
// AuthenticateWebUser authenticates web user, creates and returns a web session
// if authentication is successful. In case the existing session ID is used to authenticate,
// returns the existing session instead of creating a new one
func (s *Server) AuthenticateWebUser(req AuthenticateUserRequest) (types.WebSession, error) {
func (s *Server) AuthenticateWebUser(ctx context.Context, req AuthenticateUserRequest) (types.WebSession, error) {
username := req.Username // Empty if passwordless.
ctx := context.TODO()
authPref, err := s.GetAuthPreference(ctx)
if err != nil {
return nil, trace.Wrap(err)
@ -430,10 +430,9 @@ func AuthoritiesToTrustedCerts(authorities []types.CertAuthority) []TrustedCerts
// AuthenticateSSHUser authenticates an SSH user and returns SSH and TLS
// certificates for the public key in req.
func (s *Server) AuthenticateSSHUser(req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
func (s *Server) AuthenticateSSHUser(ctx context.Context, req AuthenticateSSHRequest) (*SSHLoginResponse, error) {
username := req.Username // Empty if passwordless.
ctx := context.TODO()
authPref, err := s.GetAuthPreference(ctx)
if err != nil {
return nil, trace.Wrap(err)

View file

@ -1274,14 +1274,14 @@ func TestWebSessionWithoutAccessRequest(t *testing.T) {
},
}
// authentication attempt fails with no password set up
_, err = proxy.AuthenticateWebUser(req)
_, err = proxy.AuthenticateWebUser(ctx, req)
require.True(t, trace.IsAccessDenied(err))
err = clt.UpsertPassword(user, pass)
require.NoError(t, err)
// success with password set up
ws, err := proxy.AuthenticateWebUser(req)
ws, err := proxy.AuthenticateWebUser(ctx, req)
require.NoError(t, err)
require.NotEqual(t, ws, "")
@ -1390,7 +1390,7 @@ func TestWebSessionMultiAccessRequests(t *testing.T) {
// Create a web session and client for the user.
proxyClient, err := tt.server.NewClient(TestBuiltin(types.RoleProxy))
require.NoError(t, err)
baseWebSession, err := proxyClient.AuthenticateWebUser(AuthenticateUserRequest{
baseWebSession, err := proxyClient.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: username,
Pass: &PassCreds{
Password: password,
@ -1560,14 +1560,14 @@ func TestWebSessionWithApprovedAccessRequestAndSwitchback(t *testing.T) {
err = clt.UpsertPassword(user, pass)
require.NoError(t, err)
ws, err := proxy.AuthenticateWebUser(req)
ws, err := proxy.AuthenticateWebUser(ctx, req)
require.NoError(t, err)
web, err := tt.server.NewClientFromWebSession(ws)
require.NoError(t, err)
initialRole := newUser.GetRoles()[0]
initialSession, err := web.GetWebSessionInfo(context.TODO(), user, ws.GetName())
initialSession, err := web.GetWebSessionInfo(ctx, user, ws.GetName())
require.NoError(t, err)
// Create a approved access request.
@ -1578,10 +1578,10 @@ func TestWebSessionWithApprovedAccessRequestAndSwitchback(t *testing.T) {
accessReq.SetAccessExpiry(tt.clock.Now().Add(time.Minute * 10))
accessReq.SetState(types.RequestState_APPROVED)
err = clt.CreateAccessRequest(context.Background(), accessReq)
err = clt.CreateAccessRequest(ctx, accessReq)
require.NoError(t, err)
sess1, err := web.ExtendWebSession(context.TODO(), WebSessionReq{
sess1, err := web.ExtendWebSession(ctx, WebSessionReq{
User: user,
PrevSessionID: ws.GetName(),
AccessRequestID: accessReq.GetMetadata().Name,
@ -1623,7 +1623,7 @@ func TestWebSessionWithApprovedAccessRequestAndSwitchback(t *testing.T) {
require.Empty(t, cmp.Diff(certRequests(sess1.GetTLSCert()), []string{accessReq.GetName()}))
// Test switch back to default role and expiry.
sess2, err := web.ExtendWebSession(context.TODO(), WebSessionReq{
sess2, err := web.ExtendWebSession(ctx, WebSessionReq{
User: user,
PrevSessionID: ws.GetName(),
Switchback: true,
@ -2308,7 +2308,7 @@ func TestCertificateFormat(t *testing.T) {
require.NoError(t, err)
// authentication attempt fails with password auth only
re, err := proxyClient.AuthenticateSSHUser(AuthenticateSSHRequest{
re, err := proxyClient.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user.GetName(),
Pass: &PassCreds{
@ -2408,21 +2408,21 @@ func TestAuthenticateWebUserOTP(t *testing.T) {
require.NoError(t, err)
// authentication attempt fails with wrong password
_, err = proxy.AuthenticateWebUser(AuthenticateUserRequest{
_, err = proxy.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
OTP: &OTPCreds{Password: []byte("wrong123"), Token: validToken},
})
require.True(t, trace.IsAccessDenied(err))
// authentication attempt fails with wrong otp
_, err = proxy.AuthenticateWebUser(AuthenticateUserRequest{
_, err = proxy.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
OTP: &OTPCreds{Password: pass, Token: "wrong123"},
})
require.True(t, trace.IsAccessDenied(err))
// authentication attempt fails with password auth only
_, err = proxy.AuthenticateWebUser(AuthenticateUserRequest{
_, err = proxy.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{
Password: pass,
@ -2431,7 +2431,7 @@ func TestAuthenticateWebUserOTP(t *testing.T) {
require.True(t, trace.IsAccessDenied(err))
// authentication succeeds
ws, err := proxy.AuthenticateWebUser(AuthenticateUserRequest{
ws, err := proxy.AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
OTP: &OTPCreds{Password: pass, Token: validToken},
})
@ -2480,7 +2480,7 @@ func TestLoginAttempts(t *testing.T) {
},
}
// authentication attempt fails with bad password
_, err = proxy.AuthenticateWebUser(req)
_, err = proxy.AuthenticateWebUser(ctx, req)
require.True(t, trace.IsAccessDenied(err))
// creates first failed login attempt
@ -2490,7 +2490,7 @@ func TestLoginAttempts(t *testing.T) {
// try second time with wrong pass
req.Pass.Password = pass
_, err = proxy.AuthenticateWebUser(req)
_, err = proxy.AuthenticateWebUser(ctx, req)
require.NoError(t, err)
// clears all failed attempts after success
@ -2583,7 +2583,7 @@ func TestLoginNoLocalAuth(t *testing.T) {
require.NoError(t, err)
// Make sure access is denied for web login.
_, err = tt.server.Auth().AuthenticateWebUser(AuthenticateUserRequest{
_, err = tt.server.Auth().AuthenticateWebUser(ctx, AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{
Password: pass,
@ -2594,7 +2594,7 @@ func TestLoginNoLocalAuth(t *testing.T) {
// Make sure access is denied for SSH login.
_, pub, err := native.GenerateKeyPair()
require.NoError(t, err)
_, err = tt.server.Auth().AuthenticateSSHUser(AuthenticateSSHRequest{
_, err = tt.server.Auth().AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Pass: &PassCreds{

View file

@ -1561,20 +1561,14 @@ func (h *Handler) createWebSession(w http.ResponseWriter, r *http.Request, p htt
switch cap.GetSecondFactor() {
case constants.SecondFactorOff:
webSession, err = h.auth.AuthWithoutOTP(req.User, req.Pass, clientMeta)
webSession, err = h.auth.AuthWithoutOTP(r.Context(), req.User, req.Pass, clientMeta)
case constants.SecondFactorOTP, constants.SecondFactorOn:
webSession, err = h.auth.AuthWithOTP(
req.User, req.Pass, req.SecondFactorToken, clientMeta,
)
webSession, err = h.auth.AuthWithOTP(r.Context(), req.User, req.Pass, req.SecondFactorToken, clientMeta)
case constants.SecondFactorOptional:
if req.SecondFactorToken == "" {
webSession, err = h.auth.AuthWithoutOTP(
req.User, req.Pass, clientMeta,
)
webSession, err = h.auth.AuthWithoutOTP(r.Context(), req.User, req.Pass, clientMeta)
} else {
webSession, err = h.auth.AuthWithOTP(
req.User, req.Pass, req.SecondFactorToken, clientMeta,
)
webSession, err = h.auth.AuthWithOTP(r.Context(), req.User, req.Pass, req.SecondFactorToken, clientMeta)
}
default:
return nil, trace.AccessDenied("unknown second factor type: %q", cap.GetSecondFactor())
@ -1599,7 +1593,7 @@ func (h *Handler) createWebSession(w http.ResponseWriter, r *http.Request, p htt
return nil, trace.Wrap(err)
}
ctx, err := h.auth.newSessionContext(req.User, webSession.GetName())
ctx, err := h.auth.newSessionContext(r.Context(), req.User, webSession.GetName())
if err != nil {
h.log.WithError(err).Warnf("Access attempt denied for user %q.", req.User)
return nil, trace.AccessDenied("need auth")
@ -1626,7 +1620,7 @@ func clientMetaFromReq(r *http.Request) *auth.ForwardedClientMetadata {
// {"message": "ok"}
//
func (h *Handler) deleteSession(w http.ResponseWriter, r *http.Request, _ httprouter.Params, ctx *SessionContext) (interface{}, error) {
err := h.logout(w, ctx)
err := h.logout(r.Context(), w, ctx)
if err != nil {
return nil, trace.Wrap(err)
}
@ -1634,8 +1628,8 @@ func (h *Handler) deleteSession(w http.ResponseWriter, r *http.Request, _ httpro
return OK(), nil
}
func (h *Handler) logout(w http.ResponseWriter, ctx *SessionContext) error {
if err := ctx.Invalidate(); err != nil {
func (h *Handler) logout(ctx context.Context, w http.ResponseWriter, scx *SessionContext) error {
if err := scx.Invalidate(ctx); err != nil {
return trace.Wrap(err)
}
ClearSession(w)
@ -1730,7 +1724,7 @@ func (h *Handler) changeUserAuthentication(w http.ResponseWriter, r *http.Reques
}
sess := res.WebSession
ctx, err := h.auth.newSessionContext(sess.GetUser(), sess.GetName())
ctx, err := h.auth.newSessionContext(r.Context(), sess.GetUser(), sess.GetName())
if err != nil {
return nil, trace.Wrap(err)
}
@ -1878,7 +1872,7 @@ func (h *Handler) mfaLoginFinish(w http.ResponseWriter, r *http.Request, p httpr
}
clientMeta := clientMetaFromReq(r)
cert, err := h.auth.AuthenticateSSHUser(*req, clientMeta)
cert, err := h.auth.AuthenticateSSHUser(r.Context(), *req, clientMeta)
if err != nil {
return nil, trace.Wrap(err)
}
@ -1902,7 +1896,7 @@ func (h *Handler) mfaLoginFinishSession(w http.ResponseWriter, r *http.Request,
}
clientMeta := clientMetaFromReq(r)
session, err := h.auth.AuthenticateWebUser(req, clientMeta)
session, err := h.auth.AuthenticateWebUser(r.Context(), req, clientMeta)
if err != nil {
return nil, trace.AccessDenied("bad auth credentials")
}
@ -1913,7 +1907,7 @@ func (h *Handler) mfaLoginFinishSession(w http.ResponseWriter, r *http.Request,
return nil, trace.Wrap(err)
}
ctx, err := h.auth.newSessionContext(user, session.GetName())
ctx, err := h.auth.newSessionContext(r.Context(), user, session.GetName())
if err != nil {
return nil, trace.AccessDenied("need auth")
}
@ -2577,13 +2571,13 @@ func (h *Handler) createSSHCert(w http.ResponseWriter, r *http.Request, p httpro
switch cap.GetSecondFactor() {
case constants.SecondFactorOff:
cert, err = h.auth.GetCertificateWithoutOTP(*req, clientMeta)
cert, err = h.auth.GetCertificateWithoutOTP(r.Context(), *req, clientMeta)
case constants.SecondFactorOTP, constants.SecondFactorOn, constants.SecondFactorOptional:
// convert legacy requests to new parameter here. remove once migration to TOTP is complete.
if req.HOTPToken != "" {
req.OTPToken = req.HOTPToken
}
cert, err = h.auth.GetCertificateWithOTP(*req, clientMeta)
cert, err = h.auth.GetCertificateWithOTP(r.Context(), *req, clientMeta)
default:
return nil, trace.AccessDenied("unknown second factor type: %q", cap.GetSecondFactor())
}

View file

@ -19,13 +19,14 @@ package web
import (
"net/http"
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
"github.com/gravitational/teleport/api/client/proto"
wanlib "github.com/gravitational/teleport/lib/auth/webauthn"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/httplib"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
)
// changePasswordReq is a request to change user password
@ -88,7 +89,7 @@ func (h *Handler) createAuthenticateChallengeWithPassword(w http.ResponseWriter,
})
if err != nil && trace.IsAccessDenied(err) {
// logout in case of access denied
logoutErr := h.logout(w, ctx)
logoutErr := h.logout(r.Context(), w, ctx)
if logoutErr != nil {
return nil, trace.Wrap(logoutErr)
}

View file

@ -26,11 +26,11 @@ import (
"sync"
"time"
"github.com/gravitational/teleport/api/breaker"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/breaker"
apiclient "github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
@ -106,8 +106,8 @@ func (c *SessionContext) RemoveCloser(closer io.Closer) {
// Invalidate invalidates this context by removing the underlying session
// and closing all underlying closers
func (c *SessionContext) Invalidate() error {
return c.parent.invalidateSession(c)
func (c *SessionContext) Invalidate(ctx context.Context) error {
return c.parent.invalidateSession(ctx, c)
}
func (c *SessionContext) validateBearerToken(ctx context.Context, token string) error {
@ -555,10 +555,11 @@ func (s *sessionCache) clearExpiredSessions(ctx context.Context) {
// AuthWithOTP authenticates the specified user with the given password and OTP token.
// Returns a new web session if successful.
func (s *sessionCache) AuthWithOTP(
ctx context.Context,
user, pass, otpToken string,
clientMeta *auth.ForwardedClientMetadata,
) (types.WebSession, error) {
return s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{
return s.proxyClient.AuthenticateWebUser(ctx, auth.AuthenticateUserRequest{
Username: user,
Pass: &auth.PassCreds{Password: []byte(pass)},
OTP: &auth.OTPCreds{
@ -572,9 +573,9 @@ func (s *sessionCache) AuthWithOTP(
// AuthWithoutOTP authenticates the specified user with the given password.
// Returns a new web session if successful.
func (s *sessionCache) AuthWithoutOTP(
user, pass string, clientMeta *auth.ForwardedClientMetadata,
ctx context.Context, user, pass string, clientMeta *auth.ForwardedClientMetadata,
) (types.WebSession, error) {
return s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{
return s.proxyClient.AuthenticateWebUser(ctx, auth.AuthenticateUserRequest{
Username: user,
Pass: &auth.PassCreds{
Password: []byte(pass),
@ -584,7 +585,7 @@ func (s *sessionCache) AuthWithoutOTP(
}
func (s *sessionCache) AuthenticateWebUser(
req *client.AuthenticateWebUserRequest, clientMeta *auth.ForwardedClientMetadata,
ctx context.Context, req *client.AuthenticateWebUserRequest, clientMeta *auth.ForwardedClientMetadata,
) (types.WebSession, error) {
authReq := auth.AuthenticateUserRequest{
Username: req.User,
@ -593,14 +594,14 @@ func (s *sessionCache) AuthenticateWebUser(
if req.WebauthnAssertionResponse != nil {
authReq.Webauthn = req.WebauthnAssertionResponse
}
return s.proxyClient.AuthenticateWebUser(authReq)
return s.proxyClient.AuthenticateWebUser(ctx, authReq)
}
// GetCertificateWithoutOTP returns a new user certificate for the specified request.
func (s *sessionCache) GetCertificateWithoutOTP(
c client.CreateSSHCertReq, clientMeta *auth.ForwardedClientMetadata,
ctx context.Context, c client.CreateSSHCertReq, clientMeta *auth.ForwardedClientMetadata,
) (*auth.SSHLoginResponse, error) {
return s.proxyClient.AuthenticateSSHUser(auth.AuthenticateSSHRequest{
return s.proxyClient.AuthenticateSSHUser(ctx, auth.AuthenticateSSHRequest{
AuthenticateUserRequest: auth.AuthenticateUserRequest{
Username: c.User,
Pass: &auth.PassCreds{
@ -619,9 +620,9 @@ func (s *sessionCache) GetCertificateWithoutOTP(
// GetCertificateWithOTP returns a new user certificate for the specified request.
// The request is used with the given OTP token.
func (s *sessionCache) GetCertificateWithOTP(
c client.CreateSSHCertReq, clientMeta *auth.ForwardedClientMetadata,
ctx context.Context, c client.CreateSSHCertReq, clientMeta *auth.ForwardedClientMetadata,
) (*auth.SSHLoginResponse, error) {
return s.proxyClient.AuthenticateSSHUser(auth.AuthenticateSSHRequest{
return s.proxyClient.AuthenticateSSHUser(ctx, auth.AuthenticateSSHRequest{
AuthenticateUserRequest: auth.AuthenticateUserRequest{
Username: c.User,
OTP: &auth.OTPCreds{
@ -639,8 +640,7 @@ func (s *sessionCache) GetCertificateWithOTP(
}
func (s *sessionCache) AuthenticateSSHUser(
c client.AuthenticateSSHUserRequest,
clientMeta *auth.ForwardedClientMetadata,
ctx context.Context, c client.AuthenticateSSHUserRequest, clientMeta *auth.ForwardedClientMetadata,
) (*auth.SSHLoginResponse, error) {
authReq := auth.AuthenticateUserRequest{
Username: c.User,
@ -658,7 +658,7 @@ func (s *sessionCache) AuthenticateSSHUser(
Token: c.TOTPCode,
}
}
return s.proxyClient.AuthenticateSSHUser(auth.AuthenticateSSHRequest{
return s.proxyClient.AuthenticateSSHUser(ctx, auth.AuthenticateSSHRequest{
AuthenticateUserRequest: authReq,
PublicKey: c.PubKey,
CompatibilityMode: c.Compatibility,
@ -687,28 +687,28 @@ func (s *sessionCache) validateSession(ctx context.Context, user, sessionID stri
if !trace.IsNotFound(err) {
return nil, trace.Wrap(err)
}
return s.newSessionContext(user, sessionID)
return s.newSessionContext(ctx, user, sessionID)
}
func (s *sessionCache) invalidateSession(ctx *SessionContext) error {
defer ctx.Close()
clt, err := ctx.GetClient()
func (s *sessionCache) invalidateSession(ctx context.Context, scx *SessionContext) error {
defer scx.Close()
clt, err := scx.GetClient()
if err != nil {
return trace.Wrap(err)
}
// Delete just the session - leave the bearer token to linger to avoid
// failing a client query still using the old token.
err = clt.WebSessions().Delete(context.TODO(), types.DeleteWebSessionRequest{
User: ctx.user,
SessionID: ctx.session.GetName(),
err = clt.WebSessions().Delete(ctx, types.DeleteWebSessionRequest{
User: scx.user,
SessionID: scx.session.GetName(),
})
if err != nil && !trace.IsNotFound(err) {
return trace.Wrap(err)
}
if err := clt.DeleteUserAppSessions(context.TODO(), &proto.DeleteUserAppSessionsRequest{Username: ctx.user}); err != nil {
if err := clt.DeleteUserAppSessions(ctx, &proto.DeleteUserAppSessionsRequest{Username: scx.user}); err != nil {
return trace.Wrap(err)
}
if err := s.releaseResources(ctx.GetUser(), ctx.session.GetName()); err != nil {
if err := s.releaseResources(scx.GetUser(), scx.session.GetName()); err != nil {
return trace.Wrap(err)
}
return nil
@ -793,8 +793,8 @@ func (s *sessionCache) upsertSessionContext(user string) *sessionResources {
}
// newSessionContext creates a new web session context for the specified user/session ID
func (s *sessionCache) newSessionContext(user, sessionID string) (*SessionContext, error) {
session, err := s.proxyClient.AuthenticateWebUser(auth.AuthenticateUserRequest{
func (s *sessionCache) newSessionContext(ctx context.Context, user, sessionID string) (*SessionContext, error) {
session, err := s.proxyClient.AuthenticateWebUser(ctx, auth.AuthenticateUserRequest{
Username: user,
Session: &auth.SessionCreds{
ID: sessionID,