challah 1.6.1 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +5 -38
  4. data/VERSION +1 -1
  5. data/app/controllers/sessions_controller.rb +11 -10
  6. data/app/models/authorization.rb +2 -0
  7. data/lib/challah/audit.rb +38 -36
  8. data/lib/challah/authenticators/api_key.rb +4 -2
  9. data/lib/challah/authenticators/password.rb +3 -1
  10. data/lib/challah/authenticators.rb +5 -3
  11. data/lib/challah/concerns/authorizeable.rb +4 -0
  12. data/lib/challah/concerns/user/attributeable.rb +35 -33
  13. data/lib/challah/concerns/user/authenticateable.rb +2 -0
  14. data/lib/challah/concerns/user/authorizable.rb +16 -12
  15. data/lib/challah/concerns/user/findable.rb +13 -10
  16. data/lib/challah/concerns/user/passwordable.rb +5 -3
  17. data/lib/challah/concerns/user/provideable.rb +22 -20
  18. data/lib/challah/concerns/user/statusable.rb +3 -21
  19. data/lib/challah/concerns/user/validateable.rb +3 -1
  20. data/lib/challah/concerns/userable.rb +1 -3
  21. data/lib/challah/controller.rb +69 -65
  22. data/lib/challah/cookie_store.rb +7 -5
  23. data/lib/challah/encrypter.rb +4 -2
  24. data/lib/challah/engine.rb +5 -18
  25. data/lib/challah/providers/password_provider.rb +9 -7
  26. data/lib/challah/providers.rb +3 -1
  27. data/lib/challah/random.rb +6 -4
  28. data/lib/challah/routes.rb +6 -6
  29. data/lib/challah/session.rb +27 -25
  30. data/lib/challah/signup.rb +5 -3
  31. data/lib/challah/simple_cookie_store.rb +82 -80
  32. data/lib/challah/techniques/api_key_technique.rb +2 -2
  33. data/lib/challah/techniques/password_technique.rb +2 -1
  34. data/lib/challah/techniques/token_technique.rb +1 -1
  35. data/lib/challah/techniques.rb +2 -0
  36. data/lib/challah/test.rb +6 -0
  37. data/lib/challah/validators/email_validator.rb +2 -0
  38. data/lib/challah/validators/password_validator.rb +5 -3
  39. data/lib/challah/version.rb +3 -1
  40. data/lib/challah.rb +2 -5
  41. data/lib/generators/challah_generator.rb +2 -8
  42. data/lib/generators/templates/{migration.rb → migration.erb} +3 -6
  43. metadata +42 -19
  44. data/lib/challah/plugins.rb +0 -54
@@ -1,20 +1,21 @@
1
1
  module Challah
2
2
  class PasswordProvider
3
+
3
4
  def self.save(user)
4
5
  set(uid: user.username, token: user.password, user_id: user.id, authorization: user.class.authorization_model)
5
6
  end
6
7
 
7
8
  def self.set(options = {})
8
9
  user_id = options.fetch(:user_id)
9
- uid = options.fetch(:uid, '')
10
- token = options.fetch(:token, '')
10
+ uid = options.fetch(:uid, "")
11
+ token = options.fetch(:token, "")
11
12
  auth_model = options.fetch(:authorization, ::Authorization)
12
13
 
13
14
  if token.to_s.blank?
14
- authorization = auth_model.get({
15
+ authorization = auth_model.get(
15
16
  user_id: user_id,
16
17
  provider: :password
17
- })
18
+ )
18
19
 
19
20
  if authorization
20
21
  token = authorization.token
@@ -23,12 +24,12 @@ module Challah
23
24
  token = Challah::Encrypter.encrypt(token)
24
25
  end
25
26
 
26
- auth_model.set({
27
+ auth_model.set(
27
28
  provider: :password,
28
29
  user_id: user_id,
29
30
  uid: uid,
30
31
  token: token
31
- })
32
+ )
32
33
  end
33
34
 
34
35
  def self.valid?(record)
@@ -36,5 +37,6 @@ module Challah
36
37
  password_validator.new(force: true).validate(record)
37
38
  record.errors[:password].size.zero?
38
39
  end
40
+
39
41
  end
40
- end
42
+ end
@@ -1,5 +1,6 @@
1
1
  module Challah
2
2
  module Providers
3
+
3
4
  # Get a list of all authorization providers other than password provider
4
5
  def custom_providers
5
6
  providers.reject { |k, v| k == :password }
@@ -18,5 +19,6 @@ module Challah
18
19
  def providers
