github.com/greenpau/go-authcrunch@v1.1.4/pkg/ids/local/store.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 local 16 17 import ( 18 "encoding/json" 19 20 "github.com/greenpau/go-authcrunch/pkg/authn/enums/operator" 21 "github.com/greenpau/go-authcrunch/pkg/authn/icons" 22 "github.com/greenpau/go-authcrunch/pkg/errors" 23 "github.com/greenpau/go-authcrunch/pkg/requests" 24 "go.uber.org/zap" 25 ) 26 27 const ( 28 storeKind = "local" 29 ) 30 31 // Config holds the configuration for the identity store. 32 type Config struct { 33 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 34 Realm string `json:"realm,omitempty" xml:"realm,omitempty" yaml:"realm,omitempty"` 35 Path string `json:"path,omitempty" xml:"path,omitempty" yaml:"path,omitempty"` 36 Users []*User `json:"users,omitempty" xml:"users,omitempty" yaml:"users,omitempty"` 37 38 // LoginIcon is the UI login icon attributes. 39 LoginIcon *icons.LoginIcon `json:"login_icon,omitempty" xml:"login_icon,omitempty" yaml:"login_icon,omitempty"` 40 41 // RegistrationEnabled controls whether visitors can registers. 42 RegistrationEnabled bool `json:"registration_enabled,omitempty" xml:"registration_enabled,omitempty" yaml:"registration_enabled,omitempty"` 43 // UsernameRecoveryEnabled controls whether a user could recover username by providing an email address. 44 UsernameRecoveryEnabled bool `json:"username_recovery_enabled,omitempty" xml:"username_recovery_enabled,omitempty" yaml:"username_recovery_enabled,omitempty"` 45 // PasswordRecoveryEnabled controls whether a user could recover password by providing an email address. 46 PasswordRecoveryEnabled bool `json:"password_recovery_enabled,omitempty" xml:"password_recovery_enabled,omitempty" yaml:"password_recovery_enabled,omitempty"` 47 // ContactSupportEnabled controls whether contact support link is available. 48 ContactSupportEnabled bool `json:"contact_support_enabled,omitempty" xml:"contact_support_enabled,omitempty" yaml:"contact_support_enabled,omitempty"` 49 50 // SupportLink is the link to the support portal. 51 SupportLink string `json:"support_link,omitempty" xml:"support_link,omitempty" yaml:"support_link,omitempty"` 52 // SupportEmail is the email address to reach support. 53 SupportEmail string `json:"support_email,omitempty" xml:"support_email,omitempty" yaml:"support_email,omitempty"` 54 } 55 56 // IdentityStore represents authentication provider with local identity store. 57 type IdentityStore struct { 58 config *Config `json:"-"` 59 authenticator *Authenticator `json:"-"` 60 logger *zap.Logger 61 configured bool 62 } 63 64 // NewIdentityStore return an instance of AuthDB-based identity store. 65 func NewIdentityStore(cfg *Config, logger *zap.Logger) (*IdentityStore, error) { 66 if logger == nil { 67 return nil, errors.ErrIdentityStoreConfigureLoggerNotFound 68 } 69 70 b := &IdentityStore{ 71 config: cfg, 72 logger: logger, 73 } 74 75 // Configure UI login icon. 76 if b.config.LoginIcon == nil { 77 b.config.LoginIcon = icons.NewLoginIcon(storeKind) 78 } else { 79 b.config.LoginIcon.Configure(storeKind) 80 } 81 82 if err := b.config.Validate(); err != nil { 83 return nil, err 84 } 85 86 return b, nil 87 } 88 89 // GetRealm return authentication realm. 90 func (b *IdentityStore) GetRealm() string { 91 return b.config.Realm 92 } 93 94 // GetName return the name associated with this identity store. 95 func (b *IdentityStore) GetName() string { 96 return b.config.Name 97 } 98 99 // GetKind returns the authentication method associated with this identity store. 100 func (b *IdentityStore) GetKind() string { 101 return storeKind 102 } 103 104 // Configured returns true if the identity store was configured. 105 func (b *IdentityStore) Configured() bool { 106 return b.configured 107 } 108 109 // Request performs the requested identity store operation. 110 func (b *IdentityStore) Request(op operator.Type, r *requests.Request) error { 111 switch op { 112 case operator.Authenticate: 113 return b.Authenticate(r) 114 case operator.IdentifyUser: 115 return b.authenticator.IdentifyUser(r) 116 case operator.ChangePassword: 117 return b.authenticator.ChangePassword(r) 118 case operator.AddKeySSH: 119 return b.authenticator.AddPublicKey(r) 120 case operator.AddKeyGPG: 121 return b.authenticator.AddPublicKey(r) 122 case operator.DeletePublicKey: 123 return b.authenticator.DeletePublicKey(r) 124 case operator.AddMfaToken: 125 return b.authenticator.AddMfaToken(r) 126 case operator.DeleteMfaToken: 127 return b.authenticator.DeleteMfaToken(r) 128 case operator.AddAPIKey: 129 return b.authenticator.AddAPIKey(r) 130 case operator.DeleteAPIKey: 131 return b.authenticator.DeleteAPIKey(r) 132 case operator.GetPublicKeys: 133 return b.authenticator.GetPublicKeys(r) 134 case operator.GetPublicKey: 135 return b.authenticator.GetPublicKey(r) 136 case operator.GetAPIKeys: 137 return b.authenticator.GetAPIKeys(r) 138 case operator.GetAPIKey: 139 return b.authenticator.GetAPIKey(r) 140 case operator.GetMfaTokens: 141 return b.authenticator.GetMfaTokens(r) 142 case operator.GetMfaToken: 143 return b.authenticator.GetMfaToken(r) 144 case operator.AddUser: 145 return b.authenticator.AddUser(r) 146 case operator.GetUsers: 147 return b.authenticator.GetUsers(r) 148 case operator.GetUser: 149 return b.authenticator.GetUser(r) 150 case operator.DeleteUser: 151 return b.authenticator.DeleteUser(r) 152 case operator.LookupAPIKey: 153 return b.authenticator.LookupAPIKey(r) 154 } 155 156 b.logger.Error( 157 "detected unsupported identity store operation", 158 zap.Any("op", op), 159 zap.Any("params", r), 160 ) 161 return errors.ErrOperatorNotSupported.WithArgs(op) 162 } 163 164 // Configure configures IdentityStore. 165 func (b *IdentityStore) Configure() error { 166 if b.authenticator == nil { 167 b.authenticator = NewAuthenticator() 168 } 169 b.authenticator.logger = b.logger 170 171 if err := b.authenticator.Configure(b.config.Path, b.config.Users); err != nil { 172 return err 173 } 174 175 b.logger.Info( 176 "successfully configured identity store", 177 zap.String("name", b.config.Name), 178 zap.String("kind", storeKind), 179 zap.String("db_path", b.config.Path), 180 zap.Any("login_icon", b.config.LoginIcon), 181 ) 182 183 b.configured = true 184 return nil 185 } 186 187 // GetConfig returns IdentityStore configuration. 188 func (b *IdentityStore) GetConfig() map[string]interface{} { 189 var m map[string]interface{} 190 j, _ := json.Marshal(b.config) 191 json.Unmarshal(j, &m) 192 return m 193 } 194 195 // Authenticate performs authentication. 196 func (b *IdentityStore) Authenticate(r *requests.Request) error { 197 if err := b.authenticator.AuthenticateUser(r); err != nil { 198 return errors.ErrIdentityStoreLocalAuthFailed.WithArgs(err) 199 } 200 return nil 201 } 202 203 // Validate validates identity store configuration. 204 func (cfg *Config) Validate() error { 205 if cfg.Name == "" { 206 return errors.ErrIdentityStoreConfigureNameEmpty 207 } 208 if cfg.Realm == "" { 209 return errors.ErrIdentityStoreConfigureRealmEmpty 210 } 211 if cfg.Path == "" { 212 return errors.ErrIdentityStoreLocalConfigurePathEmpty 213 } 214 return nil 215 } 216 217 // GetLoginIcon returns the instance of the icon associated with the provider. 218 func (b *IdentityStore) GetLoginIcon() *icons.LoginIcon { 219 // Add support and credentials recovery to the UI login icon. 220 b.config.LoginIcon.RegistrationEnabled = b.config.RegistrationEnabled 221 b.config.LoginIcon.UsernameRecoveryEnabled = b.config.UsernameRecoveryEnabled 222 b.config.LoginIcon.PasswordRecoveryEnabled = b.config.PasswordRecoveryEnabled 223 b.config.LoginIcon.ContactSupportEnabled = b.config.ContactSupportEnabled 224 b.config.LoginIcon.SupportLink = b.config.SupportLink 225 b.config.LoginIcon.SupportEmail = b.config.SupportEmail 226 return b.config.LoginIcon 227 }