Add support for multiple verifiers
continuous-integration/drone/tag Build is passing Details

main v0.4.7
René Jochum 2 years ago
parent 666e1335aa
commit 0a7672adcf
Signed by: jochum
GPG Key ID: F7D906F5E51E8E5E

@ -17,8 +17,10 @@ import (
"jochum.dev/jo-micro/auth2/cmd/microauth2sqld/db" "jochum.dev/jo-micro/auth2/cmd/microauth2sqld/db"
"jochum.dev/jo-micro/auth2/internal/argon2" "jochum.dev/jo-micro/auth2/internal/argon2"
"jochum.dev/jo-micro/auth2/internal/proto/authpb" "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/auth2/shared/sjwt"
"jochum.dev/jo-micro/components" "jochum.dev/jo-micro/components"
"jochum.dev/jo-micro/logruscomponent"
"jochum.dev/jo-micro/router" "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 return nil
} }

@ -27,7 +27,6 @@ import (
"jochum.dev/jo-micro/router" "jochum.dev/jo-micro/router"
"jochum.dev/jo-micro/auth2/plugins/client/jwt" "jochum.dev/jo-micro/auth2/plugins/client/jwt"
"jochum.dev/jo-micro/auth2/plugins/verifier/endpointroles"
) )
var ( var (
@ -247,46 +246,6 @@ func main() {
logger := logruscomponent.MustReg(cReg).Logger() 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 // 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") == "" { 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) logger.Fatal(ErrorNoKeys)

@ -37,7 +37,7 @@ func (p *noopClientPlugin) Health(ctx context.Context) error {
return nil return nil
} }
func (p *noopClientPlugin) SetVerifier(v VerifierPlugin) { func (p *noopClientPlugin) AddVerifier(v VerifierPlugin) {
} }
func (p *noopClientPlugin) ServiceContext(ctx context.Context) (context.Context, error) { func (p *noopClientPlugin) ServiceContext(ctx context.Context) (context.Context, error) {

@ -28,7 +28,10 @@ type registryFuncs interface {
type VerifierPlugin interface { type VerifierPlugin interface {
// Verify verifies that the user is allowed to access the request, it MUST handle AnonUser // 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 // ClientPlugin is for services that act as client's behind GinRouter
@ -36,7 +39,7 @@ type ClientPlugin interface {
registryFuncs registryFuncs
// Set the Verifier for this Client // 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 adds the ServiceUser to the context (when using JWT's it will overwrite the Authorization Header)
ServiceContext(ctx context.Context) (context.Context, error) ServiceContext(ctx context.Context) (context.Context, error)

@ -14,7 +14,6 @@ import (
"go-micro.dev/v4/metadata" "go-micro.dev/v4/metadata"
"go-micro.dev/v4/server" "go-micro.dev/v4/server"
"jochum.dev/jo-micro/auth2" "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/sjwt"
"jochum.dev/jo-micro/auth2/shared/sutil" "jochum.dev/jo-micro/auth2/shared/sutil"
"jochum.dev/jo-micro/components" "jochum.dev/jo-micro/components"
@ -22,9 +21,7 @@ import (
func New() auth2.ClientPlugin { func New() auth2.ClientPlugin {
return &jwtPlugin{ return &jwtPlugin{
verifier: endpointroles.NewVerifier( verifiers: []auth2.VerifierPlugin{},
endpointroles.NoDefaultDeny(),
),
} }
} }
@ -32,7 +29,7 @@ type jwtPlugin struct {
audiences []string audiences []string
pubKey any pubKey any
privKey any privKey any
verifier auth2.VerifierPlugin verifiers []auth2.VerifierPlugin
} }
func (p *jwtPlugin) String() string { func (p *jwtPlugin) String() string {
@ -86,8 +83,8 @@ func (p *jwtPlugin) Health(ctx context.Context) error {
return nil return nil
} }
func (p *jwtPlugin) SetVerifier(v auth2.VerifierPlugin) { func (p *jwtPlugin) AddVerifier(v auth2.VerifierPlugin) {
p.verifier = v p.verifiers = append(p.verifiers, v)
} }
func (p *jwtPlugin) ServiceContext(ctx context.Context) (context.Context, error) { 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) ctx = context.WithValue(ctx, auth2.ContextUserKey{}, u)
if err = p.verifier.Verify(ctx, u, req); err != nil { var defaultDenyOk bool
return err for _, v := range p.verifiers {
err, defaultDenyOk = v.Verify(ctx, u, req)
if !defaultDenyOk && err != nil {
return err
}
} }
return nil return err
} }

@ -41,29 +41,29 @@ func (v *EndpointRolesVerifier) logrus() *logrus.Logger {
return v.options.Logrus 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 ep, ok := v.rules[req.Endpoint()]; ok {
if auth2.IntersectsRoles(u, ep.RolesDeny...) { if auth2.IntersectsRoles(u, ep.RolesDeny...) {
v.logrus().WithField("endpoint", req.Endpoint()).WithField("rolesDeny", ep.RolesDeny).WithField("userRoles", u.Roles).Debug("Unauthorized") 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...) { if auth2.IntersectsRoles(u, ep.RolesAllow...) {
v.logrus().WithField("endpoint", req.Endpoint()).WithField("rolesAllow", ep.RolesAllow).WithField("userRoles", u.Roles).Trace("Authorized") v.logrus().WithField("endpoint", req.Endpoint()).WithField("rolesAllow", ep.RolesAllow).WithField("userRoles", u.Roles).Trace("Authorized")
// Allowed by role // Allowed by role
return nil return nil, false
} }
if v.options.DefaultDeny { 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") 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 { if !v.options.DefaultDeny {
v.logrus().WithField("endpoint", req.Endpoint()).WithField("endpoints", v.endpointnames).Trace("DefaultAllow: No rule") 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") 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
} }

Loading…
Cancel
Save