From 0a7672adcf2497c2d40343484cfc8d461c9ac970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Jochum?= Date: Sun, 25 Sep 2022 21:10:54 +0200 Subject: [PATCH] Add support for multiple verifiers --- cmd/microauth2sqld/handler/auth2.go | 42 ++++++++++++++++++++++ cmd/microauth2sqld/main.go | 41 --------------------- noop.go | 2 +- plugin.go | 7 ++-- plugins/client/jwt/jwt.go | 21 +++++------ plugins/verifier/endpointroles/verifier.go | 12 +++---- 6 files changed, 65 insertions(+), 60 deletions(-) diff --git a/cmd/microauth2sqld/handler/auth2.go b/cmd/microauth2sqld/handler/auth2.go index 48bbcf7..0ad646b 100644 --- a/cmd/microauth2sqld/handler/auth2.go +++ b/cmd/microauth2sqld/handler/auth2.go @@ -17,8 +17,10 @@ import ( "jochum.dev/jo-micro/auth2/cmd/microauth2sqld/db" "jochum.dev/jo-micro/auth2/internal/argon2" "jochum.dev/jo-micro/auth2/internal/proto/authpb" + "jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles" "jochum.dev/jo-micro/auth2/shared/sjwt" "jochum.dev/jo-micro/components" + "jochum.dev/jo-micro/logruscomponent" "jochum.dev/jo-micro/router" ) @@ -122,6 +124,46 @@ func (h *Handler) Init(cReg *components.Registry, c InitConfig) error { ), ) + authVerifier := endpointroles.NewVerifier( + endpointroles.WithLogrus(logruscomponent.MustReg(h.cReg).Logger()), + ) + authVerifier.AddRules( + endpointroles.RouterRule, + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Delete), + endpointroles.RolesAllow(auth2.RolesServiceAndAdmin), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Detail), + endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Inspect), + endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.List), + endpointroles.RolesAllow(auth2.RolesServiceAndAdmin), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Login), + endpointroles.RolesAllow(auth2.RolesAllAndAnon), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Refresh), + endpointroles.RolesAllow(auth2.RolesAllAndAnon), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.Register), + endpointroles.RolesAllow(auth2.RolesAllAndAnon), + ), + endpointroles.NewRule( + endpointroles.Endpoint(authpb.AuthService.UpdateRoles), + endpointroles.RolesAllow(auth2.RolesAdmin), + ), + ) + auth2.ClientAuthMustReg(h.cReg).Plugin().AddVerifier(authVerifier) + return nil } diff --git a/cmd/microauth2sqld/main.go b/cmd/microauth2sqld/main.go index ec3674a..5692435 100644 --- a/cmd/microauth2sqld/main.go +++ b/cmd/microauth2sqld/main.go @@ -27,7 +27,6 @@ import ( "jochum.dev/jo-micro/router" "jochum.dev/jo-micro/auth2/plugins/client/jwt" - "jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles" ) var ( @@ -247,46 +246,6 @@ func main() { logger := logruscomponent.MustReg(cReg).Logger() - authVerifier := endpointroles.NewVerifier( - endpointroles.WithLogrus(logger), - ) - authVerifier.AddRules( - endpointroles.RouterRule, - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Delete), - endpointroles.RolesAllow(auth2.RolesServiceAndAdmin), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Detail), - endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Inspect), - endpointroles.RolesAllow(auth2.RolesServiceAndUsersAndAdmin), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.List), - endpointroles.RolesAllow(auth2.RolesServiceAndAdmin), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Login), - endpointroles.RolesAllow(auth2.RolesAllAndAnon), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Refresh), - endpointroles.RolesAllow(auth2.RolesAllAndAnon), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.Register), - endpointroles.RolesAllow(auth2.RolesAllAndAnon), - ), - endpointroles.NewRule( - endpointroles.Endpoint(authpb.AuthService.UpdateRoles), - endpointroles.RolesAllow(auth2.RolesAdmin), - ), - ) - auth2ClientReg.Plugin().SetVerifier(authVerifier) - // Check if we got keys if c.String("auth2_jwt_pub_key") == "" || c.String("auth2_jwt_priv_key") == "" || c.String("auth2_jwt_refresh_pub_key") == "" || c.String("auth2_jwt_refresh_priv_key") == "" { logger.Fatal(ErrorNoKeys) diff --git a/noop.go b/noop.go index 686ee7d..1bf9b4c 100644 --- a/noop.go +++ b/noop.go @@ -37,7 +37,7 @@ func (p *noopClientPlugin) Health(ctx context.Context) error { return nil } -func (p *noopClientPlugin) SetVerifier(v VerifierPlugin) { +func (p *noopClientPlugin) AddVerifier(v VerifierPlugin) { } func (p *noopClientPlugin) ServiceContext(ctx context.Context) (context.Context, error) { diff --git a/plugin.go b/plugin.go index 63f8865..076c40c 100644 --- a/plugin.go +++ b/plugin.go @@ -28,7 +28,10 @@ type registryFuncs interface { type VerifierPlugin interface { // Verify verifies that the user is allowed to access the request, it MUST handle AnonUser - Verify(ctx context.Context, u *User, req server.Request) error + // @return + // error nil if its allowed, else an error + // bool if the error given is a default error + Verify(ctx context.Context, u *User, req server.Request) (error, bool) } // ClientPlugin is for services that act as client's behind GinRouter @@ -36,7 +39,7 @@ type ClientPlugin interface { registryFuncs // Set the Verifier for this Client - SetVerifier(v VerifierPlugin) + AddVerifier(v VerifierPlugin) // ServiceContext adds the ServiceUser to the context (when using JWT's it will overwrite the Authorization Header) ServiceContext(ctx context.Context) (context.Context, error) diff --git a/plugins/client/jwt/jwt.go b/plugins/client/jwt/jwt.go index a347b03..3807e4c 100644 --- a/plugins/client/jwt/jwt.go +++ b/plugins/client/jwt/jwt.go @@ -14,7 +14,6 @@ import ( "go-micro.dev/v4/metadata" "go-micro.dev/v4/server" "jochum.dev/jo-micro/auth2" - "jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles" "jochum.dev/jo-micro/auth2/shared/sjwt" "jochum.dev/jo-micro/auth2/shared/sutil" "jochum.dev/jo-micro/components" @@ -22,9 +21,7 @@ import ( func New() auth2.ClientPlugin { return &jwtPlugin{ - verifier: endpointroles.NewVerifier( - endpointroles.NoDefaultDeny(), - ), + verifiers: []auth2.VerifierPlugin{}, } } @@ -32,7 +29,7 @@ type jwtPlugin struct { audiences []string pubKey any privKey any - verifier auth2.VerifierPlugin + verifiers []auth2.VerifierPlugin } func (p *jwtPlugin) String() string { @@ -86,8 +83,8 @@ func (p *jwtPlugin) Health(ctx context.Context) error { return nil } -func (p *jwtPlugin) SetVerifier(v auth2.VerifierPlugin) { - p.verifier = v +func (p *jwtPlugin) AddVerifier(v auth2.VerifierPlugin) { + p.verifiers = append(p.verifiers, v) } func (p *jwtPlugin) ServiceContext(ctx context.Context) (context.Context, error) { @@ -172,9 +169,13 @@ func (p *jwtPlugin) WrapHandlerFunc(ctx context.Context, req server.Request, rsp } ctx = context.WithValue(ctx, auth2.ContextUserKey{}, u) - if err = p.verifier.Verify(ctx, u, req); err != nil { - return err + var defaultDenyOk bool + for _, v := range p.verifiers { + err, defaultDenyOk = v.Verify(ctx, u, req) + if !defaultDenyOk && err != nil { + return err + } } - return nil + return err } diff --git a/plugins/verifier/endpointroles/verifier.go b/plugins/verifier/endpointroles/verifier.go index 9112f93..031fb4a 100644 --- a/plugins/verifier/endpointroles/verifier.go +++ b/plugins/verifier/endpointroles/verifier.go @@ -41,29 +41,29 @@ func (v *EndpointRolesVerifier) logrus() *logrus.Logger { return v.options.Logrus } -func (v *EndpointRolesVerifier) Verify(ctx context.Context, u *auth2.User, req server.Request) error { +func (v *EndpointRolesVerifier) Verify(ctx context.Context, u *auth2.User, req server.Request) (error, bool) { if ep, ok := v.rules[req.Endpoint()]; ok { if auth2.IntersectsRoles(u, ep.RolesDeny...) { v.logrus().WithField("endpoint", req.Endpoint()).WithField("rolesDeny", ep.RolesDeny).WithField("userRoles", u.Roles).Debug("Unauthorized") - return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|Denied by rule", "Unauthorized") + return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|Denied by rule", "Unauthorized"), false } if auth2.IntersectsRoles(u, ep.RolesAllow...) { v.logrus().WithField("endpoint", req.Endpoint()).WithField("rolesAllow", ep.RolesAllow).WithField("userRoles", u.Roles).Trace("Authorized") // Allowed by role - return nil + return nil, false } if v.options.DefaultDeny { v.logrus().WithField("endpoint", req.Endpoint()).WithField("user_roles", u.Roles).WithField("roles_allow", ep.RolesAllow).Debug("DefaultDeny: No matching role") - return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No matching role", "Unauthorized") + return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No matching role", "Unauthorized"), true } } if !v.options.DefaultDeny { v.logrus().WithField("endpoint", req.Endpoint()).WithField("endpoints", v.endpointnames).Trace("DefaultAllow: No rule") - return nil + return nil, true } v.logrus().WithField("endpoint", req.Endpoint()).WithField("endpoints", v.endpointnames).Debug("DefaultDeny: no rule") - return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No rule", "Unauthorized") + return errors.Unauthorized("auth2/plugins/verifier/endpointroles/EndpointRolesVerifier.Verify|No rule", "Unauthorized"), false }