Skip to content

[Auth] - user_domain_name and project_domain_name are silently collapsed into a single field #3738

Description

@abhijith-darshan

What happened?

When authenticating via clouds.yaml with a user and project in different domains, gophercloud v2
ignores the distinction between user_domain_name and project_domain_name and collapses both into
a single DomainName field:

// openstack/config/clouds/clouds.go
DomainName: coalesce(options.domainName, cloud.AuthInfo.UserDomainName, cloud.AuthInfo.ProjectDomainName, cloud.AuthInfo.DomainName),

This single DomainName value is then used for both the user identity lookup and the project
scope in the resulting gophercloud.AuthOptions. The clouds.yaml spec explicitly supports separate
user_domain_name and project_domain_name for exactly this scenario, but gophercloud silently
discards the distinction.

For example, with the following clouds.yaml:

clouds:
  openstack:
    auth:
      auth_url: https://identity.example.com/v3
      username: myuser
      password: mypassword
      user_domain_name: Default     # user lives in Default domain
      project_name: myproject
      project_domain_name: some_domain  # project lives in some_domain
    auth_type: password

The coalesce picks user_domain_name: Default (first non-empty value) and uses it for both the user
lookup and the project scope. Keystone then looks for myproject in Default, finds nothing, and
returns a 401 Unauthorized — with no indication that the domain scoping is the cause.

All three combinations fail:

  • user_domain_name: Default only → project scoped to Default → project not found → 401
  • project_domain_name: some_domain only → user looked up in some_domain → user not found → 401
  • both set → coalesce picks the first, same result as above

The only workaround is to use IDs instead of names (user_domain_id + project_id), since
DomainID and TenantID are separate fields that are not coalesced together.

Expectation:

user_domain_name and project_domain_name should be treated as distinct fields, mapping to
separate parts of the Keystone v3 auth request — user_domain_name scoping the user identity
lookup, and project_domain_name scoping the project. This is how the OpenStack clouds.yaml
spec defines them and how direct use of tokens.AuthOptions already handles it via the Scope
struct:

// tokens.AuthOptions correctly separates user domain from project domain
opts := &tokens.AuthOptions{
    Username:   "myuser",
    Password:   "mypassword",
    DomainName: "Default",       // user domain
    Scope: tokens.Scope{
        ProjectName: "myproject",
        DomainName:  "some_domain",  // project domain — separate field
    },
}

The clouds.yaml parsing path should produce equivalent behaviour to constructing tokens.AuthOptions
directly.

Version

v2 (current)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions