knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/apis/duck/v1/destination.go (about) 1 /* 2 Copyright 2019 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1 18 19 import ( 20 "context" 21 "crypto/x509" 22 "encoding/pem" 23 24 "knative.dev/pkg/apis" 25 ) 26 27 // Destination represents a target of an invocation over HTTP. 28 type Destination struct { 29 // Ref points to an Addressable. 30 // +optional 31 Ref *KReference `json:"ref,omitempty"` 32 33 // URI can be an absolute URL(non-empty scheme and non-empty host) pointing to the target or a relative URI. Relative URIs will be resolved using the base URI retrieved from Ref. 34 // +optional 35 URI *apis.URL `json:"uri,omitempty"` 36 37 // CACerts are Certification Authority (CA) certificates in PEM format 38 // according to https://www.rfc-editor.org/rfc/rfc7468. 39 // If set, these CAs are appended to the set of CAs provided 40 // by the Addressable target, if any. 41 // +optional 42 CACerts *string `json:"CACerts,omitempty"` 43 44 // Audience is the OIDC audience. 45 // This need only be set, if the target is not an Addressable 46 // and thus the Audience can't be received from the Addressable itself. 47 // In case the Addressable specifies an Audience too, the Destinations 48 // Audience takes preference. 49 // +optional 50 Audience *string `json:"audience,omitempty"` 51 } 52 53 // Validate the Destination has all the necessary fields and check the 54 // Namespace matches that of the parent object (using apis.ParentMeta). 55 func (d *Destination) Validate(ctx context.Context) *apis.FieldError { 56 if d == nil { 57 return nil 58 } 59 return ValidateDestination(ctx, *d).ViaField(apis.CurrentField) 60 } 61 62 // ValidateDestination validates Destination. 63 func ValidateDestination(ctx context.Context, dest Destination) *apis.FieldError { 64 ref := dest.Ref 65 uri := dest.URI 66 caCerts := dest.CACerts 67 if ref == nil && uri == nil { 68 return apis.ErrGeneric("expected at least one, got none", "ref", "uri") 69 } 70 71 if ref != nil && uri != nil && uri.URL().IsAbs() { 72 return apis.ErrGeneric("Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present", "[apiVersion, kind, name]", "ref", "uri") 73 } 74 // IsAbs() check whether the URL has a non-empty scheme. Besides the non-empty scheme, we also require uri has a non-empty host 75 if ref == nil && uri != nil && (!uri.URL().IsAbs() || uri.Host == "") { 76 return apis.ErrInvalidValue("Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent", "uri") 77 } 78 if ref != nil && uri == nil { 79 return ref.Validate(ctx).ViaField("ref") 80 } 81 if caCerts != nil { 82 return validateCACerts(caCerts) 83 } 84 return nil 85 } 86 87 // GetRef gets the KReference from this Destination, if one is present. If no ref is present, 88 // then nil is returned. 89 func (d *Destination) GetRef() *KReference { 90 if d == nil { 91 return nil 92 } 93 return d.Ref 94 } 95 96 func (d *Destination) SetDefaults(ctx context.Context) { 97 if d == nil { 98 return 99 } 100 101 if d.Ref != nil && d.Ref.Namespace == "" { 102 d.Ref.Namespace = apis.ParentMeta(ctx).Namespace 103 } 104 } 105 106 func validateCACerts(caCert *string) *apis.FieldError { 107 // Check the object. 108 var errs *apis.FieldError 109 110 block, err := pem.Decode([]byte(*caCert)) 111 if err != nil && block == nil { 112 errs = errs.Also(apis.ErrInvalidValue("CA Cert provided is invalid", "caCert")) 113 return errs 114 } 115 if block.Type != "CERTIFICATE" { 116 errs = errs.Also(apis.ErrInvalidValue("CA Cert provided is not a certificate", "caCert")) 117 } else if _, err := x509.ParseCertificate(block.Bytes); err != nil { 118 errs = errs.Also(apis.ErrInvalidValue("CA Cert provided is invalid", "caCert")) 119 } 120 return errs 121 }