github.com/newrelic/go-agent@v3.26.0+incompatible/internal/security_policies.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package internal 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "reflect" 10 ) 11 12 // Security policies documentation: 13 // https://source.datanerd.us/agents/agent-specs/blob/master/Language-Agent-Security-Policies.md 14 15 // SecurityPolicies contains the security policies. 16 type SecurityPolicies struct { 17 RecordSQL securityPolicy `json:"record_sql"` 18 AttributesInclude securityPolicy `json:"attributes_include"` 19 AllowRawExceptionMessages securityPolicy `json:"allow_raw_exception_messages"` 20 CustomEvents securityPolicy `json:"custom_events"` 21 CustomParameters securityPolicy `json:"custom_parameters"` 22 } 23 24 // PointerIfPopulated returns a reference to the security policies if they have 25 // been populated from JSON. 26 func (sp *SecurityPolicies) PointerIfPopulated() *SecurityPolicies { 27 emptyPolicies := SecurityPolicies{} 28 if nil != sp && *sp != emptyPolicies { 29 return sp 30 } 31 return nil 32 } 33 34 type securityPolicy struct { 35 EnabledVal *bool `json:"enabled"` 36 } 37 38 func (p *securityPolicy) Enabled() bool { return nil == p.EnabledVal || *p.EnabledVal } 39 func (p *securityPolicy) SetEnabled(enabled bool) { p.EnabledVal = &enabled } 40 func (p *securityPolicy) IsSet() bool { return nil != p.EnabledVal } 41 42 type policyer interface { 43 SetEnabled(bool) 44 IsSet() bool 45 } 46 47 // UnmarshalJSON decodes security policies sent from the preconnect endpoint. 48 func (sp *SecurityPolicies) UnmarshalJSON(data []byte) (er error) { 49 defer func() { 50 // Zero out all fields if there is an error to ensure that the 51 // populated check works. 52 if er != nil { 53 *sp = SecurityPolicies{} 54 } 55 }() 56 57 var raw map[string]struct { 58 Enabled bool `json:"enabled"` 59 Required bool `json:"required"` 60 } 61 err := json.Unmarshal(data, &raw) 62 if err != nil { 63 return fmt.Errorf("unable to unmarshal security policies: %v", err) 64 } 65 66 knownPolicies := make(map[string]policyer) 67 68 spv := reflect.ValueOf(sp).Elem() 69 for i := 0; i < spv.NumField(); i++ { 70 fieldAddress := spv.Field(i).Addr() 71 field := fieldAddress.Interface().(policyer) 72 name := spv.Type().Field(i).Tag.Get("json") 73 knownPolicies[name] = field 74 } 75 76 for name, policy := range raw { 77 p, ok := knownPolicies[name] 78 if !ok { 79 if policy.Required { 80 return errUnknownRequiredPolicy{name: name} 81 } 82 } else { 83 p.SetEnabled(policy.Enabled) 84 } 85 } 86 for name, policy := range knownPolicies { 87 if !policy.IsSet() { 88 return errUnsetPolicy{name: name} 89 } 90 } 91 return nil 92 } 93 94 type errUnknownRequiredPolicy struct{ name string } 95 96 func (err errUnknownRequiredPolicy) Error() string { 97 return fmt.Sprintf("policy '%s' is unrecognized, please check for a newer agent version or contact support", err.name) 98 } 99 100 type errUnsetPolicy struct{ name string } 101 102 func (err errUnsetPolicy) Error() string { 103 return fmt.Sprintf("policy '%s' not received, please contact support", err.name) 104 } 105 106 func isDisconnectSecurityPolicyError(e error) bool { 107 if _, ok := e.(errUnknownRequiredPolicy); ok { 108 return true 109 } 110 if _, ok := e.(errUnsetPolicy); ok { 111 return true 112 } 113 return false 114 }