Skip to content

fix+feat:withconfig but not set usersetter+domain rbac#61

Closed
Jarnpher553 wants to merge 1 commit intolabstack:masterfrom
Jarnpher553:master
Closed

fix+feat:withconfig but not set usersetter+domain rbac#61
Jarnpher553 wants to merge 1 commit intolabstack:masterfrom
Jarnpher553:master

Conversation

@Jarnpher553
Copy link
Copy Markdown

fix bug and add feature.

func MiddlewareWithConfig(config Config) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = DefaultConfig.Skipper
	}
        /** add some code 
	if config.UserGetter == nil {
		config.UserGetter = DefaultConfig.UserGetter
	}
        */
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			if pass, err := config.CheckPermission(c); err == nil && pass {
				return next(c)
			} else if err != nil {
				return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
			}

			return echo.ErrForbidden
		}
	}
}

if use this method, but can not set UserGetter, will get a panic at runtime

// Config defines the config for CasbinAuth middleware.
	Config struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// Enforcer CasbinAuth main rule.
		// Required.
		Enforcer *casbin.Enforcer

		// Method to get the username - defaults to using basic auth
		UserGetter func(c echo.Context) (string, error)

		// Method to get the domain
		DomainGetter func(c echo.Context) (string, error)

		// Method to handle error
		ErrorHandler func(c echo.Context, err error) error

		// Method to handle forbidden
		ForbiddenHandler func(c echo.Context) error
	}
)

add some custom handler to make this middleware greater!!

@aldas
Copy link
Copy Markdown
Contributor

aldas commented Sep 18, 2021

If do not think that logic for matching domain is best choice because of Enforcer.Enforce() is pretty much interface magic which means that some day someone need their own special fields for their requirements.

I propose adding more generic field for custom Enforce handling that you could implement for your needs.

type (
	// Config defines the config for CasbinAuth middleware.
	Config struct {
		// Skipper defines a function to skip middleware.
		Skipper middleware.Skipper

		// Enforcer CasbinAuth main rule.
		// One of Enforcer or EnforceHandler fields is required.
		Enforcer *casbin.Enforcer

		// EnforceHandler is custom callback to handle enforcing.
		// One of Enforcer or EnforceHandler fields is required.
		EnforceHandler func(c echo.Context, user string) (bool, error)

		// Method to get the username - defaults to using basic auth
		UserGetter func(c echo.Context) (string, error)

		// Method to handle errors
		ErrorHandler func(c echo.Context, internal error, proposedStatus int) error
	}
)

var (
	// DefaultConfig is the default CasbinAuth middleware config.
	DefaultConfig = Config{
		Skipper: middleware.DefaultSkipper,
		UserGetter: func(c echo.Context) (string, error) {
			username, _, _ := c.Request().BasicAuth()
			return username, nil
		},
		ErrorHandler: func(c echo.Context, internal error, proposedStatus int) error {
			err := echo.NewHTTPError(proposedStatus, internal.Error())
			err.Internal = internal
			return err
		},
	}
)

// Middleware returns a CasbinAuth middleware.
//
// For valid credentials it calls the next handler.
// For missing or invalid credentials, it sends "401 - Unauthorized" response.
func Middleware(ce *casbin.Enforcer) echo.MiddlewareFunc {
	c := DefaultConfig
	c.Enforcer = ce
	return MiddlewareWithConfig(c)
}

// MiddlewareWithConfig returns a CasbinAuth middleware with config.
// See `Middleware()`.
func MiddlewareWithConfig(config Config) echo.MiddlewareFunc {
	if config.Enforcer == nil && config.EnforceHandler == nil {
		panic("one of casbin middleware Enforcer or EnforceHandler fields must be set")
	}
	if config.Skipper == nil {
		config.Skipper = DefaultConfig.Skipper
	}
	if config.UserGetter == nil {
		config.UserGetter = DefaultConfig.UserGetter
	}
	if config.ErrorHandler == nil {
		config.ErrorHandler = DefaultConfig.ErrorHandler
	}
	if config.EnforceHandler == nil {
		config.EnforceHandler = func(c echo.Context, user string) (bool, error) {
			return config.Enforcer.Enforce(user, c.Request().URL.Path, c.Request().Method)
		}
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			user, err := config.UserGetter(c)
			if err != nil {
				return config.ErrorHandler(c, err, http.StatusForbidden)
			}
			pass, err := config.EnforceHandler(c, user)
			if err != nil {
				return config.ErrorHandler(c, err, http.StatusInternalServerError)
			}
			if !pass {
				return config.ErrorHandler(c, errors.New("enforce did not pass"), http.StatusForbidden)
			}
			return next(c)
		}
	}
}

@Jarnpher553
Copy link
Copy Markdown
Author

thank you for your's reply and example code

@aldas
Copy link
Copy Markdown
Contributor

aldas commented Dec 7, 2021

@Jarnpher553 this PR goes on in #66 where I add config.EnforceHandler to handle custom enforcing. With that we can satisfy #65 needs also.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants