diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ba1d9c0b8..4c569a80e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -3494,6 +3494,9 @@ definitions: ldap_group_search_scope: type: integer description: The scope to search ldap. '0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE' + ldap_group_admin_dn: + type: string + description: Specify the ldap group which have the same privilege with Harbor admin. project_creation_restriction: type: string description: >- diff --git a/make/common/templates/adminserver/env b/make/common/templates/adminserver/env index d991be6cd..33226706d 100644 --- a/make/common/templates/adminserver/env +++ b/make/common/templates/adminserver/env @@ -61,3 +61,4 @@ REGISTRY_STORAGE_PROVIDER_NAME=$storage_provider_name READ_ONLY=false SKIP_RELOAD_ENV_PATTERN=$skip_reload_env_pattern RELOAD_KEY=$reload_key +LDAP_GROUP_ADMIN_DN=$ldap_group_admin_dn \ No newline at end of file diff --git a/make/prepare b/make/prepare index bc8989d2b..a9c503d9c 100755 --- a/make/prepare +++ b/make/prepare @@ -344,6 +344,8 @@ else: #Use reload_key to avoid reload config after restart harbor reload_key = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) if reload_config == "true" else "" +ldap_group_admin_dn = rcp.get("configuration", "ldap_group_admin_dn") if rcp.has_option("configuration", "ldap_group_admin_dn") else "" + render(os.path.join(templates_dir, "adminserver", "env"), adminserver_conf_env, reload_config=reload_config, @@ -364,6 +366,7 @@ render(os.path.join(templates_dir, "adminserver", "env"), ldap_group_filter=ldap_group_filter, ldap_group_gid=ldap_group_gid, ldap_group_scope=ldap_group_scope, + ldap_group_admin_dn=ldap_group_admin_dn, db_password=db_password, db_host=db_host, db_user=db_user, diff --git a/src/adminserver/systemcfg/systemcfg.go b/src/adminserver/systemcfg/systemcfg.go index 62a2becbc..7fe0f77e2 100644 --- a/src/adminserver/systemcfg/systemcfg.go +++ b/src/adminserver/systemcfg/systemcfg.go @@ -163,7 +163,8 @@ var ( env: "READ_ONLY", parse: parseStringToBool, }, - common.ReloadKey: "RELOAD_KEY", + common.ReloadKey: "RELOAD_KEY", + common.LdapGroupAdminDn: "LDAP_GROUP_ADMIN_DN", } // configurations need read from environment variables diff --git a/src/common/const.go b/src/common/const.go index b53ec35ea..5f8d15402 100644 --- a/src/common/const.go +++ b/src/common/const.go @@ -108,4 +108,5 @@ const ( DefaultNotaryEndpoint = "http://notary-server:4443" LdapGroupType = 1 ReloadKey = "reload_key" + LdapGroupAdminDn = "ldap_group_admin_dn" ) diff --git a/src/common/models/ldap.go b/src/common/models/ldap.go index 7d666b3a6..ce7793a44 100644 --- a/src/common/models/ldap.go +++ b/src/common/models/ldap.go @@ -33,6 +33,7 @@ type LdapGroupConf struct { LdapGroupFilter string `json:"ldap_group_filter,omitempty"` LdapGroupNameAttribute string `json:"ldap_group_name_attribute,omitempty"` LdapGroupSearchScope int `json:"ldap_group_search_scope"` + LdapGroupAdminDN string `json:"ldap_group_admin_dn,omitempty"` } // LdapUser ... diff --git a/src/ui/auth/ldap/ldap.go b/src/ui/auth/ldap/ldap.go index 05363c0cf..d0e21e2b8 100644 --- a/src/ui/auth/ldap/ldap.go +++ b/src/ui/auth/ldap/ldap.go @@ -27,6 +27,7 @@ import ( ldapUtils "github.com/vmware/harbor/src/common/utils/ldap" "github.com/vmware/harbor/src/common/utils/log" "github.com/vmware/harbor/src/ui/auth" + "github.com/vmware/harbor/src/ui/config" ) // Auth implements AuthenticateHelper interface to authenticate against LDAP @@ -84,8 +85,17 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) { return nil, auth.NewErrAuth(err.Error()) } + //Retrieve ldap related info in login to avoid too many traffic with LDAP server. + //Get group admin dn + groupCfg, err := config.LDAPGroupConf() + groupAdminDN := strings.TrimSpace(groupCfg.LdapGroupAdminDN) //Attach user group for _, groupDN := range ldapUsers[0].GroupDNList { + + if len(groupAdminDN) > 0 && groupAdminDN == groupDN { + u.HasAdminRole = true + } + userGroupQuery := models.UserGroup{ GroupType: 1, LdapGroupDN: groupDN, @@ -210,7 +220,8 @@ func (l *Auth) PostAuthenticate(u *models.User) error { return nil } u.UserID = dbUser.UserID - u.HasAdminRole = dbUser.HasAdminRole + //If user has admin role already, do not overwrite by user info in DB. + u.HasAdminRole = u.HasAdminRole || dbUser.HasAdminRole if dbUser.Email != u.Email { Re := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`) diff --git a/src/ui/auth/ldap/ldap_test.go b/src/ui/auth/ldap/ldap_test.go index d09b9a2b3..2e65b2fab 100644 --- a/src/ui/auth/ldap/ldap_test.go +++ b/src/ui/auth/ldap/ldap_test.go @@ -69,6 +69,7 @@ var adminServerLdapTestConfig = map[string]interface{}{ common.LDAPGroupBaseDN: "dc=example,dc=com", common.LDAPGroupAttributeName: "cn", common.LDAPGroupSearchScope: 2, + common.LdapGroupAdminDn: "cn=harbor_users,ou=groups,dc=example,dc=com", } func TestMain(m *testing.M) { @@ -181,6 +182,38 @@ func TestSearchUser(t *testing.T) { t.Errorf("Search user failed %v", user) } } +func TestAuthenticateWithAdmin(t *testing.T) { + var person models.AuthModel + var authHelper *Auth + person.Principal = "mike" + person.Password = "zhu88jie" + user, err := authHelper.Authenticate(person) + if err != nil { + t.Errorf("unexpected ldap authenticate fail: %v", err) + } + if user.Username != "mike" { + t.Errorf("unexpected ldap user authenticate fail: %s = %s", "user.Username", user.Username) + } + if !user.HasAdminRole { + t.Errorf("ldap user mike should have admin role!") + } +} +func TestAuthenticateWithoutAdmin(t *testing.T) { + var person models.AuthModel + var authHelper *Auth + person.Principal = "user001" + person.Password = "zhu88jie" + user, err := authHelper.Authenticate(person) + if err != nil { + t.Errorf("unexpected ldap authenticate fail: %v", err) + } + if user.Username != "user001" { + t.Errorf("unexpected ldap user authenticate fail: %s = %s", "user.Username", user.Username) + } + if user.HasAdminRole { + t.Errorf("ldap user user001 should not have admin role!") + } +} func TestSearchUser_02(t *testing.T) { var username = "nonexist" var auth *Auth diff --git a/src/ui/config/config.go b/src/ui/config/config.go index 230909c1f..ec651ec44 100644 --- a/src/ui/config/config.go +++ b/src/ui/config/config.go @@ -249,6 +249,9 @@ func LDAPGroupConf() (*models.LdapGroupConf, error) { ldapGroupConf.LdapGroupSearchScope = int(scopeFloat) } } + if _, ok := cfg[common.LdapGroupAdminDn]; ok { + ldapGroupConf.LdapGroupAdminDN = cfg[common.LdapGroupAdminDn].(string) + } return ldapGroupConf, nil }