Skip to content

Commit

Permalink
refactored the Authorizer API to be consistent with Validator
Browse files Browse the repository at this point in the history
  • Loading branch information
johnabass committed Jul 11, 2024
1 parent 7d7da18 commit 539a004
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 25 deletions.
28 changes: 13 additions & 15 deletions authorizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,34 @@ type Authorizer[R any] interface {
// cancelation semantics.
//
// If this method doesn't support the given token, it should return nil.
Authorize(ctx context.Context, token Token, resource R) error
Authorize(ctx context.Context, resource R, token Token) error
}

// AuthorizerFunc is a closure type that implements Authorizer.
type AuthorizerFunc[R any] func(context.Context, Token, R) error
type AuthorizerFunc[R any] func(context.Context, R, Token) error

func (af AuthorizerFunc[R]) Authorize(ctx context.Context, token Token, resource R) error {
return af(ctx, token, resource)
func (af AuthorizerFunc[R]) Authorize(ctx context.Context, resource R, token Token) error {
return af(ctx, resource, token)
}

// Authorizers is a collection of Authorizers.
type Authorizers[R any] []Authorizer[R]

// Add appends authorizers to this aggregate Authorizers.
func (as *Authorizers[R]) Add(a ...Authorizer[R]) {
if *as == nil {
*as = make(Authorizers[R], 0, len(a))
}

*as = append(*as, a...)
// Append tacks on one or more authorizers to this collection. The possibly
// new Authorizers instance is returned. The semantics of this method are
// the same as the built-in append.
func (as Authorizers[R]) Append(a ...Authorizer[R]) Authorizers[R] {
return append(as, a...)
}

// Authorize requires all authorizers in this sequence to allow access. This
// method supplies a logical AND.
//
// Because authorization can be arbitrarily expensive, execution halts at the first failed
// authorization attempt.
func (as Authorizers[R]) Authorize(ctx context.Context, token Token, resource R) error {
func (as Authorizers[R]) Authorize(ctx context.Context, resource R, token Token) error {
for _, a := range as {
if err := a.Authorize(ctx, token, resource); err != nil {
if err := a.Authorize(ctx, resource, token); err != nil {
return err
}
}
Expand All @@ -61,10 +59,10 @@ type requireAny[R any] struct {

// Authorize returns nil at the first authorizer that returns nil, i.e. accepts the access.
// Otherwise, this method returns an aggregate error of all the authorization errors.
func (ra requireAny[R]) Authorize(ctx context.Context, token Token, resource R) error {
func (ra requireAny[R]) Authorize(ctx context.Context, resource R, token Token) error {
var err error
for _, a := range ra.a {
authErr := a.Authorize(ctx, token, resource)
authErr := a.Authorize(ctx, resource, token)
if authErr == nil {
return nil
}
Expand Down
16 changes: 8 additions & 8 deletions authorizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ func (suite *AuthorizersTestSuite) TestAuthorize() {

for _, err := range testCase.results {
err := err
as.Add(
AuthorizerFunc[string](func(ctx context.Context, token Token, resource string) error {
as = as.Append(
AuthorizerFunc[string](func(ctx context.Context, resource string, token Token) error {
suite.Same(testCtx, ctx)
suite.Same(testToken, token)
suite.Equal(placeholderResource, resource)
Expand All @@ -75,7 +75,7 @@ func (suite *AuthorizersTestSuite) TestAuthorize() {

suite.Equal(
testCase.expectedErr,
as.Authorize(testCtx, testToken, placeholderResource),
as.Authorize(testCtx, placeholderResource, testToken),
)
})
}
Expand Down Expand Up @@ -123,8 +123,8 @@ func (suite *AuthorizersTestSuite) TestAny() {

for _, err := range testCase.results {
err := err
as.Add(
AuthorizerFunc[string](func(ctx context.Context, token Token, resource string) error {
as = as.Append(
AuthorizerFunc[string](func(ctx context.Context, resource string, token Token) error {
suite.Same(testCtx, ctx)
suite.Same(testToken, token)
suite.Equal(placeholderResource, resource)
Expand All @@ -136,21 +136,21 @@ func (suite *AuthorizersTestSuite) TestAny() {
anyAs := as.Any()
suite.Equal(
testCase.expectedErr,
anyAs.Authorize(testCtx, testToken, placeholderResource),
anyAs.Authorize(testCtx, placeholderResource, testToken),
)

if len(as) > 0 {
// the any instance should be distinct
as[0] = AuthorizerFunc[string](
func(context.Context, Token, string) error {
func(context.Context, string, Token) error {
suite.Fail("should not have been called")
return nil
},
)

suite.Equal(
testCase.expectedErr,
anyAs.Authorize(testCtx, testToken, placeholderResource),
anyAs.Authorize(testCtx, placeholderResource, testToken),
)
}
})
Expand Down
4 changes: 2 additions & 2 deletions basculehttp/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func WithChallenges(ch ...Challenge) MiddlewareOption {
// This is useful for use cases like admin access or alternate capabilities.
func WithAuthorization(a ...bascule.Authorizer[*http.Request]) MiddlewareOption {
return middlewareOptionFunc(func(m *Middleware) error {
m.authorization.Add(a...)
m.authorization = m.authorization.Append(a...)
return nil
})
}
Expand Down Expand Up @@ -199,7 +199,7 @@ func (m *Middleware) authenticate(ctx context.Context, request *http.Request, to
}

func (m *Middleware) authorize(ctx context.Context, token bascule.Token, request *http.Request) error {
return m.authorization.Authorize(ctx, token, request)
return m.authorization.Authorize(ctx, request, token)
}

// frontDoor is the internal handler implementation that protects a handler
Expand Down

0 comments on commit 539a004

Please sign in to comment.