mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 09:35:07 +01:00 
			
		
		
		
	Merge branch '189-refactor-authentication-module' of https://github.com/ClusterCockpit/cc-backend into 189-refactor-authentication-module
This commit is contained in:
		@@ -211,10 +211,7 @@ func main() {
 | 
			
		||||
	var authentication *auth.Authentication
 | 
			
		||||
	if !config.Keys.DisableAuthentication {
 | 
			
		||||
		var err error
 | 
			
		||||
		if authentication, err = auth.Init(map[string]interface{}{
 | 
			
		||||
			"ldap": config.Keys.LdapConfig,
 | 
			
		||||
			"jwt":  config.Keys.JwtConfig,
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
		if authentication, err = auth.Init(); err != nil {
 | 
			
		||||
			log.Fatalf("auth initialization failed: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/repository"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
			
		||||
@@ -21,7 +22,6 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Authenticator interface {
 | 
			
		||||
	Init(config interface{}) error
 | 
			
		||||
	CanLogin(user *schema.User, username string, rw http.ResponseWriter, r *http.Request) (*schema.User, bool)
 | 
			
		||||
	Login(user *schema.User, rw http.ResponseWriter, r *http.Request) (*schema.User, error)
 | 
			
		||||
}
 | 
			
		||||
@@ -80,7 +80,7 @@ func (auth *Authentication) AuthViaSession(
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Init(configs map[string]interface{}) (*Authentication, error) {
 | 
			
		||||
func Init() (*Authentication, error) {
 | 
			
		||||
	auth := &Authentication{}
 | 
			
		||||
 | 
			
		||||
	sessKey := os.Getenv("SESSION_KEY")
 | 
			
		||||
@@ -101,9 +101,9 @@ func Init(configs map[string]interface{}) (*Authentication, error) {
 | 
			
		||||
		auth.sessionStore = sessions.NewCookieStore(bytes)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if config, ok := configs["ldap"]; ok {
 | 
			
		||||
	if config.Keys.LdapConfig != nil {
 | 
			
		||||
		ldapAuth := &LdapAuthenticator{}
 | 
			
		||||
		if err := ldapAuth.Init(config); err != nil {
 | 
			
		||||
		if err := ldapAuth.Init(); err != nil {
 | 
			
		||||
			log.Warn("Error while initializing authentication -> ldapAuth init failed")
 | 
			
		||||
		} else {
 | 
			
		||||
			auth.LdapAuth = ldapAuth
 | 
			
		||||
@@ -113,32 +113,32 @@ func Init(configs map[string]interface{}) (*Authentication, error) {
 | 
			
		||||
		log.Info("Missing LDAP configuration: No LDAP support!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if config, ok := configs["jwt"]; ok {
 | 
			
		||||
	if config.Keys.JwtConfig != nil {
 | 
			
		||||
		auth.JwtAuth = &JWTAuthenticator{}
 | 
			
		||||
		if err := auth.JwtAuth.Init(config); err != nil {
 | 
			
		||||
		if err := auth.JwtAuth.Init(); err != nil {
 | 
			
		||||
			log.Error("Error while initializing authentication -> jwtAuth init failed")
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		jwtSessionAuth := &JWTSessionAuthenticator{}
 | 
			
		||||
		if err := jwtSessionAuth.Init(config); err != nil {
 | 
			
		||||
			log.Warn("Error while initializing authentication -> jwtSessionAuth init failed")
 | 
			
		||||
		if err := jwtSessionAuth.Init(); err != nil {
 | 
			
		||||
			log.Info("jwtSessionAuth init failed: No JWT login support!")
 | 
			
		||||
		} else {
 | 
			
		||||
			auth.authenticators = append(auth.authenticators, jwtSessionAuth)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		jwtCookieSessionAuth := &JWTCookieSessionAuthenticator{}
 | 
			
		||||
		if err := jwtCookieSessionAuth.Init(configs["jwt"]); err != nil {
 | 
			
		||||
			log.Warn("Error while initializing authentication -> jwtCookieSessionAuth init failed")
 | 
			
		||||
		if err := jwtCookieSessionAuth.Init(); err != nil {
 | 
			
		||||
			log.Info("jwtCookieSessionAuth init failed: No JWT cookie login support!")
 | 
			
		||||
		} else {
 | 
			
		||||
			auth.authenticators = append(auth.authenticators, jwtCookieSessionAuth)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Info("Missing JWT configuration: No JWT token login support!")
 | 
			
		||||
		log.Info("Missing JWT configuration: No JWT token support!")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auth.LocalAuth = &LocalAuthenticator{}
 | 
			
		||||
	if err := auth.LocalAuth.Init(nil); err != nil {
 | 
			
		||||
	if err := auth.LocalAuth.Init(); err != nil {
 | 
			
		||||
		log.Error("Error while initializing authentication -> localAuth init failed")
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -152,11 +152,11 @@ func (auth *Authentication) Login(
 | 
			
		||||
	onfailure func(rw http.ResponseWriter, r *http.Request, loginErr error)) http.Handler {
 | 
			
		||||
 | 
			
		||||
	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		err := errors.New("no authenticator applied")
 | 
			
		||||
		username := r.FormValue("username")
 | 
			
		||||
		var dbUser *schema.User
 | 
			
		||||
 | 
			
		||||
		if username != "" {
 | 
			
		||||
			var err error
 | 
			
		||||
			dbUser, err = repository.GetUserRepository().GetUser(username)
 | 
			
		||||
			if err != nil && err != sql.ErrNoRows {
 | 
			
		||||
				log.Errorf("Error while loading user '%v'", username)
 | 
			
		||||
@@ -170,7 +170,7 @@ func (auth *Authentication) Login(
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			user, err = authenticator.Login(user, rw, r)
 | 
			
		||||
			user, err := authenticator.Login(user, rw, r)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Warnf("user login failed: %s", err.Error())
 | 
			
		||||
				onfailure(rw, r, err)
 | 
			
		||||
@@ -203,7 +203,7 @@ func (auth *Authentication) Login(
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log.Debugf("login failed: no authenticator applied")
 | 
			
		||||
		onfailure(rw, r, err)
 | 
			
		||||
		onfailure(rw, r, errors.New("no authenticator applied"))
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/repository"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
			
		||||
@@ -22,12 +23,9 @@ import (
 | 
			
		||||
type JWTAuthenticator struct {
 | 
			
		||||
	publicKey  ed25519.PublicKey
 | 
			
		||||
	privateKey ed25519.PrivateKey
 | 
			
		||||
	config     *schema.JWTAuthConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ja *JWTAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
	ja.config = conf.(*schema.JWTAuthConfig)
 | 
			
		||||
 | 
			
		||||
func (ja *JWTAuthenticator) Init() error {
 | 
			
		||||
	pubKey, privKey := os.Getenv("JWT_PUBLIC_KEY"), os.Getenv("JWT_PRIVATE_KEY")
 | 
			
		||||
	if pubKey == "" || privKey == "" {
 | 
			
		||||
		log.Warn("environment variables 'JWT_PUBLIC_KEY' or 'JWT_PRIVATE_KEY' not set (token based authentication will not work)")
 | 
			
		||||
@@ -87,7 +85,7 @@ func (ja *JWTAuthenticator) AuthViaJWT(
 | 
			
		||||
	var roles []string
 | 
			
		||||
 | 
			
		||||
	// Validate user + roles from JWT against database?
 | 
			
		||||
	if ja.config != nil && ja.config.ValidateUser {
 | 
			
		||||
	if config.Keys.JwtConfig.ValidateUser {
 | 
			
		||||
		ur := repository.GetUserRepository()
 | 
			
		||||
		user, err := ur.GetUser(sub)
 | 
			
		||||
 | 
			
		||||
@@ -130,8 +128,8 @@ func (ja *JWTAuthenticator) ProvideJWT(user *schema.User) (string, error) {
 | 
			
		||||
		"roles": user.Roles,
 | 
			
		||||
		"iat":   now.Unix(),
 | 
			
		||||
	}
 | 
			
		||||
	if ja.config != nil && ja.config.MaxAge != "" {
 | 
			
		||||
		d, err := time.ParseDuration(ja.config.MaxAge)
 | 
			
		||||
	if config.Keys.JwtConfig.MaxAge != "" {
 | 
			
		||||
		d, err := time.ParseDuration(config.Keys.JwtConfig.MaxAge)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", errors.New("cannot parse max-age config key")
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/repository"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
			
		||||
@@ -22,15 +23,11 @@ type JWTCookieSessionAuthenticator struct {
 | 
			
		||||
	publicKey           ed25519.PublicKey
 | 
			
		||||
	privateKey          ed25519.PrivateKey
 | 
			
		||||
	publicKeyCrossLogin ed25519.PublicKey // For accepting externally generated JWTs
 | 
			
		||||
 | 
			
		||||
	config *schema.JWTAuthConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Authenticator = (*JWTCookieSessionAuthenticator)(nil)
 | 
			
		||||
 | 
			
		||||
func (ja *JWTCookieSessionAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
	ja.config = conf.(*schema.JWTAuthConfig)
 | 
			
		||||
 | 
			
		||||
func (ja *JWTCookieSessionAuthenticator) Init() error {
 | 
			
		||||
	pubKey, privKey := os.Getenv("JWT_PUBLIC_KEY"), os.Getenv("JWT_PRIVATE_KEY")
 | 
			
		||||
	if pubKey == "" || privKey == "" {
 | 
			
		||||
		log.Warn("environment variables 'JWT_PUBLIC_KEY' or 'JWT_PRIVATE_KEY' not set (token based authentication will not work)")
 | 
			
		||||
@@ -65,17 +62,18 @@ func (ja *JWTCookieSessionAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
		return errors.New("environment variable 'CROSS_LOGIN_JWT_PUBLIC_KEY' not set (cross login token based authentication will not work)")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	jc := config.Keys.JwtConfig
 | 
			
		||||
	// Warn if other necessary settings are not configured
 | 
			
		||||
	if ja.config != nil {
 | 
			
		||||
		if ja.config.CookieName == "" {
 | 
			
		||||
			log.Warn("cookieName for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
	if jc != nil {
 | 
			
		||||
		if jc.CookieName == "" {
 | 
			
		||||
			log.Info("cookieName for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
			return errors.New("cookieName for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
		}
 | 
			
		||||
		if !ja.config.ValidateUser {
 | 
			
		||||
			log.Warn("forceJWTValidationViaDatabase not set to true: CC will accept users and roles defined in JWTs regardless of its own database!")
 | 
			
		||||
		if !jc.ValidateUser {
 | 
			
		||||
			log.Info("forceJWTValidationViaDatabase not set to true: CC will accept users and roles defined in JWTs regardless of its own database!")
 | 
			
		||||
		}
 | 
			
		||||
		if ja.config.TrustedIssuer == "" {
 | 
			
		||||
			log.Warn("trustedExternalIssuer for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
		if jc.TrustedIssuer == "" {
 | 
			
		||||
			log.Info("trustedExternalIssuer for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
			return errors.New("trustedExternalIssuer for JWTs not configured (cross login via JWT cookie will fail)")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -93,9 +91,10 @@ func (ja *JWTCookieSessionAuthenticator) CanLogin(
 | 
			
		||||
	rw http.ResponseWriter,
 | 
			
		||||
	r *http.Request) (*schema.User, bool) {
 | 
			
		||||
 | 
			
		||||
	jc := config.Keys.JwtConfig
 | 
			
		||||
	cookieName := ""
 | 
			
		||||
	if ja.config != nil && ja.config.CookieName != "" {
 | 
			
		||||
		cookieName = ja.config.CookieName
 | 
			
		||||
	if jc.CookieName != "" {
 | 
			
		||||
		cookieName = jc.CookieName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Try to read the JWT cookie
 | 
			
		||||
@@ -115,7 +114,8 @@ func (ja *JWTCookieSessionAuthenticator) Login(
 | 
			
		||||
	rw http.ResponseWriter,
 | 
			
		||||
	r *http.Request) (*schema.User, error) {
 | 
			
		||||
 | 
			
		||||
	jwtCookie, err := r.Cookie(ja.config.CookieName)
 | 
			
		||||
	jc := config.Keys.JwtConfig
 | 
			
		||||
	jwtCookie, err := r.Cookie(jc.CookieName)
 | 
			
		||||
	var rawtoken string
 | 
			
		||||
 | 
			
		||||
	if err == nil && jwtCookie.Value != "" {
 | 
			
		||||
@@ -128,7 +128,7 @@ func (ja *JWTCookieSessionAuthenticator) Login(
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		unvalidatedIssuer, success := t.Claims.(jwt.MapClaims)["iss"].(string)
 | 
			
		||||
		if success && unvalidatedIssuer == ja.config.TrustedIssuer {
 | 
			
		||||
		if success && unvalidatedIssuer == jc.TrustedIssuer {
 | 
			
		||||
			// The (unvalidated) issuer seems to be the expected one,
 | 
			
		||||
			// use public cross login key from config
 | 
			
		||||
			return ja.publicKeyCrossLogin, nil
 | 
			
		||||
@@ -167,7 +167,7 @@ func (ja *JWTCookieSessionAuthenticator) Login(
 | 
			
		||||
 | 
			
		||||
	var roles []string
 | 
			
		||||
 | 
			
		||||
	if ja.config.ValidateUser {
 | 
			
		||||
	if jc.ValidateUser {
 | 
			
		||||
		// Deny any logins for unknown usernames
 | 
			
		||||
		if user == nil {
 | 
			
		||||
			log.Warn("Could not find user from JWT in internal database.")
 | 
			
		||||
@@ -189,7 +189,7 @@ func (ja *JWTCookieSessionAuthenticator) Login(
 | 
			
		||||
 | 
			
		||||
	// (Ask browser to) Delete JWT cookie
 | 
			
		||||
	deletedCookie := &http.Cookie{
 | 
			
		||||
		Name:     ja.config.CookieName,
 | 
			
		||||
		Name:     jc.CookieName,
 | 
			
		||||
		Value:    "",
 | 
			
		||||
		Path:     "/",
 | 
			
		||||
		MaxAge:   -1,
 | 
			
		||||
@@ -208,7 +208,7 @@ func (ja *JWTCookieSessionAuthenticator) Login(
 | 
			
		||||
			AuthSource: schema.AuthViaToken,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ja.config.SyncUserOnLogin {
 | 
			
		||||
		if jc.SyncUserOnLogin {
 | 
			
		||||
			if err := repository.GetUserRepository().AddUser(user); err != nil {
 | 
			
		||||
				log.Errorf("Error while adding user '%s' to DB", user.Username)
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/repository"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
			
		||||
@@ -20,15 +21,11 @@ import (
 | 
			
		||||
 | 
			
		||||
type JWTSessionAuthenticator struct {
 | 
			
		||||
	loginTokenKey []byte // HS256 key
 | 
			
		||||
 | 
			
		||||
	config *schema.JWTAuthConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Authenticator = (*JWTSessionAuthenticator)(nil)
 | 
			
		||||
 | 
			
		||||
func (ja *JWTSessionAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
	ja.config = conf.(*schema.JWTAuthConfig)
 | 
			
		||||
 | 
			
		||||
func (ja *JWTSessionAuthenticator) Init() error {
 | 
			
		||||
	if pubKey := os.Getenv("CROSS_LOGIN_JWT_HS512_KEY"); pubKey != "" {
 | 
			
		||||
		bytes, err := base64.StdEncoding.DecodeString(pubKey)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -96,7 +93,7 @@ func (ja *JWTSessionAuthenticator) Login(
 | 
			
		||||
 | 
			
		||||
	var roles []string
 | 
			
		||||
 | 
			
		||||
	if ja.config.ValidateUser {
 | 
			
		||||
	if config.Keys.JwtConfig.ValidateUser {
 | 
			
		||||
		// Deny any logins for unknown usernames
 | 
			
		||||
		if user == nil {
 | 
			
		||||
			log.Warn("Could not find user from JWT in internal database.")
 | 
			
		||||
@@ -142,7 +139,7 @@ func (ja *JWTSessionAuthenticator) Login(
 | 
			
		||||
			AuthSource: schema.AuthViaToken,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ja.config.SyncUserOnLogin {
 | 
			
		||||
		if config.Keys.JwtConfig.SyncUserOnLogin {
 | 
			
		||||
			if err := repository.GetUserRepository().AddUser(user); err != nil {
 | 
			
		||||
				log.Errorf("Error while adding user '%s' to DB", user.Username)
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/internal/repository"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
			
		||||
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
			
		||||
@@ -19,25 +20,22 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LdapAuthenticator struct {
 | 
			
		||||
	config       *schema.LdapConfig
 | 
			
		||||
	syncPassword string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ Authenticator = (*LdapAuthenticator)(nil)
 | 
			
		||||
 | 
			
		||||
func (la *LdapAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
 | 
			
		||||
	la.config = conf.(*schema.LdapConfig)
 | 
			
		||||
 | 
			
		||||
func (la *LdapAuthenticator) Init() error {
 | 
			
		||||
	la.syncPassword = os.Getenv("LDAP_ADMIN_PASSWORD")
 | 
			
		||||
	if la.syncPassword == "" {
 | 
			
		||||
		log.Warn("environment variable 'LDAP_ADMIN_PASSWORD' not set (ldap sync will not work)")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if la.config != nil && la.config.SyncInterval != "" {
 | 
			
		||||
		interval, err := time.ParseDuration(la.config.SyncInterval)
 | 
			
		||||
	if config.Keys.LdapConfig.SyncInterval != "" {
 | 
			
		||||
		interval, err := time.ParseDuration(config.Keys.LdapConfig.SyncInterval)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Warnf("Could not parse duration for sync interval: %v", la.config.SyncInterval)
 | 
			
		||||
			log.Warnf("Could not parse duration for sync interval: %v",
 | 
			
		||||
				config.Keys.LdapConfig.SyncInterval)
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +55,7 @@ func (la *LdapAuthenticator) Init(conf interface{}) error {
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Info("Missing LDAP configuration key sync_interval")
 | 
			
		||||
		log.Info("LDAP configuration key sync_interval invalid")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -69,12 +67,14 @@ func (la *LdapAuthenticator) CanLogin(
 | 
			
		||||
	rw http.ResponseWriter,
 | 
			
		||||
	r *http.Request) (*schema.User, bool) {
 | 
			
		||||
 | 
			
		||||
	lc := config.Keys.LdapConfig
 | 
			
		||||
 | 
			
		||||
	if user != nil {
 | 
			
		||||
		if user.AuthSource == schema.AuthViaLDAP {
 | 
			
		||||
			return user, true
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if la.config.SyncUserOnLogin {
 | 
			
		||||
		if lc.SyncUserOnLogin {
 | 
			
		||||
			l, err := la.getLdapConnection(true)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Error("LDAP connection error")
 | 
			
		||||
@@ -83,9 +83,9 @@ func (la *LdapAuthenticator) CanLogin(
 | 
			
		||||
 | 
			
		||||
			// Search for the given username
 | 
			
		||||
			searchRequest := ldap.NewSearchRequest(
 | 
			
		||||
				la.config.UserBase,
 | 
			
		||||
				lc.UserBase,
 | 
			
		||||
				ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
 | 
			
		||||
				fmt.Sprintf("(&%s(uid=%s))", la.config.UserFilter, username),
 | 
			
		||||
				fmt.Sprintf("(&%s(uid=%s))", lc.UserFilter, username),
 | 
			
		||||
				[]string{"dn", "uid", "gecos"}, nil)
 | 
			
		||||
 | 
			
		||||
			sr, err := l.Search(searchRequest)
 | 
			
		||||
@@ -138,7 +138,7 @@ func (la *LdapAuthenticator) Login(
 | 
			
		||||
	}
 | 
			
		||||
	defer l.Close()
 | 
			
		||||
 | 
			
		||||
	userDn := strings.Replace(la.config.UserBind, "{username}", user.Username, -1)
 | 
			
		||||
	userDn := strings.Replace(config.Keys.LdapConfig.UserBind, "{username}", user.Username, -1)
 | 
			
		||||
	if err := l.Bind(userDn, r.FormValue("password")); err != nil {
 | 
			
		||||
		log.Errorf("AUTH/LDAP > Authentication for user %s failed: %v",
 | 
			
		||||
			user.Username, err)
 | 
			
		||||
@@ -153,6 +153,7 @@ func (la *LdapAuthenticator) Sync() error {
 | 
			
		||||
	const IN_LDAP int = 2
 | 
			
		||||
	const IN_BOTH int = 3
 | 
			
		||||
	ur := repository.GetUserRepository()
 | 
			
		||||
	lc := config.Keys.LdapConfig
 | 
			
		||||
 | 
			
		||||
	users := map[string]int{}
 | 
			
		||||
	usernames, err := ur.GetLdapUsernames()
 | 
			
		||||
@@ -172,9 +173,9 @@ func (la *LdapAuthenticator) Sync() error {
 | 
			
		||||
	defer l.Close()
 | 
			
		||||
 | 
			
		||||
	ldapResults, err := l.Search(ldap.NewSearchRequest(
 | 
			
		||||
		la.config.UserBase,
 | 
			
		||||
		lc.UserBase,
 | 
			
		||||
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
 | 
			
		||||
		la.config.UserFilter,
 | 
			
		||||
		lc.UserFilter,
 | 
			
		||||
		[]string{"dn", "uid", "gecos"}, nil))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("LDAP search error")
 | 
			
		||||
@@ -198,7 +199,7 @@ func (la *LdapAuthenticator) Sync() error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for username, where := range users {
 | 
			
		||||
		if where == IN_DB && la.config.SyncDelOldUsers {
 | 
			
		||||
		if where == IN_DB && lc.SyncDelOldUsers {
 | 
			
		||||
			ur.DelUser(username)
 | 
			
		||||
			log.Debugf("sync: remove %v (does not show up in LDAP anymore)", username)
 | 
			
		||||
		} else if where == IN_LDAP {
 | 
			
		||||
@@ -231,14 +232,15 @@ func (la *LdapAuthenticator) Sync() error {
 | 
			
		||||
// that so that connections can be reused/cached.
 | 
			
		||||
func (la *LdapAuthenticator) getLdapConnection(admin bool) (*ldap.Conn, error) {
 | 
			
		||||
 | 
			
		||||
	conn, err := ldap.DialURL(la.config.Url)
 | 
			
		||||
	lc := config.Keys.LdapConfig
 | 
			
		||||
	conn, err := ldap.DialURL(lc.Url)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("LDAP URL dial failed")
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if admin {
 | 
			
		||||
		if err := conn.Bind(la.config.SearchDN, la.syncPassword); err != nil {
 | 
			
		||||
		if err := conn.Bind(lc.SearchDN, la.syncPassword); err != nil {
 | 
			
		||||
			conn.Close()
 | 
			
		||||
			log.Warn("LDAP connection bind failed")
 | 
			
		||||
			return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,7 @@ type LocalAuthenticator struct {
 | 
			
		||||
 | 
			
		||||
var _ Authenticator = (*LocalAuthenticator)(nil)
 | 
			
		||||
 | 
			
		||||
func (la *LocalAuthenticator) Init(
 | 
			
		||||
	_ interface{}) error {
 | 
			
		||||
 | 
			
		||||
func (la *LocalAuthenticator) Init() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ var Keys schema.ProgramConfig = schema.ProgramConfig{
 | 
			
		||||
	Archive:                   json.RawMessage(`{\"kind\":\"file\",\"path\":\"./var/job-archive\"}`),
 | 
			
		||||
	DisableArchive:            false,
 | 
			
		||||
	Validate:                  false,
 | 
			
		||||
	LdapConfig:                nil,
 | 
			
		||||
	SessionMaxAge:             "168h",
 | 
			
		||||
	StopJobsExceedingWalltime: 0,
 | 
			
		||||
	ShortRunningJobsDuration:  5 * 60,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user