From 16243cfbbc121e14fa4ba9df0e73c473dffdf98f Mon Sep 17 00:00:00 2001 From: stonezdj Date: Wed, 1 Nov 2017 18:19:58 +0800 Subject: [PATCH 1/2] Add LDAP remote certifcate validation push test Add unit test for ldap verify cert remove common.VerifyRemoteCert Update code with PR review comments Add change ldaps config and add UT testcase for TLS feature add ldap verfiy cert checkbox about #3513 Draft harbor ova install guide Search and import ldap user when add project members Add unit test case for SearchAndImportUser ova guide Add ova install guide Add ova install guide 2 Add ova install guide 3 Call ValidateLdapConf before search ldap trim space in username Remove leading space in openLdap username Remove doc change in this branch Update unit test for ldap search and import user Add test case about ldap verify cert checkbox Modify ldap testcase --- make/common/templates/adminserver/env | 1 + src/adminserver/systemcfg/systemcfg.go | 4 ++ src/adminserver/systemcfg/systemcfg_test.go | 10 +++ src/common/const.go | 1 + src/common/models/config.go | 1 + src/common/models/ldap.go | 1 + src/common/utils/ldap/ldap.go | 43 +++++++++++- src/common/utils/ldap/ldap_test.go | 65 +++++++++++++++++++ src/ui/api/config.go | 2 + src/ui/api/member.go | 25 +++++-- src/ui/config/config.go | 6 +- src/ui_ng/lib/src/config/config.ts | 2 + .../config/auth/config-auth.component.html | 9 +++ .../app/config/auth/config-auth.component.ts | 4 ++ src/ui_ng/src/i18n/lang/en-us-lang.json | 6 +- src/ui_ng/src/i18n/lang/es-es-lang.json | 6 +- src/ui_ng/src/i18n/lang/zh-cn-lang.json | 6 +- tests/ldapprepare.sh | 3 +- .../Harbor-Pages/Configuration.robot | 45 ++++++++++++- .../Harbor-Pages/Configuration_Elements.robot | 3 +- tests/resources/Harbor-Util.robot | 5 +- tests/robot-cases/Group0-BAT/BAT.robot | 20 ++++-- 22 files changed, 242 insertions(+), 26 deletions(-) diff --git a/make/common/templates/adminserver/env b/make/common/templates/adminserver/env index 0b7c555bc..cfcd1b591 100644 --- a/make/common/templates/adminserver/env +++ b/make/common/templates/adminserver/env @@ -11,6 +11,7 @@ LDAP_FILTER=$ldap_filter LDAP_UID=$ldap_uid LDAP_SCOPE=$ldap_scope LDAP_TIMEOUT=$ldap_timeout +LDAP_VERIFY_CERT=true DATABASE_TYPE=mysql MYSQL_HOST=$db_host MYSQL_PORT=$db_port diff --git a/src/adminserver/systemcfg/systemcfg.go b/src/adminserver/systemcfg/systemcfg.go index 9cbb5d4c8..b60aedd43 100644 --- a/src/adminserver/systemcfg/systemcfg.go +++ b/src/adminserver/systemcfg/systemcfg.go @@ -81,6 +81,10 @@ var ( env: "LDAP_TIMEOUT", parse: parseStringToInt, }, + common.LDAPVerifyCert: &parser{ + env: "LDAP_VERIFY_CERT", + parse: parseStringToBool, + }, common.EmailHost: "EMAIL_HOST", common.EmailPort: &parser{ env: "EMAIL_PORT", diff --git a/src/adminserver/systemcfg/systemcfg_test.go b/src/adminserver/systemcfg/systemcfg_test.go index 6a55ceece..cbc71a29a 100644 --- a/src/adminserver/systemcfg/systemcfg_test.go +++ b/src/adminserver/systemcfg/systemcfg_test.go @@ -90,11 +90,16 @@ func TestLoadFromEnv(t *testing.T) { t.Fatalf("failed to set env: %v", err) } + if err := os.Setenv("LDAP_VERIFY_CERT", "false"); err != nil { + t.Fatalf("failed to set env: %v", err) + } + cfgs = map[string]interface{}{} err = LoadFromEnv(cfgs, false) assert.Nil(t, err) assert.Equal(t, extEndpoint, cfgs[common.ExtEndpoint]) assert.Equal(t, ldapURL, cfgs[common.LDAPURL]) + assert.Equal(t, false, cfgs[common.LDAPVerifyCert]) os.Clearenv() if err := os.Setenv("LDAP_URL", ldapURL); err != nil { @@ -104,6 +109,10 @@ func TestLoadFromEnv(t *testing.T) { t.Fatalf("failed to set env: %v", err) } + if err := os.Setenv("LDAP_VERIFY_CERT", "true"); err != nil { + t.Fatalf("failed to set env: %v", err) + } + cfgs = map[string]interface{}{ common.LDAPURL: "ldap_url", } @@ -111,4 +120,5 @@ func TestLoadFromEnv(t *testing.T) { assert.Nil(t, err) assert.Equal(t, extEndpoint, cfgs[common.ExtEndpoint]) assert.Equal(t, "ldap_url", cfgs[common.LDAPURL]) + assert.Equal(t, true, cfgs[common.LDAPVerifyCert]) } diff --git a/src/common/const.go b/src/common/const.go index ae39ee3ea..c3f01cc81 100644 --- a/src/common/const.go +++ b/src/common/const.go @@ -48,6 +48,7 @@ const ( LDAPFilter = "ldap_filter" LDAPScope = "ldap_scope" LDAPTimeout = "ldap_timeout" + LDAPVerifyCert = "ldap_verify_cert" TokenServiceURL = "token_service_url" RegistryURL = "registry_url" EmailHost = "email_host" diff --git a/src/common/models/config.go b/src/common/models/config.go index ba5c91863..d5c7c4e21 100644 --- a/src/common/models/config.go +++ b/src/common/models/config.go @@ -33,6 +33,7 @@ type LDAP struct { UID string `json:"uid"` Scope int `json:"scope"` Timeout int `json:"timeout"` // in second + VerifyCert bool `json:"verify_cert"` } // Database ... diff --git a/src/common/models/ldap.go b/src/common/models/ldap.go index e26cdfe3f..48e03cc77 100644 --- a/src/common/models/ldap.go +++ b/src/common/models/ldap.go @@ -24,6 +24,7 @@ type LdapConf struct { LdapUID string `json:"ldap_uid"` LdapScope int `json:"ldap_scope"` LdapConnectionTimeout int `json:"ldap_connection_timeout"` + LdapVerifyCert bool `json:"ldap_verify_cert"` } // LdapUser ... diff --git a/src/common/utils/ldap/ldap.go b/src/common/utils/ldap/ldap.go index dc1a7cd97..524008793 100644 --- a/src/common/utils/ldap/ldap.go +++ b/src/common/utils/ldap/ldap.go @@ -60,6 +60,7 @@ func GetSystemLdapConf() (models.LdapConf, error) { ldapConfs.LdapUID = ldap.UID ldapConfs.LdapScope = ldap.Scope ldapConfs.LdapConnectionTimeout = ldap.Timeout + ldapConfs.LdapVerifyCert = ldap.VerifyCert // ldapConfs = config.LDAP().URL // ldapConfs.LdapSearchDn = config.LDAP().SearchDn @@ -205,7 +206,8 @@ func SearchUser(ldapConfs models.LdapConf) ([]models.LdapUser, error) { for _, ldapEntry := range result.Entries { var u models.LdapUser for _, attr := range ldapEntry.Attributes { - val := attr.Values[0] + //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): @@ -337,6 +339,7 @@ func dialLDAP(ldapConfs models.LdapConf) (*goldap.Conn, 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 @@ -346,7 +349,8 @@ func dialLDAP(ldapConfs models.LdapConf) (*goldap.Conn, error) { case "ldap": ldap, err = goldap.Dial("tcp", hostport) case "ldaps": - ldap, err = goldap.DialTLS("tcp", hostport, &tls.Config{InsecureSkipVerify: true}) + log.Debug("Start to dial ldaps") + ldap, err = goldap.DialTLS("tcp", hostport, &tls.Config{ServerName: host, InsecureSkipVerify: !ldapConfs.LdapVerifyCert}) } return ldap, err @@ -401,3 +405,38 @@ 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 + + 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 + } + + ldapConfs.LdapFilter = MakeFilter(username, ldapConfs.LdapFilter, ldapConfs.LdapUID) + log.Debugf("Search with LDAP with filter %s", ldapConfs.LdapFilter) + + ldapUsers, err := SearchUser(ldapConfs) + if err != nil { + log.Errorf("Can not search ldap, error %v, filter: %s", err, ldapConfs.LdapFilter) + return 0, err + } + + 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 +} diff --git a/src/common/utils/ldap/ldap_test.go b/src/common/utils/ldap/ldap_test.go index 9dae96da7..bfff44330 100644 --- a/src/common/utils/ldap/ldap_test.go +++ b/src/common/utils/ldap/ldap_test.go @@ -17,6 +17,7 @@ package ldap import ( //"fmt" //"strings" + "os" "testing" @@ -65,6 +66,45 @@ var adminServerLdapTestConfig = map[string]interface{}{ common.AdminInitialPassword: "password", } +var adminServerDefaultConfigWithVerifyCert = map[string]interface{}{ + common.ExtEndpoint: "https://host01.com", + common.AUTHMode: common.LDAPAuth, + 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.SelfRegistration: true, + common.LDAPURL: "ldap://127.0.0.1:389", + 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.LDAPVerifyCert: true, + common.TokenServiceURL: "http://token_service", + common.RegistryURL: "http://registry", + common.EmailHost: "127.0.0.1", + common.EmailPort: 25, + common.EmailUsername: "user01", + common.EmailPassword: "password", + common.EmailFrom: "from", + common.EmailSSL: true, + common.EmailIdentity: "", + common.ProjectCreationRestriction: common.ProCrtRestrAdmOnly, + common.MaxJobWorkers: 3, + common.TokenExpiration: 30, + common.CfgExpiration: 5, + common.AdminInitialPassword: "password", + common.AdmiralEndpoint: "http://www.vmware.com", + common.WithNotary: false, + common.WithClair: false, +} + func TestMain(t *testing.T) { server, err := test.NewAdminserver(adminServerLdapTestConfig) if err != nil { @@ -125,6 +165,7 @@ func TestGetSystemLdapConf(t *testing.T) { } func TestValidateLdapConf(t *testing.T) { + testLdapConfig, err := GetSystemLdapConf() if err != nil { t.Fatalf("failed to get system ldap config %v", err) @@ -138,6 +179,7 @@ func TestValidateLdapConf(t *testing.T) { } func TestMakeFilter(t *testing.T) { + testLdapConfig, err := GetSystemLdapConf() if err != nil { @@ -254,3 +296,26 @@ func TestSearchUser(t *testing.T) { t.Errorf("unexpected ldap user search result: %s = %s", "ldapUsers[0].Username", ldapUsers[0].Username) } } + +func TestSearchAndImportUser(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!") + t.Fail() + } +} diff --git a/src/ui/api/config.go b/src/ui/api/config.go index 768394ba4..79beb1d52 100644 --- a/src/ui/api/config.go +++ b/src/ui/api/config.go @@ -40,6 +40,7 @@ var ( common.LDAPFilter, common.LDAPScope, common.LDAPTimeout, + common.LDAPVerifyCert, common.EmailHost, common.EmailPort, common.EmailUsername, @@ -80,6 +81,7 @@ var ( common.EmailSSL, common.EmailInsecure, common.SelfRegistration, + common.LDAPVerifyCert, } passwordKeys = []string{ diff --git a/src/ui/api/member.go b/src/ui/api/member.go index e1bc02041..07426a1be 100644 --- a/src/ui/api/member.go +++ b/src/ui/api/member.go @@ -17,10 +17,13 @@ package api import ( "fmt" "net/http" + "strings" "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" ) // ProjectMemberAPI handles request to /api/projects/{}/members/{} @@ -158,12 +161,26 @@ func (pma *ProjectMemberAPI) Post() { var req memberReq pma.DecodeJSONReq(&req) - username := req.Username + username := strings.TrimSpace(req.Username) userID := checkUserExists(username) if userID <= 0 { - log.Warningf("User does not exist, user name: %s", username) - pma.RenderError(http.StatusNotFound, "User does not exist") - return + //check current authorization mode + authMode, err := config.AuthMode() + if err != nil || authMode != "ldap_auth" { + log.Warningf("User does not exist, user name: %s", username) + pma.RenderError(http.StatusNotFound, "User does not exist") + return + } + + //search and import user + newUserID, err := ldapUtils.SearchAndImportUser(username) + if err == nil || newUserID > 0 { + userID = int(newUserID) + } else { + log.Warningf("User does not exist, user name: %s", username) + pma.RenderError(http.StatusNotFound, "User does not exist") + return + } } rolelist, err := dao.GetUserProjectRoles(userID, projectID) if err != nil { diff --git a/src/ui/config/config.go b/src/ui/config/config.go index 8d3d9c8bf..a70945df7 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -173,7 +173,6 @@ func LDAP() (*models.LDAP, error) { if err != nil { return nil, err } - ldap := &models.LDAP{} ldap.URL = cfg[common.LDAPURL].(string) ldap.SearchDN = cfg[common.LDAPSearchDN].(string) @@ -183,6 +182,11 @@ func LDAP() (*models.LDAP, error) { ldap.Filter = cfg[common.LDAPFilter].(string) ldap.Scope = int(cfg[common.LDAPScope].(float64)) ldap.Timeout = int(cfg[common.LDAPTimeout].(float64)) + if cfg[common.LDAPVerifyCert] != nil { + ldap.VerifyCert = cfg[common.LDAPVerifyCert].(bool) + } else { + ldap.VerifyCert = false + } return ldap, nil } diff --git a/src/ui_ng/lib/src/config/config.ts b/src/ui_ng/lib/src/config/config.ts index fe024927c..decc1fd95 100644 --- a/src/ui_ng/lib/src/config/config.ts +++ b/src/ui_ng/lib/src/config/config.ts @@ -64,6 +64,7 @@ export class Configuration { ldap_timeout: NumberValueItem; ldap_uid: StringValueItem; ldap_url: StringValueItem; + ldap_verify_cert: BoolValueItem; email_host: StringValueItem; email_identity: StringValueItem; email_from: StringValueItem; @@ -89,6 +90,7 @@ export class Configuration { this.ldap_timeout = new NumberValueItem(5, true); this.ldap_uid = new StringValueItem("", true); this.ldap_url = new StringValueItem("", true); + this.ldap_verify_cert = new BoolValueItem(true, true); this.email_host = new StringValueItem("", true); this.email_identity = new StringValueItem("", true); this.email_from = new StringValueItem("", true); diff --git a/src/ui_ng/src/app/config/auth/config-auth.component.html b/src/ui_ng/src/app/config/auth/config-auth.component.html index d982f0894..23bbf383b 100644 --- a/src/ui_ng/src/app/config/auth/config-auth.component.html +++ b/src/ui_ng/src/app/config/auth/config-auth.component.html @@ -111,6 +111,15 @@ {{'CONFIG.TOOLTIP.LDAP_SCOPE' | translate}} +
+ + + + + {{'CONFIG.TOOLTIP.VERIFY_CERT' | translate}} + + +
diff --git a/src/ui_ng/src/app/config/auth/config-auth.component.ts b/src/ui_ng/src/app/config/auth/config-auth.component.ts index 37a9afb6e..80e86bbaa 100644 --- a/src/ui_ng/src/app/config/auth/config-auth.component.ts +++ b/src/ui_ng/src/app/config/auth/config-auth.component.ts @@ -50,6 +50,10 @@ export class ConfigurationAuthComponent { } } + setVerifyCertValue($event: any) { + this.currentConfig.ldap_verify_cert.value = $event; + } + disabled(prop: any): boolean { return !(prop && prop.editable); } diff --git a/src/ui_ng/src/i18n/lang/en-us-lang.json b/src/ui_ng/src/i18n/lang/en-us-lang.json index 2031a765e..d0a7a1c75 100644 --- a/src/ui_ng/src/i18n/lang/en-us-lang.json +++ b/src/ui_ng/src/i18n/lang/en-us-lang.json @@ -425,7 +425,8 @@ "TOKEN_EXPIRATION": "The expiration time (in minutes) of a token created by the token service. Default is 30 minutes.", "PRO_CREATION_RESTRICTION": "The flag to define what users have permission to create projects. By default, everyone can create a project. Set to 'Admin Only' so that only an administrator can create a project.", "ROOT_CERT_DOWNLOAD": "Download the root certificate of registry.", - "SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday." + "SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday.", + "VERIFY_CERT": "Verify Cert from LDAP Server" }, "LDAP": { "URL": "LDAP URL", @@ -434,7 +435,8 @@ "BASE_DN": "LDAP Base DN", "FILTER": "LDAP Filter", "UID": "LDAP UID", - "SCOPE": "LDAP Scope" + "SCOPE": "LDAP Scope", + "VERIFY_CERT": "LDAP Verify Cert" }, "SCANNING": { "TRIGGER_SCAN_ALL_SUCCESS": "Trigger scan all successfully!", diff --git a/src/ui_ng/src/i18n/lang/es-es-lang.json b/src/ui_ng/src/i18n/lang/es-es-lang.json index ac73c9578..a3ee89d89 100644 --- a/src/ui_ng/src/i18n/lang/es-es-lang.json +++ b/src/ui_ng/src/i18n/lang/es-es-lang.json @@ -426,7 +426,8 @@ "TOKEN_EXPIRATION": "El tiempo de expiración (en minutos) del token creado por el servicio de tokens. Por defecto son 30 minutos.", "PRO_CREATION_RESTRICTION": "Marca para definir qué usuarios tienen permisos para crear proyectos. Por defecto, todos pueden crear proyectos. Seleccione 'Solo Administradores' para que solamente los administradores puedan crear proyectos.", "ROOT_CERT_DOWNLOAD": "Download the root certificate of registry.", - "SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday." + "SCANNING_POLICY": "Set image scanning policy based on different requirements. 'None': No active policy; 'Daily At': Triggering scanning at the specified time everyday.", + "VERIFY_CERT": "Verify Cert from LDAP Server" }, "LDAP": { "URL": "LDAP URL", @@ -435,7 +436,8 @@ "BASE_DN": "LDAP Base DN", "FILTER": "LDAP Filtro", "UID": "LDAP UID", - "SCOPE": "LDAP Ámbito" + "SCOPE": "LDAP Ámbito", + "VERIFY_CERT": "LDAP Verify Cert" }, "SCANNING": { "TRIGGER_SCAN_ALL_SUCCESS": "Trigger scan all successfully!", diff --git a/src/ui_ng/src/i18n/lang/zh-cn-lang.json b/src/ui_ng/src/i18n/lang/zh-cn-lang.json index a16a6f328..ad3c0037c 100644 --- a/src/ui_ng/src/i18n/lang/zh-cn-lang.json +++ b/src/ui_ng/src/i18n/lang/zh-cn-lang.json @@ -425,7 +425,8 @@ "TOKEN_EXPIRATION": "由令牌服务创建的令牌的过期时间(分钟),默认为30分钟。", "PRO_CREATION_RESTRICTION": "用来确定哪些用户有权限创建项目,默认为’所有人‘,设置为’仅管理员‘则只有管理员可以创建项目。", "ROOT_CERT_DOWNLOAD": "下载镜像库根证书.", - "SCANNING_POLICY": "基于不同需求设置镜像扫描策略。‘无’:不设置任何策略;‘每日定时’:每天在设置的时间定时执行扫描。" + "SCANNING_POLICY": "基于不同需求设置镜像扫描策略。‘无’:不设置任何策略;‘每日定时’:每天在设置的时间定时执行扫描。". + "VERIFY_CERT": "检查来自LDAP服务端的证书" }, "LDAP": { "URL": "LDAP URL", @@ -434,7 +435,8 @@ "BASE_DN": "LDAP基础DN", "FILTER": "LDAP过滤器", "UID": "LDAP用户UID的属性", - "SCOPE": "LDAP搜索范围" + "SCOPE": "LDAP搜索范围", + "VERIFY_CERT": "LDAP 检查证书" }, "SCANNING": { "TRIGGER_SCAN_ALL_SUCCESS": "启动扫描所有镜像任务成功!", diff --git a/tests/ldapprepare.sh b/tests/ldapprepare.sh index dded75a38..2734ca825 100755 --- a/tests/ldapprepare.sh +++ b/tests/ldapprepare.sh @@ -5,11 +5,12 @@ docker rm -f $NAME 2>/dev/null docker run --env LDAP_ORGANISATION="Harbor." \ --env LDAP_DOMAIN="example.com" \ --env LDAP_ADMIN_PASSWORD="admin" \ +--env LDAP_TLS_VERIFY_CLIENT="never" \ -p 389:389 \ -p 636:636 \ --detach --name $NAME osixia/openldap:1.1.7 -sleep 3 +sleep 5 docker cp ldap_test.ldif ldap_server:/ docker exec ldap_server ldapadd -x -D "cn=admin,dc=example,dc=com" -w admin -f /ldap_test.ldif -ZZ diff --git a/tests/resources/Harbor-Pages/Configuration.robot b/tests/resources/Harbor-Pages/Configuration.robot index 584d0ac37..ccb780b3b 100644 --- a/tests/resources/Harbor-Pages/Configuration.robot +++ b/tests/resources/Harbor-Pages/Configuration.robot @@ -24,17 +24,18 @@ Init LDAP ${rc} ${output}= Run And Return Rc And Output ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}' Log ${output} Sleep 2 - Input Text xpath=//*[@id="ldapUrl"] ldap://${output} + Input Text xpath=//*[@id="ldapUrl"] ldaps://${output} Sleep 1 - Input Text xpath=//*[@id="ldapSearchDN"] cn=admin,dc=example,dc=org + Input Text xpath=//*[@id="ldapSearchDN"] cn=admin,dc=example,dc=com Sleep 1 Input Text xpath=//*[@id="ldapSearchPwd"] admin Sleep 1 - Input Text xpath=//*[@id="ldapBaseDN"] dc=example,dc=org + Input Text xpath=//*[@id="ldapBaseDN"] dc=example,dc=com Sleep 1 Input Text xpath=//*[@id="ldapUid"] cn Sleep 1 Capture Page Screenshot + Disable Ldap Verify Cert Checkbox Click Element xpath=/html/body/harbor-app/harbor-shell/clr-main-container/div/div/config/div/div/div/button[1] Sleep 2 Click Element xpath=/html/body/harbor-app/harbor-shell/clr-main-container/div/div/config/div/div/div/button[3] @@ -45,6 +46,44 @@ Switch To Configure Click Element xpath=/html/body/harbor-app/harbor-shell/clr-main-container/div/nav/section/section/ul/li[3]/a Sleep 2 +Test Ldap Connection + ${rc} ${output}= Run And Return Rc And Output ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}' + Log ${output} + Sleep 2 + Input Text xpath=//*[@id="ldapUrl"] ldaps://${output} + Sleep 1 + Input Text xpath=//*[@id="ldapSearchDN"] cn=admin,dc=example,dc=com + Sleep 1 + Input Text xpath=//*[@id="ldapSearchPwd"] admin + Sleep 1 + Input Text xpath=//*[@id="ldapBaseDN"] dc=example,dc=com + Sleep 1 + Input Text xpath=//*[@id="ldapUid"] cn + Sleep 1 + + # default is checked, click test connection to verify fail as no cert. + Click Element xpath=${test_ldap_xpath} + Sleep 1 + Wait Until Page Contains Failed to verify LDAP server with error + Sleep 5 + + Disable Ldap Verify Cert Checkbox + # ldap checkbox unchecked, click test connection to verify success. + Sleep 1 + Click Element xpath=${test_ldap_xpath} + Capture Page Screenshot + Wait Until Page Contains Connection to LDAP server is verified timeout=15 + +Disable Ldap Verify Cert Checkbox + Mouse Down xpath=//*[@id="clr-checkbox-ldapVerifyCert"] + Mouse Up xpath=//*[@id="clr-checkbox-ldapVerifyCert"] + Sleep 2 + Capture Page Screenshot + Ldap Verify Cert Checkbox Should Be Disabled + +Ldap Verify Cert Checkbox Should Be Disabled + Checkbox Should Not Be Selected xpath=//*[@id="clr-checkbox-ldapVerifyCert"] + Set Pro Create Admin Only #set limit to admin only Sleep 2 diff --git a/tests/resources/Harbor-Pages/Configuration_Elements.robot b/tests/resources/Harbor-Pages/Configuration_Elements.robot index 5aa0e5e0d..47c600058 100644 --- a/tests/resources/Harbor-Pages/Configuration_Elements.robot +++ b/tests/resources/Harbor-Pages/Configuration_Elements.robot @@ -17,4 +17,5 @@ Documentation This resource provides any keywords related to the Harbor private *** Variables *** ${project_create_xpath} //project//div[@class="option-left"]/button -${self_reg_xpath} //input[@id="clr-checkbox-selfReg"] \ No newline at end of file +${self_reg_xpath} //input[@id="clr-checkbox-selfReg"] +${test_ldap_xpath} /html/body/harbor-app/harbor-shell/clr-main-container/div/div/config/div/div/div/button[3] \ No newline at end of file diff --git a/tests/resources/Harbor-Util.robot b/tests/resources/Harbor-Util.robot index 028ce0375..668603736 100644 --- a/tests/resources/Harbor-Util.robot +++ b/tests/resources/Harbor-Util.robot @@ -71,11 +71,12 @@ Switch To LDAP Config Harbor cfg auth=ldap_auth http_proxy=https Prepare Up Harbor - ${rc}= Run And Return Rc docker pull vmware/harbor-ldap-test:1.1.1 + ${rc}= Run And Return Rc docker pull osixia/openldap:1.1.7 Log ${rc} Should Be Equal As Integers ${rc} 0 - ${rc}= Run And Return Rc docker run --name ldap-container -p 389:389 --detach vmware/harbor-ldap-test:1.1.1 + ${rc} ${output}= Run And Return Rc And Output cd tests && ./ldapprepare.sh Log ${rc} + Log ${output} Should Be Equal As Integers ${rc} 0 ${rc} ${output}= Run And Return Rc And Output docker ps Log ${output} diff --git a/tests/robot-cases/Group0-BAT/BAT.robot b/tests/robot-cases/Group0-BAT/BAT.robot index 044d94e54..1fd7ea6db 100644 --- a/tests/robot-cases/Group0-BAT/BAT.robot +++ b/tests/robot-cases/Group0-BAT/BAT.robot @@ -328,30 +328,38 @@ Test Case - Admin Push Signed Image Test Case - Admin Push Un-Signed Image ${rc} ${output}= Run And Return Rc And Output docker push ${ip}/library/hello-world:latest Log To Console ${output} - -Test Case - Ldap Sign in and out + +Test Case - Ldap Verify Cert Switch To LDAP + Init Chrome Driver + Sign In Harbor ${HARBOR_URL} %{HARBOR_ADMIN} %{HARBOR_PASSWORD} + Switch To Configure + Test Ldap Connection + Close Browser + +Test Case - Ldap Sign in and out Init Chrome Driver Sign In Harbor ${HARBOR_URL} %{HARBOR_ADMIN} %{HARBOR_PASSWORD} Switch To Configure Init LDAP Logout Harbor - Sign In Harbor ${HARBOR_URL} user001 user001 + Sign In Harbor ${HARBOR_URL} test 123456 Close Browser Test Case - Ldap User Create Project Init Chrome Driver ${d}= Get Current Date result_format=%m%s - Sign In Harbor ${HARBOR_URL} user001 user001 + Sign In Harbor ${HARBOR_URL} test 123456 Create An New Project project${d} Close Browser Test Case - Ldap User Push An Image Init Chrome Driver ${d}= Get Current Date result_format=%m%s - Sign In Harbor ${HARBOR_URL} user001 user001 + Sign In Harbor ${HARBOR_URL} test 123456 Create An New Project project${d} - Push Image ${ip} user001 user001 project${d} hello-world:latest + + Push Image ${ip} test 123456 project${d} hello-world:latest Go Into Project project${d} Wait Until Page Contains project${d}/hello-world Close Browser From 1179769e314f761b640bcbbbc60c3f8668a4fded Mon Sep 17 00:00:00 2001 From: stonezdj Date: Fri, 24 Nov 2017 14:53:34 +0800 Subject: [PATCH 2/2] Update with PR review comment --- src/ui/api/member.go | 26 +++++++++++++++++++------- src/ui/config/config.go | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/ui/api/member.go b/src/ui/api/member.go index 07426a1be..0ac5e35af 100644 --- a/src/ui/api/member.go +++ b/src/ui/api/member.go @@ -166,21 +166,33 @@ func (pma *ProjectMemberAPI) Post() { if userID <= 0 { //check current authorization mode authMode, err := config.AuthMode() - if err != nil || authMode != "ldap_auth" { - log.Warningf("User does not exist, user name: %s", username) + if err != nil { + log.Errorf("Failed the retrieve auth_mode, error: %s", err) + pma.RenderError(http.StatusInternalServerError, "Failed to retrieve auth_mode") + return + } + + if authMode != "ldap_auth" { + log.Errorf("User does not exist, user name: %s", username) pma.RenderError(http.StatusNotFound, "User does not exist") return } //search and import user newUserID, err := ldapUtils.SearchAndImportUser(username) - if err == nil || newUserID > 0 { - userID = int(newUserID) - } else { - log.Warningf("User does not exist, user name: %s", username) - pma.RenderError(http.StatusNotFound, "User does not exist") + if err != nil { + log.Errorf("Search and import user failed, error: %v ", err) + pma.RenderError(http.StatusInternalServerError, "Failed to search and import user") return } + + if newUserID <= 0 { + log.Error("Failed to create user") + pma.RenderError(http.StatusNotFound, "Failed to create user") + return + } + + userID = int(newUserID) } rolelist, err := dao.GetUserProjectRoles(userID, projectID) if err != nil { diff --git a/src/ui/config/config.go b/src/ui/config/config.go index a70945df7..1609e82d3 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -185,7 +185,7 @@ func LDAP() (*models.LDAP, error) { if cfg[common.LDAPVerifyCert] != nil { ldap.VerifyCert = cfg[common.LDAPVerifyCert].(bool) } else { - ldap.VerifyCert = false + ldap.VerifyCert = true } return ldap, nil