Skip to content

Commit

Permalink
refactor: only use resolvers
Browse files Browse the repository at this point in the history
  • Loading branch information
katallaxie committed Jun 12, 2024
1 parent 0884f2a commit c0ce59a
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 76 deletions.
7 changes: 7 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}
ADD zscaler.pem /usr/local/share/ca-certificates/zscaler.crt
RUN sudo chmod 644 /usr/local/share/ca-certificates/zscaler.crt && sudo update-ca-certificates

# zScaler certificate, for all busy engineers
ADD zscaler.pem /usr/local/share/ca-certificates/zscaler.crt
RUN sudo chmod 644 /usr/local/share/ca-certificates/zscaler.crt && sudo update-ca-certificates

# Set the environment variable NODE_EXTRA_CA_CERTS to the zScaler certificate
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/zscaler.crt

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install protobuf-compiler
6 changes: 3 additions & 3 deletions authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ type JWSValidator interface {
// NewAuthenticator ...
func NewAuthenticator(c AuthzChecker, v JWSValidator) openapi3filter.AuthenticationFunc {
return func(ctx context.Context, input *openapi3filter.AuthenticationInput) error {
return Authenticate(ctx, c, v, input)
return Authenticated(ctx, c, v, input)
}
}

// ErrForbidden ...
var ErrForbidden = errors.New("forbidden")

// Authenticate ...
func Authenticate(ctx context.Context, checker AuthzChecker, validate JWSValidator, input *openapi3filter.AuthenticationInput) error {
// Authenticated ...
func Authenticated(ctx context.Context, checker AuthzChecker, validate JWSValidator, input *openapi3filter.AuthenticationInput) error {
if input.SecuritySchemeName != "BearerAuth" {
return fmt.Errorf("security scheme %s != 'BearerAuth'", input.SecuritySchemeName)
}
Expand Down
112 changes: 53 additions & 59 deletions authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,21 @@ func (a AuthzAction) String() string {
}

const (
AuthzNoPrincipial = ""
AuthzNoObject = ""
AuthzNoAction = ""
AuthzNoPrincipial AuthzPrincipal = ""
AuthzNoObject AuthzObject = ""
AuthzNoAction AuthzAction = ""
)

// AuthzActionDefaults are the default actions.
const (
Read AuthzAction = "read"
Write AuthzAction = "write"
Admin AuthzAction = "admin"
SuperAdmin AuthzAction = "superadmin"
)
// AuthzParams is the struct that holds the principal, object and action from the context.
// There needs to be a :principal, :object and :action in the context.
type AuthzParams struct {
// Principal is the subject.
Principal AuthzPrincipal `json:"principal" params:"principal" query:"principal" form:"principal"`
// Object is the object.
Object AuthzObject `json:"object" params:"object" query:"object" form:"object"`
// Action is the action.
Action AuthzAction `json:"action" params:"action" query:"action" form:"action"`
}

// AuthzChecker is the interface that wraps the Allowed method.
type AuthzChecker interface {
Expand Down Expand Up @@ -99,6 +102,15 @@ type Config struct {
// Checker is implementing the AuthzChecker interface.
Checker AuthzChecker

// ObjectResolver is the object resolver.
ObjectResolver AuthzObjectResolver

// ActionResolver is the action resolver.
ActionResolver AuthzActionResolver

// PrincipalResolver is the principal resolver.
PrincipalResolver AuthzPrincipalResolver

// ErrorHandler is executed when an error is returned from fiber.Handler.
//
// Optional. Default: DefaultErrorHandler
Expand All @@ -107,8 +119,11 @@ type Config struct {

// ConfigDefault is the default config.
var ConfigDefault = Config{
ErrorHandler: defaultErrorHandler,
Checker: NewNoop(),
ErrorHandler: defaultErrorHandler,
ObjectResolver: NewNoopObjectResolver(),
PrincipalResolver: NewNoopPrincipalResolver(),
ActionResolver: NewNoopActionResolver(),
Checker: NewNoop(),
}

// default ErrorHandler that process return error from fiber.Handler
Expand All @@ -134,48 +149,33 @@ type AuthzActionResolver interface {
Resolve(c *fiber.Ctx) (AuthzAction, error)
}

// SetAuthzHandler is a middleware that sets the principal and user in the context.
// This function can map any thing.
func SetAuthzHandler(object AuthzObjectResolver, action AuthzActionResolver, principal AuthzPrincipalResolver) func(c *fiber.Ctx) error {
// Authenticate is a middleware that sets the principal and user in the context.
func Authenticate(handler fiber.Handler, config ...Config) func(c *fiber.Ctx) error {
cfg := configDefault(config...)

return func(c *fiber.Ctx) error {
object, err := object.Resolve(c)
if err != nil {
return err
if cfg.Next != nil && cfg.Next(c) {
return c.Next()
}

principal, err := principal.Resolve(c)
object, err := cfg.ObjectResolver.Resolve(c)
if err != nil {
return err
}

action, err := action.Resolve(c)
principal, err := cfg.PrincipalResolver.Resolve(c)
if err != nil {
return err
}

return ContextWithAuthz(c, principal, object, action).Next()
}
}

// NewTBACHandler there is a new fiber.Handler that checks if the principal can perform the action on the object.
func NewTBACHandler(handler fiber.Handler, action AuthzAction, param string, config ...Config) fiber.Handler {
cfg := configDefault(config...)

return func(c *fiber.Ctx) error {
if cfg.Next != nil && cfg.Next(c) {
return c.Next()
}

team := AuthzObject(c.Params(param, ""))

principal, _, _, err := AuthzFromContext(c)
action, err := cfg.ActionResolver.Resolve(c)
if err != nil {
return defaultErrorHandler(c, err)
return err
}

allowed, err := cfg.Checker.Allowed(c.Context(), principal, team, action)
allowed, err := cfg.Checker.Allowed(c.Context(), principal, object, action)
if err != nil {
return defaultErrorHandler(c, err)
return cfg.ErrorHandler(c, err)
}

if !allowed {
Expand All @@ -202,12 +202,12 @@ func NewCheckerHandler(config ...Config) fiber.Handler {
}{}

if err := c.BodyParser(&payload); err != nil {
return defaultErrorHandler(c, err)
return cfg.ErrorHandler(c, err)
}

allowed, err := cfg.Checker.Allowed(c.Context(), payload.Principal, payload.Object, payload.Permission)
if err != nil {
return defaultErrorHandler(c, err)
return cfg.ErrorHandler(c, err)
}

if allowed {
Expand All @@ -218,24 +218,6 @@ func NewCheckerHandler(config ...Config) fiber.Handler {
}
}

// ContextWithAuthz returns a new context with the principal, object and action set.
func ContextWithAuthz(ctx *fiber.Ctx, principal AuthzPrincipal, object AuthzObject, action AuthzAction) *fiber.Ctx {
ctx.Locals(authzPrincipial, principal)
ctx.Locals(authzObject, object)
ctx.Locals(authzAction, action)

return ctx
}

// AuthzFromContext return the principal, object and action from the context.
func AuthzFromContext(ctx *fiber.Ctx) (AuthzPrincipal, AuthzObject, AuthzAction, error) {
principal := ctx.Locals(authzPrincipial)
object := ctx.Locals(authzObject)
action := ctx.Locals(authzAction)

return principal.(AuthzPrincipal), object.(AuthzObject), action.(AuthzAction), nil
}

// Helper function to set default values
func configDefault(config ...Config) Config {
if len(config) < 1 {
Expand All @@ -253,6 +235,18 @@ func configDefault(config ...Config) Config {
cfg.ErrorHandler = ConfigDefault.ErrorHandler
}

if cfg.ObjectResolver == nil {
cfg.ObjectResolver = ConfigDefault.ObjectResolver
}

if cfg.PrincipalResolver == nil {
cfg.PrincipalResolver = ConfigDefault.PrincipalResolver
}

if cfg.ActionResolver == nil {
cfg.ActionResolver = ConfigDefault.ActionResolver
}

return cfg
}

Expand Down
12 changes: 5 additions & 7 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sort"

authz "github.com/zeiss/fiber-authz"
"github.com/zeiss/fiber-authz/tbrac"

"github.com/gofiber/fiber/v2"
ll "github.com/gofiber/fiber/v2/middleware/logger"
Expand Down Expand Up @@ -150,7 +151,7 @@ func run(_ context.Context) error {

providers.RegisterProvider(github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"))

err = authz.RunMigrations(conn)
err = tbrac.RunMigrations(conn)
if err != nil {
return err
}
Expand All @@ -174,11 +175,6 @@ func run(_ context.Context) error {
}

app.Use(goth.NewProtectMiddleware(gothConfig))
app.Use(authz.SetAuthzHandler(authz.NewNoopObjectResolver(), authz.NewNoopActionResolver(), authz.NewGothAuthzPrincipalResolver()))

config := authz.Config{
Checker: authz.NewTBAC(conn),
}

indexHandler := func(c *fiber.Ctx) error {
session, err := goth.SessionFromContext(c)
Expand All @@ -194,7 +190,9 @@ func run(_ context.Context) error {
return t.Execute(c.Response().BodyWriter(), providerIndex)
})

app.Get("/:team", authz.NewTBACHandler(indexHandler, authz.AuthzAction("admin"), "team", config))
team := app.Get("/:team", authz.Authenticate(indexHandler))
team.Use()

app.Get("/login/:provider", goth.NewBeginAuthHandler(gothConfig))
app.Get("/auth/:provider/callback", goth.NewCompleteAuthHandler(gothConfig))
app.Get("/logout", goth.NewLogoutHandler(gothConfig))
Expand Down
13 changes: 7 additions & 6 deletions tbac.go → tbrac/tbrac.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package authz
package tbrac

import (
"context"
Expand All @@ -7,6 +7,7 @@ import (
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
authz "github.com/zeiss/fiber-authz"
"github.com/zeiss/fiber-goth/adapters"
"gorm.io/gorm"
)
Expand Down Expand Up @@ -203,8 +204,8 @@ type APIKeyRole struct {
}

var (
_ AuthzChecker = (*tbac)(nil)
_ adapters.Adapter = (*tbac)(nil)
_ authz.AuthzChecker = (*tbac)(nil)
_ adapters.Adapter = (*tbac)(nil)
)

type tbac struct {
Expand All @@ -221,7 +222,7 @@ func NewTBAC(db *gorm.DB) *tbac {
}

// Allowed is a method that returns true if the principal is allowed to perform the action on the user.
func (t *tbac) Allowed(ctx context.Context, principal AuthzPrincipal, object AuthzObject, action AuthzAction) (bool, error) {
func (t *tbac) Allowed(ctx context.Context, principal authz.AuthzPrincipal, object authz.AuthzObject, action authz.AuthzAction) (bool, error) {
var allowed int64

team := t.db.WithContext(ctx).Model(&Team{}).Select("id").Where("slug = ?", object)
Expand All @@ -239,8 +240,8 @@ func (t *tbac) Allowed(ctx context.Context, principal AuthzPrincipal, object Aut
}

// Resolve ...
func (t *tbac) Resolve(c *fiber.Ctx) (AuthzObject, error) {
return AuthzObject(c.Params("team")), nil
func (t *tbac) Resolve(c *fiber.Ctx) (authz.AuthzObject, error) {
return authz.AuthzObject(c.Params("team")), nil
}

// CreateUser ...
Expand Down
2 changes: 1 addition & 1 deletion tbac_test.go → tbrac/tbrac_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package authz
package tbrac

import (
"testing"
Expand Down

0 comments on commit c0ce59a

Please sign in to comment.