Skip to content

Commit 17dbe7c

Browse files
authored
[IAM] Implement federated provider (#126)
[IAM] Implement federated provider Which issue this PR fixes Fixes #123 Reviewed-by: None <None> Reviewed-by: Anton Sidelnikov <None> Reviewed-by: Rodion Gyrbu <fpsoff@outlook.com>
1 parent d2432de commit 17dbe7c

File tree

6 files changed

+399
-0
lines changed

6 files changed

+399
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package v3
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
8+
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools"
9+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/identity/v3/federation/providers"
10+
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
11+
)
12+
13+
func TestFederatedProviderLifecycle(t *testing.T) {
14+
if os.Getenv("OS_TENANT_ADMIN") == "" {
15+
t.Skip("Requires iam:identityProviders:createIdentityProvider permission")
16+
}
17+
18+
client, err := clients.NewIdentityV3Client()
19+
th.AssertNoErr(t, err)
20+
21+
cOpts := providers.CreateOpts{
22+
ID: tools.RandomString("test-", 5),
23+
Description: tools.RandomString("This is ", 30),
24+
Enabled: true,
25+
}
26+
27+
provider, err := providers.Create(client, cOpts).Extract()
28+
th.AssertNoErr(t, err)
29+
30+
defer func() {
31+
err = providers.Delete(client, provider.ID).ExtractErr()
32+
th.AssertNoErr(t, err)
33+
}()
34+
35+
th.AssertEquals(t, cOpts.Enabled, provider.Enabled)
36+
37+
got, err := providers.Get(client, provider.ID).Extract()
38+
th.AssertNoErr(t, err)
39+
th.AssertDeepEquals(t, provider, got)
40+
41+
pages, err := providers.List(client).AllPages()
42+
th.AssertNoErr(t, err)
43+
44+
providerList, err := providers.ExtractProviders(pages)
45+
th.AssertNoErr(t, err)
46+
found := false
47+
for _, p := range providerList {
48+
if p.ID == provider.ID {
49+
found = true
50+
break
51+
}
52+
}
53+
if !found {
54+
t.Fatalf("created provider not found in the list")
55+
}
56+
57+
iFalse := false
58+
uOpts := providers.UpdateOpts{
59+
Enabled: &iFalse,
60+
}
61+
updated, err := providers.Update(client, provider.ID, uOpts).Extract()
62+
th.AssertNoErr(t, err)
63+
th.AssertEquals(t, false, updated.Enabled)
64+
65+
got2, err := providers.Get(client, provider.ID).Extract()
66+
th.AssertNoErr(t, err)
67+
th.AssertDeepEquals(t, updated, got2)
68+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package providers
2+
3+
import (
4+
"fmt"
5+
6+
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
7+
"github.com/opentelekomcloud/gophertelekomcloud/pagination"
8+
)
9+
10+
type CreateOptsBuilder interface {
11+
Id() string
12+
ToProviderCreateMap() (map[string]interface{}, error)
13+
}
14+
15+
type CreateOpts struct {
16+
ID string `json:"-"`
17+
Description string `json:"description,omitempty"`
18+
Enabled bool `json:"enabled,omitempty"`
19+
}
20+
21+
func (opts CreateOpts) ToProviderCreateMap() (map[string]interface{}, error) {
22+
return golangsdk.BuildRequestBody(opts, "identity_provider")
23+
}
24+
25+
func (opts CreateOpts) Id() string {
26+
return opts.ID
27+
}
28+
29+
func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
30+
if opts.Id() == "" {
31+
r.Err = fmt.Errorf("missing identity provider ID")
32+
return
33+
}
34+
b, err := opts.ToProviderCreateMap()
35+
if err != nil {
36+
r.Err = fmt.Errorf("error building provider create body: %s", err)
37+
}
38+
_, r.Err = client.Put(providerURL(client, opts.Id()), b, &r.Body, &golangsdk.RequestOpts{
39+
OkCodes: []int{201},
40+
})
41+
return
42+
}
43+
44+
func Get(client *golangsdk.ServiceClient, id string) (r GetResult) {
45+
_, r.Err = client.Get(providerURL(client, id), &r.Body, nil)
46+
return
47+
}
48+
49+
func List(client *golangsdk.ServiceClient) pagination.Pager {
50+
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
51+
return ProviderPage{pagination.LinkedPageBase{PageResult: r}}
52+
})
53+
}
54+
55+
type UpdateOptsBuilder interface {
56+
ToUpdateOptsMap() (map[string]interface{}, error)
57+
}
58+
59+
type UpdateOpts struct {
60+
Description string `json:"description,omitempty"`
61+
Enabled *bool `json:"enabled,omitempty"`
62+
}
63+
64+
func (opts UpdateOpts) ToUpdateOptsMap() (map[string]interface{}, error) {
65+
return golangsdk.BuildRequestBody(opts, "identity_provider")
66+
}
67+
68+
func Update(client *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
69+
b, err := opts.ToUpdateOptsMap()
70+
if err != nil {
71+
r.Err = err
72+
return
73+
}
74+
_, r.Err = client.Patch(providerURL(client, id), b, &r.Body, &golangsdk.RequestOpts{
75+
OkCodes: []int{200},
76+
})
77+
return
78+
}
79+
80+
func Delete(client *golangsdk.ServiceClient, id string) (r DeleteResult) {
81+
_, r.Err = client.Delete(providerURL(client, id), nil)
82+
return
83+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package providers
2+
3+
import (
4+
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
5+
"github.com/opentelekomcloud/gophertelekomcloud/pagination"
6+
)
7+
8+
type Provider struct {
9+
ID string `json:"id"`
10+
Description string `json:"description"`
11+
Enabled bool `json:"enabled"`
12+
RemoteIDs []string `json:"remote_ids"`
13+
Links map[string]string `json:"links"`
14+
}
15+
16+
type commonResult struct {
17+
golangsdk.Result
18+
}
19+
20+
func (r commonResult) Extract() (*Provider, error) {
21+
s := new(Provider)
22+
return s, r.ExtractIntoStructPtr(s, "identity_provider")
23+
}
24+
25+
type CreateResult struct {
26+
commonResult
27+
}
28+
29+
type GetResult struct {
30+
commonResult
31+
}
32+
33+
type ProviderPage struct {
34+
pagination.LinkedPageBase
35+
}
36+
37+
func (p ProviderPage) IsEmpty() (bool, error) {
38+
providers, err := ExtractProviders(p)
39+
if err != nil {
40+
return false, err
41+
}
42+
return len(providers) == 0, err
43+
}
44+
45+
func ExtractProviders(r pagination.Page) ([]Provider, error) {
46+
var providers []Provider
47+
err := (r.(ProviderPage)).ExtractIntoSlicePtr(&providers, "identity_providers")
48+
return providers, err
49+
}
50+
51+
type UpdateResult struct {
52+
commonResult
53+
}
54+
55+
type DeleteResult struct {
56+
golangsdk.ErrResult
57+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package testing
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
const (
9+
providerID = "ACME"
10+
providerDescription = "Stores ACME identities"
11+
12+
listURI = "/OS-FEDERATION/identity_providers"
13+
)
14+
15+
var (
16+
providerURI = fmt.Sprintf("%s/%s", listURI, providerID)
17+
18+
providerResponse = fmt.Sprintf(`
19+
{
20+
"identity_provider": {
21+
"description": "%s",
22+
"enabled": true,
23+
"id": "%s",
24+
"remote_ids": [],
25+
"links": {
26+
"protocols": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME/protocols",
27+
"self": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME"
28+
}
29+
}
30+
}
31+
`, providerDescription, providerID)
32+
33+
providerListResponse = fmt.Sprintf(`
34+
{
35+
"identity_providers": [
36+
{
37+
"description": "%s",
38+
"enabled": true,
39+
"id": "%s",
40+
"remote_ids": [],
41+
"links": {
42+
"protocols": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME/protocols",
43+
"self": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME"
44+
}
45+
},
46+
{
47+
"description": "Stores contractor identities",
48+
"enabled": false,
49+
"remote_ids": [],
50+
"id": "ACME-contractors",
51+
"links": {
52+
"protocols": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME-contractors/protocols",
53+
"self": "https://example.com/v3/OS-FEDERATION/identity_providers/ACME-contractors"
54+
}
55+
}
56+
],
57+
"links": {
58+
"next": null,
59+
"previous": null,
60+
"self": "https://example.com/v3/OS-FEDERATION/identity_providers"
61+
}
62+
}
63+
`, providerDescription, providerID)
64+
65+
updatedProviderResposnse = strings.ReplaceAll(providerResponse, "true", "false")
66+
)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package testing
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/identity/v3/federation/providers"
9+
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
10+
fake "github.com/opentelekomcloud/gophertelekomcloud/testhelper/client"
11+
)
12+
13+
func TestProviderCreateRequest(t *testing.T) {
14+
th.SetupHTTP()
15+
defer th.TeardownHTTP()
16+
17+
th.Mux.HandleFunc(providerURI, func(w http.ResponseWriter, r *http.Request) {
18+
th.TestMethod(t, r, "PUT")
19+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
20+
th.TestHeader(t, r, "Content-Type", "application/json")
21+
th.TestHeader(t, r, "Accept", "application/json")
22+
w.WriteHeader(201)
23+
_, _ = fmt.Fprint(w, providerResponse)
24+
})
25+
26+
opts := providers.CreateOpts{
27+
ID: providerID,
28+
Description: providerDescription,
29+
Enabled: true,
30+
}
31+
p, err := providers.Create(fake.ServiceClient(), opts).Extract()
32+
th.AssertNoErr(t, err)
33+
th.AssertEquals(t, opts.ID, p.ID)
34+
th.AssertEquals(t, opts.Enabled, p.Enabled)
35+
th.AssertEquals(t, 0, len(p.RemoteIDs))
36+
}
37+
38+
func TestProviderGetRequest(t *testing.T) {
39+
th.SetupHTTP()
40+
defer th.TeardownHTTP()
41+
42+
th.Mux.HandleFunc(providerURI, func(w http.ResponseWriter, r *http.Request) {
43+
th.TestMethod(t, r, "GET")
44+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
45+
th.TestHeader(t, r, "Accept", "application/json")
46+
_, _ = fmt.Fprint(w, providerResponse)
47+
})
48+
49+
p, err := providers.Get(fake.ServiceClient(), providerID).Extract()
50+
th.AssertNoErr(t, err)
51+
th.AssertEquals(t, true, p.Enabled)
52+
th.AssertEquals(t, providerDescription, p.Description)
53+
}
54+
55+
func TestProviderListRequest(t *testing.T) {
56+
th.SetupHTTP()
57+
defer th.TeardownHTTP()
58+
59+
th.Mux.HandleFunc(listURI, func(w http.ResponseWriter, r *http.Request) {
60+
th.TestMethod(t, r, "GET")
61+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
62+
63+
w.Header().Add("Content-Type", "application/json")
64+
_, _ = fmt.Fprint(w, providerListResponse)
65+
})
66+
67+
pages, err := providers.List(fake.ServiceClient()).AllPages()
68+
th.AssertNoErr(t, err)
69+
70+
providerList, err := providers.ExtractProviders(pages)
71+
th.AssertNoErr(t, err)
72+
th.AssertEquals(t, 2, len(providerList))
73+
}
74+
75+
func TestProviderUpdateRequest(t *testing.T) {
76+
th.SetupHTTP()
77+
defer th.TeardownHTTP()
78+
79+
th.Mux.HandleFunc(providerURI, func(w http.ResponseWriter, r *http.Request) {
80+
th.TestMethod(t, r, "PATCH")
81+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
82+
83+
w.Header().Add("Content-Type", "application/json")
84+
_, _ = fmt.Fprint(w, updatedProviderResposnse)
85+
})
86+
87+
iFalse := false
88+
opts := providers.UpdateOpts{
89+
Enabled: &iFalse,
90+
}
91+
p, err := providers.Update(fake.ServiceClient(), providerID, opts).Extract()
92+
93+
th.AssertNoErr(t, err)
94+
th.AssertEquals(t, iFalse, p.Enabled)
95+
}
96+
97+
func TestProviderDeleteRequest(t *testing.T) {
98+
th.SetupHTTP()
99+
defer th.TeardownHTTP()
100+
101+
th.Mux.HandleFunc(providerURI, func(w http.ResponseWriter, r *http.Request) {
102+
th.TestMethod(t, r, "DELETE")
103+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
104+
w.WriteHeader(204)
105+
})
106+
107+
err := providers.Delete(fake.ServiceClient(), providerID).ExtractErr()
108+
th.AssertNoErr(t, err)
109+
}

0 commit comments

Comments
 (0)