19
20
  @providers.dup
20
21
  end
22
+
21
23
  end
22
- end
24
+ end
@@ -2,17 +2,19 @@ module Challah
2
2
  # Random string class, uses ActiveSupport's SecureRandom if possible, otherwise gives a fairly
3
3
  # secure random string
4
4
  class Random
5
+
5
6
  # Returns a random string for use as a token at the given length.
6
7
  def self.token(length = 30)
7
- return SecureRandom.hex(length/2) if secure_random?
8
+ return SecureRandom.hex(length / 2) if secure_random?
8
9
 
9
- c = [(0..9),('a'..'z'),('A'..'Z')].map {|i| i.to_a }.flatten
10
- (1..length).map{ c[rand(c.length)] }.join
10
+ c = [(0..9), ("a".."z"), ("A".."Z")].map { |i| i.to_a }.flatten
11
+ (1..length).map { c[rand(c.length)] }.join
11
12
  end
12
13
 
13
14
  # Is ActiveSupport::SecureRandom available. If so, we'll use it.
14
15
  def self.secure_random?
15
16
  defined?(::SecureRandom)
16
17
  end
18
+
17
19
  end
18
- end
20
+ end
@@ -1,11 +1,11 @@
1
1
  Rails.application.routes.draw do
2
2
  unless Challah.options[:skip_routes]
3
- post '/sign-in', to: 'sessions#create', as: 'authenticate'
4
- get '/sign-in', to: 'sessions#new', as: 'signin'
5
- get '/sign-out', to: 'sessions#destroy', as: 'signout'
3
+ post "/sign-in", to: "sessions#create", as: "authenticate"
4
+ get "/sign-in", to: "sessions#new", as: "signin"
5
+ get "/sign-out", to: "sessions#destroy", as: "signout"
6
6
 
7
- post '/login', to: 'sessions#create', as: 'submit_login'
8
- get '/login', to: 'sessions#new', as: 'login'
9
- get '/logout', to: 'sessions#destroy', as: 'logout'
7
+ post "/login", to: "sessions#create", as: "submit_login"
8
+ get "/login", to: "sessions#new", as: "login"
9
+ get "/logout", to: "sessions#destroy", as: "logout"
10
10
  end
11
11
  end
@@ -1,5 +1,6 @@
1
1
  module Challah
2
2
  class Session
3
+
3
4
  extend ActiveModel::Naming
4
5
  include ActiveModel::Conversion
5
6
 
@@ -34,7 +35,7 @@ module Challah
34
35
  end
35
36
 
36
37
  def inspect
37
- "#<Session:0x#{object_id.to_s(16)} valid=#{valid?} store=#{self.store.inspect} user=#{user_id || 'nil'}>"
38
+ "#<Session:0x#{ object_id.to_s(16) } valid=#{ valid? } store=#{ self.store.inspect } user=#{ user_id || 'nil' }>"
38
39
  end
39
40
 
40
41
  def persist?
@@ -43,7 +44,7 @@ module Challah
43
44
 
44
45
  def read
45
46
  persistence_token, user_id = self.store.read
46
- return false if persistence_token.nil? or user_id.nil?
47
+ return false if persistence_token.nil? || user_id.nil?
47
48
 
48
49
  store_user = nil
49
50
 
@@ -53,7 +54,7 @@ module Challah
53
54
  nil
54
55
  end
55
56
 
56
- if store_user and store_user.valid_session? and store_user.persistence_token == persistence_token
57
+ if store_user && store_user.valid_session? && (store_user.persistence_token == persistence_token)
57
58
  if store_user.valid_session?
58
59
  self.user = store_user
59
60
  @valid = true
@@ -66,7 +67,7 @@ module Challah
66
67
  def save
67
68
  return false unless valid?
68
69
 
69
- if self.user and persist?
70
+ if self.user && persist?
70
71
  self.store.save(self.user.persistence_token, user_id)
71
72
  return true
72
73
  end
@@ -90,7 +91,7 @@ module Challah
90
91
  # Returns true if this session has been authenticated and is ready to save.
91
92
  def valid?
92
93
  return @valid if @valid != nil
93
- return true if self.user and self.user.valid_session?
94
+ return true if self.user && self.user.valid_session?
94
95
  authenticate!
95
96
  end
96
97
 
@@ -126,7 +127,7 @@ module Challah
126
127
  end
127
128
  end
128
129
 
129
- if user_record and user_record.valid_session?
130
+ if user_record && user_record.valid_session?
130
131
  session.user = user_record
