kankri 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 136760abbcab49dfdada252777f2e0597e0167d3
4
- data.tar.gz: c9da45c3e30a82533f71840801b2c8ab35907125
3
+ metadata.gz: 1a28b6708e74babd3eb76fbe143d1e9ddad83b7e
4
+ data.tar.gz: 589070377d1025cb55c66f96d9952bf4144789fb
5
5
  SHA512:
6
- metadata.gz: 122cf49d0d79df39cbc7a3b7dda429c9081f785e8047690ea88c1528f97c3e55d6b24980c9bcc6a42f3cdab289d883e4d22cd7be7e2bed006572c8888302f106
7
- data.tar.gz: 12e15471a892db8476ef77b235a03f5ea4c619900a90390749fabe4dba521a3dbe409206ac03a53d184a6e1454537fbd57ecbe82861cf977a644a17f60f6d414
6
+ metadata.gz: 338b0fb18ad4fdc91105e070412bfff3c750ffb60c01155ef53167d43d5a5e90a9efc751ab84d2ae12210aee0b71c726be83d52e05026247831fd132841bb9ce
7
+ data.tar.gz: 34d9fccd754ae9b75e05c6a56b9fd4e9f1046c3196417f32571c13d0f2417135697bb8ae68d7932298a91e88f8916860cd3b48edfd10543f01cb5f3504d0fe99
data/.gitignore CHANGED
@@ -16,3 +16,5 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
+
20
+ measurements
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+ 0.1.1
2
+ - Some refactoring
3
+ - 100% code and YARD coverage
4
+
5
+ 0.1.0
6
+ - Initial version
data/Rakefile CHANGED
@@ -1,7 +1,14 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'yard'
4
+ require 'yardstick/rake/measurement'
5
+ require 'yardstick/rake/verify'
3
6
 
4
7
  RSpec::Core::RakeTask.new
8
+ YARD::Rake::YardocTask.new
9
+ Yardstick::Rake::Verify.new
10
+ Yardstick::Rake::Measurement.new
5
11
 
6
12
  task :default => :spec
13
+ task :doc => :yard
7
14
  task :test => :spec
data/kankri.gemspec CHANGED
@@ -24,8 +24,11 @@ Gem::Specification.new do |spec|
24
24
  spec.require_paths = ['lib']
25
25
 
26
26
  spec.add_development_dependency 'bundler', '~> 1.3'
27
- spec.add_development_dependency 'rake'
28
- spec.add_development_dependency 'rspec'
29
- spec.add_development_dependency 'simplecov'
30
- spec.add_development_dependency 'fuubar'
27
+ spec.add_development_dependency 'rake', '~> 10', '>= 10.1.1'
28
+ spec.add_development_dependency 'rspec', '~> 2', '>= 2.14'
29
+ spec.add_development_dependency 'simplecov', '~> 0.8'
30
+ spec.add_development_dependency 'fuubar', '~> 1'
31
+ spec.add_development_dependency 'yard', '~> 0.8'
32
+ spec.add_development_dependency 'yardstick', '~> 0.9'
33
+ spec.add_development_dependency 'backports', '~> 3', '>= 3.3.5'
31
34
  end
data/lib/kankri.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'kankri/password_check'
2
+ require 'kankri/privilege_check'
2
3
  require 'kankri/privilege_set'
3
4
  require 'kankri/privilege_subject'
4
5
  require 'kankri/simple_authenticator'
@@ -26,7 +27,7 @@ module Kankri
26
27
  #
27
28
  # @api public
28
29
  # @example Create an authenticator from a hash of users.
29
- # Kankri.authenticator_From_hash(
30
+ # Kankri.authenticator_from_hash(
30
31
  # admin: {
31
32
  # password: 'hunter2',
32
33
  # privileges: {
@@ -1,3 +1,4 @@
1
+ # Exceptions for Kankri.
1
2
  module Kankri
2
3
  # Exception generated when authentication fails.
3
4
  AuthenticationFailure = Class.new(RuntimeError)
@@ -1,34 +1,110 @@
1
1
  module Kankri
2
2
  # A method object that represents a check on username/password pairs
3
+ #
4
+ # This is a basic check based on string comparison, failing if either
5
+ # username or password are empty or nil. If used with a hashing
6
+ # authenticator, the hashing must be done before the password checking.
7
+ # Similarly, PasswordCheck does not convert to or from symbols; the
8
+ # authenticator must do this itself.
3
9
  class PasswordCheck
10
+ # Creates a password check instance
11
+ #
12
+ # Passwords may be literal passwords, hashes or any other secret that
13
+ # can be compared by ==. Any hashing or other processing (such as type
14
+ # conversion) must be done by the Authenticator.
15
+ #
16
+ # @api public
17
+ # @example Initialises a PasswordCheck.
18
+ # PasswordCheck.new('alf', 'hunter2', 'alf' => 'hunter2')
19
+ #
20
+ # @param username [Object] The username; this is typically a Symbol or a
21
+ # String.
22
+ # @param password [String] The password to check against the passwords
23
+ # database.
24
+ # @param passwords [Hash] The hash mapping usernames to their passwords.
4
25
  def initialize(username, password, passwords)
5
26
  @username = username
6
27
  @password = password
7
28
  @passwords = passwords
8
29
  end
9
30
 
31
+ # Checks to see if the authentication credentials are correct
32
+ #
33
+ # @api public
34
+ # @example Perform a successful authentication check.
35
+ # checker.ok?
36
+ # #=> true
37
+ # @example Perform an unsuccessful authentication check.
38
+ # checker.ok?
39
+ # #=> false
40
+ #
41
+ # @return [Boolean] True if the password matches; false otherwise.
10
42
  def ok?
11
43
  auth_present? && user_known? && password_match?
12
44
  end
13
45
 
46
+ # Creates and runs a password check
47
+ #
48
+ # @api public
49
+ # @example Check a correct password.
50
+ # PasswordCheck.check('alf', 'hunter2', 'alf' => 'hunter2')
51
+ # #=> true
52
+ # @example Check an incorrect password.
53
+ # PasswordCheck.check('alf', 'nope', 'alf' => 'hunter2')
54
+ # #=> false
55
+ #
56
+ # @param (see #initialize)
57
+ #
58
+ # @return (see #ok?)
59
+ def self.check(*args)
60
+ PasswordCheck.new(*args).ok?
61
+ end
62
+
63
+ private
64
+
65
+ # Checks to see if the authentication credentials are present and non-empty
66
+ #
67
+ # @api private
68
+ #
69
+ # @return [Boolean] True if the credentials are present; false otherwise.
14
70
  def auth_present?
15
71
  username_present? && password_present?
16
72
  end
17
73
 
74
+ # Checks to see if the username is present and non-empty
75
+ #
76
+ # @api private
77
+ #
78
+ # @return [Boolean] True if the username is present; false otherwise.
18
79
  def username_present?
19
80
  !(@username.nil? || @username.empty?)
20
81
  end
21
82
 
83
+ # Checks to see if the password is present and non-empty
84
+ #
85
+ # @api private
86
+ #
87
+ # @return [Boolean] True if the password is present; false otherwise.
22
88
  def password_present?
23
89
  !(@password.nil? || @password.empty?)
24
90
  end
25
91
 
26
- def password_match?
27
- @passwords.fetch(@username) == @password
28
- end
29
-
92
+ # Checks to see if the user has a known password
93
+ #
94
+ # @api private
95
+ #
96
+ # @return [Boolean] True if the user's password is known; false otherwise.
30
97
  def user_known?
31
98
  @passwords.key?(@username)
32
99
  end
100
+
101
+ # Checks to see if the password matches that on record for the user
102
+ #
103
+ # @api private
104
+ #
105
+ # @return [Boolean] True if the password matches; false otherwise.
106
+ def password_match?
107
+ @passwords.fetch(@username) == @password
108
+ end
33
109
  end
