1// Copyright 2018 Istio Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cel 16 17import ( 18 "errors" 19 "fmt" 20 "reflect" 21 "time" 22 23 "github.com/golang/protobuf/ptypes" 24 dpb "github.com/golang/protobuf/ptypes/duration" 25 tpb "github.com/golang/protobuf/ptypes/timestamp" 26 "github.com/google/cel-go/checker/decls" 27 "github.com/google/cel-go/common/types" 28 "github.com/google/cel-go/common/types/ref" 29 "github.com/google/cel-go/common/types/traits" 30 exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 31 32 "istio.io/api/policy/v1beta1" 33 "istio.io/istio/mixer/pkg/lang" 34 "istio.io/pkg/attribute" 35) 36 37func convertType(typ v1beta1.ValueType) *exprpb.Type { 38 switch typ { 39 case v1beta1.STRING: 40 return decls.String 41 case v1beta1.INT64: 42 return decls.Int 43 case v1beta1.DOUBLE: 44 return decls.Double 45 case v1beta1.BOOL: 46 return decls.Bool 47 case v1beta1.TIMESTAMP: 48 return decls.Timestamp 49 case v1beta1.DURATION: 50 return decls.Duration 51 case v1beta1.STRING_MAP: 52 return stringMapType 53 case v1beta1.IP_ADDRESS: 54 return decls.NewObjectType(ipAddressType) 55 case v1beta1.EMAIL_ADDRESS: 56 return decls.NewObjectType(emailAddressType) 57 case v1beta1.URI: 58 return decls.NewObjectType(uriType) 59 case v1beta1.DNS_NAME: 60 return decls.NewObjectType(dnsType) 61 } 62 return &exprpb.Type{TypeKind: &exprpb.Type_Dyn{}} 63} 64 65func recoverType(typ *exprpb.Type) v1beta1.ValueType { 66 if typ == nil { 67 return v1beta1.VALUE_TYPE_UNSPECIFIED 68 } 69 switch t := typ.TypeKind.(type) { 70 case *exprpb.Type_Primitive: 71 switch t.Primitive { 72 case exprpb.Type_STRING: 73 return v1beta1.STRING 74 case exprpb.Type_INT64: 75 return v1beta1.INT64 76 case exprpb.Type_DOUBLE: 77 return v1beta1.DOUBLE 78 case exprpb.Type_BOOL: 79 return v1beta1.BOOL 80 } 81 82 case *exprpb.Type_WellKnown: 83 switch t.WellKnown { 84 case exprpb.Type_TIMESTAMP: 85 return v1beta1.TIMESTAMP 86 case exprpb.Type_DURATION: 87 return v1beta1.DURATION 88 } 89 90 case *exprpb.Type_MessageType: 91 switch t.MessageType { 92 case ipAddressType: 93 return v1beta1.IP_ADDRESS 94 case emailAddressType: 95 return v1beta1.EMAIL_ADDRESS 96 case uriType: 97 return v1beta1.URI 98 case dnsType: 99 return v1beta1.DNS_NAME 100 } 101 102 case *exprpb.Type_MapType_: 103 if reflect.DeepEqual(t.MapType.KeyType, decls.String) && 104 reflect.DeepEqual(t.MapType.ValueType, decls.String) { 105 return v1beta1.STRING_MAP 106 } 107 108 // remaining maps are not yet supported 109 } 110 return v1beta1.VALUE_TYPE_UNSPECIFIED 111} 112 113func convertValue(typ v1beta1.ValueType, value interface{}) ref.Val { 114 switch typ { 115 case v1beta1.STRING, v1beta1.INT64, v1beta1.DOUBLE, v1beta1.BOOL: 116 return types.DefaultTypeAdapter.NativeToValue(value) 117 case v1beta1.TIMESTAMP: 118 t := value.(time.Time) 119 tproto, err := ptypes.TimestampProto(t) 120 if err != nil { 121 return types.NewErr("incorrect timestamp: %v", err) 122 } 123 return types.Timestamp{Timestamp: tproto} 124 case v1beta1.DURATION: 125 d := value.(time.Duration) 126 return types.Duration{Duration: ptypes.DurationProto(d)} 127 case v1beta1.STRING_MAP: 128 sm := value.(attribute.StringMap) 129 return stringMapValue{value: sm} 130 case v1beta1.IP_ADDRESS: 131 return wrapperValue{typ: typ, bytes: value.([]byte)} 132 case v1beta1.EMAIL_ADDRESS, v1beta1.URI, v1beta1.DNS_NAME: 133 return wrapperValue{typ: typ, s: value.(string)} 134 } 135 return types.NewErr("cannot convert value %#v of type %q", value, typ) 136} 137 138func recoverValue(value ref.Val) (interface{}, error) { 139 switch value.Type() { 140 case types.ErrType: 141 if err, ok := value.Value().(error); ok { 142 return nil, err 143 } 144 return nil, errors.New("unrecoverable error value") 145 case types.StringType, types.IntType, types.DoubleType, types.BoolType: 146 return value.Value(), nil 147 case types.TimestampType: 148 t := value.Value().(*tpb.Timestamp) 149 return ptypes.Timestamp(t) 150 case types.DurationType: 151 d := value.Value().(*dpb.Duration) 152 return ptypes.Duration(d) 153 case types.MapType: 154 size := value.(traits.Sizer).Size() 155 if size.Type() == types.IntType && size.Value().(int64) == 0 { 156 return emptyStringMap.value, nil 157 } 158 return value.Value(), nil 159 case wrapperType: 160 return value.Value(), nil 161 case types.ListType: 162 size := value.(traits.Sizer).Size() 163 if size.Type() == types.IntType && size.Value().(int64) == 0 { 164 return []string{}, nil 165 } 166 return value.Value(), nil 167 } 168 return nil, fmt.Errorf("failed to recover of type %s", value.Type()) 169} 170 171var defaultValues = map[v1beta1.ValueType]ref.Val{ 172 v1beta1.STRING: types.String(""), 173 v1beta1.INT64: types.Int(0), 174 v1beta1.DOUBLE: types.Double(0), 175 v1beta1.BOOL: types.Bool(false), 176 v1beta1.TIMESTAMP: types.Timestamp{Timestamp: &tpb.Timestamp{}}, 177 v1beta1.DURATION: types.Duration{Duration: &dpb.Duration{}}, 178 v1beta1.STRING_MAP: emptyStringMap, 179 v1beta1.IP_ADDRESS: wrapperValue{typ: v1beta1.IP_ADDRESS, bytes: []byte{}}, 180 v1beta1.EMAIL_ADDRESS: wrapperValue{typ: v1beta1.EMAIL_ADDRESS, s: ""}, 181 v1beta1.URI: wrapperValue{typ: v1beta1.URI, s: ""}, 182 v1beta1.DNS_NAME: wrapperValue{typ: v1beta1.DNS_NAME, s: ""}, 183} 184 185func defaultValue(typ v1beta1.ValueType) ref.Val { 186 if out, ok := defaultValues[typ]; ok { 187 return out 188 } 189 return types.NewErr("cannot provide defaults for %q", typ) 190} 191 192var ( 193 stringMapType = &exprpb.Type{TypeKind: &exprpb.Type_MapType_{MapType: &exprpb.Type_MapType{ 194 KeyType: &exprpb.Type{TypeKind: &exprpb.Type_Primitive{Primitive: exprpb.Type_STRING}}, 195 ValueType: &exprpb.Type{TypeKind: &exprpb.Type_Primitive{Primitive: exprpb.Type_STRING}}, 196 }}} 197 emptyStringMap = stringMapValue{value: attribute.WrapStringMap(nil)} 198 199 // domain specific types do not implement any of type traits for now 200 wrapperType = types.NewTypeValue("wrapper") 201) 202 203const ( 204 ipAddressType = "istio.policy.v1beta1.IPAddress" 205 emailAddressType = "istio.policy.v1beta1.EmailAddress" 206 uriType = "istio.policy.v1beta1.Uri" 207 dnsType = "istio.policy.v1beta1.DNSName" 208) 209 210type stringMapValue struct { 211 value attribute.StringMap 212} 213 214func (v stringMapValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 215 return nil, errors.New("cannot convert stringmap to native types") 216} 217func (v stringMapValue) ConvertToType(typeValue ref.Type) ref.Val { 218 return types.NewErr("cannot convert stringmap to CEL types") 219} 220func (v stringMapValue) Equal(other ref.Val) ref.Val { 221 return types.NewErr("stringmap does not support equality") 222} 223func (v stringMapValue) Type() ref.Type { 224 return types.MapType 225} 226func (v stringMapValue) Value() interface{} { 227 return v.value 228} 229func (v stringMapValue) Get(index ref.Val) ref.Val { 230 if index.Type() != types.StringType { 231 return types.NewErr("index should be a string") 232 } 233 234 field := index.Value().(string) 235 value, found := v.value.Get(field) 236 if found { 237 return types.String(value) 238 } 239 return types.NewErr("no such key: '%s'", field) 240} 241func (v stringMapValue) Contains(index ref.Val) ref.Val { 242 if index.Type() != types.StringType { 243 return types.NewErr("index should be a string") 244 } 245 246 field := index.Value().(string) 247 _, found := v.value.Get(field) 248 return types.Bool(found) 249} 250func (v stringMapValue) Size() ref.Val { 251 return types.NewErr("size not implemented on stringmaps") 252} 253 254type wrapperValue struct { 255 typ v1beta1.ValueType 256 bytes []byte 257 s string 258} 259 260func (v wrapperValue) ConvertToNative(typeDesc reflect.Type) (interface{}, error) { 261 return nil, errors.New("cannot convert wrapper value to native types") 262} 263func (v wrapperValue) ConvertToType(typeValue ref.Type) ref.Val { 264 return types.NewErr("cannot convert wrapper value to CEL types") 265} 266func (v wrapperValue) Equal(other ref.Val) ref.Val { 267 if other.Type() != wrapperType { 268 return types.NewErr("cannot compare types") 269 } 270 w, ok := other.(wrapperValue) 271 if !ok { 272 return types.NewErr("cannot compare types") 273 } 274 if v.typ != w.typ { 275 return types.NewErr("cannot compare %s and %s", v.typ, w.typ) 276 } 277 var out bool 278 var err error 279 switch v.typ { 280 case v1beta1.IP_ADDRESS: 281 out = lang.ExternIPEqual(v.bytes, w.bytes) 282 case v1beta1.DNS_NAME: 283 out, err = lang.ExternDNSNameEqual(v.s, w.s) 284 case v1beta1.EMAIL_ADDRESS: 285 out, err = lang.ExternEmailEqual(v.s, w.s) 286 case v1beta1.URI: 287 out, err = lang.ExternURIEqual(v.s, w.s) 288 } 289 if err != nil { 290 return types.NewErr(err.Error()) 291 } 292 return types.Bool(out) 293} 294func (v wrapperValue) Type() ref.Type { 295 return wrapperType 296} 297func (v wrapperValue) Value() interface{} { 298 switch v.typ { 299 case v1beta1.IP_ADDRESS: 300 return v.bytes 301 default: 302 return v.s 303 } 304} 305