131
132
  session.persist = true
132
133
  end
@@ -157,32 +158,33 @@ module Challah
157
158
 
158
159
  protected
159
160
 
160
- # Try and authenticate against the various auth techniques. If one
161
- # technique works, then just exit and make the session active.
162
- def authenticate!
163
- Challah.techniques.values.each do |klass|
164
- technique = klass.new(self)
165
- technique.user_model = user_model if technique.respond_to?(:"user_model=")
161
+ # Try and authenticate against the various auth techniques. If one
162
+ # technique works, then just exit and make the session active.
163
+ def authenticate!
164
+ Challah.techniques.values.each do |klass|
165
+ technique = klass.new(self)
166
+ technique.user_model = user_model if technique.respond_to?(:"user_model=")
166
167
 
167
- @user = technique.authenticate
168
+ @user = technique.authenticate
168
169
 
169
- if @user
170
- @persist = technique.respond_to?(:persist?) ? technique.persist? : false
171
- break
170
+ if @user
171
+ @persist = technique.respond_to?(:persist?) ? technique.persist? : false
172
+ break
173
+ end
172
174
  end
173
- end
174
175
 
175
- if @user
176
- # Only update user record if persistence is on for the technique.
177
- # Otherwise this builds up quick (one session for each API call)
178
- if @persist
179
- @user.successful_authentication!(ip)
176
+ if @user
177
+ # Only update user record if persistence is on for the technique.
178
+ # Otherwise this builds up quick (one session for each API call)
179
+ if @persist
180
+ @user.successful_authentication!(ip)
181
+ end
182
+
183
+ return @valid = true
180
184
  end
181
185
 
182
- return @valid = true
186
+ @valid = false
183
187
  end
184
188
 
185
- @valid = false
186
- end
187
189
  end
188
190
  end
@@ -1,5 +1,6 @@
1
1
  module Challah
2
2
  class Signup
3
+
3
4
  extend ActiveModel::Naming
4
5
  include ActiveModel::Conversion
5
6
 
@@ -17,7 +18,7 @@ module Challah
17
18
  return unless Hash === value
18
19
 
19
20
  value.each do |key, value|
20
- self.send("#{key}=", value)
21
+ self.send("#{ key }=", value)
21
22
  end
22
23
  end
23
24
 
@@ -60,7 +61,7 @@ module Challah
60
61
  user.errors.each { |a, e| @errors.add(a, e) }
61
62
  end
62
63
 
63
- if !provider or !valid_provider?
64
+ if !provider || !valid_provider?
64
65
  result = false
65
66
  user.errors.each { |a, e| @errors.add(a, e) unless @errors.added?(a, e) }
66
67
  end
@@ -71,5 +72,6 @@ module Challah
71
72
  def self.model_name
72
73
  ActiveModel::Name.new(Challah::Signup, Challah, "Signup")
73
74
  end
75
+
74
76
  end
75
- end
77
+ end
@@ -4,6 +4,7 @@ module Challah
4
4
  # To use a different storage method for persisting a session, just create
5
5
  # a new class that responds to +read+, +save+ and +destroy+
6
6
  class SimpleCookieStore
7
+
7
8
  def initialize(session)
8
9
  @session = session
9
10
  end
@@ -13,7 +14,7 @@ module Challah
13
14
  end
14
15
 
15
16
  def inspect
16
- "#<SimpleCookieStore:0x#{object_id.to_s(16)} valid=#{existing?}>"
17
+ "#<SimpleCookieStore:0x#{ object_id.to_s(16) } valid=#{ existing? }>"
17
18
  end
18
19
 
19
20
  def read
@@ -29,107 +30,108 @@ module Challah
29
30
 
30
31
  private
31
32
 
32
- def clear
33
- cookies.delete(session_cookie_name, domain: domain)
34
- cookies.delete(validation_cookie_name, domain: domain)
35
- end
33
+ def clear
34
+ cookies.delete(session_cookie_name, domain: domain)
35
+ cookies.delete(validation_cookie_name, domain: domain)
36
+ end
36
37
 
37
- def cookie_values
38
- session_cookie && session_cookie.to_s.split(joiner)
39
- end
38
+ def cookie_values
39
+ session_cookie && session_cookie.to_s.split(joiner)
40
+ end
40
41
 
41
- def cookies
42
- request.cookie_jar
43
- end
42
+ def cookies
43
+ request.cookie_jar
44
+ end
44
45
 
45
- def default_cookie_prefix
46
- Challah.options[:cookie_prefix]
47
- end
46
+ def default_cookie_prefix
47
+ Challah.options[:cookie_prefix]
48
+ end
48
49
 