34
110
  end
@@ -0,0 +1,104 @@
1
+ module Kankri
2
+ # A method object for checking privileges
3
+ #
4
+ # A PrivilegeChecker takes the target privilege key and required privilege,
5
+ # as well as the hash mapping privilege keys to their
6
+ class PrivilegeChecker
7
+ # Creates a PrivilegeChecker
8
+ #
9
+ # @api public
10
+ # @example Initialise a passing privilege check.
11
+ # PrivilegeChecker.new(:foo, :bar, foo: [:bar])
12
+ # @example Initialise a failing privilege check.
13
+ # PrivilegeChecker.new(:foo, :bar, foo: [])
14
+ #
15
+ # @param target [Symbol] The privilege key that is the target of this
16
+ # privilege check.
17
+ # @param requisite [Symbol] The privilege required under the privilege
18
+ # key.
19
+ # @param privileges [Hash] A hash mapping privilege keys to their
20
+ # privilege lists.
21
+ def initialize(target, requisite, privileges)
22
+ @target = target
23
+ @requisite = requisite
24
+ @privileges = privileges
25
+ end
26
+
27
+ # Runs the privilege checker and checks the privilege
28
+ #
29
+ # @api public
30
+ # @example Runs a passing privilege checker.
31
+ # checker.run
32
+ # #=> true
33
+ # @example Runs a failing privilege checker.
34
+ # checker.run
35
+ # #=> false
36
+ #
37
+ # @return [Boolean] True if the privilege is held by the privilege set
38
+ # for the target; false otherwise.
39
+ def valid?
40
+ target_in_privileges? && has_privilege?
41
+ end
42
+
43
+ # Creates and runs a privilege checker
44
+ #
45
+ # @api public
46
+ # @example Do a passing privilege check.
47
+ # PrivilegeChecker.check(:foo, :bar, foo: [:bar])
48
+ # #=> true
49
+ #
50
+ # @example Do a failing privilege check.
51
+ # PrivilegeChecker.check(:foo, :bar, foo: [])
52
+ # #=> false
53
+ #
54
+ # @param (see #initialize)
55
+ #
56
+ # @return (see #valid?)
57
+ def self.check(*args)
58
+ new(*args).valid?
59
+ end
60
+
61
+ private
62
+
63
+ # Checks to see if the target is in the privileges set
64
+ #
65
+ # @api private
66
+ #
67
+ # @return [Boolean] True if the target key is in the privileges set;
68
+ # false otherwise.
69
+ def target_in_privileges?
70
+ @privileges.key?(@target)
71
+ end
72
+
73
+ # Checks to see if the privilege request is satisfied for the target
74
+ #
75
+ # This assumes that the target exists in the privilege list.
76
+ #
77
+ # @api private
78
+ #
79
+ # @return [Boolean] True if the privilege is held by the privilege set
80
+ # for the target; false otherwise.
81
+ def has_privilege?
82
+ has_all? || has_direct?
83
+ end
84
+
85
+ # Checks to see if the privilege request is satisfied by an 'all' clause
86
+ #
87
+ # @api private
88
+ # @return [Boolean] True if this privilege set has all privileges for a
89
+ # target; false otherwise.
90
+ def has_all?
91
+ @privileges.fetch(@target) == :all
92
+ end
93
+
94
+ # Checks to see if the privilege request is satisfied directly
95
+ #
96
+ # @api private
97
+ #
98
+ # @return [Boolean] True if this privilege set explicitly has a certain
99
+ # privilege for a certain target; false otherwise.
100
+ def has_direct?
101
+ @privileges.fetch(@target).include?(@requisite)
102
+ end
103
+ end
104
+ end
@@ -1,21 +1,32 @@
1
1
  require 'kankri/exceptions'
2
+ require 'kankri/privilege_check'
2
3
 
3
4
  module Kankri
