This commit is contained in:
TMHBOFH 2025-10-01 10:24:19 +01:00 committed by GitHub
commit 977121d6fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 90 additions and 4 deletions

View File

@ -8985,6 +8985,9 @@ definitions:
ldap_group_attach_parallel:
$ref: '#/definitions/BoolConfigItem'
description: Attach LDAP user group information in parallel.
ldap_ad_nested_group:
$ref: '#/definitions/BoolConfigItem'
description: Enable LDAP Active Directory NestedGroup feature.
ldap_scope:
$ref: '#/definitions/IntegerConfigItem'
description: The scope to search ldap users,'0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE'
@ -9186,6 +9189,11 @@ definitions:
description: Attach LDAP user group information in parallel, the parallel worker count is 5
x-omitempty: true
x-isnullable: true
ldap_ad_nested_group:
type: boolean
description: Enable Active Directory nested group membership resolution
x-omitempty: true
x-isnullable: true
ldap_scope:
type: integer
description: The scope to search ldap users,'0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE'

View File

@ -136,6 +136,7 @@ const (
LDAPGroupAdminDn = "ldap_group_admin_dn"
LDAPGroupMembershipAttribute = "ldap_group_membership_attribute"
LDAPGroupAttachParallel = "ldap_group_attach_parallel"
LDAPADNestedGroup = "ldap_ad_nested_group"
DefaultRegistryControllerEndpoint = "http://registryctl:8080"
DefaultPortalURL = "http://portal:8080"
DefaultRegistryCtlURL = "http://registryctl:8080"

View File

@ -97,6 +97,7 @@ var (
{Name: common.LDAPVerifyCert, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_VERIFY_CERT", DefaultValue: "true", ItemType: &BoolType{}, Editable: false, Description: `Whether verify your OIDC server certificate, disable it if your OIDC server is hosted via self-hosted certificate.`},
{Name: common.LDAPGroupMembershipAttribute, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_GROUP_MEMBERSHIP_ATTRIBUTE", DefaultValue: "memberof", ItemType: &StringType{}, Editable: true, Description: `The user attribute to identify the group membership`},
{Name: common.LDAPGroupAttachParallel, Scope: UserScope, Group: LdapBasicGroup, EnvKey: "LDAP_GROUP_ATTACH_PARALLEL", DefaultValue: "false", ItemType: &BoolType{}, Editable: true, Description: `Attach LDAP group information to Harbor in parallel`},
{Name: common.LDAPADNestedGroup, Scope: UserScope, Group: LdapGroupGroup, EnvKey: "LDAP_AD_NESTED_GROUP", DefaultValue: "false", ItemType: &BoolType{}, Editable: true, Description: `Enable Active Directory nested group membership resolution`},
{Name: common.MaxJobWorkers, Scope: SystemScope, Group: BasicGroup, EnvKey: "MAX_JOB_WORKERS", DefaultValue: "10", ItemType: &IntType{}, Editable: false},
{Name: common.ScanAllPolicy, Scope: UserScope, Group: BasicGroup, EnvKey: "", DefaultValue: "", ItemType: &MapType{}, Editable: false, Description: `The policy to scan images`},

View File

@ -96,6 +96,7 @@ type GroupConf struct {
AdminDN string `json:"ldap_group_admin_dn,omitempty"`
MembershipAttribute string `json:"ldap_group_membership_attribute,omitempty"`
AttachParallel bool `json:"ldap_group_attach_parallel,omitempty"`
ADNestedGroup bool `json:"ldap_ad_nested_group,omitempty"`
}
type GDPRSetting struct {

View File

@ -82,6 +82,7 @@ func LDAPGroupConf(ctx context.Context) (*cfgModels.GroupConf, error) {
AdminDN: mgr.Get(ctx, common.LDAPGroupAdminDn).GetString(),
MembershipAttribute: mgr.Get(ctx, common.LDAPGroupMembershipAttribute).GetString(),
AttachParallel: mgr.Get(ctx, common.LDAPGroupAttachParallel).GetBool(),
ADNestedGroup: mgr.Get(ctx, common.LDAPADNestedGroup).GetBool(),
}, nil
}

View File

@ -179,6 +179,25 @@ func (s *Session) SearchUser(username string) ([]model.User, error) {
}
u.GroupDNList = groupDNList
}
if s.groupCfg.ADNestedGroup {
log.Debugf("Searching for nested groups")
nestedGroupDNList := make([]string, 0)
nestedGroupFilter, err := createADNestedGroupFilter(s.groupCfg.Filter, ldapEntry.DN)
if err != nil {
return nil, err
}
result, err := s.SearchLdapAttribute(s.groupCfg.BaseDN, nestedGroupFilter, []string{s.groupCfg.NameAttribute})
if err != nil {
return nil, err
}
for _, groupEntry := range result.Entries {
nestedGroupDNList = append(nestedGroupDNList, strings.TrimSpace(groupEntry.DN))
log.Debugf("Found group %v", groupEntry.DN)
}
u.GroupDNList = nestedGroupDNList
log.Debugf("Done searching for nested groups")
}
u.DN = ldapEntry.DN
ldapUsers = append(ldapUsers, u)
}
@ -430,3 +449,19 @@ func createGroupSearchFilter(baseFilter, groupName, groupNameAttr string) (strin
fb := base.And(gFilter)
return fb.String()
}
// createADNestedGroupFilter - Create nested group search filter for user
func createADNestedGroupFilter(baseFilter, userDN string) (string, error) {
base, err := NewFilterBuilder(baseFilter)
if err != nil {
log.Errorf("failed to create group search filter:%v", baseFilter)
return "", err
}
nFilter, err := NewFilterBuilder("(member:1.2.840.113556.1.4.1941:=" + userDN + ")")
if err != nil {
log.Errorf("invalid ldap filter:%v", userDN)
return "", err
}
fb := base.And(nFilter)
return fb.String()
}

View File

@ -519,9 +519,7 @@
<clr-checkbox-wrapper>
<input
(ngModelChange)="setLdapGroupAttachParallelValue($event)"
[disabled]="
disabled(currentConfig.ldap_group_attach_parallel)
"
[disabled]="disabled(currentConfig.ldap_group_attach_parallel)"
[ngModel]="currentConfig.ldap_group_attach_parallel.value"
clrCheckbox
id="ldapGroupAttachParallel"
@ -529,6 +527,35 @@
type="checkbox" />
</clr-checkbox-wrapper>
</clr-checkbox-container>
<clr-checkbox-container>
<label for="ldapADNestedGroup">
{{ 'CONFIG.LDAP.LDAP_AD_NESTED_GROUP' | translate }}
<clr-tooltip>
<clr-icon
clrTooltipTrigger
shape="info-circle"
size="24"></clr-icon>
<clr-tooltip-content
*clrIfOpen
clrPosition="top-right"
clrSize="lg">
<span>{{
'CONFIG.LDAP.LDAP_AD_NESTED_GROUP_INFO' | translate
}}</span>
</clr-tooltip-content>
</clr-tooltip>
</label>
<clr-checkbox-wrapper>
<input
(ngModelChange)="setLdapADNestedGroupValue($event)"
[disabled]="disabled(currentConfig.ldap_ad_nested_group)"
[ngModel]="currentConfig.ldap_ad_nested_group.value"
clrCheckbox
id="ldapADNestedGroup"
name="ldapADNestedGroup"
type="checkbox" />
</clr-checkbox-wrapper>
</clr-checkbox-container>
</section>
<clr-checkbox-container *ngIf="showSelfReg">
<label for="selfReg"

View File

@ -135,6 +135,10 @@ export class ConfigurationAuthComponent implements OnInit {
setLdapGroupAttachParallelValue($event: any) {
this.currentConfig.ldap_group_attach_parallel.value = $event;
}
setLdapADNestedGroupValue($event: any) {
this.currentConfig.ldap_ad_nested_group.value = $event;
}
public pingTestServer(): void {
if (this.testingOnGoing) {
return; // Should not come here

View File

@ -73,6 +73,7 @@ export class Configuration {
ldap_group_membership_attribute: StringValueItem;
ldap_group_admin_dn: StringValueItem;
ldap_group_attach_parallel: BoolValueItem;
ldap_ad_nested_group: BoolValueItem;
uaa_client_id: StringValueItem;
uaa_client_secret?: StringValueItem;
uaa_endpoint: StringValueItem;
@ -141,6 +142,7 @@ export class Configuration {
this.ldap_group_search_scope = new NumberValueItem(0, true);
this.ldap_group_membership_attribute = new StringValueItem('', true);
this.ldap_group_admin_dn = new StringValueItem('', true);
this.ldap_ad_nested_group = new BoolValueItem(false, true);
this.uaa_client_id = new StringValueItem('', true);
this.uaa_client_secret = new StringValueItem('', true);
this.uaa_endpoint = new StringValueItem('', true);

View File

@ -147,6 +147,10 @@ describe('ProjectComponent', () => {
value: true,
editable: true,
},
ldap_ad_nested_group: {
value: false,
editable: true,
},
notification_enable: {
value: true,
editable: true,

View File

@ -957,7 +957,9 @@
"GROUP_SCOPE": "LDAP Group Search Scope",
"GROUP_SCOPE_INFO": "The scope to search for groups, select Subtree by default.",
"GROUP_ATTACH_PARALLEL": "LDAP Group Attached In Parallel",
"GROUP_ATTACH_PARALLEL_INFO": "Enable this option to attach group in parallel to avoid timeout when there are too many groups. If disabled, the LDAP group information will be attached sequentially."
"GROUP_ATTACH_PARALLEL_INFO": "Enable this option to attach group in parallel to avoid timeout when there are too many groups. If disabled, the LDAP group information will be attached sequentially.",
"LDAP_AD_NESTED_GROUP": "Support Nested Group in Active Directory",
"LDAP_AD_NESTED_GROUP_INFO": "This option allows nested group resolution in Active Directory by using the LDAP_MATCHING_RULE_IN_CHAIN."
},
"UAA": {
"ENDPOINT": "UAA Endpoint",