Class: Incline::UserManager
- Inherits:
-
AuthEngineBase
- Object
- AuthEngineBase
- Incline::UserManager
- Defined in:
- lib/incline/user_manager.rb
Overview
Handles the user management tasks between an authentication system and the database.
The default authentication system is the database, but other systems are supported. Out of the box we support LDAP, but the class can be extended to add other functionality.
Class Method Summary collapse
-
.authenticate(email, password, client_ip) ⇒ Object
Attempts to authenticate the user and returns the model on success.
-
.begin_external_authentication(request) ⇒ Object
Returns a URL if an external login is to be used, or nil to use local authentication.
-
.clear_auth_engine(*domains) ⇒ Object
Clears any registered authentication engine for one or more domains.
-
.end_external_authentication(request) ⇒ Object
Returns a URL if an external logout is to be used, or nil to use local authentication.
-
.register_auth_engine(engine, *domains) ⇒ Object
Registers an authentication engine for one or more domains.
Instance Method Summary collapse
-
#authenticate(email, password, client_ip) ⇒ Object
Attempts to authenticate the user and returns the model on success.
-
#begin_external_authentication(request) ⇒ Object
The begin_external_authentication method takes a request object to determine if it should process a login or return nil.
-
#clear_auth_engine(*domains) ⇒ Object
Clears any registered authentication engine for one or more domains.
-
#end_external_authentication(request) ⇒ Object
The end_external_authentication method takes a request object to determine if it should process a logout or return nil.
-
#initialize(options = {}) ⇒ UserManager
constructor
Creates a new user manager.
-
#register_auth_engine(engine, *domains) ⇒ Object
Registers an authentication engine for one or more domains.
Constructor Details
#initialize(options = {}) ⇒ UserManager
Creates a new user manager.
The user manager itself takes no options, however options will be passed to any registered authentication engines when they are instantiated.
The options can be used to pre-register engines and provide configuration for them. The engines will have specific configurations, but the UserManager class recognizes the ‘engines’ key.
{
:engines => {
'example.com' => {
:engine => MySuperAuthEngine.new(...)
},
'example.org' => {
:engine => 'incline_ldap/auth_engine',
:config => {
:host => 'ldap.example.org',
:port => 636,
:base_dn => 'DC=ldap,DC=example,DC=org'
}
}
}
}
When an ‘engines’ key is processed, the configuration options for the engines are pulled from the subkeys. Once the processing of the ‘engines’ key is complete, it will be removed from the options hash so any engines registered in the future will not receive the extra options.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/incline/user_manager.rb', line 41 def initialize( = {}) @options = ( || {}).deep_symbolize_keys Incline::User.ensure_admin_exists! if @options[:engines].is_a?(::Hash) @options[:engines].each do |domain_name, domain_config| if domain_config[:engine].blank? ::Incline::Log::info "Domain #{domain_name} is missing an engine definition and will not be registered." elsif domain_config[:engine].is_a?(::Incline::AuthEngineBase) ::Incline::Log::info "Using supplied auth engine for #{domain_name}." register_auth_engine domain_config[:engine], domain_name else engine = begin domain_config[:engine].to_s.classify.constantize rescue NameError nil end if engine engine = engine.new(domain_config[:config] || {}) if engine.is_a?(::Incline::AuthEngineBase) ::Incline::Log::info "Using newly created auth engine for #{domain_name}." register_auth_engine engine, domain_name else ::Incline::Log::warn "Object created for #{domain_name} does not inherit from Incline::AuthEngineBase." end else ::Incline::Log::warn "Failed to create auth engine for #{domain_name}." end end end end @options.delete(:engines) end |
Class Method Details
.authenticate(email, password, client_ip) ⇒ Object
Attempts to authenticate the user and returns the model on success.
145 146 147 |
# File 'lib/incline/user_manager.rb', line 145 def self.authenticate(email, password, client_ip) default.authenticate email, password, client_ip end |
.begin_external_authentication(request) ⇒ Object
Returns a URL if an external login is to be used, or nil to use local authentication.
151 152 153 |
# File 'lib/incline/user_manager.rb', line 151 def self.begin_external_authentication(request) default.begin_external_authentication request end |
.clear_auth_engine(*domains) ⇒ Object
Clears any registered authentication engine for one or more domains.
226 227 228 |
# File 'lib/incline/user_manager.rb', line 226 def self.clear_auth_engine(*domains) default.clear_auth_engine(*domains) end |
.end_external_authentication(request) ⇒ Object
Returns a URL if an external logout is to be used, or nil to use local authentication.
157 158 159 |
# File 'lib/incline/user_manager.rb', line 157 def self.end_external_authentication(request) default.end_external_authentication request end |
.register_auth_engine(engine, *domains) ⇒ Object
Registers an authentication engine for one or more domains.
The engine
passed in should take an options hash as the only argument to initialize
and should provide an authenticate
method that takes the email
, password
, and client_ip
.
The authenticate
method of the engine should return an Incline::User object on success or nil on failure.
214 215 216 |
# File 'lib/incline/user_manager.rb', line 214 def self.register_auth_engine(engine, *domains) default.register_auth_engine(engine, *domains) end |
Instance Method Details
#authenticate(email, password, client_ip) ⇒ Object
Attempts to authenticate the user and returns the model on success.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/incline/user_manager.rb', line 81 def authenticate(email, password, client_ip) return nil unless Incline::EmailValidator.valid?(email) email = email.downcase # If an engine is registered for the email domain, then use it. engine = get_auth_engine(email) if engine return engine.authenticate(email, password, client_ip) end # Otherwise we will be using the database. user = User.find_by(email: email) if user # user must be enabled and the password must match. unless user.enabled? add_failure_to user, '(DB) account disabled', client_ip return nil end if user.authenticate(password) add_success_to user, '(DB)', client_ip return user else add_failure_to user, '(DB) invalid password', client_ip return nil end end add_failure_to email, 'invalid email', client_ip nil end |
#begin_external_authentication(request) ⇒ Object
The begin_external_authentication method takes a request object to determine if it should process a login or return nil. If it decides to process authentication, it should return a URL to redirect to.
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/incline/user_manager.rb', line 114 def begin_external_authentication(request) # We don't have an email domain to work from. # Instead, we'll call each engine's authenticate_external method. # If one of them returns a user, then we return that value and skip further processing. auth_engines.each do |dom,engine| unless engine.nil? url = engine.begin_external_authentication(request) return url unless url.blank? end end nil end |
#clear_auth_engine(*domains) ⇒ Object
Clears any registered authentication engine for one or more domains.
220 221 222 |
# File 'lib/incline/user_manager.rb', line 220 def clear_auth_engine(*domains) register_auth_engine(nil, *domains) end |
#end_external_authentication(request) ⇒ Object
The end_external_authentication method takes a request object to determine if it should process a logout or return nil. If it decides to process authentication, it should return a URL to redirect to.
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/incline/user_manager.rb', line 130 def end_external_authentication(request) # We don't have an email domain to work from. # Instead, we'll call each engine's authenticate_external method. # If one of them returns a user, then we return that value and skip further processing. auth_engines.each do |dom,engine| unless engine.nil? url = engine.end_external_authentication(request) return url unless url.blank? end end nil end |
#register_auth_engine(engine, *domains) ⇒ Object
Registers an authentication engine for one or more domains.
The engine
passed in should take an options hash as the only argument to initialize
and should provide an authenticate
method that takes the email
, password
, and client_ip
. You can optionally define an authenticate_external
method that takes the current request
as the only parameter.
The authenticate
method of the engine should return an Incline::User object on success or nil on failure. The begin_external_authentication
method of the engine should return a URL to redirect to on success or nil on failure.
class MyAuthEngine
def initialize(options = {})
...
end
def authenticate(email, password, client_ip)
...
end
def begin_external_authentication(request)
...
end
end
Incline::UserManager.register_auth_engine(MyAuthEngine, 'example.com', 'example.net', 'example.org')
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/incline/user_manager.rb', line 189 def register_auth_engine(engine, *domains) unless engine.nil? unless engine.is_a?(::Incline::AuthEngineBase) raise ArgumentError, "The 'engine' parameter must be an instance of an auth engine or a class defining an auth engine." unless engine.is_a?(::Class) engine = engine.new(@options) raise ArgumentError, "The 'engine' parameter must be an instance of an auth engine or a class defining an auth engine." unless engine.is_a?(::Incline::AuthEngineBase) end end domains.map do |dom| dom = dom.to_s.downcase.strip raise ArgumentError, "The domain #{dom.inspect} does not appear to be a valid domain." unless dom =~ /\A[a-z0-9]+(?:[-.][a-z0-9]+)*\.[a-z]+\Z/ dom end.each do |dom| auth_engines[dom] = engine end end |