4
- # Wrapper around a set of privileges a client has
5
+ # Wrapper around a set of privileges a user has
6
+ #
7
+ # The PrivilegeSet is the return value of an Authenticator, and represents
8
+ # the level of privilege the
5
9
  class PrivilegeSet
6
- # Initialises a privilege set.
10
+ # Initialises a privilege set
7
11
  #
8
12
  # @api public
9
- # @example Create a privilege set with no privileges.
13
+ # @example Create a privilege set with no privileges.
10
14
  # PrivilegeSet.new({})
11
- # @example Create a privilege set with some privileges.
15
+ # @example Create a privilege set with some privileges.
12
16
  # PrivilegeSet.new({channel_set: [:get, :put]})
13
17
  def initialize(privileges)
14
- @privileges = privileges
15
- symbolise_privileges
18
+ @privileges = symbolise_privileges(privileges)
16
19
  end
17
20
 
18
21
  # Requires a certain privilege on a certain target
22
+ #
23
+ # @api public
24
+ # @example Check your privilege.
25
+ # privs.require(:channel, :put)
26
+ #
27
+ # @param (see #has?)
28
+ #
29
+ # @return [void]
19
30
  def require(target, privilege)
20
31
  fail(InsufficientPrivilegeError) unless has?(target, privilege)
21
32
  end
@@ -23,65 +34,47 @@ module Kankri
23
34
  # Checks to see if a certain privilege exists on a given target
24
35
  #
25
36
  # @api public
26
- # @example Check your privilege.
37
+ # @example Check your privilege.
27
38
  # privs.has?(:channel, :put)
28
39
  # #=> false
29
40
  #
30
- # @param target [Symbol] The handler target the privilege is for.
31
- # @param privilege [Symbol] The privilege (one of :get, :put, :post or
41
+ # @param target [Symbol] The handler target the privilege is for.
42
+ # @param privilege [Symbol] The privilege (one of :get, :put, :post or
32
43
  # :delete).
33
44
  #
34
- # @return [Boolean] true if the privileges are sufficient; false
45
+ # @return [Boolean] True if the privileges are sufficient; false
35
46
  # otherwise.
36
47
  def has?(privilege, target)
37
- PrivilegeChecker.new(target, privilege, @privileges).check?
48
+ PrivilegeChecker.check(target.to_sym, privilege.to_sym, @privileges)
38
49
  end
39
50
 
40
51
  private
41
52
 
42
- def symbolise_privileges
43
- @privileges = Hash[@privileges.map do |key, key_privs|
44
- [key.to_sym, symbolise_privilege_list(key_privs)]
45
- end]
53
+ # Converts the keys and values in a privileges hash into Symbols
54
+ #
55
+ # @api private
56
+ #
57
+ # @param privileges [Hash] The privilege hash to symbolise.
58
+ #
59
+ # @return [Hash] The symbolised privileges set.
60
+ def symbolise_privileges(privileges)
61
+ Hash[
62
+ privileges.map do |key, key_privs|
63
+ [key.to_sym, symbolise_privilege_list(key_privs)]
64
+ end
65
+ ]
46
66
  end
47
67
 
68
+ # Converts a privilege list to Symbols
69
+ #
70
+ # If the privilege list is the String 'all', it will become :all.
71
+ # If it is an actual list, each privilege will be converted to a Symbol.
72
+ #
73
+ # @api private
74
+ #
75
+ # @return [Object] The symbolised privilege list.
48
76
  def symbolise_privilege_list(privlist)
49
77
  privlist.is_a?(Array) ? privlist.map(&:to_sym) : privlist.to_sym
50
78
  end
51
79
  end
