merbful_authentication 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +25 -0
- data/README +69 -0
- data/Rakefile +35 -0
- data/TODO +5 -0
- data/activerecord_generators/merbful_authentication_model/merbful_authentication_model_generator.rb +65 -0
- data/activerecord_generators/merbful_authentication_model/templates/authenticated_system_orm_map.rb +34 -0
- data/activerecord_generators/merbful_authentication_model/templates/migration.rb +20 -0
- data/activerecord_generators/merbful_authentication_model/templates/model.rb +63 -0
- data/datamapper_generators/merbful_authentication_model/merbful_authentication_model_generator.rb +60 -0
- data/datamapper_generators/merbful_authentication_model/templates/authenticated_system_orm_map.rb +34 -0
- data/datamapper_generators/merbful_authentication_model/templates/model.rb +78 -0
- data/lib/merbful_authentication.rb +10 -0
- data/lib/merbful_authentication/merbtasks.rb +6 -0
- data/merb_generators/authentication/USAGE +5 -0
- data/merb_generators/authentication/authentication_generator.rb +256 -0
- data/merb_generators/authentication/templates/activation.html.erb +1 -0
- data/merb_generators/authentication/templates/activation.text.erb +1 -0
- data/merb_generators/authentication/templates/authenticated_system_controller.rb +132 -0
- data/merb_generators/authentication/templates/authenticated_system_model.rb +97 -0
- data/merb_generators/authentication/templates/login.html.erb +14 -0
- data/merb_generators/authentication/templates/mail_controller.rb +13 -0
- data/merb_generators/authentication/templates/model_controller.rb +33 -0
- data/merb_generators/authentication/templates/new_model.html.erb +18 -0
- data/merb_generators/authentication/templates/session_controller.rb +33 -0
- data/merb_generators/authentication/templates/signup.html.erb +8 -0
- data/merb_generators/authentication/templates/signup.text.erb +8 -0
- data/rspec_generators/merbful_authentication_tests/merbful_authentication_tests_generator.rb +83 -0
- data/rspec_generators/merbful_authentication_tests/templates/authenticated_system_spec_helper.rb +22 -0
- data/rspec_generators/merbful_authentication_tests/templates/model_controller_spec.rb +78 -0
- data/rspec_generators/merbful_authentication_tests/templates/model_spec.rb +357 -0
- data/rspec_generators/merbful_authentication_tests/templates/model_spec_helper.rb +8 -0
- data/rspec_generators/merbful_authentication_tests/templates/session_controller_spec.rb +101 -0
- data/rspec_generators/merbful_authentication_tests/templates/user_mailer_spec.rb +70 -0
- data/test_unit_generators/merbful_authentication_tests/USAGE +5 -0
- data/test_unit_generators/merbful_authentication_tests/merbful_authentication_tests_generator.rb +84 -0
- data/test_unit_generators/merbful_authentication_tests/templates/authenticated_system_test_helper.rb +50 -0
- data/test_unit_generators/merbful_authentication_tests/templates/functional_test.rb +92 -0
- data/test_unit_generators/merbful_authentication_tests/templates/mailer_test.rb +66 -0
- data/test_unit_generators/merbful_authentication_tests/templates/model_functional_test.rb +92 -0
- data/test_unit_generators/merbful_authentication_tests/templates/model_test_helper.rb +8 -0
- data/test_unit_generators/merbful_authentication_tests/templates/unit_test.rb +142 -0
- metadata +114 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
# make sure we're running inside Merb
|
2
|
+
if defined?(Merb::Plugins)
|
3
|
+
|
4
|
+
# Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
|
5
|
+
Merb::Plugins.config[:merbful_authentication] = {
|
6
|
+
:chickens => false
|
7
|
+
}
|
8
|
+
|
9
|
+
Merb::Plugins.add_rakefiles "merbful_authentication/merbtasks"
|
10
|
+
end
|
@@ -0,0 +1,256 @@
|
|
1
|
+
require 'merb'
|
2
|
+
class AuthenticationGenerator < RubiGen::Base
|
3
|
+
|
4
|
+
default_options :author => nil
|
5
|
+
|
6
|
+
attr_reader :name,
|
7
|
+
:class_name,
|
8
|
+
:class_path,
|
9
|
+
:file_name,
|
10
|
+
:class_nesting,
|
11
|
+
:class_nesting_depth,
|
12
|
+
:plural_name,
|
13
|
+
:singular_name,
|
14
|
+
:controller_name,
|
15
|
+
:controller_class_path,
|
16
|
+
:controller_file_path,
|
17
|
+
:controller_class_nesting,
|
18
|
+
:controller_class_nesting_depth,
|
19
|
+
:controller_class_name,
|
20
|
+
:controller_singular_name,
|
21
|
+
:controller_plural_name
|
22
|
+
alias_method :controller_file_name, :controller_singular_name
|
23
|
+
alias_method :controller_table_name, :controller_plural_name
|
24
|
+
attr_reader :model_controller_name,
|
25
|
+
:model_controller_class_path,
|
26
|
+
:model_controller_file_path,
|
27
|
+
:model_controller_class_nesting,
|
28
|
+
:model_controller_class_nesting_depth,
|
29
|
+
:model_controller_class_name,
|
30
|
+
:model_controller_singular_name,
|
31
|
+
:model_controller_plural_name
|
32
|
+
alias_method :model_controller_file_name, :model_controller_singular_name
|
33
|
+
alias_method :model_controller_table_name, :model_controller_plural_name
|
34
|
+
attr_reader :include_activation
|
35
|
+
|
36
|
+
def initialize(runtime_args, runtime_options = {})
|
37
|
+
usage if runtime_args.empty?
|
38
|
+
super
|
39
|
+
extract_options
|
40
|
+
assign_names!(runtime_args.shift)
|
41
|
+
@include_activation = options[:include_activation]
|
42
|
+
|
43
|
+
@controller_name = runtime_args.shift || 'sessions'
|
44
|
+
@model_controller_name = @name.pluralize
|
45
|
+
@mailer_controller_name = @name
|
46
|
+
|
47
|
+
# sessions controller
|
48
|
+
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
|
49
|
+
@controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
|
50
|
+
|
51
|
+
if @controller_class_nesting.empty?
|
52
|
+
@controller_class_name = @controller_class_name_without_nesting
|
53
|
+
else
|
54
|
+
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# model controller
|
58
|
+
base_name, @model_controller_class_path, @model_controller_file_path, @model_controller_class_nesting, @model_controller_class_nesting_depth = extract_modules(@model_controller_name)
|
59
|
+
@model_controller_class_name_without_nesting, @model_controller_singular_name, @model_controller_plural_name = inflect_names(base_name)
|
60
|
+
|
61
|
+
if @model_controller_class_nesting.empty?
|
62
|
+
@model_controller_class_name = @model_controller_class_name_without_nesting
|
63
|
+
else
|
64
|
+
@model_controller_class_name = "#{@model_controller_class_nesting}::#{@model_controller_class_name_without_nesting}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def manifest
|
69
|
+
manifest_result = record do |m|
|
70
|
+
# Check for class naming collisions.
|
71
|
+
m.class_collisions controller_class_path, "#{controller_class_name}", # Sessions Controller
|
72
|
+
"Merb::#{controller_class_name}Helper"
|
73
|
+
m.class_collisions model_controller_class_path, "#{model_controller_class_name}", # Model Controller
|
74
|
+
"Merb::#{model_controller_class_name}Helper"
|
75
|
+
m.class_collisions class_path, "#{class_name}", "#{class_name}Mailer"# , "#{class_name}MailerTest", "#{class_name}Observer"
|
76
|
+
m.class_collisions [], 'AuthenticatedSystem::Controller', 'AuthenticatedSystem::Model'
|
77
|
+
|
78
|
+
# Controller, helper, views, and test directories.
|
79
|
+
|
80
|
+
m.directory File.join('app/controllers', controller_class_path)
|
81
|
+
m.directory File.join('app/controllers', model_controller_class_path)
|
82
|
+
|
83
|
+
m.directory File.join('app/helpers', controller_class_path)
|
84
|
+
m.directory File.join('app/views', controller_class_path, controller_file_name)
|
85
|
+
|
86
|
+
m.directory File.join('app/controllers', model_controller_class_path)
|
87
|
+
m.directory File.join('app/helpers', model_controller_class_path)
|
88
|
+
m.directory File.join('app/views', model_controller_class_path, model_controller_file_name)
|
89
|
+
|
90
|
+
# Generate the authenticated system" libraries
|
91
|
+
m.directory "lib"
|
92
|
+
m.template "authenticated_system_controller.rb", "lib/authenticated_system_controller.rb"
|
93
|
+
m.template "authenticated_system_model.rb", "lib/authenticated_system_model.rb"
|
94
|
+
|
95
|
+
# Mailer directory for activation
|
96
|
+
if options[:include_activation]
|
97
|
+
m.directory File.join('app/mailers/views', "#{singular_name}_mailer")
|
98
|
+
m.template "mail_controller.rb", File.join('app/mailers',
|
99
|
+
"#{singular_name}_mailer.rb")
|
100
|
+
[:html, :text].each do |format|
|
101
|
+
[:signup, :activation].each do |action|
|
102
|
+
m.template "#{action}.#{format}.erb", File.join('app/mailers/views',
|
103
|
+
"#{singular_name}_mailer",
|
104
|
+
"#{action}_notification.#{format}.erb")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Generate the model
|
110
|
+
model_attributes = {
|
111
|
+
:class_name => class_name,
|
112
|
+
:class_path => class_path,
|
113
|
+
:file_name => file_name,
|
114
|
+
:class_nesting => class_nesting,
|
115
|
+
:class_nesting_depth => class_nesting_depth,
|
116
|
+
:plural_name => plural_name,
|
117
|
+
:singular_name => singular_name,
|
118
|
+
:include_activation => options[:include_activation]
|
119
|
+
}
|
120
|
+
m.dependency "merbful_authentication_model", [name], model_attributes
|
121
|
+
|
122
|
+
# Generate the sessions controller
|
123
|
+
m.template "session_controller.rb", File.join('app/controllers',
|
124
|
+
controller_class_path,
|
125
|
+
"#{controller_file_name}.rb")
|
126
|
+
|
127
|
+
# Generate the model controller
|
128
|
+
m.template "model_controller.rb", File.join('app/controllers',
|
129
|
+
model_controller_class_path,
|
130
|
+
"#{model_controller_file_name}.rb")
|
131
|
+
|
132
|
+
# Controller templates
|
133
|
+
m.template 'login.html.erb', File.join('app/views', controller_class_path, controller_file_name, "new.html.erb")
|
134
|
+
m.template 'new_model.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.html.erb")
|
135
|
+
|
136
|
+
|
137
|
+
controller_attributes = {
|
138
|
+
:controller_name => controller_name,
|
139
|
+
:controller_class_path => controller_class_path,
|
140
|
+
:controller_file_path => controller_file_path,
|
141
|
+
:controller_class_nesting => controller_class_nesting,
|
142
|
+
:controller_class_nesting_depth => controller_class_nesting_depth,
|
143
|
+
:controller_class_name => controller_class_name,
|
144
|
+
:controller_singular_name => controller_singular_name,
|
145
|
+
:controller_plural_name => controller_plural_name,
|
146
|
+
:model_controller_name => model_controller_name,
|
147
|
+
:model_controller_class_path => model_controller_class_path,
|
148
|
+
:model_controller_file_path => model_controller_file_path,
|
149
|
+
:model_controller_class_nesting => model_controller_class_nesting,
|
150
|
+
:model_controller_class_nesting_depth => model_controller_class_nesting_depth,
|
151
|
+
:model_controller_class_name => model_controller_class_name,
|
152
|
+
:model_controller_singular_name => model_controller_singular_name,
|
153
|
+
:model_controller_plural_name => model_controller_plural_name,
|
154
|
+
:include_activation => options[:include_activation]
|
155
|
+
}
|
156
|
+
# Generate the tests
|
157
|
+
m.dependency "merbful_authentication_tests", [name], model_attributes.dup.merge!(controller_attributes)
|
158
|
+
end
|
159
|
+
|
160
|
+
action = nil
|
161
|
+
action = $0.split("/")[1]
|
162
|
+
case action
|
163
|
+
when 'generate'
|
164
|
+
puts finishing_message
|
165
|
+
when 'destroy'
|
166
|
+
puts "Thanx for using merbful_authentication"
|
167
|
+
end
|
168
|
+
|
169
|
+
manifest_result
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
protected
|
174
|
+
# Override with your own usage banner.
|
175
|
+
def banner
|
176
|
+
out = <<-EOD;
|
177
|
+
Usage: #{$0} authenticated ModelName [ControllerName]
|
178
|
+
EOD
|
179
|
+
end
|
180
|
+
|
181
|
+
def add_options!(opt)
|
182
|
+
opt.separator ''
|
183
|
+
opt.separator 'Options:'
|
184
|
+
opt.on("--skip-migration",
|
185
|
+
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
|
186
|
+
opt.on("--include-activation",
|
187
|
+
"Generate signup 'activation code' confirmation via email") { |v| options[:include_activation] = true }
|
188
|
+
end
|
189
|
+
|
190
|
+
def extract_options
|
191
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
192
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
193
|
+
# raw instance variable value.
|
194
|
+
# @author = options[:author]
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# Borrowed from RailsGenerators
|
199
|
+
# Extract modules from filesystem-style or ruby-style path:
|
200
|
+
# good/fun/stuff
|
201
|
+
# Good::Fun::Stuff
|
202
|
+
# produce the same results.
|
203
|
+
def extract_modules(name)
|
204
|
+
modules = name.include?('/') ? name.split('/') : name.split('::')
|
205
|
+
name = modules.pop
|
206
|
+
path = modules.map { |m| m.underscore }
|
207
|
+
file_path = (path + [name.underscore]).join('/')
|
208
|
+
nesting = modules.map { |m| m.camelize }.join('::')
|
209
|
+
[name, path, file_path, nesting, modules.size]
|
210
|
+
end
|
211
|
+
|
212
|
+
def inflect_names(name)
|
213
|
+
camel = name.camelize
|
214
|
+
under = camel.underscore
|
215
|
+
plural = under.pluralize
|
216
|
+
[camel, under, plural]
|
217
|
+
end
|
218
|
+
|
219
|
+
def assign_names!(name)
|
220
|
+
@name = name
|
221
|
+
base_name, @class_path, @file_name, @class_nesting, @class_nesting_depth = extract_modules(@name)
|
222
|
+
@class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
|
223
|
+
@table_name = @name.pluralize
|
224
|
+
# @table_name = (!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names) ? plural_name : singular_name
|
225
|
+
@table_name.gsub! '/', '_'
|
226
|
+
if @class_nesting.empty?
|
227
|
+
@class_name = @class_name_without_nesting
|
228
|
+
else
|
229
|
+
@table_name = @class_nesting.underscore << "_" << @table_name
|
230
|
+
@class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def finishing_message
|
237
|
+
output = <<-EOD
|
238
|
+
#{"-" * 70}
|
239
|
+
Don't forget to:
|
240
|
+
|
241
|
+
- add named routes for authentication. These are currently required
|
242
|
+
In config/router.rb
|
243
|
+
|
244
|
+
r.resources :#{plural_name}
|
245
|
+
r.match("/login").to(:controller => "#{controller_class_name}", :action => "create").name(:login)
|
246
|
+
r.match("/logout").to(:controller => "#{controller_class_name}", :action => "destroy").name(:logout)
|
247
|
+
EOD
|
248
|
+
if options[:include_activation]
|
249
|
+
output << " r.match(\"/#{plural_name}/activate/:activation_code\").to(:controller => \"#{model_controller_class_name}\", :action => \"activate\").name(:#{singular_name}_activation)"
|
250
|
+
end
|
251
|
+
|
252
|
+
output << "\n\n" << ("-" * 70)
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Your email has been authenticated <%%= @<%= singular_name %>.login %>
|
@@ -0,0 +1 @@
|
|
1
|
+
Your email has been authenticated <%%= @<%= singular_name %>.login %>
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module AuthenticatedSystem
|
2
|
+
module Controller
|
3
|
+
protected
|
4
|
+
# Returns true or false if the <%= singular_name %> is logged in.
|
5
|
+
# Preloads @current_<%= singular_name %> with the <%= singular_name %> model if they're logged in.
|
6
|
+
def logged_in?
|
7
|
+
current_<%= singular_name %> != :false
|
8
|
+
end
|
9
|
+
|
10
|
+
# Accesses the current <%= singular_name %> from the session. Set it to :false if login fails
|
11
|
+
# so that future calls do not hit the database.
|
12
|
+
def current_<%= singular_name %>
|
13
|
+
@current_<%= singular_name %> ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Store the given <%= singular_name %> in the session.
|
17
|
+
def current_<%= singular_name %>=(new_<%= singular_name %>)
|
18
|
+
session[:<%= singular_name %>] = (new_<%= singular_name %>.nil? || new_<%= singular_name %>.is_a?(Symbol)) ? nil : new_<%= singular_name %>.id
|
19
|
+
@current_<%= singular_name %> = new_<%= singular_name %>
|
20
|
+
end
|
21
|
+
|
22
|
+
# Check if the <%= singular_name %> is authorized
|
23
|
+
#
|
24
|
+
# Override this method in your controllers if you want to restrict access
|
25
|
+
# to only a few actions or if you want to check if the <%= singular_name %>
|
26
|
+
# has the correct rights.
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
#
|
30
|
+
# # only allow nonbobs
|
31
|
+
# def authorized?
|
32
|
+
# current_<%= singular_name %>.login != "bob"
|
33
|
+
# end
|
34
|
+
def authorized?
|
35
|
+
logged_in?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Filter method to enforce a login requirement.
|
39
|
+
#
|
40
|
+
# To require logins for all actions, use this in your controllers:
|
41
|
+
#
|
42
|
+
# before_filter :login_required
|
43
|
+
#
|
44
|
+
# To require logins for specific actions, use this in your controllers:
|
45
|
+
#
|
46
|
+
# before_filter :login_required, :only => [ :edit, :update ]
|
47
|
+
#
|
48
|
+
# To skip this in a subclassed controller:
|
49
|
+
#
|
50
|
+
# skip_before_filter :login_required
|
51
|
+
#
|
52
|
+
def login_required
|
53
|
+
authorized? || throw(:halt, :access_denied)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Redirect as appropriate when an access request fails.
|
57
|
+
#
|
58
|
+
# The default action is to redirect to the login screen.
|
59
|
+
#
|
60
|
+
# Override this method in your controllers if you want to have special
|
61
|
+
# behavior in case the <%= singular_name %> is not authorized
|
62
|
+
# to access the requested action. For example, a popup window might
|
63
|
+
# simply close itself.
|
64
|
+
def access_denied
|
65
|
+
case content_type
|
66
|
+
when :html
|
67
|
+
store_location
|
68
|
+
redirect url(:login)
|
69
|
+
when :xml
|
70
|
+
headers["Status"] = "Unauthorized"
|
71
|
+
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
|
72
|
+
set_status(401)
|
73
|
+
render :text => "Couldn't authenticate you"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Store the URI of the current request in the session.
|
78
|
+
#
|
79
|
+
# We can return to this location by calling #redirect_back_or_default.
|
80
|
+
def store_location
|
81
|
+
session[:return_to] = request.uri
|
82
|
+
end
|
83
|
+
|
84
|
+
# Redirect to the URI stored by the most recent store_location call or
|
85
|
+
# to the passed default.
|
86
|
+
def redirect_back_or_default(default)
|
87
|
+
redirect(session[:return_to] || default)
|
88
|
+
session[:return_to] = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Inclusion hook to make #current_<%= singular_name %> and #logged_in?
|
92
|
+
# available as ActionView helper methods.
|
93
|
+
# def self.included(base)
|
94
|
+
# base.send :helper_method, :current_<%= singular_name %>, :logged_in?
|
95
|
+
# end
|
96
|
+
|
97
|
+
# Called from #current_<%= singular_name %>. First attempt to login by the <%= singular_name %> id stored in the session.
|
98
|
+
def login_from_session
|
99
|
+
self.current_<%= singular_name %> = <%= class_name %>.find_authenticated_model_with_id(session[:<%= singular_name %>]) if session[:<%= singular_name %>]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Called from #current_<%= singular_name %>. Now, attempt to login by basic authentication information.
|
103
|
+
def login_from_basic_auth
|
104
|
+
<%= singular_name %>name, passwd = get_auth_data
|
105
|
+
self.current_<%= singular_name %> = <%= class_name %>.authenticate(<%= singular_name %>name, passwd) if <%= singular_name %>name && passwd
|
106
|
+
end
|
107
|
+
|
108
|
+
# Called from #current_<%= singular_name %>. Finaly, attempt to login by an expiring token in the cookie.
|
109
|
+
def login_from_cookie
|
110
|
+
<%= singular_name %> = cookies[:auth_token] && <%= class_name %>.find_authenticated_model_with_remember_token(cookies[:auth_token])
|
111
|
+
if <%= singular_name %> && <%= singular_name %>.remember_token?
|
112
|
+
<%= singular_name %>.remember_me
|
113
|
+
cookies[:auth_token] = { :value => <%= singular_name %>.remember_token, :expires => <%= singular_name %>.remember_token_expires_at }
|
114
|
+
self.current_<%= singular_name %> = <%= singular_name %>
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def reset_session
|
119
|
+
session.data.each{|k,v| session.data.delete(k)}
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
@@http_auth_headers = %w(Authorization HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION)
|
124
|
+
|
125
|
+
# gets BASIC auth info
|
126
|
+
def get_auth_data
|
127
|
+
auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
|
128
|
+
auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
|
129
|
+
return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'authenticated_system_orm_map'
|
2
|
+
module AuthenticatedSystem
|
3
|
+
module Model
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
base.send(:extend, ClassMethods)
|
8
|
+
base.send(:extend, AuthenticatedSystem::OrmMap )
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def authenticated?(password)
|
13
|
+
crypted_password == encrypt(password)
|
14
|
+
end
|
15
|
+
|
16
|
+
# before filter
|
17
|
+
def encrypt_password
|
18
|
+
return if password.blank?
|
19
|
+
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
|
20
|
+
self.crypted_password = encrypt(password)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Encrypts the password with the <%= singular_name %> salt
|
24
|
+
def encrypt(password)
|
25
|
+
self.class.encrypt(password, salt)
|
26
|
+
end
|
27
|
+
|
28
|
+
def remember_token?
|
29
|
+
remember_token_expires_at && DateTime.now < DateTime.parse(remember_token_expires_at.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
def remember_me_until(time)
|
33
|
+
self.remember_token_expires_at = time
|
34
|
+
self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
|
35
|
+
save
|
36
|
+
end
|
37
|
+
|
38
|
+
def remember_me_for(time)
|
39
|
+
remember_me_until (Time.now + time)
|
40
|
+
end
|
41
|
+
|
42
|
+
# These create and unset the fields required for remembering <%= singular_name %>s between browser closes
|
43
|
+
# Default of 2 weeks
|
44
|
+
def remember_me
|
45
|
+
remember_me_for (Merb::Const::WEEK * 2)
|
46
|
+
end
|
47
|
+
|
48
|
+
def forget_me
|
49
|
+
self.remember_token_expires_at = nil
|
50
|
+
self.remember_token = nil
|
51
|
+
self.save
|
52
|
+
end
|
53
|
+
<% if include_activation -%>
|
54
|
+
# Returns true if the <%= singular_name %> has just been activated.
|
55
|
+
def recently_activated?
|
56
|
+
@activated
|
57
|
+
end
|
58
|
+
|
59
|
+
def activated?
|
60
|
+
return false if self.new_record?
|
61
|
+
!! activation_code.nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
def active?
|
65
|
+
# the existence of an activation code means they have not activated yet
|
66
|
+
activation_code.nil?
|
67
|
+
end
|
68
|
+
<% end %>
|
69
|
+
protected
|
70
|
+
<% if include_activation -%>
|
71
|
+
def make_activation_code
|
72
|
+
self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
|
73
|
+
end
|
74
|
+
<% end -%>
|
75
|
+
|
76
|
+
def password_required?
|
77
|
+
crypted_password.blank? || !password.blank?
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
module ClassMethods
|
83
|
+
# Encrypts some data with the salt.
|
84
|
+
def encrypt(password, salt)
|
85
|
+
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
86
|
+
end
|
87
|
+
|
88
|
+
# Authenticates a <%= singular_name %> by their login name and unencrypted password. Returns the <%= singular_name %> or nil.
|
89
|
+
def authenticate(login, password)
|
90
|
+
u = find_activated_authenticated_model_with_login(login) # need to get the salt
|
91
|
+
u && u.authenticated?(password) ? u : nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|