Skip to content

Commit 1c8812e

Browse files
committed
Updated auth
1 parent b06bb74 commit 1c8812e

File tree

7 files changed

+284
-15
lines changed

7 files changed

+284
-15
lines changed

pkg/handler/auth/client/client.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Implements an API client for the Token auth API (https://github.com/mutablelogic/go-server/pkg/handler/auth)
3+
*/
4+
package client
5+
6+
import (
7+
8+
// Packages
9+
"time"
10+
11+
"github.com/mutablelogic/go-client"
12+
"github.com/mutablelogic/go-server/pkg/handler/auth"
13+
)
14+
15+
///////////////////////////////////////////////////////////////////////////////
16+
// TYPES
17+
18+
type Client struct {
19+
*client.Client
20+
}
21+
22+
///////////////////////////////////////////////////////////////////////////////
23+
// LIFECYCLE
24+
25+
// Create a new API client, providing the endpoint (ie, http://example.com/api/auth)
26+
func New(endPoint string, opts ...client.ClientOpt) (*Client, error) {
27+
// Create client
28+
client, err := client.New(append(opts, client.OptEndpoint(endPoint))...)
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
// Return the client
34+
return &Client{client}, nil
35+
}
36+
37+
///////////////////////////////////////////////////////////////////////////////
38+
// METHODS
39+
40+
// Return all tokens
41+
func (c *Client) List() ([]auth.Token, error) {
42+
var response []auth.Token
43+
if err := c.Do(nil, &response); err != nil {
44+
return nil, err
45+
}
46+
return response, nil
47+
}
48+
49+
// Get token details (apart from the value)
50+
func (c *Client) Get(name string) (auth.Token, error) {
51+
var response auth.Token
52+
if err := c.Do(nil, &response, client.OptPath(name)); err != nil {
53+
return auth.Token{}, err
54+
}
55+
return response, nil
56+
}
57+
58+
// Delete a token
59+
func (c *Client) Delete(name string) error {
60+
if err := c.Do(client.MethodDelete, nil, client.OptPath(name)); err != nil {
61+
return err
62+
}
63+
// Return success
64+
return nil
65+
}
66+
67+
// Create a token with name, duration and scopes, and return the token
68+
func (c *Client) Create(name string, expires_in time.Duration, scopes ...string) (auth.Token, error) {
69+
var response auth.Token
70+
71+
// Request->Response
72+
if payload, err := client.NewJSONRequest(auth.NewCreateToken(name, expires_in, scopes...)); err != nil {
73+
return auth.Token{}, err
74+
} else if err := c.Do(payload, &response); err != nil {
75+
return auth.Token{}, err
76+
}
77+
78+
// Return success
79+
return response, nil
80+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package client_test
2+
3+
import (
4+
"os"
5+
"testing"
6+
"time"
7+
8+
// Packages
9+
client "github.com/mutablelogic/go-client"
10+
auth "github.com/mutablelogic/go-server/pkg/handler/auth/client"
11+
assert "github.com/stretchr/testify/assert"
12+
)
13+
14+
func Test_client_001(t *testing.T) {
15+
assert := assert.New(t)
16+
opts := []client.ClientOpt{
17+
client.OptTrace(os.Stderr, true),
18+
}
19+
client, err := auth.New(GetEndpoint(t), opts...)
20+
assert.NoError(err)
21+
assert.NotNil(client)
22+
}
23+
24+
func Test_client_002(t *testing.T) {
25+
assert := assert.New(t)
26+
opts := []client.ClientOpt{
27+
client.OptTrace(os.Stderr, true),
28+
}
29+
if token := GetToken(t); token != "" {
30+
opts = append(opts, client.OptReqToken(client.Token{
31+
Scheme: "Bearer",
32+
Value: token,
33+
}))
34+
}
35+
36+
client, err := auth.New(GetEndpoint(t), opts...)
37+
assert.NoError(err)
38+
39+
tokens, err := client.List()
40+
assert.NoError(err)
41+
assert.NotEmpty(tokens)
42+
}
43+
44+
func Test_client_003(t *testing.T) {
45+
assert := assert.New(t)
46+
opts := []client.ClientOpt{
47+
client.OptTrace(os.Stderr, true),
48+
}
49+
if token := GetToken(t); token != "" {
50+
opts = append(opts, client.OptReqToken(client.Token{
51+
Scheme: "Bearer",
52+
Value: token,
53+
}))
54+
}
55+
client, err := auth.New(GetEndpoint(t), opts...)
56+
assert.NoError(err)
57+
58+
// Create a new token which doesn't expire
59+
token, err := client.Create(t.Name(), 0)
60+
if !assert.NoError(err) {
61+
t.SkipNow()
62+
}
63+
64+
// Get the token
65+
token2, err := client.Get(t.Name())
66+
if !assert.NoError(err) {
67+
t.SkipNow()
68+
}
69+
70+
// Delete the token
71+
err = client.Delete(t.Name())
72+
assert.NoError(err)
73+
74+
// Check tokens
75+
assert.Equal(token.Name, token2.Name)
76+
}
77+
78+
func Test_client_004(t *testing.T) {
79+
assert := assert.New(t)
80+
opts := []client.ClientOpt{
81+
client.OptTrace(os.Stderr, true),
82+
}
83+
if token := GetToken(t); token != "" {
84+
opts = append(opts, client.OptReqToken(client.Token{
85+
Scheme: "Bearer",
86+
Value: token,
87+
}))
88+
}
89+
client, err := auth.New(GetEndpoint(t), opts...)
90+
assert.NoError(err)
91+
92+
// Create a new token with scopes "a", "b" and "c" which expires in 1 minute
93+
token, err := client.Create(t.Name(), time.Minute, "a", "b", "c")
94+
if !assert.NoError(err) {
95+
t.SkipNow()
96+
}
97+
98+
// Get the token
99+
token2, err := client.Get(t.Name())
100+
if !assert.NoError(err) {
101+
t.SkipNow()
102+
}
103+
104+
// Check the scopes
105+
assert.ElementsMatch(token.Scope, token2.Scope)
106+
assert.Equal(token.Expire, token2.Expire)
107+
108+
// Delete the token
109+
err = client.Delete(t.Name())
110+
assert.NoError(err)
111+
112+
t.Log(token, token2)
113+
}
114+
115+
///////////////////////////////////////////////////////////////////////////////
116+
// ENVIRONMENT
117+
118+
func GetEndpoint(t *testing.T) string {
119+
key := os.Getenv("AUTH_ENDPOINT")
120+
if key == "" {
121+
t.Skip("AUTH_ENDPOINT not set")
122+
t.SkipNow()
123+
}
124+
if key[len(key)-1] != '/' {
125+
key += "/"
126+
}
127+
return key
128+
}
129+
130+
func GetToken(t *testing.T) string {
131+
return os.Getenv("AUTH_TOKEN")
132+
}

pkg/handler/auth/context.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package auth
22

33
import (
44
"context"
5-
6-
"github.com/mutablelogic/go-server/pkg/version"
75
)
86

97
////////////////////////////////////////////////////////////////////////////////
@@ -14,11 +12,6 @@ type authContextKey int
1412
////////////////////////////////////////////////////////////////////////////////
1513
// GLOBALS
1614

17-
var (
18-
// Root scope allows ANY operation
19-
ScopeRoot = version.GitSource + "/scope/root"
20-
)
21-
2215
const (
2316
_ authContextKey = iota
2417
contextName

pkg/handler/auth/endpoints.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,30 +37,37 @@ var (
3737
// PUBLIC METHODS - ENDPOINTS
3838

3939
// Add endpoints to the router
40-
func (service *auth) AddEndpoints(ctx context.Context, router server.Router) {
40+
func (service *auth) AddEndpoints(ctx context.Context, r server.Router) {
4141
// Path: /
4242
// Methods: GET
4343
// Scopes: read // TODO: Add scopes
4444
// Description: Get current set of tokens and groups
45-
router.AddHandlerFuncRe(ctx, reRoot, service.ListTokens, http.MethodGet)
45+
r.AddHandlerFuncRe(ctx, reRoot, service.ListTokens, http.MethodGet).(router.Route).
46+
SetScope(service.ScopeRead()...)
4647

4748
// Path: /
4849
// Methods: POST
4950
// Scopes: write // TODO: Add scopes
5051
// Description: Create a new token
51-
router.AddHandlerFuncRe(ctx, reRoot, service.CreateToken, http.MethodPost)
52+
r.AddHandlerFuncRe(ctx, reRoot, service.CreateToken, http.MethodPost).(router.Route).
53+
SetScope(service.ScopeRead()...).
54+
SetScope(service.ScopeWrite()...)
5255

5356
// Path: /<token-name>
5457
// Methods: GET
5558
// Scopes: read // TODO: Add scopes
5659
// Description: Get a token
57-
router.AddHandlerFuncRe(ctx, reToken, service.GetToken, http.MethodGet)
60+
r.AddHandlerFuncRe(ctx, reToken, service.GetToken, http.MethodGet).(router.Route).
61+
SetScope(service.ScopeRead()...)
5862

5963
// Path: /<token-name>
6064
// Methods: DELETE, PATCH
6165
// Scopes: write // TODO: Add scopes
6266
// Description: Delete or update a token
63-
router.AddHandlerFuncRe(ctx, reToken, service.UpdateToken, http.MethodDelete, http.MethodPatch)
67+
r.AddHandlerFuncRe(ctx, reToken, service.UpdateToken, http.MethodDelete, http.MethodPatch).(router.Route).
68+
SetScope(service.ScopeRead()...).
69+
SetScope(service.ScopeWrite()...)
70+
6471
}
6572

6673
///////////////////////////////////////////////////////////////////////////////
@@ -81,7 +88,7 @@ func (service *auth) ListTokens(w http.ResponseWriter, r *http.Request) {
8188
// Get a token
8289
func (service *auth) GetToken(w http.ResponseWriter, r *http.Request) {
8390
urlParameters := router.Params(r.Context())
84-
token := service.jar.GetWithName(strings.ToLower(urlParameters[0]))
91+
token := service.jar.GetWithName(urlParameters[0])
8592
if token.IsZero() {
8693
httpresponse.Error(w, http.StatusNotFound)
8794
return
@@ -149,7 +156,7 @@ func (service *auth) CreateToken(w http.ResponseWriter, r *http.Request) {
149156
// Update (patch, delete) an existing token
150157
func (service *auth) UpdateToken(w http.ResponseWriter, r *http.Request) {
151158
urlParameters := router.Params(r.Context())
152-
token := service.jar.GetWithName(strings.ToLower(urlParameters[0]))
159+
token := service.jar.GetWithName(urlParameters[0])
153160
if token.IsZero() {
154161
httpresponse.Error(w, http.StatusNotFound)
155162
return

pkg/handler/auth/interface.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package auth
22

33
import (
4-
"context"
4+
// Packages
5+
server "github.com/mutablelogic/go-server"
56
)
67

78
type TokenJar interface {

pkg/handler/auth/scope.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package auth
2+
3+
import (
4+
// Packages
5+
"github.com/mutablelogic/go-server/pkg/version"
6+
)
7+
8+
////////////////////////////////////////////////////////////////////////////////
9+
// GLOBALS
10+
11+
var (
12+
// Prefix
13+
scopePrefix = version.GitSource + "/scope/"
14+
15+
// Root scope allows ANY operation
16+
ScopeRoot = scopePrefix + "root"
17+
)
18+
19+
////////////////////////////////////////////////////////////////////////////////
20+
// PUBLIC METHODS
21+
22+
func (auth *auth) ScopeRead() []string {
23+
// Return read (list, get) scopes
24+
return []string{
25+
scopePrefix + auth.Label() + "/read",
26+
scopePrefix + defaultName + "/read",
27+
}
28+
}
29+
30+
func (auth *auth) ScopeWrite() []string {
31+
// Return write (create, delete, update) scopes
32+
return []string{
33+
scopePrefix + auth.Label() + "/write",
34+
scopePrefix + defaultName + "/write",
35+
}
36+
}

pkg/handler/auth/token.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,26 @@ func NewToken(name string, length int, duration time.Duration, scope ...string)
5151
}
5252
}
5353

54+
// Create a new create token request
55+
func NewCreateToken(name string, expires_in time.Duration, scope ...string) TokenCreate {
56+
// Truncase the duration to the nearest minute
57+
if expires_in > 0 {
58+
expires_in = expires_in.Truncate(time.Minute)
59+
if expires_in < time.Minute {
60+
expires_in = time.Minute
61+
}
62+
} else {
63+
expires_in = 0
64+
}
65+
66+
// Return the token
67+
return TokenCreate{
68+
Name: name,
69+
Duration: duration{expires_in},
70+
Scope: scope,
71+
}
72+
}
73+
5474
/////////////////////////////////////////////////////////////////////
5575
// STRINGIFY
5676

0 commit comments

Comments
 (0)