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

main v0.4.7
René Jochum 1 year 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/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
}

@ -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)

@ -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) {

@ -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)

@ -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
}

@ -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
}

Loading…
Cancel
Save