Class: Aker::Authorities::Composite
- Inherits:
-
Object
- Object
- Aker::Authorities::Composite
- Includes:
- Support::FindSoleUser
- Defined in:
- lib/aker/authorities/composite.rb
Overview
This authority provides a uniform entry point for multiple authorities.
The documentation on each method describes how the implementation for a specific authority should work in addition to the way this authority aggregates results. For any particular authority, all methods are optional (of course, it would be pointless to configure in an authority which doesn’t implement any of them).
Instance Attribute Summary collapse
-
#authorities ⇒ Array
The ordered series of authorities whose results this authority aggregates.
Instance Method Summary collapse
-
#amplify!(user) ⇒ Aker::User
Fills in any information about the user which the authority knows but which is not already present in the given object.
-
#find_users(*criteria) ⇒ Array<Aker::User>
Finds users matching the given criteria.
-
#initialize(config) ⇒ Composite
constructor
Creates a new instance.
-
#on_authentication_failure(user, kind, credentials, reason) ⇒ void
A callback which is invoked when #valid_credentials? is going to return ‘false` or `nil`.
-
#on_authentication_success(user, kind, credentials, authenticating_authority) ⇒ void
A callback which is invoked when #valid_credentials? is about to return a new user.
-
#valid_credentials?(kind, *credentials) ⇒ Aker::User, ...
The main authentication and authorization entry point for an authority.
-
#veto?(user) ⇒ Boolean
Allows an authority to unconditionally block access for a user.
Methods included from Support::FindSoleUser
Constructor Details
#initialize(config) ⇒ Composite
Creates a new instance.
33 34 35 |
# File 'lib/aker/authorities/composite.rb', line 33 def initialize(config) @config = config end |
Instance Attribute Details
#authorities ⇒ Array
The ordered series of authorities whose results this authority aggregates. The members of this array should implement one or more of the methods in the authority informal interface (i.e., the other methods in this class).
21 22 23 |
# File 'lib/aker/authorities/composite.rb', line 21 def @authorities end |
Instance Method Details
#amplify!(user) ⇒ Aker::User
Fills in any information about the user which the authority knows but which is not already present in the given object. In addition to the simple attributes on User, this method should fill in all available authorization information.
The composite behavior is to invoke ‘amplify!` on each of the configured #authorities in series, passing the given user to each.
214 215 216 217 218 |
# File 'lib/aker/authorities/composite.rb', line 214 def amplify!(user) user.default_portal = @config.portal if @config.portal? && !user.default_portal poll(:amplify!, user) user end |
#find_users(*criteria) ⇒ Array<Aker::User>
Finds users matching the given criteria. Criteria may either be ‘String`s or `Hash`es. If it’s a single ‘String`, it is interpreted as a username and this method will return an array containing either a single user with that username or an empty array. If the criteria is a `Hash`, the behavior will be authority-dependent. However, all the attributes of User are reserved parameter names — if an authority interprets the value associated with a User attribute name, it must be interpreted as an exact-match criteria for that authority’s understanding of that attribute (whatever it is).
If more than one criterion is provided, each value is treated separately according to the description given above for a single value. The resulting array will contain each matching user exactly once. It will not be possible to determine from the results alone which returned user matched which criterion.
Examples:
.find_users("wakibbe") # => that single user, if
# the username is known
.find_users(:first_name => 'Warren')
# => all the users named
# Warren
.find_users(
:first_name => 'Warren', :last_name => 'Kibbe')
# => all the users named
# Warren Kibbe
.find_users(
{ :first_name => 'Warren' }, { :last_name => 'Kibbe' })
# => all the users with
# first name Warren or
# last name Kibbe
The composite behavior is to invoke ‘find_users` on all the authorities which support it and merge the resulting lists. Any users with the same username are merged using User#merge!. Finally, all the users are amplified.
This method will always return an array.
267 268 269 270 271 272 273 |
# File 'lib/aker/authorities/composite.rb', line 267 def find_users(*criteria) poll(:find_users, *criteria). collect { |result, | result }. compact. inject([]) { |aggregate, users| merge_user_lists!(aggregate, users.compact) }. each { |user| amplify!(user) } end |
#on_authentication_failure(user, kind, credentials, reason) ⇒ void
This method returns an undefined value.
A callback which is invoked when #valid_credentials? is going to return ‘false` or `nil`. It has no control over whether authentication will proceed — it’s just a notification.
The composite behavior is to invoke the callback on all the authorities which implement it.
193 194 195 196 197 |
# File 'lib/aker/authorities/composite.rb', line 193 def on_authentication_failure(user, kind, credentials, reason) @config.logger.info("Authentication attempt#{" by \"#{user.username}\"" if user} " << "failed: #{reason}.") poll(:on_authentication_failure, user, kind, credentials, reason) end |
#on_authentication_success(user, kind, credentials, authenticating_authority) ⇒ void
This method returns an undefined value.
A callback which is invoked when #valid_credentials? is about to return a new user. It has no control over whether authentication will proceed — it’s just a notification.
The composite behavior is to invoke the callback on all the authorities which implement it.
166 167 168 169 170 |
# File 'lib/aker/authorities/composite.rb', line 166 def on_authentication_success(user, kind, credentials, ) @config.logger.info("User \"#{user.username}\" was successfully authenticated " << "by #{.class}.") poll(:on_authentication_success, user, kind, credentials, ) end |
#valid_credentials?(kind, *credentials) ⇒ Aker::User, ...
The main authentication and authorization entry point for an authority. A concrete authority can return one of four things from its implementation of this method:
-
A User instance if the credentials are valid. The instance represents the user that corresponds to these credentials, with all the attributes and authorization information that the verifying authority knows about.
-
‘nil` if the credentials aren’t valid according to the authority.
-
‘false` if the authority wants to prevent the presenter of these credentials from authenticating, even if another authority says they are valid.
-
‘:unsupported` if the authority can never authenticate credentials of the provided kind. Semantically this is the same as `nil`, but it allows `Composite` to provide a useful debugging message if none of the authorities are capable of validating a submitted kind.
The composite implementation provided by this class does the following:
-
Executes ‘valid_credentials?` on all the configured authorities that implement it.
-
Returns ‘false` if any of the authorities return `false`.
-
Returns ‘nil` if none of the authorities returned a user.
-
Selects the first user returned by any of the authorities.
-
Returns ‘false` if any of the authorities veto the user.
-
Otherwise returns the user, amplified.
On failure, the #on_authentication_failure callback is called on any authority which provides it. Similarly on success, the #on_authentication_success callback is called on all the authorities which support it.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/aker/authorities/composite.rb', line 89 def valid_credentials?(kind, *credentials) results = poll(:valid_credentials?, kind, *credentials) if results.empty? raise "No authentication-providing authority is configured. " << "At least one authority must implement #valid_credentials?." end user, = results.detect { |r, | r && r != :unsupported } unless user msg = if results.collect { |r, auth| r }.uniq == [:unsupported] "no configured authorities support #{kind.inspect} credentials" else "invalid credentials" end on_authentication_failure(nil, kind, credentials, msg) return nil end vc_vetoers = results.select { |r, | r == false }.collect { |r, | } unless vc_vetoers.empty? msg = "credentials vetoed by #{vc_vetoers.collect(&:to_s).join(', ')}" on_authentication_failure(user, kind, credentials, msg) return false end veto_vetoers = poll(:veto?, user). select { |result, | result }.collect { |result, | } unless veto_vetoers.empty? msg = "user vetoed by #{veto_vetoers.collect(&:to_s).join(', ')}" on_authentication_failure(user, kind, credentials, msg) return false end amplify!(user) on_authentication_success(user, kind, credentials, ) user end |
#veto?(user) ⇒ Boolean
Allows an authority to unconditionally block access for a user.
If an authority sometimes wishes to prevent authentication for a user, even if some authority has indicated that he or she has valid credentials, it can implement this method and return true when appropriate.
The composite behavior aggregates the responses for all implementing authorities, returning true if any of them return true.
144 145 146 |
# File 'lib/aker/authorities/composite.rb', line 144 def veto?(user) poll(:veto?, user).detect { |result, | result } end |