Skip to content

Commit

Permalink
identity: use AuthOptionsBuilder for v2 auth
Browse files Browse the repository at this point in the history
Rather than creating a tokens2.AuthOptions inside the authentication
flow for identity v2, allow any structure that implements the
tokens2.AuthBuilderOptions interface to be used. The interface is
modified to add a CanReauth function like the v3 version has but
provides a default implementation. The gophercloud.AuthOptions already
implements this interface so there is no change to its API. Lastly add
an AuthenticateV2Ext function which will allow an out of tree identity
v2 auth mechanism to be implemented. fixes #2651. ref #1330.
  • Loading branch information
cardoe committed Jun 22, 2023
1 parent efb556a commit a5cc0d8
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 18 deletions.
30 changes: 13 additions & 17 deletions openstack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOp

switch chosen.ID {
case v2:
return v2auth(client, endpoint, options, gophercloud.EndpointOpts{})
return v2auth(client, endpoint, &options, gophercloud.EndpointOpts{})
case v3:
return v3auth(client, endpoint, &options, gophercloud.EndpointOpts{})
default:
Expand All @@ -113,10 +113,15 @@ func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOp

// AuthenticateV2 explicitly authenticates against the identity v2 endpoint.
func AuthenticateV2(client *gophercloud.ProviderClient, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
return v2auth(client, "", &options, eo)
}

// AuthenticateV2Ext explicitly authenticates against the identity v2 endpoint.
func AuthenticateV2Ext(client *gophercloud.ProviderClient, options tokens2.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
return v2auth(client, "", options, eo)
}

func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
func v2auth(client *gophercloud.ProviderClient, endpoint string, options tokens2.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
v2Client, err := NewIdentityV2(client, eo)
if err != nil {
return err
Expand All @@ -126,17 +131,7 @@ func v2auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
v2Client.Endpoint = endpoint
}

v2Opts := tokens2.AuthOptions{
IdentityEndpoint: options.IdentityEndpoint,
Username: options.Username,
Password: options.Password,
TenantID: options.TenantID,
TenantName: options.TenantName,
AllowReauth: options.AllowReauth,
TokenID: options.TokenID,
}

result := tokens2.Create(v2Client, v2Opts)
result := tokens2.Create(v2Client, options)

err = client.SetTokenAndAuthResult(result)
if err != nil {
Expand All @@ -148,18 +143,19 @@ func v2auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
return err
}

if options.AllowReauth {
// use if the client's ReauthFunc is set to avoid needing to copy the AuthOptions and mutating the AllowReauth value
// when creating the reauthentication function below. this allows breaking of the loop without v2auth having to have
// knowledge of the supplied struct, allowing for out of tree extensions
if options.CanReauth() && client.ReauthFunc != nil {
// here we're creating a throw-away client (tac). it's a copy of the user's provider client, but
// with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`,
// this should retry authentication only once
tac := *client
tac.SetThrowaway(true)
tac.ReauthFunc = nil
tac.SetTokenAndAuthResult(nil)
tao := options
tao.AllowReauth = false
client.ReauthFunc = func() error {
err := v2auth(&tac, endpoint, tao, eo)
err := v2auth(&tac, endpoint, options, eo)
if err != nil {
return err
}
Expand Down
7 changes: 6 additions & 1 deletion openstack/identity/v2/tokens/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type AuthOptionsBuilder interface {
// ToTokenCreateMap assembles the Create request body, returning an error
// if parameters are missing or inconsistent.
ToTokenV2CreateMap() (map[string]interface{}, error)
CanReauth() bool
}

// AuthOptions are the valid options for Openstack Identity v2 authentication.
Expand All @@ -53,7 +54,7 @@ type AuthOptions struct {
}

// ToTokenV2CreateMap builds a token request body from the given AuthOptions.
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
func (opts *AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
v2Opts := AuthOptionsV2{
TenantID: opts.TenantID,
TenantName: opts.TenantName,
Expand All @@ -77,6 +78,10 @@ func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
return b, nil
}

func (opts *AuthOptions) CanReauth() bool {
return opts.AllowReauth
}

// Create authenticates to the identity service and attempts to acquire a Token.
// Generally, rather than interact with this call directly, end users should
// call openstack.AuthenticatedClient(), which abstracts all of the gory details
Expand Down

0 comments on commit a5cc0d8

Please sign in to comment.