Harbor Enterprise Identity Provider Integration: LDAP/AD and OIDC Authentication Explained
Harbor integrates with enterprise identity providers by using a configurable auth_mode setting that switches between LDAP/Active Directory and OpenID Connect (OIDC) plugins, both of which authenticate users, synchronize group memberships, and map administrative privileges through a unified authentication framework.
Harbor, the open-source cloud-native registry, provides robust enterprise identity provider integration through its pluggable authentication architecture. By setting the auth_mode configuration to either ldap_auth or oidc_auth, administrators can connect Harbor to existing corporate directories or identity platforms like Active Directory, Keycloak, or Dex. This guide examines the implementation details in the goharbor/harbor source code to show exactly how these integrations function.
Authentication Mode Configuration
Harbor's identity provider integration centers on the auth_mode configuration key defined in src/common/const.go. The system supports three primary modes: db_auth for local database authentication, ldap_auth for LDAP/Active Directory, and oidc_auth for OpenID Connect providers.
The configuration is accessed at runtime through config.AuthMode in src/lib/config/userconfig.go:
// src/lib/config/userconfig.go
func AuthMode(ctx context.Context) (string, error) {
mgr := DefaultMgr()
err := mgr.Load(ctx)
if err != nil {
log.Errorf("failed to load config, error %v", err)
return "db_auth", err
}
return mgr.Get(ctx, common.AUTHMode).GetString(), nil
}
Harbor's UI, API handlers, and CLI tools invoke this function to determine which authentication plugin to execute for each request.
LDAP and Active Directory Integration
When auth_mode is set to ldap_auth, Harbor delegates authentication to an external LDAP or Active Directory server. This implementation resides in src/core/auth/ldap/ldap.go and supports user authentication, group synchronization, and administrative role mapping.
Configuration Schema
LDAP settings are retrieved via LDAPConf in src/lib/config/userconfig.go, which loads parameters including server URL, bind credentials, base DN, and group search filters:
// src/lib/config/userconfig.go
func LDAPConf(ctx context.Context) (*cfgModels.LdapConf, error) {
// ...
return &cfgModels.LdapConf{
URL: mgr.Get(ctx, common.LDAPURL).GetString(),
SearchDn: mgr.Get(ctx, common.LDAPSearchDN).GetString(),
SearchPassword: mgr.Get(ctx, common.LDAPSearchPwd).GetString(),
BaseDn: mgr.Get(ctx, common.LDAPBaseDN).GetString(),
UID: mgr.Get(ctx, common.LDAPUID).GetString(),
Filter: mgr.Get(ctx, common.LDAPFilter).GetString(),
Scope: mgr.Get(ctx, common.LDAPScope).GetInt(),
ConnectionTimeout: mgr.Get(ctx, common.LDAPTimeout).GetInt(),
VerifyCert: mgr.Get(ctx, common.LDAPVerifyCert).GetBool(),
}, nil
}
Authentication Flow and Session Management
The LDAP authentication process follows these steps implemented in src/core/auth/ldap/ldap.go and src/controller/ldap/controller.go:
- Session Establishment: The
Sessionmethod insrc/controller/ldap/controller.gocreates a connection to the configured LDAP server:
// src/controller/ldap/controller.go
func (c *controller) Session(ctx context.Context) (*ldap.Session, error) {
cfg, groupCfg, err := c.ldapConfigs(ctx)
// ...
return ldap.NewSession(*cfg, *groupCfg), nil
}
-
User Search and Bind: The system searches for the user's DN using the configured
UIDattribute (typicallysAMAccountNamefor Active Directory oruidfor OpenLDAP), then performs an LDAP bind with the supplied password. -
Group Attachment: Upon successful authentication,
attachLDAPGroupmaps LDAP group memberships to Harbor's internal group system:
// src/core/auth/ldap/ldap.go
func (l *Auth) attachLDAPGroup(ctx context.Context, ldapUsers []model.User, u *models.User, sess *ldap.Session) {
// read LDAP group config, map group DN → Harbor group
// if group matches the admin DN, set u.AdminRoleInAuth = true
// populate user‑group relationships via ugCtl.Ctl.Populate
}
Administrative Privileges via LDAP Groups
Harbor grants system administrator privileges when a user's LDAP group DN matches the ldap_group_admin_dn configuration value. During the attachLDAPGroup execution, the system sets u.AdminRoleInAuth = true if the user belongs to the designated administrative group, allowing centralized privilege management through your directory service.
OIDC Integration
For modern identity platforms, Harbor's oidc_auth mode implements the OpenID Connect Authorization Code flow. This integration is handled by src/core/auth/oidc/oidc.go and the security middleware in src/server/middleware/security/idtoken.go.
OIDC Configuration Parameters
Settings are loaded via OIDCSetting in src/lib/config/userconfig.go:
// src/lib/config/userconfig.go
func OIDCSetting(ctx context.Context) (*cfgModels.OIDCSetting, error) {
// ...
return &cfgModels.OIDCSetting{
Name: mgr.Get(ctx, common.OIDCName).GetString(),
Endpoint: mgr.Get(ctx, common.OIDCEndpoint).GetString(),
VerifyCert: mgr.Get(ctx, common.OIDCVerifyCert).GetBool(),
AutoOnboard: mgr.Get(ctx, common.OIDCAutoOnboard).GetBool(),
ClientID: mgr.Get(ctx, common.OIDCCLientID).GetString(),
ClientSecret: mgr.Get(ctx, common.OIDCClientSecret).GetString(),
GroupsClaim: mgr.Get(ctx, common.OIDCGroupsClaim).GetString(),
GroupFilter: mgr.Get(ctx, common.OIDCGroupFilter).GetString(),
AdminGroup: mgr.Get(ctx, common.OIDCAdminGroup).GetString(),
// ...
}, nil
}
Authorization Code Flow Implementation
The OIDC login process routes through handlers defined in src/server/route.go:
-
Initiation: Users click "Log in with OIDC" which redirects to
common.OIDCLoginPathhandled bysrc/server/handler/oidc.go. -
Token Exchange: After the IdP redirects to
common.OIDCCallbackPath, Harbor exchanges the authorization code for ID and access tokens. -
Token Validation: The
src/server/middleware/security/idtoken.gomiddleware validates the ID token signature, issuer, and audience, then extracts user claims:
// src/server/middleware/security/idtoken.go
setting, err := config.OIDCSetting(ctx)
// validate signature, issuer, audience etc.
// extract sub, iss, user claim, groups claim
Group Synchronization and Auto-Onboarding
When AutoOnboard is enabled, Harbor automatically creates local user records from validated ID tokens. Group memberships are derived from the claim specified by GroupsClaim (commonly groups), filtered by the GroupFilter regular expression. Members of the group named in OIDCAdminGroup receive Harbor system administrator privileges.
The user response includes WithOIDCInfo: auth == common.OIDCAuth && id > 1 as implemented in src/server/v2.0/handler/user.go (line 231), enabling the UI to display OIDC-specific elements like CLI secret management.
Plugin Registration and Unified Framework
Both authentication methods register themselves in their respective init() functions, enabling Harbor's dispatcher to route authentication requests appropriately:
// src/core/auth/ldap/ldap.go
func init() { auth.Register(common.LDAPAuth, &Auth{}) }
// src/core/auth/oidc/oidc.go
func init() { auth.Register(common.OIDCAuth, &Auth{}) }
This architecture allows Harbor to switch between identity providers without code changes, simply by updating the auth_mode configuration and restarting the service.
Configuration Examples
Enabling LDAP Authentication
Configure LDAP integration in harbor.yml or through the UI:
auth_mode: ldap_auth
ldap_url: ldap://ldap.mycompany.com:389
ldap_search_dn: cn=admin,dc=mycompany,dc=com
ldap_search_password: <redacted>
ldap_base_dn: dc=mycompany,dc=com
ldap_uid: sAMAccountName
ldap_filter: (objectClass=person)
ldap_scope: 2
ldap_group_base_dn: ou=Groups,dc=mycompany,dc=com
ldap_group_admin_dn: cn=harbor_admin,ou=Groups,dc=mycompany,dc=com
Enabling OIDC Authentication
auth_mode: oidc_auth
oidc_name: Keycloak
oidc_endpoint: https://keycloak.mycompany.com/realms/production
oidc_client_id: harbor
oidc_client_secret: <redacted>
oidc_auto_onboard: true
oidc_groups_claim: groups
oidc_group_filter: ^harbor-.*$
oidc_admin_group: harbor-admins
oidc_scope: openid,profile,email,offline_access
CLI Authentication with OIDC
# Obtain OIDC token from your provider
export OIDC_TOKEN=$(your-oidc-helper --get-token)
# Login using token as password
harbor login myharbor.example.com --username <email> --password $OIDC_TOKEN
Creating LDAP Group Mappings via API
curl -u admin:adminpw -X POST "https://myharbor/api/v2.0/usergroups" \
-H "Content-Type: application/json" \
-d '{
"group_name": "developers",
"ldap_group_dn": "cn=dev_team,ou=Groups,dc=mycompany,dc=com",
"group_type": 1
}'
Note that group_type: 1 corresponds to LDAPGroupType defined in src/common/const.go.
Summary
- Harbor uses the
auth_modeconfiguration key to switch between database, LDAP/AD, and OIDC authentication methods loaded fromsrc/lib/config/userconfig.go. - LDAP integration binds to external directories via
src/core/auth/ldap/ldap.go, supporting user search, password validation, and group membership synchronization throughattachLDAPGroup. - OIDC integration implements the Authorization Code flow in
src/server/handler/oidc.go, validates tokens insrc/server/middleware/security/idtoken.go, and supports auto-onboarding and group claim mapping. - Both methods register via
auth.Register()using constants fromsrc/common/const.go, allowing seamless switching between identity providers. - Administrative privileges can be assigned through LDAP group DN matching (
ldap_group_admin_dn) or OIDC group membership (oidc_admin_group).
Frequently Asked Questions
How does Harbor determine which identity provider to use?
Harbor reads the auth_mode configuration from the database via config.AuthMode() in src/lib/config/userconfig.go. Valid values include db_auth for local authentication, ldap_auth for LDAP/Active Directory, and oidc_auth for OpenID Connect. The authentication dispatcher uses this value to select the appropriate registered plugin.
Can Harbor automatically create users from OIDC tokens?
Yes. When oidc_auto_onboard is set to true in the configuration, Harbor automatically creates local user records upon first successful OIDC authentication. This behavior is handled by the OIDC authentication plugin in src/core/auth/oidc/oidc.go, which implements the OnBoardGroup interface to synchronize user data without manual intervention.
How does group membership work with LDAP integration?
During LDAP authentication, the attachLDAPGroup method in src/core/auth/ldap/ldap.go queries the LDAP directory for group memberships using the configured ldap_group_base_dn and filter settings. It then maps these LDAP groups to Harbor's internal group system. If a user's group DN matches ldap_group_admin_dn, Harbor grants system administrator privileges by setting AdminRoleInAuth = true.
What OIDC claims does Harbor use for group mapping?
Harbor extracts group information from the ID token claim specified by the oidc_groups_claim configuration parameter (commonly set to groups). The optional oidc_group_filter applies a regular expression to filter which groups are imported into Harbor. Members of the group specified in oidc_admin_group automatically receive system administrator access according to the logic in src/controller/user/controller.go.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →