github.com/greenpau/go-authcrunch@v1.1.4/pkg/idp/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 idp 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "github.com/greenpau/go-authcrunch/pkg/errors" 21 "github.com/greenpau/go-authcrunch/pkg/idp/oauth" 22 "github.com/greenpau/go-authcrunch/pkg/idp/saml" 23 ) 24 25 // IdentityProviderConfig represents an identity provider configuration. 26 type IdentityProviderConfig struct { 27 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 28 Kind string `json:"kind,omitempty" xml:"kind,omitempty" yaml:"kind,omitempty"` 29 Params map[string]interface{} `json:"params,omitempty" xml:"params,omitempty" yaml:"params,omitempty"` 30 } 31 32 // NewIdentityProviderConfig returns IdentityProviderConfig instance. 33 func NewIdentityProviderConfig(name, kind string, params map[string]interface{}) (*IdentityProviderConfig, error) { 34 cfg := &IdentityProviderConfig{ 35 Name: name, 36 Kind: kind, 37 Params: params, 38 } 39 if err := cfg.Validate(); err != nil { 40 return nil, err 41 } 42 return cfg, nil 43 } 44 45 // Validate validates identity provider config. 46 func (cfg *IdentityProviderConfig) Validate() error { 47 var requiredFields, optionalFields []string 48 if cfg.Name == "" { 49 return errors.ErrIdentityProviderConfigInvalid.WithArgs("empty identity provider name") 50 } 51 52 switch cfg.Kind { 53 case "oauth": 54 requiredFields = []string{ 55 "realm", 56 "driver", 57 } 58 optionalFields = []string{ 59 "tenant_id", 60 "domain_name", 61 "client_id", 62 "client_secret", 63 "server_id", 64 "base_auth_url", 65 "metadata_url", 66 "identity_token_name", 67 "authorization_url", 68 "token_url", 69 // Disabled features. 70 "metadata_discovery_disabled", 71 "key_verification_disabled", 72 "pass_grant_type_disabled", 73 "response_type_disabled", 74 "scope_disabled", 75 "nonce_disabled", 76 // Enabled features. 77 "accept_header_enabled", 78 "js_callback_enabled", 79 "logout_enabled", 80 // Retry and delay. 81 "delay_start", 82 "retry_attempts", 83 "retry_interval", 84 // AWS Cognito. 85 "user_pool_id", 86 "region", 87 // ID Token. 88 "identity_token_cookie_enabled", 89 "identity_token_cookie_name", 90 // Misc. 91 "required_token_fields", 92 "scopes", 93 "user_group_filters", 94 "user_org_filters", 95 "response_type", 96 "jwks_keys", 97 "tls_insecure_skip_verify", 98 "email_claim_check_disabled", 99 "login_icon", 100 "user_info_fields", 101 "user_info_roles_field_name", 102 } 103 case "saml": 104 requiredFields = []string{ 105 "realm", 106 "driver", 107 "entity_id", 108 "acs_urls", 109 } 110 optionalFields = []string{ 111 "idp_metadata_location", 112 "idp_sign_cert_location", 113 "idp_login_url", 114 "tenant_id", 115 "application_id", 116 "application_name", 117 "tls_insecure_skip_verify", 118 "login_icon", 119 } 120 case "": 121 return errors.ErrIdentityProviderConfigInvalid.WithArgs("empty identity provider type") 122 default: 123 return errors.ErrIdentityProviderConfigInvalid.WithArgs("unsupported identity provider type " + cfg.Kind) 124 } 125 126 if err := validateFields(cfg.Params, requiredFields, optionalFields); err != nil { 127 return errors.ErrIdentityProviderConfigInvalid.WithArgs(err) 128 } 129 130 b, _ := json.Marshal(cfg.Params) 131 switch cfg.Kind { 132 case "oauth": 133 config := &oauth.Config{} 134 json.Unmarshal(b, config) 135 config.Name = cfg.Name 136 if err := config.Validate(); err != nil { 137 return errors.ErrIdentityProviderConfigInvalid.WithArgs(err) 138 } 139 case "saml": 140 config := &saml.Config{} 141 json.Unmarshal(b, config) 142 config.Name = cfg.Name 143 if err := config.Validate(); err != nil { 144 return errors.ErrIdentityProviderConfigInvalid.WithArgs(err) 145 } 146 } 147 148 return nil 149 } 150 151 func validateFields(m map[string]interface{}, requiredFields, optionalFields []string) error { 152 if m == nil || len(m) == 0 { 153 return fmt.Errorf("empty identity provider parameters") 154 } 155 156 for _, k := range requiredFields { 157 if _, exists := m[k]; !exists { 158 return fmt.Errorf("required field %q not found", k) 159 } 160 } 161 162 allFields := append(optionalFields, requiredFields...) 163 for k := range m { 164 var found bool 165 for _, f := range allFields { 166 if f == k { 167 found = true 168 } 169 } 170 if !found { 171 return fmt.Errorf("found unsupported %q field", k) 172 } 173 } 174 175 return nil 176 }