X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/23d90de7344ae39d1d0082a369b0dc5e9086531d..8332284f3bb68bcf779d689129b8df9c911d5c47:/lib/controller/localdb/login_pam.go diff --git a/lib/controller/localdb/login_pam.go b/lib/controller/localdb/login_pam.go index 059e27fa26..01dfc1379d 100644 --- a/lib/controller/localdb/login_pam.go +++ b/lib/controller/localdb/login_pam.go @@ -31,7 +31,12 @@ func (ctrl *pamLoginController) Logout(ctx context.Context, opts arvados.LogoutO } func (ctrl *pamLoginController) Login(ctx context.Context, opts arvados.LoginOptions) (arvados.LoginResponse, error) { + return arvados.LoginResponse{}, errors.New("interactive login is not available") +} + +func (ctrl *pamLoginController) UserAuthenticate(ctx context.Context, opts arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) { errorMessage := "" + sentPassword := false tx, err := pam.StartFunc(ctrl.Cluster.Login.PAMService, opts.Username, func(style pam.Style, message string) (string, error) { ctxlog.FromContext(ctx).Debugf("pam conversation: style=%v message=%q", style, message) switch style { @@ -43,24 +48,38 @@ func (ctrl *pamLoginController) Login(ctx context.Context, opts arvados.LoginOpt ctxlog.FromContext(ctx).WithField("Message", message).Info("pam.TextInfo") return "", nil case pam.PromptEchoOn, pam.PromptEchoOff: + sentPassword = true return opts.Password, nil default: return "", fmt.Errorf("unrecognized message style %d", style) } }) if err != nil { - return arvados.LoginResponse{}, err + return arvados.APIClientAuthorization{}, err } err = tx.Authenticate(pam.DisallowNullAuthtok) if err != nil { - return arvados.LoginResponse{}, httpserver.ErrorWithStatus(err, http.StatusUnauthorized) + err = fmt.Errorf("PAM: %s", err) + if errorMessage != "" { + // Perhaps the error message in the + // conversation is helpful. + err = fmt.Errorf("%s; %q", err, errorMessage) + } + if sentPassword { + err = fmt.Errorf("%s (with username %q and password)", err, opts.Username) + } else { + // This might hint that the username was + // invalid. + err = fmt.Errorf("%s (with username %q; password was never requested by PAM service)", err, opts.Username) + } + return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(err, http.StatusUnauthorized) } if errorMessage != "" { - return arvados.LoginResponse{}, httpserver.ErrorWithStatus(errors.New(errorMessage), http.StatusUnauthorized) + return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(errors.New(errorMessage), http.StatusUnauthorized) } user, err := tx.GetItem(pam.User) if err != nil { - return arvados.LoginResponse{}, err + return arvados.APIClientAuthorization{}, err } email := user if domain := ctrl.Cluster.Login.PAMDefaultEmailDomain; domain != "" && !strings.Contains(email, "@") { @@ -72,20 +91,19 @@ func (ctrl *pamLoginController) Login(ctx context.Context, opts arvados.LoginOpt // Send a fake ReturnTo value instead of the caller's // opts.ReturnTo. We won't follow the resulting // redirect target anyway. - ReturnTo: opts.Remote + ",https://none.invalid", + ReturnTo: ",https://none.invalid", AuthInfo: rpc.UserSessionAuthInfo{ Username: user, Email: email, }, }) if err != nil { - return arvados.LoginResponse{}, err + return arvados.APIClientAuthorization{}, err } target, err := url.Parse(resp.RedirectLocation) if err != nil { - return arvados.LoginResponse{}, err + return arvados.APIClientAuthorization{}, err } - resp.Token = target.Query().Get("api_token") - resp.RedirectLocation = "" - return resp, err + token := target.Query().Get("api_token") + return ctrl.RailsProxy.APIClientAuthorizationCurrent(auth.NewContext(ctx, auth.NewCredentials(token)), arvados.GetOptions{}) }