ppl: add support for http_path and http_method (#2813)

* ppl: add support for http_path and http_method

* fix import ordering
This commit is contained in:
Caleb Doxsey 2021-12-10 07:28:51 -07:00 committed by GitHub
parent 54ec88fb93
commit 2d04106e6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 257 additions and 18 deletions

View file

@ -32,6 +32,7 @@ type (
}
InputHTTP struct {
Method string `json:"method"`
Path string `json:"path"`
Headers map[string][]string `json:"headers"`
}
InputSession struct {

View file

@ -0,0 +1,43 @@
package criteria
import (
"github.com/open-policy-agent/opa/ast"
"github.com/pomerium/pomerium/pkg/policy/parser"
)
type httpMethodCriterion struct {
g *Generator
}
func (httpMethodCriterion) DataType() CriterionDataType {
return CriterionDataTypeStringMatcher
}
func (httpMethodCriterion) Name() string {
return "http_method"
}
func (c httpMethodCriterion) GenerateRule(_ string, data parser.Value) (*ast.Rule, []*ast.Rule, error) {
var body ast.Body
ref := ast.RefTerm(ast.VarTerm("input"), ast.VarTerm("http"), ast.VarTerm("method"))
err := matchString(&body, ref, data)
if err != nil {
return nil, nil, err
}
rule := NewCriterionRule(c.g, c.Name(),
ReasonHTTPMethodOK, ReasonHTTPMethodUnauthorized,
body)
return rule, nil, nil
}
// HTTPMethod returns a Criterion which matches an HTTP method.
func HTTPMethod(generator *Generator) Criterion {
return httpMethodCriterion{g: generator}
}
func init() {
Register(HTTPMethod)
}

View file

@ -0,0 +1,32 @@
package criteria
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestHTTPMethod(t *testing.T) {
t.Run("ok", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- http_method:
is: GET
`, []dataBrokerRecord{}, Input{HTTP: InputHTTP{Method: "GET"}})
require.NoError(t, err)
require.Equal(t, A{true, A{ReasonHTTPMethodOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
t.Run("unauthorized", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- http_method:
is: GET
`, []dataBrokerRecord{}, Input{HTTP: InputHTTP{Method: "POST"}})
require.NoError(t, err)
require.Equal(t, A{false, A{ReasonHTTPMethodUnauthorized}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
}

View file

@ -0,0 +1,43 @@
package criteria
import (
"github.com/open-policy-agent/opa/ast"
"github.com/pomerium/pomerium/pkg/policy/parser"
)
type httpPathCriterion struct {
g *Generator
}
func (httpPathCriterion) DataType() CriterionDataType {
return CriterionDataTypeStringMatcher
}
func (httpPathCriterion) Name() string {
return "http_path"
}
func (c httpPathCriterion) GenerateRule(_ string, data parser.Value) (*ast.Rule, []*ast.Rule, error) {
var body ast.Body
ref := ast.RefTerm(ast.VarTerm("input"), ast.VarTerm("http"), ast.VarTerm("path"))
err := matchString(&body, ref, data)
if err != nil {
return nil, nil, err
}
rule := NewCriterionRule(c.g, c.Name(),
ReasonHTTPPathOK, ReasonHTTPPathUnauthorized,
body)
return rule, nil, nil
}
// HTTPPath returns a Criterion which matches an HTTP path.
func HTTPPath(generator *Generator) Criterion {
return httpPathCriterion{g: generator}
}
func init() {
Register(HTTPPath)
}

View file

@ -0,0 +1,32 @@
package criteria
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestHTTPPath(t *testing.T) {
t.Run("ok", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- http_path:
is: /test
`, []dataBrokerRecord{}, Input{HTTP: InputHTTP{Path: "/test"}})
require.NoError(t, err)
require.Equal(t, A{true, A{ReasonHTTPPathOK}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
t.Run("unauthorized", func(t *testing.T) {
res, err := evaluate(t, `
allow:
and:
- http_path:
is: /test
`, []dataBrokerRecord{}, Input{HTTP: InputHTTP{Path: "/not-test"}})
require.NoError(t, err)
require.Equal(t, A{false, A{ReasonHTTPPathUnauthorized}, M{}}, res["allow"])
require.Equal(t, A{false, A{}}, res["deny"])
})
}

View file

@ -20,6 +20,10 @@ const (
ReasonEmailUnauthorized = "email-unauthorized"
ReasonGroupsOK = "groups-ok"
ReasonGroupsUnauthorized = "groups-unauthorized"
ReasonHTTPMethodOK = "http-method-ok"
ReasonHTTPMethodUnauthorized = "http-method-unauthorized"
ReasonHTTPPathOK = "http-path-ok"
ReasonHTTPPathUnauthorized = "http-path-unauthorized"
ReasonInvalidClientCertificate = "invalid-client-certificate"
ReasonNonCORSRequest = "non-cors-request"
ReasonNonPomeriumRoute = "non-pomerium-route"