52
-
53
- # A method object for checking privileges.
54
- class PrivilegeChecker
55
- def initialize(target, requisite, privileges)
56
- @target = target.intern
57
- @requisite = requisite.intern
58
- @privileges = privileges
59
- end
60
-
61
- def check?
62
- has_all? || has_direct?
63
- end
64
-
65
- private
66
-
67
- # @return [Boolean] true if this privilege set has all privileges for a
68
- # target.
69
- def has_all?
70
- @privileges[@target] == :all
71
- end
72
-
73
- # @return [Boolean] true if this privilege set explicitly has a certain
74
- # privilege for a certain target.
75
- def has_direct?
76
- target_in_privileges? && requisite_in_target_privileges?
77
- end
78
-
79
- def target_in_privileges?
80
- @privileges.key?(@target)
81
- end
82
-
83
- def requisite_in_target_privileges?
84
- @privileges[@target].include?(@requisite)
85
- end
86
- end
87
80
  end
@@ -4,12 +4,42 @@ module Kankri
4
4
  # This expects the including class to define a method, 'privilege_key',
5
5
  # which identifies the object in the privilege set.
6
6
  module PrivilegeSubject
7
- # Checks whether an operation can proceed on this privilege subject
7
+ # Checks whether a privilege is granted for this object
8
+ #
9
+ # This looks in the privilege set under the key returned by #privilege_key.
10
+ #
11
+ # @api public
12
+ # @example Checks for a privilege that is in the set for this object.
13
+ # subject.can?(:get, privilege_set)
14
+ # #=> true
15
+ #
16
+ # @example Checks for a privilege that is not in the set for this object.
17
+ # subject.can?(:get, privilege_set)
18
+ # #=> false
19
+ #
20
+ # @param operation [Object] The String or Symbol identifying the operation
21
+ # for which privileges are required.
22
+ #
23
+ # @param privilege_set [PrivilegeSet] The set of privileges that must
24
+ # contain the required privilege.
25
+ #
26
+ # @return [Boolean] True if the privileges are sufficient; false
27
+ # otherwise.
8
28
  def can?(operation, privilege_set)
9
29
  privilege_set.has?(operation, privilege_key)
10
30
  end
11
31
 
12
- # Fails if an operation cannot proceed on this model object
32
+ # Raises an exception if a privilege is not granted for this object
33
+ #
34
+ # This looks in the privilege set under the key returned by #privilege_key.
35
+ #
36
+ # @api public
37
+ # @example Requires a privilege to continue.
38
+ # subject.require(:get, privilege_set)
39
+ #
40
+ # @param (see #can?)
41
+ #
42
+ # @return [void]
13
43
  def fail_if_cannot(operation, privilege_set)
14
44
  privilege_set.require(operation, privilege_key)
15
45
  end
@@ -6,21 +6,82 @@ module Kankri
6
6
  # This object holds user data in memory, including passwords. It is thus
7
7
  # not secure for mission-critical applications.
8
8
  class SimpleAuthenticator
9
- # Makes hashing functions for users based on SHA256.
9
+ extend Forwardable
10
+
11
+ # Makes hashing functions for users based on SHA256
12
+ #
13
+ # @api public
14
+ # @example Create a set of hashing functions for a given set of usernames
15
+ # SimpleAuthenticator::sha256_hasher(['alf', 'roy', 'busby'])
16
+ #
17
+ # @param usernames [Array] A list of usernames to form the keys of the
18
+ # hashing table.
19
+ #
20
+ # @return [Hash] A hash mapping usernames to functions that will take
21
+ # passwords and return their hashed equivalent.
10
22
  def self.sha256_hasher(usernames)
11
23
  digest_hasher(usernames, Digest::SHA256)
12
24
  end
13
25
 
14
- # Makes hashing functions for users based on a Digest implementation.
26
+ # Makes hashing functions for users based on a Digest implementation
27
+ #
28
+ # Each hashing function uses a random salt value, which is stored inside
29
+ # the function and unique to the username.
30
+ #
31
+ # @api public
32
+ # @example Create a set of hashing functions for a given set of usernames
33
+ # SimpleAuthenticator::digest_hasher(['joe', 'ron'], Digest::SHA256)
34
+ #
35
+ # @param usernames [Array] A list of usernames to form the keys of the
36
+ # hashing table.
37
+ # @param hasher [Digest] A Digest to use when hashing the user passwords
38
+ #
39
+ # @return [Hash] A hash mapping usernames to functions that will take
40
+ # passwords and return their hashed equivalent.
15
41
  def self.digest_hasher(usernames, hasher)
