github.com/greenpau/go-authcrunch@v1.1.4/pkg/authz/config.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 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 15 package authz 16 17 import ( 18 "context" 19 "github.com/greenpau/go-authcrunch/pkg/acl" 20 "github.com/greenpau/go-authcrunch/pkg/authproxy" 21 "github.com/greenpau/go-authcrunch/pkg/authz/bypass" 22 "github.com/greenpau/go-authcrunch/pkg/authz/injector" 23 "github.com/greenpau/go-authcrunch/pkg/errors" 24 "github.com/greenpau/go-authcrunch/pkg/kms" 25 cfgutil "github.com/greenpau/go-authcrunch/pkg/util/cfg" 26 logutil "github.com/greenpau/go-authcrunch/pkg/util/log" 27 "strings" 28 ) 29 30 // PolicyConfig is Gatekeeper configuration. 31 type PolicyConfig struct { 32 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 33 AuthURLPath string `json:"auth_url_path,omitempty" xml:"auth_url_path,omitempty" yaml:"auth_url_path,omitempty"` 34 AuthRedirectDisabled bool `json:"disable_auth_redirect,omitempty" xml:"disable_auth_redirect,omitempty" yaml:"disable_auth_redirect,omitempty"` 35 AuthRedirectQueryDisabled bool `json:"disable_auth_redirect_query,omitempty" xml:"disable_auth_redirect_query,omitempty" yaml:"disable_auth_redirect_query,omitempty"` 36 AuthRedirectQueryParameter string `json:"auth_redirect_query_param,omitempty" xml:"auth_redirect_query_param,omitempty" yaml:"auth_redirect_query_param,omitempty"` 37 // The status code for the HTTP redirect for non-authorized users. 38 AuthRedirectStatusCode int `json:"auth_redirect_status_code,omitempty" xml:"auth_redirect_status_code,omitempty" yaml:"auth_redirect_status_code,omitempty"` 39 // Enable the redirect with Javascript, as opposed to HTTP redirect. 40 RedirectWithJavascript bool `json:"redirect_with_javascript,omitempty" xml:"redirect_with_javascript,omitempty" yaml:"redirect_with_javascript,omitempty"` 41 // The list of URI prefixes which bypass authorization. 42 BypassConfigs []*bypass.Config `json:"bypass_configs,omitempty" xml:"bypass_configs,omitempty" yaml:"bypass_configs,omitempty"` 43 // The list of mappings between header names and field names. 44 HeaderInjectionConfigs []*injector.Config `json:"header_injection_configs,omitempty" xml:"header_injection_configs,omitempty" yaml:"header_injection_configs,omitempty"` 45 AccessListRules []*acl.RuleConfiguration `json:"access_list_rules,omitempty" xml:"access_list_rules,omitempty" yaml:"access_list_rules,omitempty"` 46 CryptoKeyConfigs []*kms.CryptoKeyConfig `json:"crypto_key_configs,omitempty" xml:"crypto_key_configs,omitempty" yaml:"crypto_key_configs,omitempty"` 47 // CryptoKeyStoreConfig hold the default configuration for the keys, e.g. token name and lifetime. 48 CryptoKeyStoreConfig map[string]interface{} `json:"crypto_key_store_config,omitempty" xml:"crypto_key_store_config,omitempty" yaml:"crypto_key_store_config,omitempty"` 49 AuthProxyConfig *authproxy.Config `json:"auth_proxy_config,omitempty" xml:"auth_proxy_config,omitempty" yaml:"auth_proxy_config,omitempty"` 50 AllowedTokenSources []string `json:"allowed_token_sources,omitempty" xml:"allowed_token_sources,omitempty" yaml:"allowed_token_sources,omitempty"` 51 StripTokenEnabled bool `json:"strip_token_enabled,omitempty" xml:"strip_token_enabled,omitempty" yaml:"strip_token_enabled,omitempty"` 52 ForbiddenURL string `json:"forbidden_url,omitempty" xml:"forbidden_url,omitempty" yaml:"forbidden_url,omitempty"` 53 UserIdentityField string `json:"user_identity_field,omitempty" xml:"user_identity_field,omitempty" yaml:"user_identity_field,omitempty"` 54 // Validate HTTP Authorization header. 55 ValidateBearerHeader bool `json:"validate_bearer_header,omitempty" xml:"validate_bearer_header,omitempty" yaml:"validate_bearer_header,omitempty"` 56 // Validate HTTP method and path. 57 ValidateMethodPath bool `json:"validate_method_path,omitempty" xml:"validate_method_path,omitempty" yaml:"validate_method_path,omitempty"` 58 // Validate HTTP path derived from JWT token. 59 ValidateAccessListPathClaim bool `json:"validate_access_list_path_claim,omitempty" xml:"validate_access_list_path_claim,omitempty" yaml:"validate_access_list_path_claim,omitempty"` 60 // Validate source address matches between HTTP request and JWT token. 61 ValidateSourceAddress bool `json:"validate_source_address,omitempty" xml:"validate_source_address,omitempty" yaml:"validate_source_address,omitempty"` 62 // Pass claims from JWT token via HTTP X- headers. 63 PassClaimsWithHeaders bool `json:"pass_claims_with_headers,omitempty" xml:"pass_claims_with_headers,omitempty" yaml:"pass_claims_with_headers,omitempty"` 64 // Validate the login hint which can be passed to the auth provider 65 LoginHintValidators []string `json:"login_hint_validators,omitempty" xml:"login_hint_validators,omitempty" yaml:"login_hint_validators,omitempty"` 66 // Allow to append scopes that come from the query parameter 'additionalScopes' 67 AdditionalScopes bool `json:"additional_scopes,omitempty" xml:"additional_scopes,omitempty" yaml:"additional_scopes,omitempty"` 68 // Holds raw crypto configuration. 69 cryptoRawConfigs []string 70 // Holds raw identity provider configuration. 71 authProxyRawConfig []string 72 73 // Indicated that the config was successfully validated. 74 validated bool 75 } 76 77 // AddRawCryptoConfigs adds raw crypto configs. 78 func (cfg *PolicyConfig) AddRawCryptoConfigs(s string) { 79 cfg.cryptoRawConfigs = append(cfg.cryptoRawConfigs, s) 80 } 81 82 // AddRawIdpConfig add raw identity provider configs. 83 func (cfg *PolicyConfig) AddRawIdpConfig(s string) { 84 cfg.authProxyRawConfig = append(cfg.authProxyRawConfig, s) 85 } 86 87 // parseRawCryptoConfigs parses raw crypto configs into CryptoKeyConfigs 88 // and CryptoKeyStoreConfig. 89 func (cfg *PolicyConfig) parseRawCryptoConfigs() error { 90 var cryptoKeyConfig, cryptoKeyStoreConfig []string 91 var cryptoKeyConfigFound, cryptoKeyStoreConfigFound bool 92 for _, encodedArgs := range cfg.cryptoRawConfigs { 93 args, err := cfgutil.DecodeArgs(encodedArgs) 94 if err != nil { 95 return errors.ErrConfigDirectiveFail.WithArgs("crypto", encodedArgs, err) 96 } 97 if len(args) < 3 { 98 return errors.ErrConfigDirectiveShort.WithArgs("crypto", args) 99 } 100 cryptoKeyConfig = append(cryptoKeyConfig, encodedArgs) 101 switch args[0] { 102 case "key": 103 cryptoKeyConfigFound = true 104 case "default": 105 cryptoKeyStoreConfig = append(cryptoKeyStoreConfig, encodedArgs) 106 cryptoKeyStoreConfigFound = true 107 default: 108 return errors.ErrConfigDirectiveValueUnsupported.WithArgs("crypto", args) 109 } 110 } 111 112 if cryptoKeyConfigFound { 113 configs, err := kms.ParseCryptoKeyConfigs(strings.Join(cryptoKeyConfig, "\n")) 114 if err != nil { 115 return errors.ErrConfigDirectiveFail.WithArgs("crypto.key", cryptoKeyConfig, err) 116 } 117 cfg.CryptoKeyConfigs = configs 118 } 119 120 if cryptoKeyStoreConfigFound { 121 configs, err := kms.ParseCryptoKeyStoreConfig(strings.Join(cryptoKeyStoreConfig, "\n")) 122 if err != nil { 123 return errors.ErrConfigDirectiveFail.WithArgs("crypto.keystore", cryptoKeyStoreConfig, err) 124 } 125 cfg.CryptoKeyStoreConfig = configs 126 } 127 return nil 128 } 129 130 // parseRawAuthProxyConfig parses raw auth proxy configs 131 // into AuthProxyConfig. 132 func (cfg *PolicyConfig) parseRawAuthProxyConfig() error { 133 if len(cfg.authProxyRawConfig) > 0 { 134 config, err := authproxy.ParseConfig(cfg.authProxyRawConfig) 135 if err != nil { 136 return errors.ErrConfigDirectiveFail.WithArgs("authproxy", cfg.authProxyRawConfig, err) 137 } 138 cfg.AuthProxyConfig = config 139 } 140 return nil 141 } 142 143 // Validate validates PolicyConfig. 144 func (cfg *PolicyConfig) Validate() error { 145 if cfg.validated { 146 return nil 147 } 148 if cfg.Name == "" { 149 return errors.ErrPolicyConfigNameNotFound 150 } 151 if err := cfg.parseRawCryptoConfigs(); err != nil { 152 return err 153 } 154 if err := cfg.parseRawAuthProxyConfig(); err != nil { 155 return err 156 } 157 158 // Set authentication redirect URL. 159 if cfg.AuthURLPath == "" { 160 cfg.AuthURLPath = "/auth" 161 } 162 163 // Set authentication redirect URI parameter. 164 if cfg.AuthRedirectQueryParameter == "" { 165 cfg.AuthRedirectQueryParameter = "redirect_url" 166 } 167 168 // Set authentication redirect status code value. 169 if cfg.AuthRedirectStatusCode == 0 { 170 cfg.AuthRedirectStatusCode = 302 171 } 172 173 // Validate bypass URLs, if necessary. 174 for _, entry := range cfg.BypassConfigs { 175 if err := entry.Validate(); err != nil { 176 return errors.ErrInvalidConfiguration.WithArgs(cfg.Name, err) 177 } 178 } 179 180 // Validate header injection configs. 181 for _, entry := range cfg.HeaderInjectionConfigs { 182 if err := entry.Validate(); err != nil { 183 return errors.ErrInvalidConfiguration.WithArgs(cfg.Name, err) 184 } 185 // cfg.PassClaimsWithHeaders = true 186 } 187 188 if len(cfg.AccessListRules) == 0 { 189 return errors.ErrInvalidConfiguration.WithArgs(cfg.Name, "access list rule config not found") 190 } 191 192 accessList := acl.NewAccessList() 193 accessList.SetLogger(logutil.NewLogger()) 194 if err := accessList.AddRules(context.Background(), cfg.AccessListRules); err != nil { 195 return errors.ErrInvalidConfiguration.WithArgs(cfg.Name, err) 196 } 197 198 cfg.validated = true 199 return nil 200 }