Files
opencloud/services/policies/pkg/engine/opa.go
Florian Schade f38a9f4385 Introduce Policies-Service (#5716)
* add policies service
add policies proxy middleware
add policies event service
add policies grpc service
prepare ci and git environments (ci, make, readme, doc)

* add webfinger to the drone conf

* fix docs
remove not used virus scan postprocessing step

* relocate example rego file
implicitly enable and disable proxy and postprocessing policy checking by setting the query.
update configuration descriptions

* move policies
update readme

* use converter func to convert pp environment to actual environment
expose and test custom rego functions
add engine unit tests
add opa unit tests
update policies readme

Co-authored-by: Martin <github@diemattels.at>

* relocate sample policies to the deployments folder
change and document policies service port

* update index.md and small fix

* add health command
add version command
add debug server

---------

Co-authored-by: Martin <github@diemattels.at>
2023-03-14 16:08:22 +01:00

125 lines
2.7 KiB
Go

package engine
import (
"bytes"
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/gabriel-vasile/mimetype"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/types"
"github.com/owncloud/ocis/v2/services/policies/pkg/config"
)
// OPA wraps open policy agent makes it possible to ask if an action is granted.
type OPA struct {
policies []string
timeout time.Duration
}
// NewOPA returns a ready to use opa engine.
func NewOPA(timeout time.Duration, conf config.Engine) (OPA, error) {
return OPA{
policies: conf.Policies,
timeout: timeout,
},
nil
}
// Evaluate evaluates the opa policies and returns the result.
func (o OPA) Evaluate(ctx context.Context, qs string, env Environment) (bool, error) {
ctx, cancel := context.WithTimeout(ctx, o.timeout)
defer cancel()
q, err := rego.New(
rego.Query(qs),
rego.Load(o.policies, nil),
GetMimetype,
GetResource,
).PrepareForEval(ctx)
if err != nil {
return false, err
}
result, err := q.Eval(ctx, rego.EvalInput(env))
if err != nil {
return false, err
}
return result.Allowed(), nil
}
var GetResource = rego.Function1(
&rego.Function{
Name: "ocis_get_resource",
Decl: types.NewFunction(types.Args(types.S), types.A),
Memoize: true,
Nondeterministic: true,
},
func(_ rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
var url string
if err := ast.As(a.Value, &url); err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
client := rhttp.GetHTTPClient(rhttp.Insecure(true))
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code from Download %v", res.StatusCode)
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(res.Body); err != nil {
return nil, err
}
v, err := ast.InterfaceToValue(buf.Bytes())
if err != nil {
return nil, err
}
return ast.NewTerm(v), nil
},
)
var GetMimetype = rego.Function1(
&rego.Function{
Name: "ocis_get_mimetype",
Decl: types.NewFunction(types.Args(types.A), types.S),
Memoize: true,
Nondeterministic: true,
},
func(_ rego.BuiltinContext, a *ast.Term) (*ast.Term, error) {
var body []byte
if err := ast.As(a.Value, &body); err != nil {
return nil, err
}
mimeInfo := mimetype.Detect(body).String()
detectedMimetype := strings.Split(mimeInfo, ";")[0]
v, err := ast.InterfaceToValue(detectedMimetype)
if err != nil {
return nil, err
}
return ast.NewTerm(v), nil
},
)