16
42
  Hash[
17
43
  usernames.map do |username|
18
44
  salt = SecureRandom.random_bytes
19
- [username, ->(password) { hasher.digest(password + salt) } ]
45
+ [username, ->(password) { hasher.digest(password + salt) }]
20
46
  end
21
47
  ]
22
48
  end
23
49
 
50
+ # Initialises the SimpleAuthenticator
51
+ #
52
+ # @api public
53
+ # @example Initialises the SimpleAuthenticator with a user hash.
54
+ # SimpleAuthenticator.new(
55
+ # admin: {
56
+ # password: 'hunter2',
57
+ # privileges: {
58
+ # foo: 'all',
59
+ # bar: ['abc', 'def', 'ghi'],
60
+ # baz: []
61
+ # }
62
+ # }
63
+ # )
64
+ # @example Initialises the SimpleAuthenticator with a custom hasher.
65
+ # SimpleAuthenticator.new(
66
+ # { admin: {
67
+ # password: 'hunter2',
68
+ # privileges: {
69
+ # foo: 'all',
70
+ # bar: ['abc', 'def', 'ghi'],
71
+ # baz: []
72
+ # }
73
+ # }
74
+ # }, hasher
75
+ # )
76
+ #
77
+ # @param users [String] A hash mapping usernames (which may be Strings or
78
+ # Symbols) to hashes containing a mapping from :password to the user's
79
+ # password, and from :privileges to a hash mapping privilege keys to
80
+ # privilege lists.
81
+ # @param hash_maker [Object] A callable that takes a list of usernames
82
+ # and returns a hash mapping the usernames to functions that hash
83
+ # passwords for those users. If nil, a sensible default hasher will be
84
+ # used.
24
85
  def initialize(users, hash_maker = nil)
25
86
  hash_maker ||= self.class.method(:sha256_hasher)
26
87
  @users = users
@@ -30,6 +91,23 @@ module Kankri
30
91
  @privilege_sets = privilege_sets
31
92
  end
32
93
 
94
+ # Attempts to authenticate with the given username and password
95
+ #
96
+ # This will fail with an AuthenticationFailure exception if the credentials
97
+ # are invalid.
98
+ #
99
+ # @api public
100
+ # @example Authenticates with a String username and password.
101
+ # auth.authenticate('joe_bloggs', 'hunter2')
102
+ # @example Authenticates with a Symbol username and String password.
103
+ # auth.authenticate(:joe_bloggs, 'hunter2')
104
+ #
105
+ # @param username [Object] The candidate username; this may be either a
106
+ # String or a Symbol, and will be normalised to a Symbol.
107
+ # @param username [Object] The candidate username; this may be either a
108
+ # String or a Symbol, and will be normalised to a String.
109
+ #
110
+ # @return [PrivilegeSet] The privilege set for the username
33
111
  def authenticate(username, password)
34
112
  auth_fail unless auth_ok?(username.intern, password.to_s)
35
113
  privileges_for(username.intern)
@@ -37,11 +115,20 @@ module Kankri
37
115
 
38
116
  private
39
117
 
40
- def privileges_for(username)
41
- @privilege_sets[username]
42
- end
118
+ # Returns the privilege set for the given username
119
+ #
120
+ # @api private
121
+ #
122
+ # @param username [Object] The username whose privilege set is sought.
123
+ #
124
+ # @return [PrivilegeSet] The privilege set for the username
125
+ def_delegator :@privilege_sets, :fetch, :privileges_for
43
126
 
44
127
  # Creates a hash mapping username symbols to their password strings
128
+ #
129
+ # @api private
130
+ #
131
+ # @return [Hash] A hash mapping usernames to passwords
45
132
  def passwords
46
133
  transform_users do |name, entry|
47
134
  plaintext = entry.fetch(:password).to_s
