//
// SPDX-License-Identifier: AGPL-3.0
+//go:build !static
+
package localdb
import (
"errors"
"fmt"
"net/http"
- "net/url"
"strings"
"git.arvados.org/arvados.git/lib/controller/rpc"
"git.arvados.org/arvados.git/sdk/go/arvados"
- "git.arvados.org/arvados.git/sdk/go/auth"
"git.arvados.org/arvados.git/sdk/go/ctxlog"
"git.arvados.org/arvados.git/sdk/go/httpserver"
"github.com/msteinert/pam"
)
type pamLoginController struct {
- Cluster *arvados.Cluster
- RailsProxy *railsProxy
+ Cluster *arvados.Cluster
+ Parent *Conn
}
func (ctrl *pamLoginController) Logout(ctx context.Context, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
- return noopLogout(ctrl.Cluster, opts)
+ return logout(ctx, ctrl.Cluster, opts)
}
func (ctrl *pamLoginController) Login(ctx context.Context, opts arvados.LoginOptions) (arvados.LoginResponse, error) {
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) {
+ tx, err := pam.StartFunc(ctrl.Cluster.Login.PAM.Service, opts.Username, func(style pam.Style, message string) (string, error) {
ctxlog.FromContext(ctx).Debugf("pam conversation: style=%v message=%q", style, message)
switch style {
case pam.ErrorMsg:
if err != nil {
return arvados.APIClientAuthorization{}, err
}
+ // Check that the given credentials are valid.
err = tx.Authenticate(pam.DisallowNullAuthtok)
if err != nil {
err = fmt.Errorf("PAM: %s", err)
if errorMessage != "" {
return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(errors.New(errorMessage), http.StatusUnauthorized)
}
+ // Check that the account/user is permitted to access this host.
+ err = tx.AcctMgmt(pam.DisallowNullAuthtok)
+ if err != nil {
+ err = fmt.Errorf("PAM: %s", err)
+ if errorMessage != "" {
+ err = fmt.Errorf("%s; %q", err, errorMessage)
+ }
+ return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(err, http.StatusUnauthorized)
+ }
user, err := tx.GetItem(pam.User)
if err != nil {
return arvados.APIClientAuthorization{}, err
}
email := user
- if domain := ctrl.Cluster.Login.PAMDefaultEmailDomain; domain != "" && !strings.Contains(email, "@") {
+ if domain := ctrl.Cluster.Login.PAM.DefaultEmailDomain; domain != "" && !strings.Contains(email, "@") {
email = email + "@" + domain
}
- ctxlog.FromContext(ctx).WithFields(logrus.Fields{"user": user, "email": email}).Debug("pam authentication succeeded")
- ctxRoot := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{ctrl.Cluster.SystemRootToken}})
- resp, err := ctrl.RailsProxy.UserSessionCreate(ctxRoot, rpc.UserSessionCreateOptions{
- // Send a fake ReturnTo value instead of the caller's
- // opts.ReturnTo. We won't follow the resulting
- // redirect target anyway.
- ReturnTo: ",https://none.invalid",
- AuthInfo: rpc.UserSessionAuthInfo{
- Username: user,
- Email: email,
- },
+ ctxlog.FromContext(ctx).WithFields(logrus.Fields{
+ "user": user,
+ "email": email,
+ }).Debug("pam authentication succeeded")
+ return ctrl.Parent.CreateAPIClientAuthorization(ctx, ctrl.Cluster.SystemRootToken, rpc.UserSessionAuthInfo{
+ Username: user,
+ Email: email,
})
- if err != nil {
- return arvados.APIClientAuthorization{}, err
- }
- target, err := url.Parse(resp.RedirectLocation)
- if err != nil {
- return arvados.APIClientAuthorization{}, err
- }
- return arvados.APIClientAuthorization{APIToken: target.Query().Get("api_token")}, err
}