Skip to content

Commit 79bb2e2

Browse files
committed
ApplicationCredential Workaround for userID requirement in OpenStack API
On-behalf-of: SAP nils.gondermann@sap.com
1 parent 5829389 commit 79bb2e2

1 file changed

Lines changed: 64 additions & 3 deletions

File tree

internal/osclients/applicationcredential.go

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ package osclients
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"iter"
2324

25+
tokens3 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens"
26+
2427
"github.com/gophercloud/gophercloud/v2"
2528
"github.com/gophercloud/gophercloud/v2/openstack"
2629
"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/applicationcredentials"
30+
"github.com/gophercloud/gophercloud/v2/openstack/identity/v3/users"
2731
"github.com/gophercloud/utils/v2/openstack/clientconfig"
2832
)
2933

@@ -66,12 +70,69 @@ func (c applicationcredentialClient) DeleteApplicationCredential(ctx context.Con
6670
return applicationcredentials.Delete(ctx, c.client, resourceID).ExtractErr()
6771
}
6872

73+
func (c applicationcredentialClient) UpdateApplicationCredential(ctx context.Context, id string, opts applicationcredentials.UpdateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) {
74+
return applicationcredentials.Update(ctx, c.client, id, opts).Extract()
75+
}
76+
6977
func (c applicationcredentialClient) GetApplicationCredential(ctx context.Context, resourceID string) (*applicationcredentials.ApplicationCredential, error) {
70-
return applicationcredentials.Get(ctx, c.client, resourceID).Extract()
78+
// The unique ID of an application credential is not enough to query it from OpenStack
79+
// OpenStack actually also requires a unique user ID.
80+
// We can not provide the user ID here, as the function signatures of ORC interfaces
81+
// expect us to return an OpenStack resource based on a single string.
82+
83+
// To work around this, we first query ApplicationCredentials for the currently
84+
// authenticated user which ORC is connected as. If that fails, we iterate over
85+
// all users we have access to and query their ApplicationCredentials.
86+
87+
// Currently authenticated user
88+
userID, err := GetAuthenticatedUserID(c.client.ProviderClient)
89+
if err == nil {
90+
appCred, appCredErr := applicationcredentials.Get(ctx, c.client, userID, resourceID).Extract()
91+
92+
if appCred != nil {
93+
return appCred, appCredErr
94+
}
95+
}
96+
97+
// If not found in currently authenticated user, try iterating over all users
98+
userPager := users.List(c.client, nil)
99+
userIterator := func(yield func(*users.User, error) bool) {
100+
_ = userPager.EachPage(ctx, yieldPage(users.ExtractUsers, yield))
101+
}
102+
103+
for user, userErr := range userIterator {
104+
if userErr != nil {
105+
continue
106+
}
107+
108+
appCred, appCredErr := applicationcredentials.Get(ctx, c.client, user.ID, resourceID).Extract()
109+
110+
if appCred != nil {
111+
return appCred, appCredErr
112+
}
113+
}
114+
115+
return nil, gophercloud.ErrResourceNotFound{
116+
Name: resourceID,
117+
ResourceType: "ApplicationCredential",
118+
}
71119
}
72120

73-
func (c applicationcredentialClient) UpdateApplicationCredential(ctx context.Context, id string, opts applicationcredentials.UpdateOptsBuilder) (*applicationcredentials.ApplicationCredential, error) {
74-
return applicationcredentials.Update(ctx, c.client, id, opts).Extract()
121+
func GetAuthenticatedUserID(providerClient *gophercloud.ProviderClient) (string, error) {
122+
r := providerClient.GetAuthResult()
123+
if r == nil {
124+
return "", errors.New("no AuthResult available")
125+
}
126+
switch r := r.(type) {
127+
case tokens3.CreateResult:
128+
u, err := r.ExtractUser()
129+
if err != nil {
130+
return "", err
131+
}
132+
return u.ID, nil
133+
default:
134+
return "", errors.New("wrong AuthResult version")
135+
}
75136
}
76137

77138
type applicationcredentialErrorClient struct{ error }

0 commit comments

Comments
 (0)