Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Evaluate preparing for CEL #272

Merged
merged 1 commit into from
Sep 23, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 149 additions & 136 deletions pkg/internal/approver/allowed/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package allowed

import (
"context"
"crypto/x509"
"crypto/x509/pkix"
"strconv"
"strings"

Expand Down Expand Up @@ -55,178 +57,189 @@ func (a allowed) Evaluate(_ context.Context, policy *policyapi.CertificateReques
return approver.EvaluationResponse{}, err
}

if len(csr.Subject.CommonName) > 0 {
if allowed.CommonName == nil || allowed.CommonName.Value == nil {
el = append(el, field.Invalid(fldPath.Child("commonName", "value"), csr.Subject.CommonName, "nil"))
} else if !util.WildcardMatches(*allowed.CommonName.Value, csr.Subject.CommonName) {
el = append(el, field.Invalid(fldPath.Child("commonName", "value"), csr.Subject.CommonName, *allowed.CommonName.Value))
}
} else if allowed.CommonName != nil && allowed.CommonName.Required != nil && *allowed.CommonName.Required {
el = append(el, field.Required(fldPath.Child("commonName", "required"), strconv.FormatBool(*allowed.CommonName.Required)))
evaluate := evaluator{
request: request,
csr: csr,
allowed: allowed,
fldPath: fldPath,
}
evaluateSubject := evaluate.Subject()

if len(csr.DNSNames) > 0 {
if allowed.DNSNames == nil || allowed.DNSNames.Values == nil {
el = append(el, field.Invalid(fldPath.Child("dnsNames", "values"), csr.DNSNames, "nil"))
} else if !util.WildcardSubset(*allowed.DNSNames.Values, csr.DNSNames) {
el = append(el, field.Invalid(fldPath.Child("dnsNames", "values"), csr.DNSNames, strings.Join(*allowed.DNSNames.Values, ", ")))
}
} else if allowed.DNSNames != nil && allowed.DNSNames.Required != nil && *allowed.DNSNames.Required {
el = append(el, field.Required(fldPath.Child("dnsNames", "required"), strconv.FormatBool(*allowed.DNSNames.Required)))
evaluateFns := []func() *field.Error{
evaluate.CommonName,
evaluate.DNSNames,
evaluate.IPAddresses,
evaluate.URIs,
evaluate.EmailAddresses,
evaluate.IsCA,
evaluate.Usages,
evaluateSubject.Organization,
evaluateSubject.Country,
evaluateSubject.OrganizationalUnit,
evaluateSubject.Locality,
evaluateSubject.Province,
evaluateSubject.StreetAddress,
evaluateSubject.PostalCode,
evaluateSubject.SerialNumber,
}

if len(csr.IPAddresses) > 0 {
var ips []string
for _, ip := range csr.IPAddresses {
ips = append(ips, ip.String())
for _, fn := range evaluateFns {
if e := fn(); e != nil {
el = append(el, e)
}
if allowed.IPAddresses == nil || allowed.IPAddresses.Values == nil {
el = append(el, field.Invalid(fldPath.Child("ipAddresses", "values"), ips, "nil"))
} else if !util.WildcardSubset(*allowed.IPAddresses.Values, ips) {
el = append(el, field.Invalid(fldPath.Child("ipAddresses", "values"), ips, strings.Join(*allowed.IPAddresses.Values, ", ")))
}
} else if allowed.IPAddresses != nil && allowed.IPAddresses.Required != nil && *allowed.IPAddresses.Required {
el = append(el, field.Required(fldPath.Child("ipAddresses", "required"), strconv.FormatBool(*allowed.IPAddresses.Required)))
}

if len(csr.URIs) > 0 {
var uris []string
for _, uri := range csr.URIs {
uris = append(uris, uri.String())
}
if allowed.URIs == nil || allowed.URIs.Values == nil {
el = append(el, field.Invalid(fldPath.Child("uris", "values"), uris, "nil"))
} else if !util.WildcardSubset(*allowed.URIs.Values, uris) {
el = append(el, field.Invalid(fldPath.Child("uris", "values"), uris, strings.Join(*allowed.URIs.Values, ", ")))
}
} else if allowed.URIs != nil && allowed.URIs.Required != nil && *allowed.URIs.Required {
el = append(el, field.Required(fldPath.Child("uris", "required"), strconv.FormatBool(*allowed.URIs.Required)))
// If there are errors, then return not approved and the aggregated errors
if len(el) > 0 {
return approver.EvaluationResponse{Result: approver.ResultDenied, Message: el.ToAggregate().Error()}, nil
}

if len(csr.EmailAddresses) > 0 {
if allowed.EmailAddresses == nil || allowed.EmailAddresses.Values == nil {
el = append(el, field.Invalid(fldPath.Child("emailAddresses", "values"), csr.EmailAddresses, "nil"))
} else if !util.WildcardSubset(*allowed.EmailAddresses.Values, csr.EmailAddresses) {
el = append(el, field.Invalid(fldPath.Child("emailAddresses", "values"), csr.EmailAddresses, strings.Join(*allowed.EmailAddresses.Values, ", ")))
}
} else if allowed.EmailAddresses != nil && allowed.EmailAddresses.Required != nil && *allowed.EmailAddresses.Required {
el = append(el, field.Required(fldPath.Child("emailAddresses", "required"), strconv.FormatBool(*allowed.EmailAddresses.Required)))
// If no evaluation errors resulting from this policy, return not denied
return approver.EvaluationResponse{Result: approver.ResultNotDenied}, nil
}

type evaluator struct {
request *cmapi.CertificateRequest
csr *x509.CertificateRequest
allowed *policyapi.CertificateRequestPolicyAllowed
fldPath *field.Path
}

func (e evaluator) CommonName() *field.Error {
return evaluateString(e.csr.Subject.CommonName, e.allowed.CommonName, e.fldPath.Child("commonName"))
}

func (e evaluator) DNSNames() *field.Error {
return evaluateSlice(e.csr.DNSNames, e.allowed.DNSNames, e.fldPath.Child("dnsNames"))
}

func (e evaluator) IPAddresses() *field.Error {
var ips []string
for _, ip := range e.csr.IPAddresses {
ips = append(ips, ip.String())
}
return evaluateSlice(ips, e.allowed.IPAddresses, e.fldPath.Child("ipAddresses"))
}

if request.Spec.IsCA {
if allowed.IsCA == nil {
el = append(el, field.Invalid(fldPath.Child("isCA"), request.Spec.IsCA, "nil"))
} else if !*allowed.IsCA {
el = append(el, field.Invalid(fldPath.Child("isCA"), request.Spec.IsCA, strconv.FormatBool(*allowed.IsCA)))
}
func (e evaluator) URIs() *field.Error {
var uris []string
for _, uri := range e.csr.URIs {
uris = append(uris, uri.String())
}
return evaluateSlice(uris, e.allowed.URIs, e.fldPath.Child("uris"))
}

func (e evaluator) EmailAddresses() *field.Error {
return evaluateSlice(e.csr.EmailAddresses, e.allowed.EmailAddresses, e.fldPath.Child("emailAddresses"))
}

if len(request.Spec.Usages) > 0 {
func (e evaluator) IsCA() *field.Error {
return evaluateBool(e.request.Spec.IsCA, e.allowed.IsCA, e.fldPath.Child("isCA"))
}

func (e evaluator) Usages() *field.Error {
if len(e.request.Spec.Usages) > 0 {
var requestUsages []string
for _, usage := range request.Spec.Usages {
for _, usage := range e.request.Spec.Usages {
requestUsages = append(requestUsages, string(usage))
}
if allowed.Usages == nil {
el = append(el, field.Invalid(fldPath.Child("usages"), requestUsages, "nil"))
if e.allowed.Usages == nil {
return field.Invalid(e.fldPath.Child("usages"), requestUsages, "nil")
} else {
var policyUsages []string
for _, usage := range *allowed.Usages {
for _, usage := range *e.allowed.Usages {
policyUsages = append(policyUsages, string(usage))
}
if !util.WildcardSubset(policyUsages, requestUsages) {
el = append(el, field.Invalid(fldPath.Child("usages"), requestUsages, strings.Join(policyUsages, ", ")))
return field.Invalid(e.fldPath.Child("usages"), requestUsages, strings.Join(policyUsages, ", "))
}
}
}
return nil
}

fldPath = fldPath.Child("subject")
allowedSub := allowed.Subject

if len(csr.Subject.Organization) > 0 {
if allowedSub == nil || allowedSub.Organizations == nil || allowedSub.Organizations.Values == nil {
el = append(el, field.Invalid(fldPath.Child("organizations", "values"), csr.Subject.Organization, "nil"))
} else if !util.WildcardSubset(*allowedSub.Organizations.Values, csr.Subject.Organization) {
el = append(el, field.Invalid(fldPath.Child("organizations", "values"), csr.Subject.Organization, strings.Join(*allowedSub.Organizations.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.Organizations != nil && allowedSub.Organizations.Required != nil && *allowedSub.Organizations.Required {
el = append(el, field.Required(fldPath.Child("organizations", "required"), strconv.FormatBool(*allowedSub.Organizations.Required)))
func (e evaluator) Subject() subjectEvaluator {
allowed := e.allowed.Subject
if allowed == nil {
allowed = new(policyapi.CertificateRequestPolicyAllowedX509Subject)
}

if len(csr.Subject.Country) > 0 {
if allowedSub == nil || allowedSub.Countries == nil {
el = append(el, field.Invalid(fldPath.Child("countries", "values"), csr.Subject.Country, "nil"))
} else if !util.WildcardSubset(*allowedSub.Countries.Values, csr.Subject.Country) {
el = append(el, field.Invalid(fldPath.Child("countries", "values"), csr.Subject.Country, strings.Join(*allowedSub.Countries.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.Countries != nil && allowedSub.Countries.Required != nil && *allowedSub.Countries.Required {
el = append(el, field.Required(fldPath.Child("countries", "required"), strconv.FormatBool(*allowedSub.Countries.Required)))
return subjectEvaluator{
sub: e.csr.Subject,
allowed: allowed,
fldPath: e.fldPath.Child("subject"),
}
}

if len(csr.Subject.OrganizationalUnit) > 0 {
if allowedSub == nil || allowedSub.OrganizationalUnits == nil {
el = append(el, field.Invalid(fldPath.Child("organizationalUnits", "values"), csr.Subject.OrganizationalUnit, "nil"))
} else if !util.WildcardSubset(*allowedSub.OrganizationalUnits.Values, csr.Subject.OrganizationalUnit) {
el = append(el, field.Invalid(fldPath.Child("organizationalUnits", "values"), csr.Subject.OrganizationalUnit, strings.Join(*allowedSub.OrganizationalUnits.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.OrganizationalUnits != nil && allowedSub.OrganizationalUnits.Required != nil && *allowedSub.OrganizationalUnits.Required {
el = append(el, field.Required(fldPath.Child("organizationalUnits", "required"), strconv.FormatBool(*allowedSub.OrganizationalUnits.Required)))
}
type subjectEvaluator struct {
sub pkix.Name
allowed *policyapi.CertificateRequestPolicyAllowedX509Subject
fldPath *field.Path
}

if len(csr.Subject.Locality) > 0 {
if allowedSub == nil || allowedSub.Localities == nil {
el = append(el, field.Invalid(fldPath.Child("localities", "values"), csr.Subject.Locality, "nil"))
} else if !util.WildcardSubset(*allowedSub.Localities.Values, csr.Subject.Locality) {
el = append(el, field.Invalid(fldPath.Child("localities", "values"), csr.Subject.Locality, strings.Join(*allowedSub.Localities.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.Localities != nil && allowedSub.Localities.Required != nil && *allowedSub.Localities.Required {
el = append(el, field.Required(fldPath.Child("localities", "required"), strconv.FormatBool(*allowedSub.Localities.Required)))
}
func (e subjectEvaluator) Organization() *field.Error {
return evaluateSlice(e.sub.Organization, e.allowed.Organizations, e.fldPath.Child("organizations"))
}

if len(csr.Subject.Province) > 0 {
if allowedSub == nil || allowedSub.Provinces == nil {
el = append(el, field.Invalid(fldPath.Child("provinces", "values"), csr.Subject.Province, "nil"))
} else if !util.WildcardSubset(*allowedSub.Provinces.Values, csr.Subject.Province) {
el = append(el, field.Invalid(fldPath.Child("provinces", "values"), csr.Subject.Province, strings.Join(*allowedSub.Provinces.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.Provinces != nil && allowedSub.Provinces.Required != nil && *allowedSub.Provinces.Required {
el = append(el, field.Required(fldPath.Child("provinces", "required"), strconv.FormatBool(*allowedSub.Provinces.Required)))
}
func (e subjectEvaluator) Country() *field.Error {
return evaluateSlice(e.sub.Country, e.allowed.Countries, e.fldPath.Child("countries"))
}

if len(csr.Subject.StreetAddress) > 0 {
if allowedSub == nil || allowedSub.StreetAddresses == nil {
el = append(el, field.Invalid(fldPath.Child("streetAddresses", "values"), csr.Subject.StreetAddress, "nil"))
} else if !util.WildcardSubset(*allowedSub.StreetAddresses.Values, csr.Subject.StreetAddress) {
el = append(el, field.Invalid(fldPath.Child("streetAddresses", "values"), csr.Subject.StreetAddress, strings.Join(*allowedSub.StreetAddresses.Values, ", ")))
}
} else if allowedSub != nil && allowedSub.StreetAddresses != nil && allowedSub.StreetAddresses.Required != nil && *allowedSub.StreetAddresses.Required {
el = append(el, field.Required(fldPath.Child("streetAddresses", "required"), strconv.FormatBool(*allowedSub.StreetAddresses.Required)))
}
func (e subjectEvaluator) OrganizationalUnit() *field.Error {
return evaluateSlice(e.sub.OrganizationalUnit, e.allowed.OrganizationalUnits, e.fldPath.Child("organizationalUnits"))
}

func (e subjectEvaluator) Locality() *field.Error {
return evaluateSlice(e.sub.Locality, e.allowed.Localities, e.fldPath.Child("localities"))
}

func (e subjectEvaluator) Province() *field.Error {
return evaluateSlice(e.sub.Province, e.allowed.Provinces, e.fldPath.Child("provinces"))
}

func (e subjectEvaluator) StreetAddress() *field.Error {
return evaluateSlice(e.sub.StreetAddress, e.allowed.StreetAddresses, e.fldPath.Child("streetAddresses"))
}

func (e subjectEvaluator) PostalCode() *field.Error {
return evaluateSlice(e.sub.PostalCode, e.allowed.PostalCodes, e.fldPath.Child("postalCodes"))
}

func (e subjectEvaluator) SerialNumber() *field.Error {
return evaluateString(e.sub.SerialNumber, e.allowed.SerialNumber, e.fldPath.Child("serialNumber"))
}

if len(csr.Subject.PostalCode) > 0 {
if allowedSub == nil || allowedSub.PostalCodes == nil {
el = append(el, field.Invalid(fldPath.Child("postalCodes", "values"), csr.Subject.PostalCode, "nil"))
} else if !util.WildcardSubset(*allowedSub.PostalCodes.Values, csr.Subject.PostalCode) {
el = append(el, field.Invalid(fldPath.Child("postalCodes", "values"), csr.Subject.PostalCode, strings.Join(*allowedSub.PostalCodes.Values, ", ")))
func evaluateString(s string, crp *policyapi.CertificateRequestPolicyAllowedString, fldPath *field.Path) *field.Error {
if len(s) > 0 {
if crp == nil || crp.Value == nil {
return field.Invalid(fldPath.Child("value"), s, "nil")
} else if !util.WildcardMatches(*crp.Value, s) {
return field.Invalid(fldPath.Child("value"), s, *crp.Value)
}
} else if allowedSub != nil && allowedSub.PostalCodes != nil && allowedSub.PostalCodes.Required != nil && *allowedSub.PostalCodes.Required {
el = append(el, field.Required(fldPath.Child("postalCodes", "required"), strconv.FormatBool(*allowedSub.PostalCodes.Required)))
} else if crp != nil && crp.Required != nil && *crp.Required {
return field.Required(fldPath.Child("required"), strconv.FormatBool(*crp.Required))
}
return nil
}

if len(csr.Subject.SerialNumber) > 0 {
if allowedSub == nil || allowedSub.SerialNumber == nil {
el = append(el, field.Invalid(fldPath.Child("serialNumber", "value"), csr.Subject.SerialNumber, "nil"))
} else if !util.WildcardMatches(*allowedSub.SerialNumber.Value, csr.Subject.SerialNumber) {
el = append(el, field.Invalid(fldPath.Child("serialNumber", "value"), csr.Subject.SerialNumber, *allowedSub.SerialNumber.Value))
func evaluateSlice(s []string, crp *policyapi.CertificateRequestPolicyAllowedStringSlice, fldPath *field.Path) *field.Error {
if len(s) > 0 {
if crp == nil || crp.Values == nil {
return field.Invalid(fldPath.Child("values"), s, "nil")
} else if !util.WildcardSubset(*crp.Values, s) {
return field.Invalid(fldPath.Child("values"), s, strings.Join(*crp.Values, ", "))
}
} else if allowedSub != nil && allowedSub.SerialNumber != nil && allowedSub.SerialNumber.Required != nil && *allowedSub.SerialNumber.Required {
el = append(el, field.Required(fldPath.Child("serialNumber", "required"), strconv.FormatBool(*allowedSub.SerialNumber.Required)))
} else if crp != nil && crp.Required != nil && *crp.Required {
return field.Required(fldPath.Child("required"), strconv.FormatBool(*crp.Required))
}
return nil
}

// If there are errors, then return not approved and the aggregated errors
if len(el) > 0 {
return approver.EvaluationResponse{Result: approver.ResultDenied, Message: el.ToAggregate().Error()}, nil
func evaluateBool(b bool, crp *bool, fldPath *field.Path) *field.Error {
if b {
if crp == nil {
return field.Invalid(fldPath, b, "nil")
} else if !*crp {
return field.Invalid(fldPath, b, strconv.FormatBool(*crp))
}
}

// If no evaluation errors resulting from this policy, return not denied
return approver.EvaluationResponse{Result: approver.ResultNotDenied}, nil
return nil
}