Skip to content

Commit 79c7c4e

Browse files
authored
[CLOUDTRUST-4658] Add client for bearer auth according to realm
1 parent fee0b0e commit 79c7c4e

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

advanced_auth_client.go

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package httpclient
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"gopkg.in/h2non/gentleman.v2/plugin"
8+
"gopkg.in/h2non/gentleman.v2/plugins/headers"
9+
)
10+
11+
// OidcTokenProvider provides OIDC tokens
12+
type OidcTokenProvider interface {
13+
ProvideToken(ctx context.Context) (string, error)
14+
ProvideTokenForRealm(ctx context.Context, realm string) (string, error)
15+
}
16+
17+
// RestClient interface
18+
type RestClient interface {
19+
Get(data interface{}, plugins ...plugin.Plugin) error
20+
Post(data interface{}, plugins ...plugin.Plugin) (string, error)
21+
Delete(plugins ...plugin.Plugin) error
22+
Put(plugins ...plugin.Plugin) error
23+
}
24+
25+
type MultiRealmTokenClient struct {
26+
client *Client
27+
tokenProvider OidcTokenProvider
28+
realm string
29+
}
30+
31+
func NewMultiRealmTokenClient(addrAPI string, reqTimeout time.Duration, tokenProvider OidcTokenProvider) (*MultiRealmTokenClient, error) {
32+
var client, err = New(addrAPI, reqTimeout)
33+
if err != nil {
34+
return nil, err
35+
}
36+
return &MultiRealmTokenClient{
37+
client: client,
38+
tokenProvider: tokenProvider,
39+
realm: "",
40+
}, nil
41+
}
42+
43+
func (mrtc *MultiRealmTokenClient) ForRealm(realm string) RestClient {
44+
return &MultiRealmTokenClient{
45+
client: mrtc.client,
46+
tokenProvider: mrtc.tokenProvider,
47+
realm: realm,
48+
}
49+
}
50+
51+
func (mrtc *MultiRealmTokenClient) withRealmAuth(next func(pluginsWithAuth ...plugin.Plugin) (string, error), plugins ...plugin.Plugin) (string, error) {
52+
var token string
53+
var err error
54+
if mrtc.realm != "" {
55+
token, err = mrtc.tokenProvider.ProvideTokenForRealm(context.Background(), mrtc.realm)
56+
} else {
57+
token, err = mrtc.tokenProvider.ProvideToken(context.Background())
58+
}
59+
if err != nil {
60+
return "", err
61+
}
62+
plugins = append(plugins, headers.Set("Authorization", "Bearer "+token))
63+
return next(plugins...)
64+
}
65+
66+
// Get is a HTTP GET method.
67+
func (mrtc *MultiRealmTokenClient) Get(data interface{}, plugins ...plugin.Plugin) error {
68+
var _, err = mrtc.withRealmAuth(func(pluginsWithAuth ...plugin.Plugin) (string, error) {
69+
return "", mrtc.client.Get(data, pluginsWithAuth...)
70+
}, plugins...)
71+
return err
72+
}
73+
74+
// Post is a HTTP POST method
75+
func (mrtc *MultiRealmTokenClient) Post(data interface{}, plugins ...plugin.Plugin) (string, error) {
76+
return mrtc.withRealmAuth(func(pluginsWithAuth ...plugin.Plugin) (string, error) {
77+
return mrtc.client.Post(data, pluginsWithAuth...)
78+
}, plugins...)
79+
}
80+
81+
// Delete is a HTTP DELETE method
82+
func (mrtc *MultiRealmTokenClient) Delete(plugins ...plugin.Plugin) error {
83+
var _, err = mrtc.withRealmAuth(func(pluginsWithAuth ...plugin.Plugin) (string, error) {
84+
return "", mrtc.client.Delete(pluginsWithAuth...)
85+
}, plugins...)
86+
return err
87+
}
88+
89+
// Put is a HTTP PUT method
90+
func (mrtc *MultiRealmTokenClient) Put(plugins ...plugin.Plugin) error {
91+
var _, err = mrtc.withRealmAuth(func(pluginsWithAuth ...plugin.Plugin) (string, error) {
92+
return "", mrtc.client.Put(pluginsWithAuth...)
93+
}, plugins...)
94+
return err
95+
}

advanced_auth_client_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package httpclient
2+
3+
import (
4+
"errors"
5+
"testing"
6+
"time"
7+
8+
"github.com/cloudtrust/httpclient/mock"
9+
"github.com/golang/mock/gomock"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestNewMultiRealmTokenClient(t *testing.T) {
14+
var mockCtrl = gomock.NewController(t)
15+
defer mockCtrl.Finish()
16+
17+
var mockTokenProvider = mock.NewOidcTokenProvider((mockCtrl))
18+
var tokenError = errors.New("token error")
19+
var realm = "my-realm"
20+
21+
t.Run("Invalid URL", func(t *testing.T) {
22+
var _, err = NewMultiRealmTokenClient(":/\000/", time.Minute, mockTokenProvider)
23+
assert.NotNil(t, err)
24+
})
25+
26+
var client, err = NewMultiRealmTokenClient("http://localhost", time.Minute, mockTokenProvider)
27+
assert.Nil(t, err)
28+
29+
t.Run("GET", func(t *testing.T) {
30+
t.Run("can't get token", func(t *testing.T) {
31+
mockTokenProvider.EXPECT().ProvideToken(gomock.Any()).Return("", tokenError)
32+
var err = client.Get(nil)
33+
assert.Equal(t, tokenError, err)
34+
})
35+
t.Run("success", func(t *testing.T) {
36+
mockTokenProvider.EXPECT().ProvideToken(gomock.Any()).Return("default-token", nil)
37+
var err = client.Get(nil)
38+
assert.NotEqual(t, tokenError, err)
39+
})
40+
})
41+
t.Run("POST", func(t *testing.T) {
42+
t.Run("can't get token", func(t *testing.T) {
43+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("", tokenError)
44+
var _, err = client.ForRealm(realm).Post(nil)
45+
assert.Equal(t, tokenError, err)
46+
})
47+
t.Run("success", func(t *testing.T) {
48+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("token-for-"+realm, nil)
49+
var _, err = client.ForRealm(realm).Post(nil)
50+
assert.NotEqual(t, tokenError, err)
51+
})
52+
})
53+
t.Run("DELETE", func(t *testing.T) {
54+
t.Run("can't get token", func(t *testing.T) {
55+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("", tokenError)
56+
var err = client.ForRealm(realm).Delete()
57+
assert.Equal(t, tokenError, err)
58+
})
59+
t.Run("success", func(t *testing.T) {
60+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("token-for-"+realm, nil)
61+
var err = client.ForRealm(realm).Delete()
62+
assert.NotEqual(t, tokenError, err)
63+
})
64+
})
65+
t.Run("PUT", func(t *testing.T) {
66+
t.Run("can't get token", func(t *testing.T) {
67+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("", tokenError)
68+
var err = client.ForRealm(realm).Put()
69+
assert.Equal(t, tokenError, err)
70+
})
71+
t.Run("success", func(t *testing.T) {
72+
mockTokenProvider.EXPECT().ProvideTokenForRealm(gomock.Any(), realm).Return("token-for-"+realm, nil)
73+
var err = client.ForRealm(realm).Put()
74+
assert.NotEqual(t, tokenError, err)
75+
})
76+
})
77+
}

mock_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ package httpclient
33
import _ "github.com/golang/mock/mockgen/model"
44

55
//go:generate mockgen --build_flags=--mod=mod -destination=./mock/http.go -package=mock -mock_names=Handler=Handler net/http Handler
6+
//go:generate mockgen --build_flags=--mod=mod -destination=./mock/token.go -package=mock -mock_names=OidcTokenProvider=OidcTokenProvider github.com/cloudtrust/httpclient OidcTokenProvider

0 commit comments

Comments
 (0)