diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 8da45da..b10c3bd 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -102,7 +102,7 @@ func Init(configs map[string]interface{}) (*Authentication, error) { } auth.JwtAuth = &JWTAuthenticator{} - if err := auth.JwtAuth.Init(configs["jwt"]); err != nil { + if err := auth.JwtAuth.Init(); err != nil { log.Error("Error while initializing authentication -> jwtAuth init failed") return nil, err } @@ -115,20 +115,26 @@ func Init(configs map[string]interface{}) (*Authentication, error) { auth.LdapAuth = ldapAuth auth.authenticators = append(auth.authenticators, auth.LdapAuth) } + } else { + log.Info("Missing LDAP configuration: No LDAP support!") } - jwtSessionAuth := &JWTSessionAuthenticator{} - if err := jwtSessionAuth.Init(configs["jwt"]); err != nil { - log.Warn("Error while initializing authentication -> jwtSessionAuth init failed") - } else { - auth.authenticators = append(auth.authenticators, jwtSessionAuth) - } + if config, ok := configs["jwt"]; ok { + jwtSessionAuth := &JWTSessionAuthenticator{} + if err := jwtSessionAuth.Init(config); err != nil { + log.Warn("Error while initializing authentication -> jwtSessionAuth init failed") + } 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") + jwtCookieSessionAuth := &JWTCookieSessionAuthenticator{} + if err := jwtCookieSessionAuth.Init(configs["jwt"]); err != nil { + log.Warn("Error while initializing authentication -> jwtCookieSessionAuth init failed") + } else { + auth.authenticators = append(auth.authenticators, jwtCookieSessionAuth) + } } else { - auth.authenticators = append(auth.authenticators, jwtCookieSessionAuth) + log.Info("Missing JWT configuration: No JWT token login support!") } auth.LocalAuth = &LocalAuthenticator{} diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index 9c0166d..4a1e4b8 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -22,12 +22,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)") diff --git a/internal/auth/jwtCookieSession.go b/internal/auth/jwtCookieSession.go index 42ebcd2..9dcba57 100644 --- a/internal/auth/jwtCookieSession.go +++ b/internal/auth/jwtCookieSession.go @@ -8,6 +8,7 @@ import ( "crypto/ed25519" "encoding/base64" "errors" + "fmt" "net/http" "os" @@ -82,6 +83,7 @@ func (ja *JWTCookieSessionAuthenticator) Init(conf interface{}) error { return errors.New("config for JWTs not configured (cross login via JWT cookie will fail)") } + log.Info("JWT Cookie Session authenticator successfully registered") return nil } @@ -137,7 +139,7 @@ func (ja *JWTCookieSessionAuthenticator) Login( return ja.publicKey, nil }) if err != nil { - log.Warn("error while parsing token") + log.Warn("JWT cookie session: error while parsing token") return nil, err } @@ -151,8 +153,16 @@ func (ja *JWTCookieSessionAuthenticator) Login( sub, _ := claims["sub"].(string) var name string - if val, ok := claims["name"]; ok { - name, _ = val.(string) + if wrap, ok := claims["name"].(map[string]interface{}); ok { + if vals, ok := wrap["values"].([]interface{}); ok { + if len(vals) != 0 { + name = fmt.Sprintf("%v", vals[0]) + + for i := 1; i < len(vals); i++ { + name += fmt.Sprintf(" %v", vals[i]) + } + } + } } var roles []string @@ -188,10 +198,12 @@ func (ja *JWTCookieSessionAuthenticator) Login( http.SetCookie(rw, deletedCookie) if user == nil { + projects := make([]string, 0) user = &schema.User{ Username: sub, Name: name, Roles: roles, + Projects: projects, AuthType: schema.AuthSession, AuthSource: schema.AuthViaToken, } diff --git a/internal/auth/jwtSession.go b/internal/auth/jwtSession.go index d9dce85..f68de90 100644 --- a/internal/auth/jwtSession.go +++ b/internal/auth/jwtSession.go @@ -6,6 +6,7 @@ package auth import ( "encoding/base64" + "errors" "fmt" "net/http" "os" @@ -37,6 +38,7 @@ func (ja *JWTSessionAuthenticator) Init(conf interface{}) error { ja.loginTokenKey = bytes } + log.Info("JWT Session authenticator successfully registered") return nil } @@ -46,7 +48,8 @@ func (ja *JWTSessionAuthenticator) CanLogin( rw http.ResponseWriter, r *http.Request) (*schema.User, bool) { - return user, r.Header.Get("Authorization") != "" || r.URL.Query().Get("login-token") != "" + return user, r.Header.Get("Authorization") != "" || + r.URL.Query().Get("login-token") != "" } func (ja *JWTSessionAuthenticator) Login( @@ -79,29 +82,38 @@ func (ja *JWTSessionAuthenticator) Login( sub, _ := claims["sub"].(string) var name string - // Java/Grails Issued Token if wrap, ok := claims["name"].(map[string]interface{}); ok { if vals, ok := wrap["values"].([]interface{}); ok { - name = fmt.Sprintf("%v %v", vals[0], vals[1]) - } - } else if val, ok := claims["name"]; ok { - name, _ = val.(string) - } + if len(vals) != 0 { + name = fmt.Sprintf("%v", vals[0]) - var roles []string - // Java/Grails Issued Token - if rawroles, ok := claims["roles"].([]interface{}); ok { - for _, rr := range rawroles { - if r, ok := rr.(string); ok { - if schema.IsValidRole(r) { - roles = append(roles, r) + for i := 1; i < len(vals); i++ { + name += fmt.Sprintf(" %v", vals[i]) } } } - } else if rawroles, ok := claims["roles"]; ok { - for _, r := range rawroles.([]string) { - if schema.IsValidRole(r) { - roles = append(roles, r) + } + + var roles []string + + if ja.config.ValidateUser { + // Deny any logins for unknown usernames + if user == nil { + log.Warn("Could not find user from JWT in internal database.") + return nil, errors.New("unknown user") + } + + // Take user roles from database instead of trusting the JWT + roles = user.Roles + } else { + // Extract roles from JWT (if present) + if rawroles, ok := claims["roles"].([]interface{}); ok { + for _, rr := range rawroles { + if r, ok := rr.(string); ok { + if schema.IsValidRole(r) { + roles = append(roles, r) + } + } } } } diff --git a/internal/auth/ldap.go b/internal/auth/ldap.go index a20e415..529179e 100644 --- a/internal/auth/ldap.go +++ b/internal/auth/ldap.go @@ -57,7 +57,7 @@ func (la *LdapAuthenticator) Init(conf interface{}) error { } }() } else { - return fmt.Errorf("missing LDAP configuration") + log.Info("Missing LDAP configuration key sync_interval") } return nil @@ -69,10 +69,12 @@ func (la *LdapAuthenticator) CanLogin( rw http.ResponseWriter, r *http.Request) (*schema.User, bool) { - if user != nil && user.AuthSource == schema.AuthViaLDAP { - return user, true + if user != nil { + if user.AuthSource == schema.AuthViaLDAP { + return user, true + } } else { - if la.config != nil && la.config.SyncUserOnLogin { + if la.config.SyncUserOnLogin { l, err := la.getLdapConnection(true) if err != nil { log.Error("LDAP connection error") @@ -89,12 +91,12 @@ func (la *LdapAuthenticator) CanLogin( sr, err := l.Search(searchRequest) if err != nil { log.Warn(err) - return user, false + return nil, false } if len(sr.Entries) != 1 { - log.Warn("User does not exist or too many entries returned") - return user, false + log.Warn("LDAP: User does not exist or too many entries returned") + return nil, false } entry := sr.Entries[0] @@ -117,12 +119,6 @@ func (la *LdapAuthenticator) CanLogin( return nil, false } - // if _, err := la.auth.db.Exec(`INSERT INTO user (username, ldap, name, roles) VALUES (?, ?, ?, ?)`, - // username, 1, name, "[\""+schema.GetRoleString(schema.RoleUser)+"\"]"); err != nil { - // log.Errorf("User '%s' new in LDAP: Insert into DB failed", username) - // return false - // } - return user, true } } @@ -144,7 +140,8 @@ func (la *LdapAuthenticator) Login( userDn := strings.Replace(la.config.UserBind, "{username}", user.Username, -1) if err := l.Bind(userDn, r.FormValue("password")); err != nil { - log.Errorf("AUTH/LOCAL > Authentication for user %s failed: %v", user.Username, err) + log.Errorf("AUTH/LOCAL > Authentication for user %s failed: %v", + user.Username, err) return nil, fmt.Errorf("AUTH/LDAP > Authentication failed") }