mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-22 23:51:27 +01:00
Refactor ldap
Changes include: 1. Use Session to manage the lifecycle of ldap connections 2. Abstract common AuthenticateHelper interface for db_auth, ldap_auth, uaa_auth mode
This commit is contained in:
parent
6f4e27ef73
commit
ec67974104
@ -15,15 +15,13 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
@ -31,77 +29,68 @@ import (
|
||||
goldap "gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
// GetSystemLdapConf ...
|
||||
func GetSystemLdapConf() (models.LdapConf, error) {
|
||||
var err error
|
||||
var ldapConfs models.LdapConf
|
||||
var authMode string
|
||||
//Session - define a LDAP session
|
||||
type Session struct {
|
||||
ldapConfig models.LdapConf
|
||||
ldapConn *goldap.Conn
|
||||
}
|
||||
|
||||
authMode, err = config.AuthMode()
|
||||
//LoadSystemLdapConfig - load LDAP configure from adminserver
|
||||
func LoadSystemLdapConfig() (*Session, error) {
|
||||
var session Session
|
||||
|
||||
authMode, err := config.AuthMode()
|
||||
if err != nil {
|
||||
log.Errorf("can't load auth mode from system, error: %v", err)
|
||||
return ldapConfs, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if authMode != "ldap_auth" {
|
||||
return ldapConfs, fmt.Errorf("system auth_mode isn't ldap_auth, please check configuration")
|
||||
return nil, fmt.Errorf("system auth_mode isn't ldap_auth, please check configuration")
|
||||
}
|
||||
|
||||
ldap, err := config.LDAP()
|
||||
|
||||
if err != nil {
|
||||
return ldapConfs, err
|
||||
return nil, err
|
||||
}
|
||||
if ldap.URL == "" {
|
||||
return nil, fmt.Errorf("can not get any available LDAP_URL")
|
||||
}
|
||||
|
||||
ldapConfs.LdapURL = ldap.URL
|
||||
ldapConfs.LdapSearchDn = ldap.SearchDN
|
||||
ldapConfs.LdapSearchPassword = ldap.SearchPassword
|
||||
ldapConfs.LdapBaseDn = ldap.BaseDN
|
||||
ldapConfs.LdapFilter = ldap.Filter
|
||||
ldapConfs.LdapUID = ldap.UID
|
||||
ldapConfs.LdapScope = ldap.Scope
|
||||
ldapConfs.LdapConnectionTimeout = ldap.Timeout
|
||||
ldapConfs.LdapVerifyCert = ldap.VerifyCert
|
||||
ldapURL, err := formatURL(ldap.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ldapConfs = config.LDAP().URL
|
||||
// ldapConfs.LdapSearchDn = config.LDAP().SearchDn
|
||||
// ldapConfs.LdapSearchPassword = config.LDAP().SearchPwd
|
||||
// ldapConfs.LdapBaseDn = config.LDAP().BaseDn
|
||||
// ldapConfs.LdapFilter = config.LDAP().Filter
|
||||
// ldapConfs.LdapUID = config.LDAP().UID
|
||||
// ldapConfs.LdapScope, err = strconv.Atoi(config.LDAP().Scope)
|
||||
// if err != nil {
|
||||
// log.Errorf("invalid LdapScope format from system, error: %v", err)
|
||||
// return ldapConfs, err
|
||||
// }
|
||||
session.ldapConfig.LdapURL = ldapURL
|
||||
session.ldapConfig.LdapSearchDn = ldap.SearchDN
|
||||
session.ldapConfig.LdapSearchPassword = ldap.SearchPassword
|
||||
session.ldapConfig.LdapBaseDn = ldap.BaseDN
|
||||
session.ldapConfig.LdapFilter = ldap.Filter
|
||||
session.ldapConfig.LdapUID = ldap.UID
|
||||
session.ldapConfig.LdapConnectionTimeout = ldap.Timeout
|
||||
session.ldapConfig.LdapVerifyCert = ldap.VerifyCert
|
||||
log.Debugf("Load system configuration: %v", ldap)
|
||||
|
||||
// ldapConfs.LdapConnectionTimeout, err = strconv.Atoi(config.LDAP().ConnectTimeout)
|
||||
// if err != nil {
|
||||
// log.Errorf("invalid LdapConnectionTimeout format from system, error: %v", err)
|
||||
// return ldapConfs, err
|
||||
// }
|
||||
|
||||
return ldapConfs, nil
|
||||
switch ldap.Scope {
|
||||
case 1:
|
||||
session.ldapConfig.LdapScope = goldap.ScopeBaseObject
|
||||
case 2:
|
||||
session.ldapConfig.LdapScope = goldap.ScopeSingleLevel
|
||||
case 3:
|
||||
session.ldapConfig.LdapScope = goldap.ScopeWholeSubtree
|
||||
default:
|
||||
log.Errorf("invalid ldap search scope %v", ldap.Scope)
|
||||
return nil, fmt.Errorf("invalid ldap search scope")
|
||||
}
|
||||
|
||||
return &session, nil
|
||||
}
|
||||
|
||||
// ValidateLdapConf ...
|
||||
func ValidateLdapConf(ldapConfs models.LdapConf) (models.LdapConf, error) {
|
||||
var err error
|
||||
// CreateWithUIConfig - create a Session with config from UI
|
||||
func CreateWithUIConfig(ldapConfs models.LdapConf) (*Session, error) {
|
||||
|
||||
if ldapConfs.LdapURL == "" {
|
||||
return ldapConfs, fmt.Errorf("can not get any available LDAP_URL")
|
||||
}
|
||||
|
||||
ldapConfs.LdapURL, err = formatLdapURL(ldapConfs.LdapURL)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("invalid LdapURL format, error: %v", err)
|
||||
return ldapConfs, err
|
||||
}
|
||||
|
||||
// Compatible with legacy codes
|
||||
// in previous harbor.cfg:
|
||||
// the scope to search for users, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE
|
||||
switch ldapConfs.LdapScope {
|
||||
case 1:
|
||||
ldapConfs.LdapScope = goldap.ScopeBaseObject
|
||||
@ -110,131 +99,44 @@ func ValidateLdapConf(ldapConfs models.LdapConf) (models.LdapConf, error) {
|
||||
case 3:
|
||||
ldapConfs.LdapScope = goldap.ScopeWholeSubtree
|
||||
default:
|
||||
return ldapConfs, fmt.Errorf("invalid ldap search scope")
|
||||
return nil, fmt.Errorf("invalid ldap search scope")
|
||||
}
|
||||
|
||||
// value := reflect.ValueOf(ldapConfs)
|
||||
// lType := reflect.TypeOf(ldapConfs)
|
||||
// for i := 0; i < value.NumField(); i++ {
|
||||
// fmt.Printf("Field %d: %v %v\n", i, value.Field(i), lType.Field(i).Name)
|
||||
// }
|
||||
|
||||
return ldapConfs, nil
|
||||
|
||||
return createWithInternalConfig(ldapConfs)
|
||||
}
|
||||
|
||||
// MakeFilter ...
|
||||
func MakeFilter(username string, ldapFilter string, ldapUID string) string {
|
||||
// createWithInternalConfig - create a Session with internal config
|
||||
func createWithInternalConfig(ldapConfs models.LdapConf) (*Session, error) {
|
||||
|
||||
var filterTag string
|
||||
var session Session
|
||||
|
||||
if username == "" {
|
||||
filterTag = "*"
|
||||
} else {
|
||||
filterTag = username
|
||||
if ldapConfs.LdapURL == "" {
|
||||
return nil, fmt.Errorf("can not get any available LDAP_URL")
|
||||
}
|
||||
|
||||
if ldapFilter == "" {
|
||||
ldapFilter = "(" + ldapUID + "=" + filterTag + ")"
|
||||
} else {
|
||||
if !strings.Contains(ldapFilter, ldapUID+"=") {
|
||||
ldapFilter = "(&" + ldapFilter + "(" + ldapUID + "=" + filterTag + "))"
|
||||
} else {
|
||||
ldapFilter = strings.Replace(ldapFilter, ldapUID+"=*", ldapUID+"="+filterTag, -1)
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("one or more ldapFilter: ", ldapFilter)
|
||||
|
||||
return ldapFilter
|
||||
}
|
||||
|
||||
// ConnectTest ...
|
||||
func ConnectTest(ldapConfs models.LdapConf) error {
|
||||
|
||||
var ldapConn *goldap.Conn
|
||||
var err error
|
||||
|
||||
ldapConn, err = dialLDAP(ldapConfs)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ldapConn.Close()
|
||||
|
||||
if ldapConfs.LdapSearchDn != "" {
|
||||
err = bindLDAPSearchDN(ldapConfs, ldapConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// SearchUser ...
|
||||
func SearchUser(ldapConfs models.LdapConf) ([]models.LdapUser, error) {
|
||||
var ldapUsers []models.LdapUser
|
||||
var ldapConn *goldap.Conn
|
||||
var err error
|
||||
|
||||
ldapConn, err = dialLDAP(ldapConfs)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ldapConn.Close()
|
||||
|
||||
if ldapConfs.LdapSearchDn != "" {
|
||||
err = bindLDAPSearchDN(ldapConfs, ldapConn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if ldapConfs.LdapBaseDn == "" {
|
||||
return nil, fmt.Errorf("can not get any available LDAP_BASE_DN")
|
||||
}
|
||||
|
||||
result, err := searchLDAP(ldapConfs, ldapConn)
|
||||
|
||||
ldapURL, err := formatURL(ldapConfs.LdapURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ldapEntry := range result.Entries {
|
||||
var u models.LdapUser
|
||||
for _, attr := range ldapEntry.Attributes {
|
||||
//OpenLDAP sometimes contains leading space in username
|
||||
val := strings.TrimSpace(attr.Values[0])
|
||||
log.Debugf("Current ldap entry attr name: %s\n", attr.Name)
|
||||
switch strings.ToLower(attr.Name) {
|
||||
case strings.ToLower(ldapConfs.LdapUID):
|
||||
u.Username = val
|
||||
case "uid":
|
||||
u.Realname = val
|
||||
case "cn":
|
||||
u.Realname = val
|
||||
case "mail":
|
||||
u.Email = val
|
||||
case "email":
|
||||
u.Email = val
|
||||
}
|
||||
}
|
||||
u.DN = ldapEntry.DN
|
||||
ldapUsers = append(ldapUsers, u)
|
||||
}
|
||||
session.ldapConfig.LdapURL = ldapURL
|
||||
session.ldapConfig.LdapSearchDn = ldapConfs.LdapSearchDn
|
||||
session.ldapConfig.LdapSearchPassword = ldapConfs.LdapSearchPassword
|
||||
session.ldapConfig.LdapBaseDn = ldapConfs.LdapBaseDn
|
||||
session.ldapConfig.LdapFilter = ldapConfs.LdapFilter
|
||||
session.ldapConfig.LdapUID = ldapConfs.LdapUID
|
||||
session.ldapConfig.LdapConnectionTimeout = ldapConfs.LdapConnectionTimeout
|
||||
session.ldapConfig.LdapVerifyCert = ldapConfs.LdapVerifyCert
|
||||
session.ldapConfig.LdapScope = ldapConfs.LdapScope
|
||||
return &session, nil
|
||||
|
||||
return ldapUsers, nil
|
||||
}
|
||||
|
||||
func formatLdapURL(ldapURL string) (string, error) {
|
||||
func formatURL(ldapURL string) (string, error) {
|
||||
|
||||
var protocol, hostport string
|
||||
var err error
|
||||
|
||||
_, err = url.Parse(ldapURL)
|
||||
_, err := url.Parse(ldapURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse Ldap Host ERR: %s", err)
|
||||
}
|
||||
@ -243,7 +145,7 @@ func formatLdapURL(ldapURL string) (string, error) {
|
||||
splitLdapURL := strings.Split(ldapURL, "://")
|
||||
protocol, hostport = splitLdapURL[0], splitLdapURL[1]
|
||||
if !((protocol == "ldap") || (protocol == "ldaps")) {
|
||||
return "", fmt.Errorf("unknown ldap protocl")
|
||||
return "", fmt.Errorf("unknown ldap protocol")
|
||||
}
|
||||
} else {
|
||||
hostport = ldapURL
|
||||
@ -275,128 +177,159 @@ func formatLdapURL(ldapURL string) (string, error) {
|
||||
|
||||
}
|
||||
|
||||
// ImportUser ...
|
||||
func ImportUser(user models.LdapUser) (int64, error) {
|
||||
var u models.User
|
||||
u.Username = user.Username
|
||||
u.Email = user.Email
|
||||
u.Realname = user.Realname
|
||||
|
||||
log.Debug("username:", u.Username, ",email:", u.Email)
|
||||
exist, err := dao.UserExists(u, "username")
|
||||
//ConnectionTest - test ldap session connection with system default setting
|
||||
func (session *Session) ConnectionTest() error {
|
||||
session, err := LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
log.Errorf("system checking user %s failed, error: %v", user.Username, err)
|
||||
return 0, fmt.Errorf("internal_error")
|
||||
return fmt.Errorf("Failed to load system ldap config")
|
||||
}
|
||||
|
||||
if exist {
|
||||
return 0, fmt.Errorf("duplicate_username")
|
||||
}
|
||||
|
||||
exist, err = dao.UserExists(u, "email")
|
||||
if err != nil {
|
||||
log.Errorf("system checking %s mailbox failed, error: %v", user.Username, err)
|
||||
return 0, fmt.Errorf("internal_error")
|
||||
}
|
||||
|
||||
if exist {
|
||||
return 0, fmt.Errorf("duplicate_mailbox")
|
||||
}
|
||||
|
||||
u.Password = "12345678AbC"
|
||||
u.Comment = "from LDAP."
|
||||
if u.Email == "" {
|
||||
u.Email = u.Username + "@placeholder.com"
|
||||
}
|
||||
|
||||
UserID, err := dao.Register(u)
|
||||
if err != nil {
|
||||
log.Errorf("system register user %s failed, error: %v", user.Username, err)
|
||||
return 0, fmt.Errorf("registe_user_error")
|
||||
}
|
||||
|
||||
return UserID, nil
|
||||
return ConnectionTestWithConfig(session.ldapConfig)
|
||||
}
|
||||
|
||||
// Bind establish a connection to ldap based on ldapConfs and bind the user with given parameters.
|
||||
func Bind(ldapConfs models.LdapConf, dn string, password string) error {
|
||||
conn, err := dialLDAP(ldapConfs)
|
||||
//ConnectionTestWithConfig - test ldap session connection, out of the scope of normal session create/close
|
||||
func ConnectionTestWithConfig(ldapConfig models.LdapConf) error {
|
||||
|
||||
//If no password present, use the system default password
|
||||
if ldapConfig.LdapSearchPassword == "" {
|
||||
|
||||
session, err := LoadSystemLdapConfig()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to load system ldap config")
|
||||
}
|
||||
|
||||
ldapConfig.LdapSearchPassword = session.ldapConfig.LdapSearchPassword
|
||||
}
|
||||
|
||||
testSession, err := createWithInternalConfig(ldapConfig)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
if ldapConfs.LdapSearchDn != "" {
|
||||
if err := bindLDAPSearchDN(ldapConfs, conn); err != nil {
|
||||
err = testSession.Open()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer testSession.Close()
|
||||
|
||||
if testSession.ldapConfig.LdapSearchDn != "" {
|
||||
err = testSession.Bind(testSession.ldapConfig.LdapSearchDn, testSession.ldapConfig.LdapSearchPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return conn.Bind(dn, password)
|
||||
}
|
||||
|
||||
func dialLDAP(ldapConfs models.LdapConf) (*goldap.Conn, error) {
|
||||
|
||||
var err error
|
||||
var ldap *goldap.Conn
|
||||
splitLdapURL := strings.Split(ldapConfs.LdapURL, "://")
|
||||
protocol, hostport := splitLdapURL[0], splitLdapURL[1]
|
||||
host := strings.Split(hostport, ":")[0]
|
||||
|
||||
// Sets a Dial Timeout for LDAP
|
||||
connectionTimeout := ldapConfs.LdapConnectionTimeout
|
||||
goldap.DefaultTimeout = time.Duration(connectionTimeout) * time.Second
|
||||
|
||||
switch protocol {
|
||||
case "ldap":
|
||||
ldap, err = goldap.Dial("tcp", hostport)
|
||||
case "ldaps":
|
||||
log.Debug("Start to dial ldaps")
|
||||
ldap, err = goldap.DialTLS("tcp", hostport, &tls.Config{ServerName: host, InsecureSkipVerify: !ldapConfs.LdapVerifyCert})
|
||||
}
|
||||
|
||||
return ldap, err
|
||||
}
|
||||
|
||||
func bindLDAPSearchDN(ldapConfs models.LdapConf, ldap *goldap.Conn) error {
|
||||
|
||||
var err error
|
||||
|
||||
ldapSearchDn := ldapConfs.LdapSearchDn
|
||||
ldapSearchPassword := ldapConfs.LdapSearchPassword
|
||||
|
||||
err = ldap.Bind(ldapSearchDn, ldapSearchPassword)
|
||||
if err != nil {
|
||||
log.Debug("Bind search dn error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func searchLDAP(ldapConfs models.LdapConf, ldap *goldap.Conn) (*goldap.SearchResult, error) {
|
||||
//SearchUser - search LDAP user by name
|
||||
func (session *Session) SearchUser(username string) ([]models.LdapUser, error) {
|
||||
var ldapUsers []models.LdapUser
|
||||
ldapFilter := session.createUserFilter(username)
|
||||
result, err := session.SearchLdap(ldapFilter)
|
||||
|
||||
var err error
|
||||
ldapBaseDn := ldapConfs.LdapBaseDn
|
||||
ldapScope := ldapConfs.LdapScope
|
||||
ldapFilter := ldapConfs.LdapFilter
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ldapEntry := range result.Entries {
|
||||
var u models.LdapUser
|
||||
for _, attr := range ldapEntry.Attributes {
|
||||
//OpenLdap sometimes contain leading space in useranme
|
||||
val := strings.TrimSpace(attr.Values[0])
|
||||
log.Debugf("Current ldap entry attr name: %s\n", attr.Name)
|
||||
switch strings.ToLower(attr.Name) {
|
||||
case strings.ToLower(session.ldapConfig.LdapUID):
|
||||
u.Username = val
|
||||
case "uid":
|
||||
u.Realname = val
|
||||
case "cn":
|
||||
u.Realname = val
|
||||
case "mail":
|
||||
u.Email = val
|
||||
case "email":
|
||||
u.Email = val
|
||||
}
|
||||
}
|
||||
u.DN = ldapEntry.DN
|
||||
ldapUsers = append(ldapUsers, u)
|
||||
|
||||
}
|
||||
|
||||
return ldapUsers, nil
|
||||
|
||||
}
|
||||
|
||||
// Bind with specified DN and password, used in authentication
|
||||
func (session *Session) Bind(dn string, password string) error {
|
||||
return session.ldapConn.Bind(dn, password)
|
||||
}
|
||||
|
||||
//Open - open Session
|
||||
func (session *Session) Open() error {
|
||||
|
||||
splitLdapURL := strings.Split(session.ldapConfig.LdapURL, "://")
|
||||
protocol, hostport := splitLdapURL[0], splitLdapURL[1]
|
||||
host := strings.Split(hostport, ":")[0]
|
||||
|
||||
connectionTimeout := session.ldapConfig.LdapConnectionTimeout
|
||||
goldap.DefaultTimeout = time.Duration(connectionTimeout) * time.Second
|
||||
|
||||
switch protocol {
|
||||
case "ldap":
|
||||
ldap, err := goldap.Dial("tcp", hostport)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.ldapConn = ldap
|
||||
case "ldaps":
|
||||
log.Debug("Start to dial ldaps")
|
||||
ldap, err := goldap.DialTLS("tcp", hostport, &tls.Config{ServerName: host, InsecureSkipVerify: !session.ldapConfig.LdapVerifyCert})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.ldapConn = ldap
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// SearchLdap to search ldap with the provide filter
|
||||
func (session *Session) SearchLdap(filter string) (*goldap.SearchResult, error) {
|
||||
|
||||
if err := session.Bind(session.ldapConfig.LdapSearchDn, session.ldapConfig.LdapSearchPassword); err != nil {
|
||||
return nil, fmt.Errorf("Can not bind search dn, error: %v", err)
|
||||
}
|
||||
|
||||
attributes := []string{"uid", "cn", "mail", "email"}
|
||||
lowerUID := strings.ToLower(ldapConfs.LdapUID)
|
||||
lowerUID := strings.ToLower(session.ldapConfig.LdapUID)
|
||||
|
||||
if lowerUID != "uid" && lowerUID != "cn" && lowerUID != "mail" && lowerUID != "email" {
|
||||
attributes = append(attributes, ldapConfs.LdapUID)
|
||||
attributes = append(attributes, session.ldapConfig.LdapUID)
|
||||
}
|
||||
log.Debugf("Search ldap with filter:%v", filter)
|
||||
searchRequest := goldap.NewSearchRequest(
|
||||
ldapBaseDn,
|
||||
ldapScope,
|
||||
session.ldapConfig.LdapBaseDn,
|
||||
session.ldapConfig.LdapScope,
|
||||
goldap.NeverDerefAliases,
|
||||
0, // Unlimited results.
|
||||
0, // Search Timeout.
|
||||
false, // Types Only
|
||||
ldapFilter,
|
||||
0, //Unlimited results
|
||||
0, //Search Timeout
|
||||
false, //Types only
|
||||
filter,
|
||||
attributes,
|
||||
nil,
|
||||
)
|
||||
|
||||
result, err := ldap.Search(searchRequest)
|
||||
result, err := session.ldapConn.Search(searchRequest)
|
||||
if result != nil {
|
||||
log.Debugf("Found entries:%v\n", len(result.Entries))
|
||||
} else {
|
||||
log.Debugf("No entries")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Debug("LDAP search error", err)
|
||||
@ -404,39 +337,36 @@ func searchLDAP(ldapConfs models.LdapConf, ldap *goldap.Conn) (*goldap.SearchRes
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
// SearchAndImportUser - Search user in LDAP, if this user exist, import it to database
|
||||
func SearchAndImportUser(username string) (int64, error) {
|
||||
var err error
|
||||
var userID int64
|
||||
//CreateUserFilter - create filter to search user with specified username
|
||||
func (session *Session) createUserFilter(username string) string {
|
||||
var filterTag string
|
||||
|
||||
ldapConfs, err := GetSystemLdapConf()
|
||||
if err != nil {
|
||||
log.Errorf("Can not get ldap configuration, error %v", err)
|
||||
return 0, err
|
||||
}
|
||||
ldapConfs, err = ValidateLdapConf(ldapConfs)
|
||||
if err != nil {
|
||||
log.Errorf("Invalid ldap request, error: %v", err)
|
||||
return 0, err
|
||||
if username == "" {
|
||||
filterTag = "*"
|
||||
} else {
|
||||
filterTag = username
|
||||
}
|
||||
|
||||
ldapConfs.LdapFilter = MakeFilter(username, ldapConfs.LdapFilter, ldapConfs.LdapUID)
|
||||
log.Debugf("Search with LDAP with filter %s", ldapConfs.LdapFilter)
|
||||
ldapFilter := session.ldapConfig.LdapFilter
|
||||
ldapUID := session.ldapConfig.LdapUID
|
||||
|
||||
ldapUsers, err := SearchUser(ldapConfs)
|
||||
if err != nil {
|
||||
log.Errorf("Can not search ldap, error %v, filter: %s", err, ldapConfs.LdapFilter)
|
||||
return 0, err
|
||||
if ldapFilter == "" {
|
||||
ldapFilter = "(" + ldapUID + "=" + filterTag + ")"
|
||||
} else {
|
||||
ldapFilter = "(&" + ldapFilter + "(" + ldapUID + "=" + filterTag + "))"
|
||||
}
|
||||
|
||||
if len(ldapUsers) > 0 {
|
||||
log.Debugf("Importing user %s to local database", ldapUsers[0].Username)
|
||||
if userID, err = ImportUser(ldapUsers[0]); err != nil {
|
||||
log.Errorf("Can not import ldap user to local db, error %v", err)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return userID, err
|
||||
log.Debug("ldap filter :", ldapFilter)
|
||||
|
||||
return ldapFilter
|
||||
}
|
||||
|
||||
//Close - close current session
|
||||
func (session *Session) Close() {
|
||||
if session.ldapConn != nil {
|
||||
session.ldapConn.Close()
|
||||
}
|
||||
}
|
||||
|
@ -11,19 +11,16 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
//"fmt"
|
||||
//"strings"
|
||||
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/test"
|
||||
uiConfig "github.com/vmware/harbor/src/ui/config"
|
||||
@ -40,29 +37,15 @@ var adminServerLdapTestConfig = map[string]interface{}{
|
||||
common.MySQLDatabase: "registry",
|
||||
common.SQLiteFile: "/tmp/registry.db",
|
||||
//config.SelfRegistration: true,
|
||||
common.LDAPURL: "ldap://127.0.0.1",
|
||||
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
|
||||
common.LDAPSearchPwd: "admin",
|
||||
common.LDAPBaseDN: "dc=example,dc=com",
|
||||
common.LDAPUID: "uid",
|
||||
common.LDAPFilter: "",
|
||||
common.LDAPScope: 3,
|
||||
common.LDAPTimeout: 30,
|
||||
// config.TokenServiceURL: "",
|
||||
// config.RegistryURL: "",
|
||||
// config.EmailHost: "",
|
||||
// config.EmailPort: 25,
|
||||
// config.EmailUsername: "",
|
||||
// config.EmailPassword: "password",
|
||||
// config.EmailFrom: "from",
|
||||
// config.EmailSSL: true,
|
||||
// config.EmailIdentity: "",
|
||||
// config.ProjectCreationRestriction: config.ProCrtRestrAdmOnly,
|
||||
// config.VerifyRemoteCert: false,
|
||||
// config.MaxJobWorkers: 3,
|
||||
// config.TokenExpiration: 30,
|
||||
common.CfgExpiration: 5,
|
||||
// config.JobLogDir: "/var/log/jobs",
|
||||
common.LDAPURL: "ldap://127.0.0.1",
|
||||
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
|
||||
common.LDAPSearchPwd: "admin",
|
||||
common.LDAPBaseDN: "dc=example,dc=com",
|
||||
common.LDAPUID: "uid",
|
||||
common.LDAPFilter: "",
|
||||
common.LDAPScope: 3,
|
||||
common.LDAPTimeout: 30,
|
||||
common.CfgExpiration: 5,
|
||||
common.AdminInitialPassword: "password",
|
||||
}
|
||||
|
||||
@ -132,15 +115,6 @@ func TestMain(t *testing.T) {
|
||||
t.Fatalf("failed to initialize configurations: %v", err)
|
||||
}
|
||||
|
||||
// if err := uiConfig.Load(); err != nil {
|
||||
// t.Fatalf("failed to load configurations: %v", err)
|
||||
// }
|
||||
|
||||
// mode, err := uiConfig.AuthMode()
|
||||
// if err != nil {
|
||||
// t.Fatalf("failed to get auth mode: %v", err)
|
||||
// }
|
||||
|
||||
database, err := uiConfig.Database()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get database configuration: %v", err)
|
||||
@ -151,171 +125,134 @@ func TestMain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSystemLdapConf(t *testing.T) {
|
||||
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
|
||||
func TestLoadSystemLdapConfig(t *testing.T) {
|
||||
session, err := LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
}
|
||||
|
||||
if testLdapConfig.LdapURL != "ldap://127.0.0.1" {
|
||||
t.Errorf("unexpected LdapURL: %s != %s", testLdapConfig.LdapURL, "ldap://test.ldap.com")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateLdapConf(t *testing.T) {
|
||||
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
if session.ldapConfig.LdapURL != "ldap://127.0.0.1:389" {
|
||||
t.Errorf("unexpected LdapURL: %s != %s", session.ldapConfig.LdapURL, "ldap://127.0.0.1:389")
|
||||
}
|
||||
|
||||
testLdapConfig, err = ValidateLdapConf(testLdapConfig)
|
||||
|
||||
if testLdapConfig.LdapScope != 2 {
|
||||
t.Errorf("unexpected LdapScope: %d != %d", testLdapConfig.LdapScope, 2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeFilter(t *testing.T) {
|
||||
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
}
|
||||
|
||||
testLdapConfig.LdapFilter = "(ou=people)"
|
||||
tempUsername := ""
|
||||
|
||||
tempFilter := MakeFilter(tempUsername, testLdapConfig.LdapFilter, testLdapConfig.LdapUID)
|
||||
if tempFilter != "(&(ou=people)(uid=*))" {
|
||||
t.Errorf("unexpected tempFilter: %s != %s", tempFilter, "(&(ou=people)(uid=*))")
|
||||
}
|
||||
|
||||
tempUsername = "user0001"
|
||||
tempFilter = MakeFilter(tempUsername, testLdapConfig.LdapFilter, testLdapConfig.LdapUID)
|
||||
if tempFilter != "(&(ou=people)(uid=user0001))" {
|
||||
t.Errorf("unexpected tempFilter: %s != %s", tempFilter, "(&(ou=people)(uid=user0001)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatLdapURL(t *testing.T) {
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
}
|
||||
|
||||
testLdapConfig.LdapURL = "test.ldap.com"
|
||||
tempLdapURL, err := formatLdapURL(testLdapConfig.LdapURL)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to format Ldap URL %v", err)
|
||||
}
|
||||
|
||||
if tempLdapURL != "ldap://test.ldap.com:389" {
|
||||
t.Errorf("unexpected tempLdapURL: %s != %s", tempLdapURL, "ldap://test.ldap.com:389")
|
||||
}
|
||||
|
||||
testLdapConfig.LdapURL = "ldaps://test.ldap.com"
|
||||
tempLdapURL, err = formatLdapURL(testLdapConfig.LdapURL)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("failed to format Ldap URL %v", err)
|
||||
}
|
||||
|
||||
if tempLdapURL != "ldaps://test.ldap.com:636" {
|
||||
t.Errorf("unexpected tempLdapURL: %s != %s", tempLdapURL, "ldap://test.ldap.com:636")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportUser(t *testing.T) {
|
||||
var u models.LdapUser
|
||||
var user models.User
|
||||
u.Username = "ldapUser0001"
|
||||
u.Realname = "ldapUser"
|
||||
_, err := ImportUser(u)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add Ldap user: %v", err)
|
||||
}
|
||||
|
||||
user.Username = "ldapUser0001"
|
||||
user.Email = "ldapUser0001@placeholder.com"
|
||||
|
||||
exist, err := dao.UserExists(user, "username")
|
||||
if !exist {
|
||||
t.Errorf("failed to add Ldap username: %v", err)
|
||||
}
|
||||
|
||||
exist, err = dao.UserExists(user, "email")
|
||||
if !exist {
|
||||
t.Errorf("failed to add Ldap user email: %v", err)
|
||||
}
|
||||
|
||||
_, err = ImportUser(u)
|
||||
if err.Error() != "duplicate_username" {
|
||||
t.Fatalf("failed to checking duplicate user: %v", err)
|
||||
if session.ldapConfig.LdapScope != 2 {
|
||||
t.Errorf("unexpected LdapScope: %d != %d", session.ldapConfig.LdapScope, 2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestConnectTest(t *testing.T) {
|
||||
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
|
||||
session, err := LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
t.Errorf("failed to load system ldap config")
|
||||
}
|
||||
err = session.ConnectionTest()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected ldap connect fail: %v", err)
|
||||
}
|
||||
|
||||
testLdapConfig.LdapURL = "ldap://localhost:389"
|
||||
}
|
||||
|
||||
err = ConnectTest(testLdapConfig)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected ldap connect fail: %v", err)
|
||||
func TestCreateUIConfig(t *testing.T) {
|
||||
var testConfigs = []struct {
|
||||
config models.LdapConf
|
||||
internalValue int
|
||||
}{
|
||||
{
|
||||
models.LdapConf{
|
||||
LdapScope: 3,
|
||||
LdapURL: "ldaps://127.0.0.1",
|
||||
}, 2},
|
||||
{
|
||||
models.LdapConf{
|
||||
LdapScope: 2,
|
||||
LdapURL: "ldaps://127.0.0.1",
|
||||
}, 1},
|
||||
{
|
||||
models.LdapConf{
|
||||
LdapScope: 1,
|
||||
LdapURL: "ldaps://127.0.0.1",
|
||||
}, 0},
|
||||
}
|
||||
|
||||
for _, val := range testConfigs {
|
||||
session, err := CreateWithUIConfig(val.config)
|
||||
if err != nil {
|
||||
t.Fatalf("Can not create with ui config, err:%v", err)
|
||||
}
|
||||
if session.ldapConfig.LdapScope != val.internalValue {
|
||||
t.Fatalf("Test failed expected %v, actual %v", val.internalValue, session.ldapConfig.LdapScope)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSearchUser(t *testing.T) {
|
||||
|
||||
testLdapConfig, err := GetSystemLdapConf()
|
||||
|
||||
session, err := LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get system ldap config %v", err)
|
||||
t.Fatalf("Can not load system ldap config")
|
||||
}
|
||||
testLdapConfig.LdapURL = "ldap://localhost:389"
|
||||
testLdapConfig.LdapFilter = MakeFilter("", testLdapConfig.LdapFilter, testLdapConfig.LdapUID)
|
||||
|
||||
ldapUsers, err := SearchUser(testLdapConfig)
|
||||
err = session.Open()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected ldap search fail: %v", err)
|
||||
t.Fatalf("failed to create ldap session %v", err)
|
||||
}
|
||||
|
||||
if ldapUsers[0].Username != "test" {
|
||||
t.Errorf("unexpected ldap user search result: %s = %s", "ldapUsers[0].Username", ldapUsers[0].Username)
|
||||
err = session.Bind(session.ldapConfig.LdapSearchDn, session.ldapConfig.LdapSearchPassword)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to bind search dn")
|
||||
}
|
||||
|
||||
defer session.Close()
|
||||
|
||||
result, err := session.SearchUser("test")
|
||||
if err != nil || len(result) == 0 {
|
||||
t.Fatalf("failed to search user test!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func InitTest(ldapTestConfig map[string]interface{}, t *testing.T) {
|
||||
server, err := test.NewAdminserver(ldapTestConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create a mock admin server: %v", err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
|
||||
t.Fatalf("failed to set env %s:%v", "ADMIN_SERVER_URL", err)
|
||||
}
|
||||
|
||||
if err := uiConfig.Init(); err != nil {
|
||||
t.Fatalf("failed to initialize configurations: %v ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchAndImportUser(t *testing.T) {
|
||||
func TestFormatURL(t *testing.T) {
|
||||
|
||||
userID, err := SearchAndImportUser("test")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Failed on error : %v ", err)
|
||||
}
|
||||
|
||||
if userID <= 0 {
|
||||
t.Fatalf("userID= %v", userID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchAndImportUserNotExist(t *testing.T) {
|
||||
|
||||
userID, _ := SearchAndImportUser("notexist")
|
||||
|
||||
if userID > 0 {
|
||||
t.Fatal("Can not import a non exist ldap user!")
|
||||
var invalidURL = "http://localhost:389"
|
||||
_, err := formatURL(invalidURL)
|
||||
if err == nil {
|
||||
t.Fatalf("Should failed on invalid URL %v", invalidURL)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
var urls = []struct {
|
||||
rawURL string
|
||||
goodURL string
|
||||
}{
|
||||
{"ldaps://127.0.0.1", "ldaps://127.0.0.1:636"},
|
||||
{"ldap://9.123.102.33", "ldap://9.123.102.33:389"},
|
||||
{"ldaps://127.0.0.1:389", "ldaps://127.0.0.1:389"},
|
||||
{"ldap://127.0.0.1:636", "ldaps://127.0.0.1:636"},
|
||||
{"112.122.122.122", "ldap://112.122.122.122:389"},
|
||||
}
|
||||
|
||||
for _, u := range urls {
|
||||
goodURL, err := formatURL(u.rawURL)
|
||||
if err != nil || goodURL != u.goodURL {
|
||||
t.Fatalf("Faild on URL: raw=%v, expected:%v, actual:%v", u.rawURL, u.goodURL, goodURL)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -23,6 +22,7 @@ import (
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
ldapUtils "github.com/vmware/harbor/src/common/utils/ldap"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
)
|
||||
|
||||
// LdapAPI handles requesst to /api/ldap/ping /api/ldap/user/search /api/ldap/user/import
|
||||
@ -47,47 +47,28 @@ func (l *LdapAPI) Prepare() {
|
||||
|
||||
// Ping ...
|
||||
func (l *LdapAPI) Ping() {
|
||||
var err error
|
||||
var ldapConfs models.LdapConf
|
||||
|
||||
l.Ctx.Input.CopyBody(1 << 32)
|
||||
if string(l.Ctx.Input.RequestBody) == "" {
|
||||
ldapConfs, err = ldapUtils.GetSystemLdapConf()
|
||||
if err != nil {
|
||||
log.Errorf("Can't load system configuration, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't load system configuration: %v", err))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
l.DecodeJSONReqAndValidate(&ldapConfs)
|
||||
v := map[string]interface{}{}
|
||||
if err := json.Unmarshal(l.Ctx.Input.RequestBody,
|
||||
&v); err != nil {
|
||||
log.Errorf("failed to unmarshal LDAP server settings: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, "")
|
||||
return
|
||||
}
|
||||
if _, ok := v["ldap_search_password"]; !ok {
|
||||
settings, err := ldapUtils.GetSystemLdapConf()
|
||||
if err != nil {
|
||||
log.Errorf("Can't load system configuration, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't load system configuration: %v", err))
|
||||
return
|
||||
}
|
||||
ldapConfs.LdapSearchPassword = settings.LdapSearchPassword
|
||||
}
|
||||
}
|
||||
var ldapSession *ldapUtils.Session
|
||||
|
||||
ldapConfs, err = ldapUtils.ValidateLdapConf(ldapConfs)
|
||||
l.Ctx.Input.CopyBody(1 << 32)
|
||||
|
||||
ldapSession, err := ldapUtils.LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
log.Errorf("Invalid ldap request, error: %v", err)
|
||||
l.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid ldap request: %v", err))
|
||||
log.Errorf("Can't load system configuration, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't load system configuration: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
err = ldapUtils.ConnectTest(ldapConfs)
|
||||
if string(l.Ctx.Input.RequestBody) == "" {
|
||||
err = ldapSession.ConnectionTest()
|
||||
} else {
|
||||
l.DecodeJSONReqAndValidate(&ldapConfs)
|
||||
err = ldapUtils.ConnectionTestWithConfig(ldapConfs)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Ldap connect fail, error: %v", err)
|
||||
log.Errorf("ldap connect fail, error: %v", err)
|
||||
l.RenderError(http.StatusBadRequest, fmt.Sprintf("ldap connect fail: %v", err))
|
||||
return
|
||||
}
|
||||
@ -98,26 +79,26 @@ func (l *LdapAPI) Search() {
|
||||
var err error
|
||||
var ldapUsers []models.LdapUser
|
||||
var ldapConfs models.LdapConf
|
||||
|
||||
var ldapSession *ldapUtils.Session
|
||||
l.Ctx.Input.CopyBody(1 << 32)
|
||||
if string(l.Ctx.Input.RequestBody) == "" {
|
||||
ldapConfs, err = ldapUtils.GetSystemLdapConf()
|
||||
ldapSession, err = ldapUtils.LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
log.Errorf("Can't load system configuration, error: %v", err)
|
||||
log.Errorf("can't load system configuration, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't load system configuration: %v", err))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
l.DecodeJSONReqAndValidate(&ldapConfs)
|
||||
ldapSession, err = ldapUtils.CreateWithUIConfig(ldapConfs)
|
||||
}
|
||||
|
||||
ldapConfs, err = ldapUtils.ValidateLdapConf(ldapConfs)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Invalid ldap request, error: %v", err)
|
||||
l.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid ldap request: %v", err))
|
||||
if err = ldapSession.Open(); err != nil {
|
||||
log.Errorf("can't Open ldap session, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't open ldap session: %v", err))
|
||||
return
|
||||
}
|
||||
defer ldapSession.Close()
|
||||
|
||||
searchName := l.GetString("username")
|
||||
|
||||
@ -131,9 +112,7 @@ func (l *LdapAPI) Search() {
|
||||
}
|
||||
}
|
||||
|
||||
ldapConfs.LdapFilter = ldapUtils.MakeFilter(searchName, ldapConfs.LdapFilter, ldapConfs.LdapUID)
|
||||
|
||||
ldapUsers, err = ldapUtils.SearchUser(ldapConfs)
|
||||
ldapUsers, err = ldapSession.SearchUser(searchName)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Ldap search fail, error: %v", err)
|
||||
@ -152,23 +131,9 @@ func (l *LdapAPI) ImportUser() {
|
||||
var ldapFailedImportUsers []models.LdapFailedImportUser
|
||||
var ldapConfs models.LdapConf
|
||||
|
||||
ldapConfs, err := ldapUtils.GetSystemLdapConf()
|
||||
if err != nil {
|
||||
log.Errorf("Can't load system configuration, error: %v", err)
|
||||
l.RenderError(http.StatusInternalServerError, fmt.Sprintf("can't load system configuration: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
l.DecodeJSONReqAndValidate(&ldapImportUsers)
|
||||
|
||||
ldapConfs, err = ldapUtils.ValidateLdapConf(ldapConfs)
|
||||
if err != nil {
|
||||
log.Errorf("Invalid ldap request, error: %v", err)
|
||||
l.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid ldap request: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
ldapFailedImportUsers, err = importUsers(ldapConfs, ldapImportUsers.LdapUIDList)
|
||||
ldapFailedImportUsers, err := importUsers(ldapConfs, ldapImportUsers.LdapUIDList)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Ldap import user fail, error: %v", err)
|
||||
@ -190,7 +155,16 @@ func importUsers(ldapConfs models.LdapConf, ldapImportUsers []string) ([]models.
|
||||
var failedImportUser []models.LdapFailedImportUser
|
||||
var u models.LdapFailedImportUser
|
||||
|
||||
tempFilter := ldapConfs.LdapFilter
|
||||
ldapSession, err := ldapUtils.LoadSystemLdapConfig()
|
||||
if err != nil {
|
||||
log.Errorf("can't load system configuration, error: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = ldapSession.Open(); err != nil {
|
||||
log.Errorf("Can't connect to ldap, error: %v", err)
|
||||
}
|
||||
defer ldapSession.Close()
|
||||
|
||||
for _, tempUID := range ldapImportUsers {
|
||||
u.UID = tempUID
|
||||
@ -214,9 +188,7 @@ func importUsers(ldapConfs models.LdapConf, ldapImportUsers []string) ([]models.
|
||||
continue
|
||||
}
|
||||
|
||||
ldapConfs.LdapFilter = ldapUtils.MakeFilter(u.UID, tempFilter, ldapConfs.LdapUID)
|
||||
|
||||
ldapUsers, err := ldapUtils.SearchUser(ldapConfs)
|
||||
ldapUsers, err := ldapSession.SearchUser(u.UID)
|
||||
if err != nil {
|
||||
u.UID = tempUID
|
||||
u.Error = "failed_search_user"
|
||||
@ -225,16 +197,21 @@ func importUsers(ldapConfs models.LdapConf, ldapImportUsers []string) ([]models.
|
||||
continue
|
||||
}
|
||||
|
||||
if ldapUsers == nil {
|
||||
if ldapUsers == nil || len(ldapUsers) <= 0 {
|
||||
u.UID = tempUID
|
||||
u.Error = "unknown_user"
|
||||
failedImportUser = append(failedImportUser, u)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = ldapUtils.ImportUser(ldapUsers[0])
|
||||
var user models.User
|
||||
|
||||
if err != nil {
|
||||
user.Username = ldapUsers[0].Username
|
||||
user.Realname = ldapUsers[0].Realname
|
||||
user.Email = ldapUsers[0].Email
|
||||
err = auth.OnBoardUser(&user)
|
||||
|
||||
if err != nil || user.UserID <= 0 {
|
||||
u.UID = tempUID
|
||||
u.Error = err.Error()
|
||||
failedImportUser = append(failedImportUser, u)
|
||||
|
@ -21,9 +21,8 @@ import (
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
ldapUtils "github.com/vmware/harbor/src/common/utils/ldap"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
)
|
||||
|
||||
// ProjectMemberAPI handles request to /api/projects/{}/members/{}
|
||||
@ -164,35 +163,35 @@ func (pma *ProjectMemberAPI) Post() {
|
||||
username := strings.TrimSpace(req.Username)
|
||||
userID := checkUserExists(username)
|
||||
if userID <= 0 {
|
||||
//check current authorization mode
|
||||
authMode, err := config.AuthMode()
|
||||
|
||||
user, err := auth.SearchUser(username)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Failed the retrieve auth_mode, error: %s", err)
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to retrieve auth_mode")
|
||||
log.Errorf("Failed the search user, error: %v", err)
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to search user")
|
||||
return
|
||||
}
|
||||
|
||||
if authMode != "ldap_auth" {
|
||||
log.Errorf("User does not exist, user name: %s", username)
|
||||
pma.RenderError(http.StatusNotFound, "User does not exist")
|
||||
if user == nil {
|
||||
log.Errorf("Current user doesn't exist: %v", username)
|
||||
pma.RenderError(http.StatusNotFound, "Failed to search user: "+username)
|
||||
return
|
||||
}
|
||||
|
||||
//search and import user
|
||||
newUserID, err := ldapUtils.SearchAndImportUser(username)
|
||||
err = auth.OnBoardUser(user)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Search and import user failed, error: %v ", err)
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to search and import user")
|
||||
log.Errorf("Failed the onboard user, error: %s", err)
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to onboard user")
|
||||
return
|
||||
}
|
||||
|
||||
if newUserID <= 0 {
|
||||
log.Error("Failed to create user")
|
||||
pma.RenderError(http.StatusNotFound, "Failed to create user")
|
||||
if user.UserID <= 0 {
|
||||
log.Error("Failed the onboard user, UserId <=0")
|
||||
pma.RenderError(http.StatusInternalServerError, "Failed to onboard user")
|
||||
return
|
||||
}
|
||||
userID = user.UserID
|
||||
|
||||
userID = int(newUserID)
|
||||
}
|
||||
rolelist, err := dao.GetUserProjectRoles(userID, projectID)
|
||||
if err != nil {
|
||||
|
@ -16,10 +16,34 @@ package auth
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common"
|
||||
)
|
||||
|
||||
var l = NewUserLock(2 * time.Second)
|
||||
|
||||
var adminServerLdapTestConfig = map[string]interface{}{
|
||||
common.ExtEndpoint: "host01.com",
|
||||
common.AUTHMode: "ldap_auth",
|
||||
common.DatabaseType: "mysql",
|
||||
common.MySQLHost: "127.0.0.1",
|
||||
common.MySQLPort: 3306,
|
||||
common.MySQLUsername: "root",
|
||||
common.MySQLPassword: "root123",
|
||||
common.MySQLDatabase: "registry",
|
||||
common.SQLiteFile: "/tmp/registry.db",
|
||||
common.LDAPURL: "ldap://127.0.0.1",
|
||||
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
|
||||
common.LDAPSearchPwd: "admin",
|
||||
common.LDAPBaseDN: "dc=example,dc=com",
|
||||
common.LDAPUID: "uid",
|
||||
common.LDAPFilter: "",
|
||||
common.LDAPScope: 3,
|
||||
common.LDAPTimeout: 30,
|
||||
common.CfgExpiration: 5,
|
||||
common.AdminInitialPassword: "password",
|
||||
}
|
||||
|
||||
func TestLock(t *testing.T) {
|
||||
t.Log("Locking john")
|
||||
l.Lock("john")
|
||||
|
@ -37,22 +37,27 @@ const (
|
||||
|
||||
var lock = NewUserLock(frozenTime)
|
||||
|
||||
// Authenticator provides interface to authenticate user credentials.
|
||||
type Authenticator interface {
|
||||
// AuthenticateHelper provides interface to authenticate user credentials.
|
||||
type AuthenticateHelper interface {
|
||||
|
||||
// Authenticate ...
|
||||
Authenticate(m models.AuthModel) (*models.User, error)
|
||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||
OnBoardUser(u *models.User) error
|
||||
// Get user information from account repository
|
||||
SearchUser(username string) (*models.User, error)
|
||||
}
|
||||
|
||||
var registry = make(map[string]Authenticator)
|
||||
var registry = make(map[string]AuthenticateHelper)
|
||||
|
||||
// Register add different authenticators to registry map.
|
||||
func Register(name string, authenticator Authenticator) {
|
||||
func Register(name string, AuthenticateHelper AuthenticateHelper) {
|
||||
if _, dup := registry[name]; dup {
|
||||
log.Infof("authenticator: %s has been registered", name)
|
||||
return
|
||||
}
|
||||
registry[name] = authenticator
|
||||
registry[name] = AuthenticateHelper
|
||||
}
|
||||
|
||||
// Login authenticates user credentials based on setting.
|
||||
@ -83,3 +88,42 @@ func Login(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
return user, err
|
||||
}
|
||||
|
||||
// getAuthenticatorByMode --
|
||||
func getAuthenticateHelperByMode(authMode string) (AuthenticateHelper, error) {
|
||||
if authMode == "" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
AuthenticateHelper, ok := registry[authMode]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Can not get current authenticator")
|
||||
}
|
||||
return AuthenticateHelper, nil
|
||||
}
|
||||
|
||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||
func OnBoardUser(user *models.User) error {
|
||||
authMode, err := config.AuthMode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
auth, err := getAuthenticateHelperByMode(authMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return auth.OnBoardUser(user)
|
||||
}
|
||||
|
||||
// SearchUser --
|
||||
func SearchUser(username string) (*models.User, error) {
|
||||
authMode, err := config.AuthMode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
auth, err := getAuthenticateHelperByMode(authMode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return auth.SearchUser(username)
|
||||
}
|
||||
|
@ -15,9 +15,9 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
)
|
||||
|
||||
// Auth implements Authenticator interface to authenticate user against DB.
|
||||
@ -32,6 +32,21 @@ func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// OnBoardUser - Dummy implementation when auth_mod is db_auth
|
||||
func (d *Auth) OnBoardUser(user *models.User) error {
|
||||
//No need to create user in local database
|
||||
return nil
|
||||
}
|
||||
|
||||
// SearchUser - Check if user exist in local db
|
||||
func (d *Auth) SearchUser(username string) (*models.User, error) {
|
||||
var queryCondition = models.User{
|
||||
Username: username,
|
||||
}
|
||||
|
||||
return dao.GetUser(queryCondition)
|
||||
}
|
||||
|
||||
func init() {
|
||||
auth.Register("db_auth", &Auth{})
|
||||
}
|
||||
|
@ -14,9 +14,139 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/utils/test"
|
||||
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
uiConfig "github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
var adminServerTestConfig = map[string]interface{}{
|
||||
common.ExtEndpoint: "host01.com",
|
||||
common.AUTHMode: "db_auth",
|
||||
common.DatabaseType: "mysql",
|
||||
common.MySQLHost: "127.0.0.1",
|
||||
common.MySQLPort: 3306,
|
||||
common.MySQLUsername: "root",
|
||||
common.MySQLPassword: "root123",
|
||||
common.MySQLDatabase: "registry",
|
||||
common.SQLiteFile: "/tmp/registry.db",
|
||||
//config.SelfRegistration: true,
|
||||
common.LDAPURL: "ldap://127.0.0.1",
|
||||
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
|
||||
common.LDAPSearchPwd: "admin",
|
||||
common.LDAPBaseDN: "dc=example,dc=com",
|
||||
common.LDAPUID: "uid",
|
||||
common.LDAPFilter: "",
|
||||
common.LDAPScope: 3,
|
||||
common.LDAPTimeout: 30,
|
||||
// config.TokenServiceURL: "",
|
||||
// config.RegistryURL: "",
|
||||
// config.EmailHost: "",
|
||||
// config.EmailPort: 25,
|
||||
// config.EmailUsername: "",
|
||||
// config.EmailPassword: "password",
|
||||
// config.EmailFrom: "from",
|
||||
// config.EmailSSL: true,
|
||||
// config.EmailIdentity: "",
|
||||
// config.ProjectCreationRestriction: config.ProCrtRestrAdmOnly,
|
||||
// config.VerifyRemoteCert: false,
|
||||
// config.MaxJobWorkers: 3,
|
||||
// config.TokenExpiration: 30,
|
||||
common.CfgExpiration: 5,
|
||||
// config.JobLogDir: "/var/log/jobs",
|
||||
common.AdminInitialPassword: "password",
|
||||
}
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
server, err := test.NewAdminserver(adminServerTestConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create a mock admin server: %v", err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
|
||||
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
|
||||
}
|
||||
|
||||
secretKeyPath := "/tmp/secretkey"
|
||||
_, err = test.GenerateKey(secretKeyPath)
|
||||
if err != nil {
|
||||
t.Errorf("failed to generate secret key: %v", err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(secretKeyPath)
|
||||
|
||||
if err := os.Setenv("KEY_PATH", secretKeyPath); err != nil {
|
||||
t.Fatalf("failed to set env %s: %v", "KEY_PATH", err)
|
||||
}
|
||||
|
||||
if err := uiConfig.Init(); err != nil {
|
||||
t.Fatalf("failed to initialize configurations: %v", err)
|
||||
}
|
||||
|
||||
database, err := uiConfig.Database()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get database configuration: %v", err)
|
||||
}
|
||||
|
||||
if err := dao.InitDatabase(database); err != nil {
|
||||
log.Fatalf("failed to initialize database: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchUser(t *testing.T) {
|
||||
//insert user first
|
||||
user := &models.User{
|
||||
Username: "existuser",
|
||||
Email: "existuser@placeholder.com",
|
||||
Realname: "Existing user",
|
||||
}
|
||||
|
||||
err := dao.OnBoardUser(user)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to OnBoardUser %v", user)
|
||||
}
|
||||
|
||||
var auth *Auth
|
||||
newUser, err := auth.SearchUser("existuser")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to search user, error %v", err)
|
||||
}
|
||||
if newUser == nil {
|
||||
t.Fatalf("Failed to search user %v", newUser)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuthenticateHelperOnboardUser(t *testing.T) {
|
||||
user := models.User{
|
||||
Username: "test01",
|
||||
Realname: "test01",
|
||||
Email: "test01@example.com",
|
||||
}
|
||||
|
||||
err := auth.OnBoardUser(&user)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to onboard user error: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuthenticateHelperSearchUser(t *testing.T) {
|
||||
|
||||
user, err := auth.SearchUser("admin")
|
||||
if err != nil {
|
||||
t.Error("Failed to search user, admin")
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
t.Error("Failed to search user admin")
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
)
|
||||
|
||||
// Auth implements Authenticator interface to authenticate against LDAP
|
||||
// Auth implements AuthenticateHelper interface to authenticate against LDAP
|
||||
type Auth struct{}
|
||||
|
||||
const metaChars = "&|!=~*<>()"
|
||||
@ -46,21 +46,19 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
ldapConfs, err := ldapUtils.GetSystemLdapConf()
|
||||
ldapSession, err := ldapUtils.LoadSystemLdapConfig()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't load system configuration: %v", err)
|
||||
return nil, fmt.Errorf("can not load system ldap config: %v", err)
|
||||
}
|
||||
|
||||
ldapConfs, err = ldapUtils.ValidateLdapConf(ldapConfs)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ldap request: %v", err)
|
||||
if err = ldapSession.Open(); err != nil {
|
||||
log.Warningf("ldap connection fail: %v", err)
|
||||
return nil, nil
|
||||
}
|
||||
defer ldapSession.Close()
|
||||
|
||||
ldapConfs.LdapFilter = ldapUtils.MakeFilter(p, ldapConfs.LdapFilter, ldapConfs.LdapUID)
|
||||
|
||||
ldapUsers, err := ldapUtils.SearchUser(ldapConfs)
|
||||
ldapUsers, err := ldapSession.SearchUser(p)
|
||||
|
||||
if err != nil {
|
||||
log.Warningf("ldap search fail: %v", err)
|
||||
@ -83,7 +81,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
dn := ldapUsers[0].DN
|
||||
|
||||
log.Debugf("username: %s, dn: %s", u.Username, dn)
|
||||
if err := ldapUtils.Bind(ldapConfs, dn, m.Password); err != nil {
|
||||
if err = ldapSession.Bind(dn, m.Password); err != nil {
|
||||
log.Warningf("Failed to bind user, username: %s, dn: %s, error: %v", u.Username, dn, err)
|
||||
return nil, nil
|
||||
}
|
||||
@ -100,18 +98,68 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
u.UserID = currentUser.UserID
|
||||
u.HasAdminRole = currentUser.HasAdminRole
|
||||
} else {
|
||||
userID, err := ldapUtils.ImportUser(ldapUsers[0])
|
||||
if err != nil {
|
||||
var user models.User
|
||||
user.Username = ldapUsers[0].Username
|
||||
user.Email = ldapUsers[0].Email
|
||||
user.Realname = ldapUsers[0].Realname
|
||||
|
||||
err = auth.OnBoardUser(&user)
|
||||
if err != nil || user.UserID <= 0 {
|
||||
log.Errorf("Can't import user %s, error: %v", ldapUsers[0].Username, err)
|
||||
return nil, fmt.Errorf("can't import user %s, error: %v", ldapUsers[0].Username, err)
|
||||
}
|
||||
u.UserID = int(userID)
|
||||
u.UserID = user.UserID
|
||||
}
|
||||
|
||||
return &u, nil
|
||||
|
||||
}
|
||||
|
||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||
func (l *Auth) OnBoardUser(u *models.User) error {
|
||||
if u.Email == "" {
|
||||
if strings.Contains(u.Username, "@") {
|
||||
u.Email = u.Username
|
||||
} else {
|
||||
u.Email = u.Username + "@placeholder.com"
|
||||
}
|
||||
}
|
||||
u.Password = "12345678AbC" //Password is not kept in local db
|
||||
u.Comment = "from LDAP." //Source is from LDAP
|
||||
|
||||
return dao.OnBoardUser(u)
|
||||
}
|
||||
|
||||
//SearchUser -- Search user in ldap
|
||||
func (l *Auth) SearchUser(username string) (*models.User, error) {
|
||||
var user models.User
|
||||
ldapSession, err := ldapUtils.LoadSystemLdapConfig()
|
||||
if err = ldapSession.Open(); err != nil {
|
||||
return nil, fmt.Errorf("Failed to load system ldap config, %v", err)
|
||||
}
|
||||
|
||||
ldapUsers, err := ldapSession.SearchUser(username)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to search user in ldap")
|
||||
}
|
||||
|
||||
if len(ldapUsers) > 1 {
|
||||
log.Warningf("There are more than one user found, return the first user")
|
||||
}
|
||||
if len(ldapUsers) > 0 {
|
||||
|
||||
user.Username = strings.TrimSpace(ldapUsers[0].Username)
|
||||
user.Realname = strings.TrimSpace(ldapUsers[0].Realname)
|
||||
|
||||
log.Debugf("Found ldap user %v", user)
|
||||
} else {
|
||||
return nil, fmt.Errorf("No user found, %v", username)
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
auth.Register("ldap_auth", &Auth{})
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/test"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
uiConfig "github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
@ -91,15 +92,6 @@ func TestMain(t *testing.T) {
|
||||
t.Fatalf("failed to initialize configurations: %v", err)
|
||||
}
|
||||
|
||||
// if err := uiConfig.Load(); err != nil {
|
||||
// t.Fatalf("failed to load configurations: %v", err)
|
||||
// }
|
||||
|
||||
// mode, err := uiConfig.AuthMode()
|
||||
// if err != nil {
|
||||
// t.Fatalf("failed to get auth mode: %v", err)
|
||||
// }
|
||||
|
||||
database, err := uiConfig.Database()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get database configuration: %v", err)
|
||||
@ -141,3 +133,71 @@ func TestAuthenticate(t *testing.T) {
|
||||
t.Errorf("Nil user for empty credentials")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchUser(t *testing.T) {
|
||||
var username = "test"
|
||||
var auth *Auth
|
||||
user, err := auth.SearchUser(username)
|
||||
if err != nil {
|
||||
t.Errorf("Search user failed %v", err)
|
||||
}
|
||||
if user == nil {
|
||||
t.Errorf("Search user failed %v", user)
|
||||
}
|
||||
}
|
||||
func TestSearchUser_02(t *testing.T) {
|
||||
var username = "nonexist"
|
||||
var auth *Auth
|
||||
user, _ := auth.SearchUser(username)
|
||||
if user != nil {
|
||||
t.Errorf("Should failed to search nonexist user")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestOnboardUser(t *testing.T) {
|
||||
user := &models.User{
|
||||
Username: "sample",
|
||||
Email: "sample@example.com",
|
||||
Realname: "Sample",
|
||||
}
|
||||
|
||||
var auth *Auth
|
||||
err := auth.OnBoardUser(user)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to onboard user")
|
||||
}
|
||||
if user.UserID <= 0 {
|
||||
t.Errorf("Failed to onboard user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthenticateHelperOnboardUser(t *testing.T) {
|
||||
user := models.User{
|
||||
Username: "test01",
|
||||
Realname: "test01",
|
||||
Email: "test01@example.com",
|
||||
}
|
||||
|
||||
err := auth.OnBoardUser(&user)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to onboard user error: %v", err)
|
||||
}
|
||||
|
||||
if user.UserID <= 0 {
|
||||
t.Errorf("Failed to onboard user, userid: %v", user.UserID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuthenticateHelperSearchUser(t *testing.T) {
|
||||
|
||||
user, err := auth.SearchUser("test")
|
||||
if err != nil {
|
||||
t.Error("Failed to search user, test")
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
t.Error("Failed to search user test")
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/uaa"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
@ -66,7 +65,7 @@ func doAuth(username, password string, client uaa.Client) (*models.User, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Auth is the implementation of Authenticator to access uaa for authentication.
|
||||
// Auth is the implementation of AuthenticateHelper to access uaa for authentication.
|
||||
type Auth struct{}
|
||||
|
||||
//Authenticate ...
|
||||
@ -78,6 +77,17 @@ func (u *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
return doAuth(m.Principal, m.Password, client)
|
||||
}
|
||||
|
||||
func init() {
|
||||
auth.Register(auth.UAAAuth, &Auth{})
|
||||
}
|
||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||
// func (u *Auth) OnBoardUser(user *models.User) error {
|
||||
// panic("not implemented")
|
||||
// }
|
||||
|
||||
// // SearchUser - search user on uaa server
|
||||
// func (u *Auth) SearchUser(username string) (*models.User, error) {
|
||||
// panic("not implemented")
|
||||
// }
|
||||
|
||||
// func init() {
|
||||
// auth.Register(auth.UAAAuth, &Auth{})
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user