49
- def domain
50
- request.session_options[:domain]
51
- end
50
+ def domain
51
+ request.session_options[:domain]
52
+ end
52
53
 
53
- # Do the cookies exist, and are they valid?
54
- def existing?
55
- exists = false
54
+ # Do the cookies exist, and are they valid?
55
+ def existing?
56
+ exists = false
56
57
 
57
- if session_cookie and validation_cookie
58
- session_tmp = session_cookie.to_s
59
- validation_tmp = validation_cookie.to_s
58
+ if session_cookie && validation_cookie
59
+ session_tmp = session_cookie.to_s
60
+ validation_tmp = validation_cookie.to_s
60
61
 
61
- if validation_tmp == validation_cookie_value(session_tmp)
62
- exists = true
62
+ if validation_tmp == validation_cookie_value(session_tmp)
63
+ exists = true
64
+ end
63
65
  end
66
+
67
+ exists
64
68
  end
65
69
 
66
- exists
67
- end
70
+ def expiration
71
+ @expiration ||= 1.month.from_now
72
+ end
68
73
 
69
- def expiration
70
- @expiration ||= 1.month.from_now
71
- end
74
+ def joiner
75
+ "@"
76
+ end
72
77
 
73
- def joiner
74
- '@'
75
- end
78
+ def prefix
79
+ @prefix ||= [ default_cookie_prefix, user_model_id ].compact.join("-")
80
+ end
76
81
 
77
- def prefix
78
- @prefix ||= [ default_cookie_prefix, user_model_id ].compact.join('-')
79
- end
82
+ def request
83
+ raise "No Request Provided" unless @session && @session.request
84
+ @session.request
85
+ end
80
86
 
81
- def request
82
- raise "No Request Provided" unless @session and @session.request
83
- @session.request
84
- end
87
+ def session_cookie
88
+ cookies[session_cookie_name]
89
+ end
85
90
 
86
- def session_cookie
87
- cookies[session_cookie_name]
88
- end
91
+ def session_cookie_name
92
+ "#{ prefix }-s"
93
+ end
89
94
 
90
- def session_cookie_name
91
- "#{prefix}-s"
92
- end
95
+ def session_cookie_value
96
+ "#@token#{ joiner }#@user_id"
97
+ end
93
98
 
94
- def session_cookie_value
95
- "#@token#{joiner}#@user_id"
96
- end
99
+ def user_model_id
100
+ if @session && @session.user_model && @session.user_model.table_name != "users"
101
+ Encrypter.md5(@session.user_model.table_name).slice(0..5)
102
+ end
103
+ end
97
104
 
98
- def user_model_id
99
- if @session && @session.user_model && @session.user_model.table_name != 'users'
100
- Encrypter.md5(@session.user_model.table_name).slice(0..5)
105
+ def validation_cookie
106
+ cookies[validation_cookie_name]
101
107
  end
102
- end
103
108
 
104
- def validation_cookie
105
- cookies[validation_cookie_name]
106
- end
109
+ def validation_cookie_name
110
+ "#{ prefix }-v"
111
+ end
107
112
 
108
- def validation_cookie_name
109
- "#{prefix}-v"
110
- end
113
+ def validation_cookie_value(value = nil)
114
+ value = session_cookie_value unless value
115
+ Encrypter.md5(value)
116
+ end
111
117
 
112
- def validation_cookie_value(value = nil)
113
- value = session_cookie_value unless value
114
- Encrypter.md5(value)
115
- end
118
+ def write_cookies!
119
+ cookies[session_cookie_name] = {
120
+ value: session_cookie_value,
121
+ expires: expiration,
122
+ secure: false,
123
+ httponly: true,
124
+ domain: domain
125
+ }
126
+
127
+ cookies[validation_cookie_name] = {
128
+ value: validation_cookie_value,
129
+ expires: expiration,
130
+ secure: false,
131
+ httponly: true,
132
+ domain: domain
133
+ }
134
+ end
116
135
 
117
- def write_cookies!
118
- cookies[session_cookie_name] = {
119
- value: session_cookie_value,
120
- expires: expiration,
121
- secure: false,
122
- httponly: true,
123
- domain: domain
124
- }
125
-
126
- cookies[validation_cookie_name] = {
127
- value: validation_cookie_value,
128
- expires: expiration,
129
- secure: false,
130
- httponly: true,
131
- domain: domain
132
- }
133
- end
134
136
  end
135
137
  end