Skip to content

Commit 8f63890

Browse files
Detailed static roles + error messages fix (#126)
Static roles: detailed openstack domain/project settings + error messages fix Added user_domain_id/name and project_domain_id/name parameters for detailed static roles management. Several error messages fixed. Acceptance tests vault-plugin-secrets-openstack % make functional Running acceptance tests... === RUN TestPlugin === RUN TestPlugin/TestCloudLifecycle === RUN TestPlugin/TestCloudLifecycle/WriteCloud === RUN TestPlugin/TestCloudLifecycle/ReadCloud === RUN TestPlugin/TestCloudLifecycle/ListClouds === RUN TestPlugin/TestCloudLifecycle/ListClouds/method-LIST === PAUSE TestPlugin/TestCloudLifecycle/ListClouds/method-LIST === RUN TestPlugin/TestCloudLifecycle/ListClouds/method-GET === PAUSE TestPlugin/TestCloudLifecycle/ListClouds/method-GET === CONT TestPlugin/TestCloudLifecycle/ListClouds/method-LIST === CONT TestPlugin/TestCloudLifecycle/ListClouds/method-GET === RUN TestPlugin/TestCloudLifecycle/DeleteCloud === RUN TestPlugin/TestCredsLifecycle === RUN TestPlugin/TestCredsLifecycle/user_domain_id_token === RUN TestPlugin/TestCredsLifecycle/root_token === RUN TestPlugin/TestCredsLifecycle/user_token === RUN TestPlugin/TestCredsLifecycle/user_password === RUN TestPlugin/TestInfo info_test.go:42: Error Trace: info_test.go:42 Error: Should NOT be empty, but was &{ } Test: TestPlugin/TestInfo === RUN TestPlugin/TestRoleLifecycle === RUN TestPlugin/TestRoleLifecycle/WriteRole === RUN TestPlugin/TestRoleLifecycle/ReadRole === RUN TestPlugin/TestRoleLifecycle/ListRoles === RUN TestPlugin/TestRoleLifecycle/ListRoles/method-LIST === PAUSE TestPlugin/TestRoleLifecycle/ListRoles/method-LIST === RUN TestPlugin/TestRoleLifecycle/ListRoles/method-GET === PAUSE TestPlugin/TestRoleLifecycle/ListRoles/method-GET === CONT TestPlugin/TestRoleLifecycle/ListRoles/method-LIST === CONT TestPlugin/TestRoleLifecycle/ListRoles/method-GET === RUN TestPlugin/TestRoleLifecycle/DeleteRole === RUN TestPlugin/TestRootRotate rotate_test.go:65: Cloud with name default1 was created rotate_test.go:68: Cloud with name 4bju was created plugin_test.go:337: Cloud with name 4bju has been removed plugin_test.go:337: Cloud with name default1 has been removed === RUN TestPlugin/TestStaticCredsLifecycle === RUN TestPlugin/TestStaticCredsLifecycle/user_password === RUN TestPlugin/TestStaticCredsLifecycle/user_token_project_id === RUN TestPlugin/TestStaticCredsLifecycle/user_token_project_name === RUN TestPlugin/TestStaticCredsLifecycle/user_domain_id_token === RUN TestPlugin/TestStaticRoleLifecycle === RUN TestPlugin/TestStaticRoleLifecycle/WriteRole === RUN TestPlugin/TestStaticRoleLifecycle/ReadRole === RUN TestPlugin/TestStaticRoleLifecycle/ListRoles === RUN TestPlugin/TestStaticRoleLifecycle/ListRoles/method-LIST === PAUSE TestPlugin/TestStaticRoleLifecycle/ListRoles/method-LIST === RUN TestPlugin/TestStaticRoleLifecycle/ListRoles/method-GET === PAUSE TestPlugin/TestStaticRoleLifecycle/ListRoles/method-GET === CONT TestPlugin/TestStaticRoleLifecycle/ListRoles/method-LIST === CONT TestPlugin/TestStaticRoleLifecycle/ListRoles/method-GET === RUN TestPlugin/TestStaticRoleLifecycle/DeleteRole --- FAIL: TestPlugin (32.71s) --- PASS: TestPlugin/TestCloudLifecycle (0.04s) --- PASS: TestPlugin/TestCloudLifecycle/WriteCloud (0.04s) --- PASS: TestPlugin/TestCloudLifecycle/ReadCloud (0.00s) --- PASS: TestPlugin/TestCloudLifecycle/ListClouds (0.00s) --- PASS: TestPlugin/TestCloudLifecycle/ListClouds/method-LIST (0.00s) --- PASS: TestPlugin/TestCloudLifecycle/ListClouds/method-GET (0.00s) --- PASS: TestPlugin/TestCloudLifecycle/DeleteCloud (0.00s) --- PASS: TestPlugin/TestCredsLifecycle (7.99s) --- PASS: TestPlugin/TestCredsLifecycle/user_domain_id_token (2.96s) --- PASS: TestPlugin/TestCredsLifecycle/root_token (0.83s) --- PASS: TestPlugin/TestCredsLifecycle/user_token (2.38s) --- PASS: TestPlugin/TestCredsLifecycle/user_password (0.97s) --- FAIL: TestPlugin/TestInfo (0.00s) --- PASS: TestPlugin/TestRoleLifecycle (0.61s) --- PASS: TestPlugin/TestRoleLifecycle/WriteRole (0.59s) --- PASS: TestPlugin/TestRoleLifecycle/ReadRole (0.00s) --- PASS: TestPlugin/TestRoleLifecycle/ListRoles (0.00s) --- PASS: TestPlugin/TestRoleLifecycle/ListRoles/method-GET (0.00s) --- PASS: TestPlugin/TestRoleLifecycle/ListRoles/method-LIST (0.00s) --- PASS: TestPlugin/TestRoleLifecycle/DeleteRole (0.00s) --- PASS: TestPlugin/TestRootRotate (4.72s) --- PASS: TestPlugin/TestStaticCredsLifecycle (16.24s) --- PASS: TestPlugin/TestStaticCredsLifecycle/user_password (3.38s) --- PASS: TestPlugin/TestStaticCredsLifecycle/user_token_project_id (4.00s) --- PASS: TestPlugin/TestStaticCredsLifecycle/user_token_project_name (3.91s) --- PASS: TestPlugin/TestStaticCredsLifecycle/user_domain_id_token (3.92s) --- PASS: TestPlugin/TestStaticRoleLifecycle (2.96s) --- PASS: TestPlugin/TestStaticRoleLifecycle/WriteRole (1.05s) --- PASS: TestPlugin/TestStaticRoleLifecycle/ReadRole (0.00s) --- PASS: TestPlugin/TestStaticRoleLifecycle/ListRoles (0.00s) --- PASS: TestPlugin/TestStaticRoleLifecycle/ListRoles/method-LIST (0.00s) --- PASS: TestPlugin/TestStaticRoleLifecycle/ListRoles/method-GET (0.00s) --- PASS: TestPlugin/TestStaticRoleLifecycle/DeleteRole (0.00s) FAIL FAIL github.com/opentelekomcloud/vault-plugin-secrets-openstack/acceptance 33.138s FAIL make: *** [functional] Error 1 Reviewed-by: Aloento Reviewed-by: Anton Sidelnikov
1 parent c29266b commit 8f63890

File tree

7 files changed

+110
-53
lines changed

7 files changed

+110
-53
lines changed

acceptance/creds_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package acceptance
66
import (
77
"fmt"
88
"net/http"
9-
"os"
109
"testing"
1110

1211
"github.com/opentelekomcloud/vault-plugin-secrets-openstack/openstack"
@@ -31,7 +30,6 @@ type testCase struct {
3130
func (p *PluginTest) TestCredsLifecycle() {
3231
t := p.T()
3332

34-
userDomainID := os.Getenv("USER_DOMAIN_ID")
3533
cloud := openstackCloudConfig(t)
3634
require.NotEmpty(t, cloud)
3735

@@ -68,7 +66,7 @@ func (p *PluginTest) TestCredsLifecycle() {
6866
"user_domain_id_token": {
6967
Cloud: cloud.Name,
7068
ProjectID: aux.ProjectID,
71-
UserDomainID: userDomainID,
69+
UserDomainID: aux.DomainID,
7270
Root: false,
7371
SecretType: "token",
7472
UserRoles: []string{"member"},

acceptance/static_creds_test.go

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ import (
1616
)
1717

1818
type testStaticCase struct {
19-
cloud string
20-
projectID string
21-
projectName string
22-
domainID string
23-
secretType string
24-
username string
25-
extensions map[string]interface{}
19+
cloud string
20+
projectID string
21+
projectName string
22+
domainID string
23+
secretType string
24+
username string
25+
userDomainId string
26+
extensions map[string]interface{}
2627
}
2728

2829
func (p *PluginTest) TestStaticCredsLifecycle() {
@@ -70,6 +71,16 @@ func (p *PluginTest) TestStaticCredsLifecycle() {
7071
"identity_api_version": "3",
7172
},
7273
},
74+
"user_domain_id_token": {
75+
cloud: cloud.Name,
76+
projectID: aux.ProjectID,
77+
username: "static-test-4",
78+
userDomainId: aux.DomainID,
79+
secretType: "token",
80+
extensions: map[string]interface{}{
81+
"identity_api_version": "3",
82+
},
83+
},
7384
}
7485

7586
for name, data := range cases {
@@ -152,13 +163,14 @@ func staticRotateCredsURL(roleName string) string {
152163

153164
func cloudToStaticRoleMap(data testStaticCase) map[string]interface{} {
154165
return fixtures.SanitizedMap(map[string]interface{}{
155-
"cloud": data.cloud,
156-
"project_id": data.projectID,
157-
"project_name": data.projectName,
158-
"domain_id": data.domainID,
159-
"secret_type": data.secretType,
160-
"username": data.username,
161-
"extensions": data.extensions,
166+
"cloud": data.cloud,
167+
"project_id": data.projectID,
168+
"project_name": data.projectName,
169+
"user_domain_id": data.userDomainId,
170+
"domain_id": data.domainID,
171+
"secret_type": data.secretType,
172+
"username": data.username,
173+
"extensions": data.extensions,
162174
})
163175
}
164176

doc/source/api.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ created. If the role exists, it will be updated with the new attributes.
182182
`domain_id`.
183183

184184
- `user_domain_id` `(string: <optional>)` - Specifies domain where user will be created with given domain id.
185-
Mutually exclusive with `user_project_name`.
185+
Mutually exclusive with `user_domain_name`.
186186

187187
- `user_domain_name` `(string: <optional>)` - Specifies domain where user will be created with given domain name.
188-
Mutually exclusive with `user_project_id`.
188+
Mutually exclusive with `user_domain_id`.
189189

190190
- `project_domain_id` `(string: <optional>)` - Specifies domain for project-scoped role with given domain id.
191191
If one of `project_id` / `project_name` is not set `project_domain_id` value is ignored.
@@ -472,7 +472,19 @@ created. If the role exists, it will be updated with the new attributes.
472472
- `domain_name` `(string: <optional>)` - Create a domain-scoped role with given domain name. Mutually exclusive with
473473
`domain_id`.
474474

475-
When none of `project_name` or `project_id` is set, created role will have a project scope.
475+
- `user_domain_id` `(string: <optional>)` - Specifies domain id of existing user.
476+
Mutually exclusive with `user_domain_name`.
477+
478+
- `user_domain_name` `(string: <optional>)` - Specifies domain name of existing user.
479+
Mutually exclusive with `user_domain_id`.
480+
481+
- `project_domain_id` `(string: <optional>)` - Specifies domain for project-scoped role with given domain id.
482+
If one of `project_id` / `project_name` is not set `project_domain_id` value is ignored.
483+
484+
- `project_domain_name` `(string: <optional>)` - Specifies domain for project-scoped role with given domain name.
485+
If one of `project_id` / `project_name` is not set `project_domain_name` value is ignored.
486+
487+
When one of `project_name` or `project_id` is set, created static role will have a project scope.
476488

477489
- `extensions` `(list: [])` - A list of strings representing a key/value pair to be used as extensions to the cloud
478490
configuration (e.g. `volume_api_version` or endpoint overrides). Format is a key and value

openstack/path_cloud.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (b *backend) pathCloudCreateUpdate(ctx context.Context, r *logical.Request,
174174
// validate template first
175175
_, err := RandomTemporaryUsername(cloudConfig.UsernameTemplate, &roleEntry{})
176176
if err != nil {
177-
return logical.ErrorResponse("invalid username template: %s", err), nil
177+
return logical.ErrorResponse("invalid username template: %w", err), nil
178178
}
179179
} else if r.Operation == logical.CreateOperation {
180180
cloudConfig.UsernameTemplate = DefaultUsernameTemplate

openstack/path_static_creds.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,12 @@ func getScopeFromStaticRole(role *roleStaticEntry) tokens.Scope {
196196
scope = tokens.Scope{
197197
ProjectID: role.ProjectID,
198198
}
199+
case role.ProjectName != "" && (role.ProjectDomainName != "" || role.ProjectDomainID != ""):
200+
scope = tokens.Scope{
201+
ProjectName: role.ProjectName,
202+
DomainName: role.ProjectDomainName,
203+
DomainID: role.ProjectDomainID,
204+
}
199205
case role.ProjectName != "":
200206
scope = tokens.Scope{
201207
ProjectName: role.ProjectName,

openstack/path_static_role.go

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,23 @@ func (b *backend) staticRoleExistenceCheck(ctx context.Context, r *logical.Reque
141141
}
142142

143143
type roleStaticEntry struct {
144-
Name string `json:"name"`
145-
Cloud string `json:"cloud"`
146-
TTL time.Duration `json:"ttl,omitempty"`
147-
RotationDuration time.Duration `json:"rotation_duration,omitempty"`
148-
SecretType secretType `json:"secret_type"`
149-
Secret string `json:"secret"`
150-
Username string `json:"username"`
151-
UserID string `json:"user_id"`
152-
ProjectID string `json:"project_id"`
153-
ProjectName string `json:"project_name"`
154-
DomainID string `json:"domain_id"`
155-
DomainName string `json:"domain_name"`
156-
Extensions map[string]string `json:"extensions"`
144+
Name string `json:"name"`
145+
Cloud string `json:"cloud"`
146+
TTL time.Duration `json:"ttl,omitempty"`
147+
RotationDuration time.Duration `json:"rotation_duration,omitempty"`
148+
SecretType secretType `json:"secret_type"`
149+
Secret string `json:"secret"`
150+
Username string `json:"username"`
151+
UserID string `json:"user_id"`
152+
ProjectID string `json:"project_id"`
153+
ProjectName string `json:"project_name"`
154+
DomainID string `json:"domain_id"`
155+
DomainName string `json:"domain_name"`
156+
UserDomainID string `json:"user_domain_id"`
157+
UserDomainName string `json:"user_domain_name"`
158+
ProjectDomainID string `json:"project_domain_id"`
159+
ProjectDomainName string `json:"project_domain_name"`
160+
Extensions map[string]string `json:"extensions"`
157161
}
158162

159163
func roleStaticStoragePath(name string) string {
@@ -193,15 +197,19 @@ func getStaticRoleByName(ctx context.Context, name string, s *logical.Request) (
193197

194198
func staticRoleToMap(src *roleStaticEntry) map[string]interface{} {
195199
return map[string]interface{}{
196-
"cloud": src.Cloud,
197-
"rotation_duration": src.RotationDuration,
198-
"secret_type": string(src.SecretType),
199-
"username": src.Username,
200-
"project_id": src.ProjectID,
201-
"project_name": src.ProjectName,
202-
"domain_id": src.DomainID,
203-
"domain_name": src.DomainName,
204-
"extensions": src.Extensions,
200+
"cloud": src.Cloud,
201+
"rotation_duration": src.RotationDuration,
202+
"secret_type": string(src.SecretType),
203+
"username": src.Username,
204+
"project_id": src.ProjectID,
205+
"project_name": src.ProjectName,
206+
"domain_id": src.DomainID,
207+
"domain_name": src.DomainName,
208+
"user_domain_id": src.UserDomainID,
209+
"user_domain_name": src.UserDomainName,
210+
"project_domain_id": src.ProjectDomainID,
211+
"project_domain_name": src.ProjectDomainName,
212+
"extensions": src.Extensions,
205213
}
206214
}
207215

@@ -255,16 +263,25 @@ func (b *backend) pathStaticRoleUpdate(ctx context.Context, req *logical.Request
255263
entry = &roleStaticEntry{Name: name, Cloud: cloudName}
256264
}
257265

266+
if name, ok := d.GetOk("user_domain_name"); ok {
267+
entry.UserDomainName = name.(string)
268+
}
269+
270+
if id, ok := d.GetOk("user_domain_id"); ok {
271+
entry.UserDomainID = id.(string)
272+
}
273+
258274
if username, ok := d.GetOk("username"); ok {
259275
entry.Username = username.(string)
260276
password, err := Passwords{}.Generate(ctx)
261277
if err != nil {
262278
return nil, err
263279
}
264280

281+
// TODO: implement situation where userDomainId != currentDomainID
265282
userId, err := b.rotateUserPassword(ctx, req, cloud, username.(string), password)
266283
if err != nil {
267-
return logical.ErrorResponse("error during role creation: %s", err), nil
284+
return logical.ErrorResponse("error during role creation: %w", err), nil
268285
}
269286

270287
entry.UserID = userId
@@ -304,6 +321,14 @@ func (b *backend) pathStaticRoleUpdate(ctx context.Context, req *logical.Request
304321
entry.DomainID = id.(string)
305322
}
306323

324+
if name, ok := d.GetOk("project_domain_name"); ok {
325+
entry.ProjectDomainName = name.(string)
326+
}
327+
328+
if id, ok := d.GetOk("project_domain_id"); ok {
329+
entry.ProjectDomainID = id.(string)
330+
}
331+
307332
if ext, ok := d.GetOk("extensions"); ok {
308333
entry.Extensions = ext.(map[string]string)
309334
}

openstack/path_static_role_test.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,19 @@ func expectedStaticRoleData(cloudName string) (*roleStaticEntry, map[string]inte
3737
DomainName: tools.RandomString("d", 5),
3838
}
3939
expectedMap := map[string]interface{}{
40-
"cloud": expected.Cloud,
41-
"project_id": "",
42-
"project_name": expected.ProjectName,
43-
"domain_id": "",
44-
"domain_name": expected.DomainName,
45-
"extensions": map[string]string{},
46-
"rotation_duration": expTTL,
47-
"secret_type": "token",
48-
"username": "static-test",
40+
"cloud": expected.Cloud,
41+
"project_id": "",
42+
"project_name": expected.ProjectName,
43+
"domain_id": "",
44+
"domain_name": expected.DomainName,
45+
"project_domain_id": "",
46+
"project_domain_name": "",
47+
"user_domain_id": "",
48+
"user_domain_name": "",
49+
"extensions": map[string]string{},
50+
"rotation_duration": expTTL,
51+
"secret_type": "token",
52+
"username": "static-test",
4953
}
5054
return expected, expectedMap
5155
}

0 commit comments

Comments
 (0)