@@ -50,29 +137,83 @@ module Kankri
50
137
  end
51
138
 
52
139
  # Creates a hash mapping username symbols to their privilege sets
140
+ #
141
+ # @api private
142
+ #
143
+ # @return [Hash] A hash mapping usernames to privilege sets
53
144
  def privilege_sets
54
145
  transform_users { |_, entry| PrivilegeSet.new(entry.fetch(:privileges)) }
55
146
  end
56
147
 
148
+ # Creates a new Hash by modifying the entries of the user hash
149
+ #
150
+ # @api private
151
+ #
152
+ # @yieldparam name [Object] The username.
153
+ # @yieldparam entry [Hash] The user entry.
154
+ #
155
+ # @return [Hash] The hash mapping usernames to the yielded values.
57
156
  def transform_users
58
157
  Hash[@users.map { |name, entry| [name.intern, (yield name, entry)] }]
59
158
  end
60
159
 
160
+ # Fails with an AuthenticationFailure exception
161
+ #
162
+ # @api private
163
+ #
164
+ # @return [void]
61
165
  def auth_fail
62
166
  fail(Kankri::AuthenticationFailure)
63
167
  end
64
168
 
169
+ # Checks to see if given authentication credentials are OK
170
+ #
171
+ # @api private
172
+ #
173
+ # @param username [Object] The username of the authentication attempt.
174
+ # @param password [Object] The password of the authentication attempt.
175
+ #
176
+ # @return [Boolean] True if the authentication attempt fails; false
177
+ # otherwise.
65
178
  def auth_ok?(username, password)
66
179
  username_present?(username) && password_ok?(username, password)
67
180
  end
68
181
 
182
+ # Checks to see if the username is in the system
183
+ #
184
+ # @api private
185
+ #
186
+ # @param username [Object] The username of the authentication attempt.
187
+ #
188
+ # @return [Boolean] True if the username exists in the authenticator;
189
+ # false otherwise.
69
190
  def username_present?(username)
70
191
  @hashers.key?(username) && @passwords.key?(username)
71
192
  end
72
193
 
194
+ # Checks the password to see if it is correct for this username
195
+ #
196
+ # @api private
197
+ #
198
+ # @param username [Object] The username of the authentication attempt.
199
+ # @param password [Object] The password of the authentication attempt.
200
+ #
201
+ # @return [Boolean] True if the password is correct; false otherwise.
73
202
  def password_ok?(username, password)
74
- hashed_pass = @hashers.fetch(username).call(password)
75
- PasswordCheck.new(username, hashed_pass, @passwords).ok?
203
+ hashed_pass = hashed_password(username, password)
204
+ PasswordCheck.check(username, hashed_pass, @passwords)
205
+ end
206
+
207
+ # Applies the user's hashing function to the candidate password
208
+ #
209
+ # @api private
210
+ #
211
+ # @param username [Object] The username of the authentication attempt.
212
+ # @param password [Object] The password of the authentication attempt.
213
+ #
214
+ # @return [Object] The hashed password.
215
+ def hashed_password(username, password)
216
+ @hashers.fetch(username).call(password)
76
217
  end
77
218
  end
78
219
  end
@@ -1,3 +1,4 @@
1
+ # The current gem version. See CHANGELOG for details.
1
2
  module Kankri
2
- VERSION = "0.1.0"
3
+ VERSION = '0.1.1'
3
4
  end
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'kankri'
3
3
 
4
+ # A mock object for testing PrivilegeSubject
4
5
  class MockPrivilegeSubject
5
6
  include Kankri::PrivilegeSubject
6
7
 
@@ -13,7 +14,7 @@ describe MockPrivilegeSubject do
13
14
  let(:privilege_set) { double(:privilege_set) }
14
15
  let(:operation) { double(:operation) }
15
16
 
16
- {fail_if_cannot: :require, can?: :has?}.each do |subject_meth, set_meth|
17
+ { fail_if_cannot: :require, can?: :has? }.each do |subject_meth, set_meth|
17
18
  describe "##{subject_meth}" do
