How Harbor Handles LDAP, OIDC, and UAA Authentication: A Source Code Analysis

Harbor delegates authentication to external identity providers through a pluggable security middleware architecture in src/server/middleware/security/security.go, where provider-specific implementations like ldap.Auth, oidcCli, and uaa.Auth transform credentials into unified security contexts for RBAC evaluation.

Harbor, the open-source cloud-native registry under the CNCF (goharbor/harbor), implements enterprise authentication via a modular pipeline. When a request enters the system, Harbor’s authentication mode configuration determines which security generator validates credentials against LDAP directories, OIDC providers, or Cloud Foundry UAA servers.

Authentication Mode Selection and Security Middleware

Every HTTP request passes through the central security middleware defined in src/server/middleware/security/security.go. This middleware reads the active authentication mode from the database configuration and injects it into the request context:

mode, err := config.AuthMode(r.Context())
if err == nil {
    r = r.WithContext(lib.WithAuthMode(r.Context(), mode))
}

The middleware maintains a prioritized slice of security generators that attempt to create a valid security context. As implemented in the source, the generators slice includes:

generators = []generator{
    &secret{},
    &oidcCli{},      // OIDC token validation
    &v2Token{},
    &idToken{},
    &authProxy{},
    &robot{},
    &basicAuth{},    // LDAP binds via basic auth
    &session{},
    &proxyCacheSecret{},
}

Each generator implements Generate(req *http.Request) security.Context. When mode is set to ldap_auth, oidc_auth, or uaa_auth, the corresponding generator handles credential validation while the others skip processing.

LDAP Authentication Flow

LDAP authentication is implemented in src/core/auth/ldap/ldap.go. When basic auth headers are present and the mode is ldap_auth, the flow proceeds as follows:

  1. Session Establishment: The ldap.Auth.Authenticate method loads system LDAP configuration via ldapCtl.Ctl.Session (lines 61-70 of ldap.go) and opens a connection to the directory server.
  2. User Lookup: The implementation calls SearchUser to resolve the username to a distinguished name (DN).
  3. Credential Validation: Harbor binds to the LDAP server using the supplied password to verify credentials.
  4. Group Attachment: Upon successful bind, attachLDAPGroup (lines 98-142) retrieves LDAP group memberships and attaches them to the user model for subsequent RBAC evaluation.

The resulting user object populates Username, Realname, and Email fields, which Harbor stores or updates in its database while maintaining the LDAP linkage for group synchronization.

OIDC Authentication Flow

OIDC support spans multiple packages: src/pkg/oidc for core logic and src/server/middleware/security/oidc_cli.go for request handling.

For incoming requests bearing an Authorization: Bearer <token> header, the oidcCli generator executes:

  1. Token Extraction: The valid function checks for header presence.
  2. Provider Verification: VerifyToken in src/pkg/oidc/helper.go (lines 220-224) validates the JWT against the configured OIDC provider, verifying audience and issuer claims.
  3. Context Injection: Upon validation, InjectGroupsToUser maps OIDC claims to Harbor groups, and the generator returns an OIDCContext implementing the security interface.

The API also exposes a testing endpoint at POST /c/oidc/onboard handled by oidcAPI.PingOIDC in src/server/v2.0/handler/oidc.go, which performs OIDC discovery against the provider to validate configuration before activation.

UAA Authentication Flow

Cloud Foundry UAA integration resides in src/core/auth/uaa/uaa.go. The implementation registers itself with Harbor’s auth registry on import using auth.Register(common.UAAAuth, &Auth{}).

When processing credentials:

  1. Token Exchange: Authenticate exchanges username/password for a UAA access token via client.PasswordAuth, then retrieves user details through client.GetUserInfo (lines 42-60).
  2. User Onboarding: If the user does not exist locally, OnBoardUser creates a Harbor user record with a default password marked "From UAA" (lines 64-77).
  3. Profile Synchronization: PostAuthenticate updates the user profile if UAA attributes have changed (lines 88-102).
  4. Directory Queries: The SearchUser method supports UI lookup functionality by querying the UAA API for user metadata (lines 105-129).

Security Context and RBAC Integration

Regardless of the provider, successful authentication returns a security.Context implementing:

  • GetUsername() string
  • GetUserID() int
  • IsSysAdmin() bool
  • GetRoles() []*rbac.Role

Harbor’s RBAC engine (src/common/rbac) consumes this context to evaluate policies against the user’s roles and LDAP/OIDC/UAA group memberships. The unified interface ensures that authorization logic remains agnostic to the authentication source.

Summary

  • Harbor selects authentication providers via the AuthMode configuration, read by security middleware in src/server/middleware/security/security.go.
  • LDAP authentication uses src/core/auth/ldap/ldap.go to bind against directories and synchronize groups via attachLDAPGroup.
  • OIDC verification occurs in src/pkg/oidc/helper.go through VerifyToken, with request handling by the oidcCli generator.
  • UAA support is implemented in src/core/auth/uaa/uaa.go, handling token exchange, user onboarding, and profile synchronization.
  • All providers implement the auth.AuthenticateHelper interface and return standardized security contexts for RBAC evaluation.

Frequently Asked Questions

How does Harbor determine which authentication provider to use?

Harbor reads the auth_mode setting from its configuration database via config.AuthMode(). This value (set in the Harbor UI) determines which security generator in src/server/middleware/security/security.go processes the request. When set to ldap_auth, oidc_auth, or uaa_auth, the corresponding implementation handles credential validation while other generators pass through.

Can Harbor authenticate users against multiple providers simultaneously?

No. Harbor operates in a single authentication mode at the system level. However, the security middleware maintains a chain of generators (including secret, robot, and basicAuth) to handle different credential types. For example, OIDC tokens and robot accounts can coexist, but all human users must authenticate through the configured primary provider (LDAP, OIDC, or UAA).

What happens when an LDAP or OIDC user logs into Harbor for the first time?

For LDAP, Harbor creates a local user record during the first successful bind, populating fields from the directory attributes. For OIDC, the InjectGroupsToUser function maps claims to Harbor groups during token validation. For UAA, the explicit OnBoardUser method in src/core/auth/uaa/uaa.go creates the user record with a placeholder password and the comment "From UAA" to indicate external origin.

Where does Harbor validate OIDC tokens before allowing API access?

Token validation occurs in src/pkg/oidc/helper.go within the VerifyToken function (lines 220-224). The oidcCli generator in the security middleware calls this function to validate JWT signatures, issuer claims, and audience against the configured OIDC provider before generating the security context.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →