Class: Kankri::SimpleAuthenticator

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/kankri/simple_authenticator.rb

Overview

An object that takes in a user hash and authenticates users

This object holds user data in memory, including passwords. It is thus not secure for mission-critical applications.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(users, hash_maker = nil) ⇒ SimpleAuthenticator

Initialises the SimpleAuthenticator

Examples:

Initialises the SimpleAuthenticator with a user hash.

SimpleAuthenticator.new(
  admin: {
    password: 'hunter2',
    privileges: {
      foo: 'all',
      bar: ['abc', 'def', 'ghi'],
      baz: []
    }
  }
)

Initialises the SimpleAuthenticator with a custom hasher.

SimpleAuthenticator.new(
  { admin: {
      password: 'hunter2',
      privileges: {
        foo: 'all',
        bar: ['abc', 'def', 'ghi'],
        baz: []
      }
    }
  }, hasher
)

Parameters:

  • users (String)

    A hash mapping usernames (which may be Strings or Symbols) to hashes containing a mapping from :password to the user’s password, and from :privileges to a hash mapping privilege keys to privilege lists.

  • hash_maker (Object) (defaults to: nil)

    A callable that takes a list of usernames and returns a hash mapping the usernames to functions that hash passwords for those users. If nil, a sensible default hasher will be used.



87
88
89
90
91
92
93
94
# File 'lib/kankri/simple_authenticator.rb', line 87

def initialize(users, hash_maker = nil)
  hash_maker ||= self.class.method(:sha256_hasher)
  @users = users

  @hashers = hash_maker.call(@users.keys)
  @passwords = passwords
  @privilege_sets = privilege_sets
end

Class Method Details

.digest_hasher(usernames, hasher) ⇒ Hash

Makes hashing functions for users based on a Digest implementation

Each hashing function uses a random salt value, which is stored inside the function and unique to the username.

Examples:

Create a set of hashing functions for a given set of usernames

SimpleAuthenticator::digest_hasher(['joe', 'ron'], Digest::SHA256)

Parameters:

  • usernames (Array)

    A list of usernames to form the keys of the hashing table.

  • hasher (Digest)

    A Digest to use when hashing the user passwords

Returns:

  • (Hash)

    A hash mapping usernames to functions that will take passwords and return their hashed equivalent.



43
44
45
46
47
48
49
50
# File 'lib/kankri/simple_authenticator.rb', line 43

def self.digest_hasher(usernames, hasher)
  Hash[
    usernames.map do |username|
      salt = SecureRandom.random_bytes
      [username, ->(password) { hasher.digest(password + salt) }]
    end
  ]
end

.sha256_hasher(usernames) ⇒ Hash

Makes hashing functions for users based on SHA256

Examples:

Create a set of hashing functions for a given set of usernames

SimpleAuthenticator::sha256_hasher(['alf', 'roy', 'busby'])

Parameters:

  • usernames (Array)

    A list of usernames to form the keys of the hashing table.

Returns:

  • (Hash)

    A hash mapping usernames to functions that will take passwords and return their hashed equivalent.



24
25
26
# File 'lib/kankri/simple_authenticator.rb', line 24

def self.sha256_hasher(usernames)
  digest_hasher(usernames, Digest::SHA256)
end

Instance Method Details

#authenticate(username, password) ⇒ PrivilegeSet

Attempts to authenticate with the given username and password

This will fail with an AuthenticationFailure exception if the credentials are invalid.

Examples:

Authenticates with a String username and password.

auth.authenticate('joe_bloggs', 'hunter2')

Authenticates with a Symbol username and String password.

auth.authenticate(:joe_bloggs, 'hunter2')

Parameters:

  • username (Object)

    The candidate username; this may be either a String or a Symbol, and will be normalised to a Symbol.

  • username (Object)

    The candidate username; this may be either a String or a Symbol, and will be normalised to a String.

Returns:



113
114
115
116
# File 'lib/kankri/simple_authenticator.rb', line 113

def authenticate(username, password)
  auth_fail unless auth_ok?(username.intern, password.to_s)
  privileges_for(username.intern)
end