mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-18 09:08:16 +02:00
Merge pull request from GHSA-pvrc-wvj2-f59p
* authorize: normalize URL query params * config: enable envoy normalize_path option * authorize: use route id from envoy for policy evaluation
This commit is contained in:
parent
32985aabe6
commit
2bc2be793f
12 changed files with 255 additions and 208 deletions
|
@ -31,9 +31,10 @@ var notFoundOutput = &Result{
|
|||
|
||||
// Request contains the inputs needed for evaluation.
|
||||
type Request struct {
|
||||
Policy *config.Policy
|
||||
HTTP RequestHTTP
|
||||
Session RequestSession
|
||||
IsInternal bool
|
||||
Policy *config.Policy
|
||||
HTTP RequestHTTP
|
||||
Session RequestSession
|
||||
}
|
||||
|
||||
// RequestHTTP is the HTTP field in the request.
|
||||
|
@ -124,42 +125,48 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error)
|
|||
ctx, span := trace.StartSpan(ctx, "authorize.Evaluator.Evaluate")
|
||||
defer span.End()
|
||||
|
||||
if req.Policy == nil {
|
||||
return notFoundOutput, nil
|
||||
}
|
||||
|
||||
id, err := req.Policy.RouteID()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("authorize: error computing policy route id: %w", err)
|
||||
}
|
||||
|
||||
policyEvaluator, ok := e.policyEvaluators[id]
|
||||
if !ok {
|
||||
return notFoundOutput, nil
|
||||
}
|
||||
|
||||
clientCA, err := e.getClientCA(req.Policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isValidClientCertificate, err := isValidClientCertificate(clientCA, req.HTTP.ClientCertificate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("authorize: error validating client certificate: %w", err)
|
||||
}
|
||||
|
||||
eg, ectx := errgroup.WithContext(ctx)
|
||||
|
||||
var policyOutput *PolicyResponse
|
||||
eg.Go(func() error {
|
||||
if req.IsInternal {
|
||||
var err error
|
||||
policyOutput, err = policyEvaluator.Evaluate(ectx, &PolicyRequest{
|
||||
HTTP: req.HTTP,
|
||||
Session: req.Session,
|
||||
IsValidClientCertificate: isValidClientCertificate,
|
||||
policyOutput, err = e.evaluateInternal(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if req.Policy == nil {
|
||||
return notFoundOutput, nil
|
||||
} else {
|
||||
id, err := req.Policy.RouteID()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("authorize: error computing policy route id: %w", err)
|
||||
}
|
||||
|
||||
policyEvaluator, ok := e.policyEvaluators[id]
|
||||
if !ok {
|
||||
return notFoundOutput, nil
|
||||
}
|
||||
|
||||
clientCA, err := e.getClientCA(req.Policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isValidClientCertificate, err := isValidClientCertificate(clientCA, req.HTTP.ClientCertificate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("authorize: error validating client certificate: %w", err)
|
||||
}
|
||||
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
policyOutput, err = policyEvaluator.Evaluate(ectx, &PolicyRequest{
|
||||
HTTP: req.HTTP,
|
||||
Session: req.Session,
|
||||
IsValidClientCertificate: isValidClientCertificate,
|
||||
})
|
||||
return err
|
||||
})
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
var headersOutput *HeadersResponse
|
||||
eg.Go(func() error {
|
||||
|
@ -170,7 +177,7 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error)
|
|||
return err
|
||||
})
|
||||
|
||||
err = eg.Wait()
|
||||
err := eg.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -186,6 +193,21 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error)
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func (e *Evaluator) evaluateInternal(_ context.Context, req *Request) (*PolicyResponse, error) {
|
||||
// these endpoints require a logged-in user
|
||||
if req.HTTP.Path == "/.pomerium/jwt" {
|
||||
if req.Session.ID == "" {
|
||||
return &PolicyResponse{
|
||||
Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &PolicyResponse{
|
||||
Allow: NewRuleResult(true, criteria.ReasonPomeriumRoute),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *Evaluator) getClientCA(policy *config.Policy) (string, error) {
|
||||
if policy != nil && policy.TLSDownstreamClientCA != "" {
|
||||
bs, err := base64.StdEncoding.DecodeString(policy.TLSDownstreamClientCA)
|
||||
|
|
|
@ -31,18 +31,20 @@ type HeadersRequest struct {
|
|||
// NewHeadersRequestFromPolicy creates a new HeadersRequest from a policy.
|
||||
func NewHeadersRequestFromPolicy(policy *config.Policy) *HeadersRequest {
|
||||
input := new(HeadersRequest)
|
||||
input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication
|
||||
input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH ||
|
||||
policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV
|
||||
if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil {
|
||||
input.FromAudience = u.Hostname()
|
||||
if policy != nil {
|
||||
input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication
|
||||
input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH ||
|
||||
policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV
|
||||
if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil {
|
||||
input.FromAudience = u.Hostname()
|
||||
}
|
||||
input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken
|
||||
for _, wu := range policy.To {
|
||||
input.ToAudience = "https://" + wu.URL.Hostname()
|
||||
}
|
||||
input.PassAccessToken = policy.GetSetAuthorizationHeader() == configpb.Route_ACCESS_TOKEN
|
||||
input.PassIDToken = policy.GetSetAuthorizationHeader() == configpb.Route_ID_TOKEN
|
||||
}
|
||||
input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken
|
||||
for _, wu := range policy.To {
|
||||
input.ToAudience = "https://" + wu.URL.Hostname()
|
||||
}
|
||||
input.PassAccessToken = policy.GetSetAuthorizationHeader() == configpb.Route_ACCESS_TOKEN
|
||||
input.PassIDToken = policy.GetSetAuthorizationHeader() == configpb.Route_ID_TOKEN
|
||||
return input
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &PolicyResponse{
|
||||
Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonNonPomeriumRoute, criteria.ReasonUserUnauthorized),
|
||||
Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonUserUnauthorized),
|
||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
||||
Traces: []contextutil.PolicyEvaluationTrace{{}},
|
||||
}, output)
|
||||
|
@ -172,7 +172,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &PolicyResponse{
|
||||
Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute),
|
||||
Allow: NewRuleResult(false),
|
||||
Deny: NewRuleResult(true, criteria.ReasonAccept),
|
||||
Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Deny: true}},
|
||||
}, output)
|
||||
|
@ -203,7 +203,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &PolicyResponse{
|
||||
Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute),
|
||||
Allow: NewRuleResult(false),
|
||||
Deny: NewRuleResult(true, criteria.ReasonAccept, criteria.ReasonInvalidClientCertificate),
|
||||
Traces: []contextutil.PolicyEvaluationTrace{{Deny: true}, {ID: "p1", Deny: true}},
|
||||
}, output)
|
||||
|
@ -289,7 +289,7 @@ func TestPolicyEvaluator(t *testing.T) {
|
|||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &PolicyResponse{
|
||||
Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute, criteria.ReasonUserUnauthenticated),
|
||||
Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated),
|
||||
Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired),
|
||||
Traces: []contextutil.PolicyEvaluationTrace{{Allow: false}},
|
||||
}, output)
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/authorize/evaluator"
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/config/envoyconfig"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/sessions"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/requestid"
|
||||
|
@ -117,6 +118,7 @@ func (a *Authorize) getEvaluatorRequestFromCheckRequest(
|
|||
) (*evaluator.Request, error) {
|
||||
requestURL := getCheckRequestURL(in)
|
||||
req := &evaluator.Request{
|
||||
IsInternal: envoyconfig.ExtAuthzContextExtensionsIsInternal(in.GetAttributes().GetContextExtensions()),
|
||||
HTTP: evaluator.NewRequestHTTP(
|
||||
in.GetAttributes().GetRequest().GetHttp().GetMethod(),
|
||||
requestURL,
|
||||
|
@ -183,6 +185,7 @@ func getCheckRequestURL(req *envoy_service_auth_v3.CheckRequest) url.URL {
|
|||
path := h.GetPath()
|
||||
if idx := strings.Index(path, "?"); idx != -1 {
|
||||
u.RawPath, u.RawQuery = path[:idx], path[idx+1:]
|
||||
u.RawQuery = u.Query().Encode()
|
||||
} else {
|
||||
u.RawPath = path
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue