-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #68 from mutablelogic/v4
Updated router for inclusion of scopes
- Loading branch information
Showing
29 changed files
with
1,087 additions
and
339 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
Implements an API client for the Token auth API (https://github.com/mutablelogic/go-server/pkg/handler/auth) | ||
*/ | ||
package client | ||
|
||
import ( | ||
|
||
// Packages | ||
"time" | ||
|
||
"github.com/mutablelogic/go-client" | ||
"github.com/mutablelogic/go-server/pkg/handler/auth" | ||
) | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
// TYPES | ||
|
||
type Client struct { | ||
*client.Client | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
// LIFECYCLE | ||
|
||
// Create a new API client, providing the endpoint (ie, http://example.com/api/auth) | ||
func New(endPoint string, opts ...client.ClientOpt) (*Client, error) { | ||
// Create client | ||
client, err := client.New(append(opts, client.OptEndpoint(endPoint))...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Return the client | ||
return &Client{client}, nil | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
// METHODS | ||
|
||
// Return all tokens | ||
func (c *Client) List() ([]auth.Token, error) { | ||
var response []auth.Token | ||
if err := c.Do(nil, &response); err != nil { | ||
return nil, err | ||
} | ||
return response, nil | ||
} | ||
|
||
// Get token details (apart from the value) | ||
func (c *Client) Get(name string) (auth.Token, error) { | ||
var response auth.Token | ||
if err := c.Do(nil, &response, client.OptPath(name)); err != nil { | ||
return auth.Token{}, err | ||
} | ||
return response, nil | ||
} | ||
|
||
// Delete a token | ||
func (c *Client) Delete(name string) error { | ||
if err := c.Do(client.MethodDelete, nil, client.OptPath(name)); err != nil { | ||
return err | ||
} | ||
// Return success | ||
return nil | ||
} | ||
|
||
// Create a token with name, duration and scopes, and return the token | ||
func (c *Client) Create(name string, expires_in time.Duration, scopes ...string) (auth.Token, error) { | ||
var response auth.Token | ||
|
||
// Request->Response | ||
if payload, err := client.NewJSONRequest(auth.NewCreateToken(name, expires_in, scopes...)); err != nil { | ||
return auth.Token{}, err | ||
} else if err := c.Do(payload, &response); err != nil { | ||
return auth.Token{}, err | ||
} | ||
|
||
// Return success | ||
return response, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package client_test | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
"time" | ||
|
||
// Packages | ||
client "github.com/mutablelogic/go-client" | ||
auth "github.com/mutablelogic/go-server/pkg/handler/auth/client" | ||
assert "github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_client_001(t *testing.T) { | ||
assert := assert.New(t) | ||
opts := []client.ClientOpt{ | ||
client.OptTrace(os.Stderr, true), | ||
} | ||
client, err := auth.New(GetEndpoint(t), opts...) | ||
assert.NoError(err) | ||
assert.NotNil(client) | ||
} | ||
|
||
func Test_client_002(t *testing.T) { | ||
assert := assert.New(t) | ||
opts := []client.ClientOpt{ | ||
client.OptTrace(os.Stderr, true), | ||
} | ||
if token := GetToken(t); token != "" { | ||
opts = append(opts, client.OptReqToken(client.Token{ | ||
Scheme: "Bearer", | ||
Value: token, | ||
})) | ||
} | ||
|
||
client, err := auth.New(GetEndpoint(t), opts...) | ||
assert.NoError(err) | ||
|
||
tokens, err := client.List() | ||
assert.NoError(err) | ||
assert.NotEmpty(tokens) | ||
} | ||
|
||
func Test_client_003(t *testing.T) { | ||
assert := assert.New(t) | ||
opts := []client.ClientOpt{ | ||
client.OptTrace(os.Stderr, true), | ||
} | ||
if token := GetToken(t); token != "" { | ||
opts = append(opts, client.OptReqToken(client.Token{ | ||
Scheme: "Bearer", | ||
Value: token, | ||
})) | ||
} | ||
client, err := auth.New(GetEndpoint(t), opts...) | ||
assert.NoError(err) | ||
|
||
// Create a new token which doesn't expire | ||
token, err := client.Create(t.Name(), 0) | ||
if !assert.NoError(err) { | ||
t.SkipNow() | ||
} | ||
|
||
// Get the token | ||
token2, err := client.Get(t.Name()) | ||
if !assert.NoError(err) { | ||
t.SkipNow() | ||
} | ||
|
||
// Delete the token | ||
err = client.Delete(t.Name()) | ||
assert.NoError(err) | ||
|
||
// Check tokens | ||
assert.Equal(token.Name, token2.Name) | ||
} | ||
|
||
func Test_client_004(t *testing.T) { | ||
assert := assert.New(t) | ||
opts := []client.ClientOpt{ | ||
client.OptTrace(os.Stderr, false), | ||
} | ||
if token := GetToken(t); token != "" { | ||
opts = append(opts, client.OptReqToken(client.Token{ | ||
Scheme: "Bearer", | ||
Value: token, | ||
})) | ||
} | ||
client, err := auth.New(GetEndpoint(t), opts...) | ||
assert.NoError(err) | ||
|
||
// Create a new token with scopes "a", "b" and "c" which expires in 1 minute | ||
token, err := client.Create(t.Name(), time.Minute, "a", "b", "c") | ||
if !assert.NoError(err) { | ||
t.SkipNow() | ||
} | ||
|
||
// Get the token | ||
token2, err := client.Get(t.Name()) | ||
if !assert.NoError(err) { | ||
t.SkipNow() | ||
} | ||
|
||
// Check the scopes | ||
assert.ElementsMatch(token.Scope, token2.Scope) | ||
assert.Equal(token.Expire, token2.Expire) | ||
|
||
// Delete the token | ||
err = client.Delete(t.Name()) | ||
assert.NoError(err) | ||
|
||
t.Log(token, token2) | ||
} | ||
|
||
/////////////////////////////////////////////////////////////////////////////// | ||
// ENVIRONMENT | ||
|
||
func GetEndpoint(t *testing.T) string { | ||
key := os.Getenv("AUTH_ENDPOINT") | ||
if key == "" { | ||
t.Skip("AUTH_ENDPOINT not set") | ||
t.SkipNow() | ||
} | ||
if key[len(key)-1] != '/' { | ||
key += "/" | ||
} | ||
return key | ||
} | ||
|
||
func GetToken(t *testing.T) string { | ||
return os.Getenv("AUTH_TOKEN") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package auth | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// TYPES | ||
|
||
type authContextKey int | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// GLOBALS | ||
|
||
const ( | ||
_ authContextKey = iota | ||
contextName | ||
contextScope | ||
) | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// PUBLIC METHODS | ||
|
||
// WithTokenName returns a context with the given auth token name | ||
func WithTokenName(ctx context.Context, token Token) context.Context { | ||
return context.WithValue(ctx, contextName, token.Name) | ||
} | ||
|
||
// WithTokenScope returns a context with the given auth token scope | ||
func WithTokenScope(ctx context.Context, token Token) context.Context { | ||
return context.WithValue(ctx, contextScope, token.Scope) | ||
} | ||
|
||
// WithToken returns a context with the given auth token | ||
func WithToken(ctx context.Context, token Token) context.Context { | ||
if token.Name != "" { | ||
ctx = WithTokenName(ctx, token) | ||
} | ||
if len(token.Scope) > 0 { | ||
ctx = WithTokenScope(ctx, token) | ||
} | ||
return ctx | ||
} | ||
|
||
// TokenName returns the token name from the context | ||
func TokenName(ctx context.Context) string { | ||
return str(ctx, contextName) | ||
} | ||
|
||
// TokenScope returns the token scope from the context, or nil | ||
func TokenScope(ctx context.Context) []string { | ||
if value, ok := ctx.Value(contextScope).([]string); ok { | ||
return value | ||
} | ||
return nil | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
// PRIVATE METHODS | ||
|
||
func str(ctx context.Context, key authContextKey) string { | ||
if value, ok := ctx.Value(key).(string); ok { | ||
return value | ||
} | ||
return "" | ||
} |
Oops, something went wrong.