Skip to content

Commit

Permalink
Vault: user_domain_id/name and project_domain_id/name implementation …
Browse files Browse the repository at this point in the history
…for dynamic users (#119)

Vault: user_domain_id/name and project_domain_id/name implementation for dynamic users

Implementation of user_domain_id/name and project_domain_id/name for dynamic users.
Changes include:

path_roles.go
path_roles_test.go
api.md
path_creds.go
path_creds_test.go
tests for new parameters

Reviewed-by: Aloento
Reviewed-by: Anton Sidelnikov
Reviewed-by: Polina Gubina
Reviewed-by: Artem Lifshits
  • Loading branch information
artem-lifshits authored Nov 21, 2022
1 parent c505d76 commit 2f5bfa8
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 86 deletions.
49 changes: 34 additions & 15 deletions acceptance/creds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package acceptance
import (
"fmt"
"net/http"
"os"
"testing"

"github.com/opentelekomcloud/vault-plugin-secrets-openstack/openstack"
Expand All @@ -15,18 +16,22 @@ import (
)

type testCase struct {
Cloud string
ProjectID string
DomainID string
Root bool
SecretType string
UserRoles []string
Extensions map[string]interface{}
Cloud string
ProjectID string
DomainID string
UserDomainID string
UserDomainName string
Root bool
SecretType string
UserRoles []string
UserGroups []string
Extensions map[string]interface{}
}

func (p *PluginTest) TestCredsLifecycle() {
t := p.T()

userDomainID := os.Getenv("USER_DOMAIN_ID")
cloud := openstackCloudConfig(t)
require.NotEmpty(t, cloud)

Expand All @@ -45,7 +50,7 @@ func (p *PluginTest) TestCredsLifecycle() {
DomainID: aux.DomainID,
Root: false,
SecretType: "token",
UserRoles: []string{"member"},
UserGroups: []string{"mygroup"},
Extensions: map[string]interface{}{
"identity_api_version": "3",
},
Expand All @@ -60,6 +65,17 @@ func (p *PluginTest) TestCredsLifecycle() {
"object_store_endpoint_override": "https://swift.example.com",
},
},
"user_domain_id_token": {
Cloud: cloud.Name,
ProjectID: aux.ProjectID,
UserDomainID: userDomainID,
Root: false,
SecretType: "token",
UserRoles: []string{"member"},
Extensions: map[string]interface{}{
"identity_api_version": "3",
},
},
}

for name, data := range cases {
Expand Down Expand Up @@ -154,12 +170,15 @@ func cloudToCloudMap(cloud *openstack.OsCloud) map[string]interface{} {

func cloudToRoleMap(data testCase) map[string]interface{} {
return fixtures.SanitizedMap(map[string]interface{}{
"cloud": data.Cloud,
"project_id": data.ProjectID,
"domain_id": data.DomainID,
"root": data.Root,
"secret_type": data.SecretType,
"user_roles": data.UserRoles,
"extensions": data.Extensions,
"cloud": data.Cloud,
"project_id": data.ProjectID,
"user_domain_id": data.UserDomainID,
"user_domain_name": data.UserDomainName,
"domain_id": data.DomainID,
"root": data.Root,
"secret_type": data.SecretType,
"user_roles": data.UserRoles,
"user_groups": data.UserGroups,
"extensions": data.Extensions,
})
}
1 change: 0 additions & 1 deletion acceptance/roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ func extractRoleData(t *testing.T, resp *http.Response) *roleData {

func (p *PluginTest) TestRoleLifecycle() {
t := p.T()

cloud := openstackCloudConfig(t)
require.NotEmpty(t, cloud)

Expand Down
16 changes: 15 additions & 1 deletion doc/source/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ created. If the role exists, it will be updated with the new attributes.
If set to `true`, `user_groups` value is ignored.
if set to `true`, `user_roles` value is ignored.
If set to `true`, `ttl` value is ignored.
if set to `true`, `user_domain_id` value is ignored.
If set to `true`, `user_domain_name` value is ignored.

- `ttl` `(string: "1h")` - Specifies TTL value for the dynamically created users as a
string duration with time suffix.
Expand All @@ -179,7 +181,19 @@ created. If the role exists, it will be updated with the new attributes.
- `domain_name` `(string: <optional>)` - Create a domain-scoped role with given domain name. Mutually exclusive with
`domain_id`.

When none of `project_name` or `project_id` is set, created role will have a project scope.
- `user_domain_id` `(string: <optional>)` - Specifies domain where user will be created with given domain id.
Mutually exclusive with `user_project_name`.

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

- `project_domain_id` `(string: <optional>)` - Specifies domain for project-scoped role with given domain id.
If one of `project_id` / `project_name` is not set `project_domain_id` value is ignored.

- `project_domain_name` `(string: <optional>)` - Specifies domain for project-scoped role with given domain name.
If one of `project_id` / `project_name` is not set `project_domain_name` value is ignored.

When one of `project_name` or `project_id` is set, created role will have a project scope.

- `extensions` `(list: [])` - A list of strings representing a key/value pair to be used as extensions to the cloud
configuration (e.g. `volume_api_version` or endpoint overrides). Format is a key and value
Expand Down
18 changes: 18 additions & 0 deletions openstack/common/gopher_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package common

import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/identity/v3/domains"
"github.com/gophercloud/gophercloud/pagination"
)

func listAvailableURL(client *gophercloud.ServiceClient) string {
return client.ServiceURL("auth", "domains")
}

func ListAvailable(client *gophercloud.ServiceClient) pagination.Pager {
url := listAvailableURL(client)
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
return domains.DomainPage{LinkedPageBase: pagination.LinkedPageBase{PageResult: r}}
})
}
146 changes: 131 additions & 15 deletions openstack/fixtures/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,73 @@ func handleGetToken(t *testing.T, w http.ResponseWriter, r *http.Request, userID
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, `
{
"token": {
"user": {
"id": "%s"
"token": {
"methods": [
"password"
],
"user": {
"domain": {
"id": "28c40f683607401da09214d373785a2d",
"name": "mydomain"
},
"id": "%s",
"name": "admin",
"password_expires_at": null
},
"audit_ids": [
"79uOElBBQguxhPHVLlCiIQ"
],
"expires_at": "2022-11-19T01:54:23.000000Z",
"issued_at": "2022-11-18T13:54:23.000000Z",
"domain": {
"id": "52af04aec5f84182b06959d2775d2000",
"name": "mydomain"
},
"roles": [
{
"id": "7d7d81cdaad4475e96d34817f1632eca",
"name": "reader"
},
{
"id": "72badea89a5d4d9cb97a4d13e8d8c486",
"name": "member"
},
{
"id": "60e69bd42e12450b925f763d574d6125",
"name": "admin"
}
],
"catalog": [
{
"endpoints": [
{
"id": "333f811aeff140768a59c9d1d9b43087",
"interface": "internal",
"region_id": "RegionOne",
"url": "http://example.com",
"region": "RegionOne"
},
{
"id": "96207c76a6154aaaa017214cd0a27810",
"interface": "admin",
"region_id": "RegionOne",
"url": "http://example.com",
"region": "RegionOne"
},
{
"id": "b3861966f62349d6ae73bf113eacb2cc",
"interface": "public",
"region_id": "RegionOne",
"url": "http://example.com",
"region": "RegionOne"
}
],
"id": "b2724497bfac49a68578e11fa7c34292",
"type": "identity",
"name": "keystone"
}
]
}
}
}
`, userID)
}
Expand Down Expand Up @@ -303,18 +365,61 @@ func handleProjectList(t *testing.T, w http.ResponseWriter, r *http.Request, pro
`, projectName)
}

func handleDomainList(t *testing.T, w http.ResponseWriter, r *http.Request, projectName string) {
t.Helper()

th.TestHeader(t, r, "Accept", "application/json")
th.TestMethod(t, r, "GET")

w.Header().Add("Content-Type", "application/json")

_, _ = fmt.Fprintf(w, `
{
"domains": [
{
"id": "test-id",
"name": "%s",
"description": "",
"enabled": true,
"tags": [],
"options": {},
"links": {
"self": "https://example.com/v3/domains/test-id"
}
},
{
"id": "default",
"name": "Default",
"description": "The default domain",
"enabled": true,
"tags": [],
"options": {},
"links": {
"self": "https://example.com/v3/domains/default"
}
}
],
"links": {
"next": null,
"self": "https://example.com/v3/domains",
"previous": null
}
}`, projectName)
}

type EnabledMocks struct {
TokenPost bool
TokenGet bool
TokenDelete bool
PasswordChange bool
ProjectList bool
UserPost bool
UserPatch bool
UserList bool
UserDelete bool
UserGet bool
GroupList bool
TokenPost bool
TokenGet bool
TokenDelete bool
PasswordChange bool
ProjectList bool
UserPost bool
UserPatch bool
UserList bool
UserDelete bool
UserGet bool
GroupList bool
AvailDomainList bool
}

func SetupKeystoneMock(t *testing.T, userID, projectName string, enabled EnabledMocks) {
Expand Down Expand Up @@ -410,4 +515,15 @@ func SetupKeystoneMock(t *testing.T, userID, projectName string, enabled Enabled
w.WriteHeader(404)
}
})

th.Mux.HandleFunc("/v3/auth/domains", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
if enabled.AvailDomainList {
handleDomainList(t, w, r, projectName)
}
default:
w.WriteHeader(404)
}
})
}
Loading

0 comments on commit 2f5bfa8

Please sign in to comment.