18
19
  context 'when given a valid privilege set and operation' do
19
20
  it "calls ##{set_meth} on the privilege set with the handler target" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kankri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Windsor
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-23 00:00:00.000000000 Z
11
+ date: 2013-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,58 +28,118 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10'
31
34
  - - '>='
32
35
  - !ruby/object:Gem::Version
33
- version: '0'
36
+ version: 10.1.1
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '10'
38
44
  - - '>='
39
45
  - !ruby/object:Gem::Version
40
- version: '0'
46
+ version: 10.1.1
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: rspec
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2'
45
54
  - - '>='
46
55
  - !ruby/object:Gem::Version
47
- version: '0'
56
+ version: '2.14'
48
57
  type: :development
49
58
  prerelease: false
50
59
  version_requirements: !ruby/object:Gem::Requirement
51
60
  requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: '2'
52
64
  - - '>='
53
65
  - !ruby/object:Gem::Version
54
- version: '0'
66
+ version: '2.14'
55
67
  - !ruby/object:Gem::Dependency
56
68
  name: simplecov
57
69
  requirement: !ruby/object:Gem::Requirement
58
70
  requirements:
59
- - - '>='
71
+ - - ~>
60
72
  - !ruby/object:Gem::Version
61
- version: '0'
73
+ version: '0.8'
62
74
  type: :development
63
75
  prerelease: false
64
76
  version_requirements: !ruby/object:Gem::Requirement
65
77
  requirements:
66
- - - '>='
78
+ - - ~>
67
79
  - !ruby/object:Gem::Version
68
- version: '0'
80
+ version: '0.8'
69
81
  - !ruby/object:Gem::Dependency
70
82
  name: fuubar
71
83
  requirement: !ruby/object:Gem::Requirement
72
84
  requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '1'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: '1'
95
+ - !ruby/object:Gem::Dependency
96
+ name: yard
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '0.8'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ version: '0.8'
109
+ - !ruby/object:Gem::Dependency
110
+ name: yardstick
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ~>
114
+ - !ruby/object:Gem::Version
115
+ version: '0.9'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ~>
121
+ - !ruby/object:Gem::Version
122
+ version: '0.9'
123
+ - !ruby/object:Gem::Dependency
124
+ name: backports
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ~>
128
+ - !ruby/object:Gem::Version
129
+ version: '3'
73
130
  - - '>='
74
131
  - !ruby/object:Gem::Version
75
- version: '0'
132
+ version: 3.3.5
76
133
  type: :development
77
134
  prerelease: false
78
135
  version_requirements: !ruby/object:Gem::Requirement
79
136
  requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ version: '3'
80
140
  - - '>='
81
141
  - !ruby/object:Gem::Version
82
- version: '0'
142
+ version: 3.3.5
83
143
  description: "\n Kankri is a library for quickly setting up basic authentication
84
144
  with\n object-action privileges. It's intended to be used in projects which
85
145
  need\n a simple auth system with no run-time requirements and little set-up.
@@ -92,6 +152,7 @@ extra_rdoc_files: []
92
152
  files:
93
153
  - .gitignore
94
154
  - .rspec
155
+ - CHANGELOG
95
156
  - Gemfile
96
157
  - LICENSE.txt
97
158
  - README.md
@@ -100,6 +161,7 @@ files:
100
161
  - lib/kankri.rb
101
162
  - lib/kankri/exceptions.rb
102
163
  - lib/kankri/password_check.rb
164
+ - lib/kankri/privilege_check.rb
103
165
  - lib/kankri/privilege_set.rb
104
166
  - lib/kankri/privilege_subject.rb
105
167
  - lib/kankri/simple_authenticator.rb
@@ -141,3 +203,4 @@ test_files:
141
203
  - spec/privilege_subject_spec.rb
142
204
  - spec/simple_authenticator_spec.rb
143
205
  - spec/spec_helper.rb
206
+ has_rdoc: