Skip to content

Commit

Permalink
(choria-io#2209) Extract authorization into a external callable
Browse files Browse the repository at this point in the history
Signed-off-by: R.I.Pienaar <[email protected]>
  • Loading branch information
ripienaar committed Jan 22, 2025
1 parent 2daf759 commit 7f22587
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 104 deletions.
4 changes: 2 additions & 2 deletions integration/agentharness/agent.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022, R.I. Pienaar and the Choria Project contributors
// Copyright (c) 2022-2025, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -70,7 +70,7 @@ type ActionMiddleware interface {
type AgentHarness struct {
name string
ddl *addl.DDL
fw mcorpc.ChoriaFramework
fw inter.Framework
log *logrus.Entry
actions map[string]*MockActionMiddleware
}
Expand Down
48 changes: 37 additions & 11 deletions providers/agent/mcorpc/agent.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2022, R.I. Pienaar and the Choria Project contributors
// Copyright (c) 2020-2025, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -30,7 +30,7 @@ type ActivationChecker func() bool
type Agent struct {
Log *logrus.Entry
Config *config.Config
Choria ChoriaFramework
Choria inter.Framework
ServerInfoSource agents.ServerInfoSource

activationCheck ActivationChecker
Expand All @@ -39,7 +39,7 @@ type Agent struct {
}

// New creates a new MCollective SimpleRPC compatible agent
func New(name string, metadata *agents.Metadata, fw ChoriaFramework, log *logrus.Entry) *Agent {
func New(name string, metadata *agents.Metadata, fw inter.Framework, log *logrus.Entry) *Agent {
a := &Agent{
meta: metadata,
Log: log.WithFields(logrus.Fields{"agent": name}),
Expand Down Expand Up @@ -218,34 +218,60 @@ func (a *Agent) parseIncomingMessage(msg []byte, request protocol.Request) (*Req
}

func (a *Agent) authorize(req *Request) bool {
if !a.Config.RPCAuthorization {
if req.Agent != a.Name() {
a.Log.Errorf("Could not process authorization for request for a different agent")
return false
}

return AuthorizeRequest(a.Choria, req, a.Config, a.ServerInfoSource, a.Log)
}

// AuthorizeRequest authorizes a request using the configured authorizer
func AuthorizeRequest(fw inter.Framework, req *Request, cfg *config.Config, si agents.ServerInfoSource, log *logrus.Entry) bool {
if cfg == nil {
log.Errorf("Could not process authorization without a configuration")
return false
}
if !cfg.RPCAuthorization {
return true
}
if req == nil {
log.Errorf("Could not process authorization without a request")
return false
}
if req.Agent == "" {
log.Errorf("Could not process authorization without a agent name")
return false
}
if si == nil {
log.Errorf("Could not process authorization without a server info source")
return false
}

prov := strings.ToLower(a.Config.RPCAuthorizationProvider)
prov := strings.ToLower(cfg.RPCAuthorizationProvider)

switch prov {
case "action_policy":
return actionPolicyAuthorize(req, a, a.Log)
return actionPolicyAuthorize(req, cfg, log)

case "rego_policy":
auth, err := regoPolicyAuthorize(req, a, a.Log)
auth, err := regoPolicyAuthorize(req, fw, si, cfg, log)
if err != nil {
a.Log.Errorf("Could not process Open Policy Agent policy: %v", err)
log.Errorf("Could not process Open Policy Agent policy: %v", err)
return false
}
return auth

case "aaasvc", "aaasvc_policy":
auth, err := aaasvcPolicyAuthorize(req, a, a.Log)
auth, err := aaasvcPolicyAuthorize(req, cfg, log)
if err != nil {
a.Log.Errorf("Could not process JWT policy: %v", err)
log.Errorf("Could not process JWT policy: %v", err)
return false
}
return auth

default:
a.Log.Errorf("Unsupported authorization provider: %s", prov)
log.Errorf("Unsupported authorization provider: %s", prov)

}

Expand Down
16 changes: 7 additions & 9 deletions providers/agent/mcorpc/authz_actionpolicy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2021, R.I. Pienaar and the Choria Project contributors
// Copyright (c) 2020-2025, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -21,17 +21,16 @@ import (
"github.com/sirupsen/logrus"
)

func actionPolicyAuthorize(req *Request, agent *Agent, log *logrus.Entry) bool {
func actionPolicyAuthorize(req *Request, cfg *config.Config, log *logrus.Entry) bool {
logger := log.WithFields(logrus.Fields{
"authorizer": "actionpolicy",
"agent": agent.Name(),
"agent": req.Agent,
"request": req.RequestID,
})

authz := &actionPolicy{
cfg: agent.Config,
cfg: cfg,
req: req,
agent: agent,
matcher: &actionPolicyPolicy{log: logger},
groups: make(map[string][]string),
log: logger,
Expand All @@ -48,7 +47,6 @@ func actionPolicyAuthorize(req *Request, agent *Agent, log *logrus.Entry) bool {
type actionPolicy struct {
cfg *config.Config
req *Request
agent *Agent
log *logrus.Entry
matcher *actionPolicyPolicy
groups map[string][]string
Expand Down Expand Up @@ -168,7 +166,7 @@ func (a *actionPolicy) checkRequestAgainstPolicy() (bool, error) {
return false, nil
}

factsMatched, err := pol.MatchesFacts(a.agent.Config, a.log)
factsMatched, err := pol.MatchesFacts(a.cfg, a.log)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -204,7 +202,7 @@ func (a *actionPolicy) defaultPolicyFileName() string {
}

func (a *actionPolicy) lookupPolicyFile() (string, error) {
agentPolicy := filepath.Join(filepath.Dir(a.cfg.ConfigFile), "policies", a.agent.Name()+".policy")
agentPolicy := filepath.Join(filepath.Dir(a.cfg.ConfigFile), "policies", a.req.Agent+".policy")

a.log.Debugf("Looking up agent policy in %s", agentPolicy)
if util.FileExist(agentPolicy) {
Expand All @@ -218,7 +216,7 @@ func (a *actionPolicy) lookupPolicyFile() (string, error) {
}
}

return "", fmt.Errorf("no policy found for %s", a.agent.Name())
return "", fmt.Errorf("no policy found for %s", a.req.Agent)
}

func (a *actionPolicy) parseGroupFile(gfile string) error {
Expand Down
10 changes: 2 additions & 8 deletions providers/agent/mcorpc/authz_actionpolicy_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020-2021, R.I. Pienaar and the Choria Project contributors
// Copyright (c) 2020-2025, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -21,7 +21,6 @@ var _ = Describe("ActionPolicy", func() {
pol *actionPolicyPolicy
logger *logrus.Entry
mockctl *gomock.Controller
fw *imock.MockFramework
cfg *config.Config
logbuffer *bytes.Buffer
)
Expand All @@ -33,7 +32,7 @@ var _ = Describe("ActionPolicy", func() {
pol = &actionPolicyPolicy{log: logger}

mockctl = gomock.NewController(GinkgoT())
fw, cfg = imock.NewFrameworkForTests(mockctl, GinkgoWriter)
_, cfg = imock.NewFrameworkForTests(mockctl, GinkgoWriter)
cfg.ClassesFile = "testdata/classes.txt"
cfg.FactSourceFile = "testdata/facts.json"
cfg.DisableSecurityProviderVerify = true
Expand All @@ -48,11 +47,6 @@ var _ = Describe("ActionPolicy", func() {
Action: "test",
CallerID: "choria=ginkgo.mcollective",
},
agent: &Agent{
Log: logger,
Config: cfg,
Choria: fw,
},
}
})

Expand Down
18 changes: 8 additions & 10 deletions providers/agent/mcorpc/authz_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,22 @@ import (
)

type aaasvcPolicy struct {
cfg *config.Config
req *Request
agent *Agent
log *logrus.Entry
cfg *config.Config
req *Request
log *logrus.Entry
}

func aaasvcPolicyAuthorize(req *Request, agent *Agent, log *logrus.Entry) (bool, error) {
func aaasvcPolicyAuthorize(req *Request, cfg *config.Config, log *logrus.Entry) (bool, error) {
logger := log.WithFields(logrus.Fields{
"authorizer": "aaasvc",
"agent": agent.Name(),
"agent": req.Agent,
"request": req.RequestID,
})

authz := &aaasvcPolicy{
cfg: agent.Config,
req: req,
agent: agent,
log: logger,
cfg: cfg,
req: req,
log: logger,
}

return authz.authorize()
Expand Down
18 changes: 9 additions & 9 deletions providers/agent/mcorpc/authz_jwt_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2022, R.I. Pienaar and the Choria Project contributors
// Copyright (c) 2022-2025, R.I. Pienaar and the Choria Project contributors
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -86,14 +86,14 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
})

It("Should fail for no caller public data", func() {
allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).To(MatchError("no policy received in request"))
Expect(allowed).To(BeFalse())
})

It("Should handle invalid tokens", func() {
req.CallerPublicData = "blah"
allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).To(MatchError("invalid token in request: token contains an invalid number of segments"))
Expect(allowed).To(BeFalse())
})
Expand All @@ -105,7 +105,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
Expect(err).ToNot(HaveOccurred())

req.Agent = "discovery"
allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).ToNot(HaveOccurred())
Expect(allowed).To(BeTrue())
Expect(logBuff).To(gbytes.Say("Allowing discovery request"))
Expand All @@ -117,7 +117,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
req.CallerPublicData, err = tokens.SignToken(claims, prik)
Expect(err).ToNot(HaveOccurred())

allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).To(MatchError("no policy received in token"))
Expect(allowed).To(BeFalse())
})
Expand All @@ -129,7 +129,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
req.CallerPublicData, err = tokens.SignToken(claims, prik)
Expect(err).ToNot(HaveOccurred())

allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).To(MatchError("invalid agent policy: fail"))
Expect(allowed).To(BeFalse())
})
Expand All @@ -140,7 +140,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
req.CallerPublicData, err = tokens.SignToken(claims, prik)
Expect(err).ToNot(HaveOccurred())

allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).ToNot(HaveOccurred())
Expect(allowed).To(BeTrue())
})
Expand All @@ -153,7 +153,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
req.CallerPublicData, err = tokens.SignToken(claims, prik)
Expect(err).ToNot(HaveOccurred())

allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(MatchRegexp("could not initialize opa evaluator"))
Expect(allowed).To(BeFalse())
Expand All @@ -165,7 +165,7 @@ var _ = Describe("McoRPC/JWTAuthorizer", func() {
req.CallerPublicData, err = tokens.SignToken(claims, prik)
Expect(err).ToNot(HaveOccurred())

allowed, err := aaasvcPolicyAuthorize(req, agent, log)
allowed, err := aaasvcPolicyAuthorize(req, agent.Config, log)
Expect(err).ToNot(HaveOccurred())
Expect(allowed).To(BeTrue())
})
Expand Down
Loading

0 comments on commit 7f22587

Please sign in to comment.