restful-authentication 1.2.1

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.
Files changed (53) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +227 -0
  3. data/Rakefile +33 -0
  4. data/TODO +15 -0
  5. data/init.rb +5 -0
  6. data/lib/authentication.rb +40 -0
  7. data/lib/authentication/by_cookie_token.rb +82 -0
  8. data/lib/authentication/by_password.rb +65 -0
  9. data/lib/authorization.rb +14 -0
  10. data/lib/authorization/aasm_roles.rb +74 -0
  11. data/lib/authorization/stateful_roles.rb +62 -0
  12. data/lib/generators/authenticated/USAGE +1 -0
  13. data/lib/generators/authenticated/authenticated_generator.rb +524 -0
  14. data/lib/generators/authenticated/templates/_model_partial.html.erb +8 -0
  15. data/lib/generators/authenticated/templates/activation.erb +3 -0
  16. data/lib/generators/authenticated/templates/authenticated_system.rb +189 -0
  17. data/lib/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  18. data/lib/generators/authenticated/templates/controller.rb +41 -0
  19. data/lib/generators/authenticated/templates/features/accounts.feature +109 -0
  20. data/lib/generators/authenticated/templates/features/sessions.feature +134 -0
  21. data/lib/generators/authenticated/templates/features/step_definitions/ra_env.rb +9 -0
  22. data/lib/generators/authenticated/templates/features/step_definitions/ra_navigation_steps.rb +48 -0
  23. data/lib/generators/authenticated/templates/features/step_definitions/ra_resource_steps.rb +178 -0
  24. data/lib/generators/authenticated/templates/features/step_definitions/ra_response_steps.rb +169 -0
  25. data/lib/generators/authenticated/templates/features/step_definitions/rest_auth_features_helper.rb +81 -0
  26. data/lib/generators/authenticated/templates/features/step_definitions/user_steps.rb +131 -0
  27. data/lib/generators/authenticated/templates/helper.rb +2 -0
  28. data/lib/generators/authenticated/templates/login.html.erb +16 -0
  29. data/lib/generators/authenticated/templates/mailer.rb +26 -0
  30. data/lib/generators/authenticated/templates/migration.rb +26 -0
  31. data/lib/generators/authenticated/templates/model.rb +87 -0
  32. data/lib/generators/authenticated/templates/model_controller.rb +83 -0
  33. data/lib/generators/authenticated/templates/model_helper.rb +93 -0
  34. data/lib/generators/authenticated/templates/model_helper_spec.rb +158 -0
  35. data/lib/generators/authenticated/templates/observer.rb +11 -0
  36. data/lib/generators/authenticated/templates/signup.html.erb +19 -0
  37. data/lib/generators/authenticated/templates/signup_notification.erb +8 -0
  38. data/lib/generators/authenticated/templates/site_keys.rb +38 -0
  39. data/lib/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  40. data/lib/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  41. data/lib/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  42. data/lib/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +198 -0
  43. data/lib/generators/authenticated/templates/spec/fixtures/users.yml +60 -0
  44. data/lib/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  45. data/lib/generators/authenticated/templates/spec/models/user_spec.rb +290 -0
  46. data/lib/generators/authenticated/templates/test/functional_test.rb +82 -0
  47. data/lib/generators/authenticated/templates/test/mailer_test.rb +32 -0
  48. data/lib/generators/authenticated/templates/test/model_functional_test.rb +93 -0
  49. data/lib/generators/authenticated/templates/test/unit_test.rb +164 -0
  50. data/lib/tasks/auth.rake +33 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. metadata +105 -0
@@ -0,0 +1,68 @@
1
+ h1. Internal Changes to code
2
+
3
+ As always, this is just a copy-and-pasted version of the CHANGELOG file in the source code tree.
4
+
5
+ h2. Changes for the May, 2008 version of restful-authentication
6
+
7
+ h3. Changes to user model
8
+
9
+ * recently_activated? belongs only if stateful
10
+ * Gave migration a 40-char limit on remember_token & an index on users by login
11
+ * **Much** stricter login and email validation
12
+ * put length constraints in migration too
13
+ * password in 6, 40
14
+ * salt and remember_token now much less predictability
15
+
16
+ h3. Changes to session_controller
17
+
18
+ * use uniform logout function
19
+ * use uniform remember_cookie functions
20
+ * avoid calling logged_in? which will auto-log-you-in (safe in the face of
21
+ logout! call, but idiot-proof)
22
+ * Moved reset_session into only the "now logged in" branch
23
+ ** wherever it goes, it has to be in front of the current_user= call
24
+ ** See more in README-Tradeoffs.txt
25
+ * made a place to take action on failed login attempt
26
+ * recycle login and remember_me setting on failed login
27
+ * nil'ed out the password field in 'new' view
28
+
29
+ h3. Changes to users_controller
30
+
31
+ * use uniform logout function
32
+ * use uniform remember_cookie functions
33
+ * Moved reset_session into only the "now logged in" branch
34
+ ** wherever it goes, it has to be in front of the current_user= call
35
+ ** See more in README-Tradeoffs.txt
36
+ * made the implicit login only happen for non-activationed sites
37
+ * On a failed signup, kick you back to the signin screen (but strip out the password & confirmation)
38
+ * more descriptive error messages in activate()
39
+
40
+ h3. users_helper
41
+
42
+ * link_to_user, link_to_current_user, link_to_signin_with_IP
43
+ * if_authorized(action, resource, &block) view function (with appropriate
44
+ warning)
45
+
46
+ h3. authenticated_system
47
+
48
+ * Made authorized? take optional arguments action=nil, resource=nil, *args
49
+ This makes its signature better match traditional approaches to access control
50
+ eg Reference Monitor in "Security Patterns":http://www.securitypatterns.org/patterns.html)
51
+ * authorized? should be a helper too
52
+ * added uniform logout! methods
53
+ * format.any (as found in access_denied) doesn't work until
54
+ http://dev.rubyonrails.org/changeset/8987 lands.
55
+ * cookies are now refreshed each time we cross the logged out/in barrier, as
56
+ "best":http://palisade.plynt.com/issues/2004Jul/safe-auth-practices/
57
+ "practice":http://www.owasp.org/index.php/Session_Management#Regeneration_of_Session_Tokens
58
+
59
+ h3. Other
60
+
61
+ * Used escapes <%= %> in email templates (among other reasons, so courtenay's
62
+ "'dumbass' test":http://tinyurl.com/684g9t doesn't complain)
63
+ * Added site key to generator, users.yml.
64
+ * Made site key generation idempotent in the most crude and hackish way
65
+ * 100% coverage apart from the stateful code. (needed some access_control
66
+ checks, and the http_auth stuff)
67
+ * Stories!
68
+
@@ -0,0 +1,227 @@
1
+ # "Restful Authentication Generator":http://github.com/technoweenie/restful-authentication
2
+
3
+ This widely-used plugin provides a foundation for securely managing user
4
+ authentication:
5
+ * Login / logout
6
+ * Secure password handling
7
+ * Account activation by validating email
8
+ * Account approval / disabling by admin
9
+ * Rudimentary hooks for authorization and access control.
10
+
11
+ Several features were updated in May, 2008.
12
+ * "Stable newer version":http://github.com/technoweenie/restful-authentication/tree/master
13
+ * "'Classic' (backward-compatible) version":http://github.com/technoweenie/restful-authentication/tree/classic
14
+ * "Experimental version":http://github.com/technoweenie/restful-authentication/tree/modular (Much more modular, needs testing & review)
15
+
16
+ > IMPORTANT: if you upgrade your site, existing user account
17
+ > passwords will stop working unless you use --old-passwords
18
+
19
+ ***************************************************************************
20
+
21
+ ## Issue Tracker
22
+
23
+ Please submit any bugs or annoyances on the lighthouse tracker at
24
+ * "http://rails_security.lighthouseapp.com/projects/15332-restful_authentication/overview":http://rails_security.lighthouseapp.com/projects/15332-restful_authentication/overview
25
+
26
+ For anything simple enough, please github message both maintainers: Rick Olson
27
+ ("technoweenie":http://github.com/technoweenie) and Flip Kromer
28
+ ("mrflip":http://github.com/mrflip).
29
+
30
+ ***************************************************************************
31
+
32
+ ## Documentation
33
+
34
+ This page has notes on
35
+ * "Installation":#INSTALL
36
+ * "New Features":#AWESOME
37
+ * "After installing":#POST-INSTALL
38
+
39
+ See the "wiki":http://github.com/technoweenie/restful-authentication/wikis/home
40
+ (or the notes/ directory) if you want to learn more about:
41
+
42
+ * "Extensions, Addons and Alternatives":addons such as HAML templates
43
+ * "Security Design Patterns":security-patterns with "snazzy diagram":http://github.com/technoweenie/restful-authentication/tree/master/notes/SecurityFramework.png
44
+ * Authentication -- Lets a visitor identify herself (and lay claim to her corresponding Roles and measure of Trust)
45
+ * "Trust Metrics":Trustification -- Confidence we can rely on the outcomes of this visitor's actions.
46
+ * Authorization and Policy -- Based on trust and identity, what actions may this visitor perform?
47
+ * Access Control -- How the Authorization policy is actually enforced in your code (A: hopefully without turning it into a spaghetti of if thens)
48
+ * Rails Plugins for Authentication, Trust, Authorization and Access Control
49
+ * Tradeoffs -- for the paranoid or the curious, a rundown of tradeoffs made in the code
50
+ * CHANGELOG -- Summary of changes to internals
51
+ * TODO -- Ideas for how you can help
52
+
53
+ These best version of the release notes are in the notes/ directory in the
54
+ "source code":http://github.com/technoweenie/restful-authentication/tree/master
55
+ -- look there for the latest version. The wiki versions are taken (manually)
56
+ from there.
57
+
58
+ ***************************************************************************
59
+
60
+ <a id="AWESOME"/> </a>
61
+
62
+ ## Exciting new features
63
+
64
+ ### Stories
65
+
66
+ There are now "Cucumber":http://wiki.github.com/aslakhellesoy/cucumber/home features that allow expressive, enjoyable tests for the
67
+ authentication code. The flexible code for resource testing in stories was
68
+ extended from "Ben Mabey's.":http://www.benmabey.com/2008/02/04/rspec-plain-text-stories-webrat-chunky-bacon/
69
+
70
+ ### Modularize to match security design patterns:
71
+
72
+ * Authentication (currently: password, browser cookie token, HTTP basic)
73
+ * Trust metric (email validation)
74
+ * Authorization (stateful roles)
75
+ * Leave a flexible framework that will play nicely with other access control / policy definition / trust metric plugins
76
+
77
+ ### Other
78
+
79
+ * Added a few helper methods for linking to user pages
80
+ * Uniform handling of logout, remember_token
81
+ * Stricter email, login field validation
82
+ * Minor security fixes -- see CHANGELOG
83
+
84
+ ***************************************************************************
85
+
86
+ ## Non-backwards compatible Changes
87
+
88
+ Here are a few changes in the May 2008 release that increase "Defense in Depth"
89
+ but may require changes to existing accounts
90
+
91
+ * If you have an existing site, none of these changes are compelling enough to
92
+ warrant migrating your userbase.
93
+ * If you are generating for a new site, all of these changes are low-impact.
94
+ You should apply them.
95
+
96
+ ### Passwords
97
+
98
+ The new password encryption (using a site key salt and stretching) will break
99
+ existing user accounts' passwords. We recommend you use the --old-passwords
100
+ option or write a migration tool and submit it as a patch. See the
101
+ [[Tradeoffs]] note for more information.
102
+
103
+ ### Validations
104
+
105
+ By default, email and usernames are validated against a somewhat strict pattern; your users' values may be now illegal. Adjust to suit.
106
+
107
+ ***************************************************************************
108
+
109
+ <a id="INSTALLATION"/> </a>
110
+
111
+ ## Installation
112
+
113
+ This is a basic restful authentication generator for rails, taken from
114
+ acts as authenticated. Currently it requires Rails 1.2.6 or above.
115
+
116
+ **IMPORTANT FOR RAILS > 2.1 USERS** To avoid a @NameError@ exception ("lighthouse tracker ticket":http://rails_security.lighthouseapp.com/projects/15332-restful_authentication/tickets/2-not-a-valid-constant-name-errors#ticket-2-2), check out the code to have an _underscore_ and not _dash_ in its name:
117
+ * either use <code>git clone git://github.com/technoweenie/restful-authentication.git restful_authentication</code>
118
+ * or rename the plugin's directory to be <code>restful_authentication</code> after fetching it.
119
+
120
+ To use the generator:
121
+
122
+ ./script/generate authenticated user sessions \
123
+ --include-activation \
124
+ --stateful \
125
+ --rspec \
126
+ --skip-migration \
127
+ --skip-routes \
128
+ --old-passwords
129
+
130
+ * The first parameter specifies the model that gets created in signup (typically
131
+ a user or account model). A model with migration is created, as well as a
132
+ basic controller with the create method. You probably want to say "User" here.
133
+
134
+ * The second parameter specifies the session controller name. This is the
135
+ controller that handles the actual login/logout function on the site.
136
+ (probably: "Session").
137
+
138
+ * --include-activation: Generates the code for a ActionMailer and its respective
139
+ Activation Code through email.
140
+
141
+ * --stateful: Builds in support for acts_as_state_machine and generates
142
+ activation code. (@--stateful@ implies @--include-activation@). Based on the
143
+ idea at [[http://www.vaporbase.com/postings/stateful_authentication]]. Passing
144
+ @--skip-migration@ will skip the user migration, and @--skip-routes@ will skip
145
+ resource generation -- both useful if you've already run this generator.
146
+ (Needs the "acts_as_state_machine plugin":http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/,
147
+ but new installs should probably run with @--aasm@ instead.)
148
+
149
+ * --aasm: Works the same as stateful but uses the "updated aasm gem":http://github.com/rubyist/aasm/tree/master
150
+
151
+ * --rspec: Generate RSpec tests and Stories in place of standard rails tests.
152
+ This requires the
153
+ "RSpec and Rspec-on-rails plugins":http://rspec.info/
154
+ (make sure you "./script/generate rspec" after installing RSpec.) The rspec
155
+ and story suite are much more thorough than the rails tests, and changes are
156
+ unlikely to be backported.
157
+
158
+ * --old-passwords: Use the older password scheme (see [[#COMPATIBILITY]], above)
159
+
160
+ * --skip-migration: Don't generate a migration file for this model
161
+
162
+ * --skip-routes: Don't generate a resource line in @config/routes.rb@
163
+
164
+ ***************************************************************************
165
+ <a id="POST-INSTALL"/> </a>
166
+
167
+ ## After installing
168
+
169
+ The below assumes a Model named 'User' and a Controller named 'Session'; please
170
+ alter to suit. There are additional security minutae in @notes/README-Tradeoffs@
171
+ -- only the paranoid or the curious need bother, though.
172
+
173
+ * Add these familiar login URLs to your @config/routes.rb@ if you like:
174
+
175
+ <pre><code>
176
+ map.signup '/signup', :controller => 'users', :action => 'new'
177
+ map.login '/login', :controller => 'session', :action => 'new'
178
+ map.logout '/logout', :controller => 'session', :action => 'destroy'
179
+ </code></pre>
180
+
181
+ * With @--include-activation@, also add to your @config/routes.rb@:
182
+
183
+ <pre><code>
184
+ map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate', :activation_code => nil
185
+ </code></pre>
186
+
187
+ and add an observer to @config/environment.rb@:
188
+
189
+ <pre><code>
190
+ config.active_record.observers = :user_observer
191
+ </code></pre>
192
+
193
+ Pay attention, may be this is not an issue for everybody, but if you should
194
+ have problems, that the sent activation_code does match with that in the
195
+ database stored, reload your user object before sending its data through email
196
+ something like:
197
+
198
+ <pre><code>
199
+ class UserObserver < ActiveRecord::Observer
200
+ def after_create(user)
201
+ user.reload
202
+ UserMailer.deliver_signup_notification(user)
203
+ end
204
+ def after_save(user)
205
+ user.reload
206
+ UserMailer.deliver_activation(user) if user.recently_activated?
207
+ end
208
+ end
209
+ </code></pre>
210
+
211
+
212
+ * With @--stateful@, add an observer to config/environment.rb:
213
+
214
+ <pre><code>
215
+ config.active_record.observers = :user_observer
216
+ </code></pre>
217
+
218
+ and modify the users resource line to read
219
+
220
+ map.resources :users, :member => { :suspend => :put,
221
+ :unsuspend => :put,
222
+ :purge => :delete }
223
+
224
+ * If you use a public repository for your code (such as github, rubyforge,
225
+ gitorious, etc.) make sure to NOT post your site_keys.rb (add a line like
226
+ '/config/initializers/site_keys.rb' to your .gitignore or do the svn ignore
227
+ dance), but make sure you DO keep it backed up somewhere safe.
@@ -0,0 +1,33 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'bundler/gem_tasks'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the restful_authentication plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the restful_authentication plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'RestfulAuthentication'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+ gemspec = eval(File.read("#{File.dirname(__FILE__)}/restful-authentication.gemspec"))
27
+ PKG_NAME = gemspec.name
28
+ PKG_VERSION = gemspec.version
29
+
30
+ Rake::GemPackageTask.new(gemspec) do |pkg|
31
+ pkg.need_zip = true
32
+ pkg.need_tar = true
33
+ end
data/TODO ADDED
@@ -0,0 +1,15 @@
1
+
2
+ h3. Authentication security projects for a later date
3
+
4
+
5
+ * Track 'failed logins this hour' and demand a captcha after say 5 failed logins
6
+ ("RECAPTCHA plugin.":http://agilewebdevelopment.com/plugins/recaptcha)
7
+ "De-proxy-ficate IP address": http://wiki.codemongers.com/NginxHttpRealIpModule
8
+
9
+ * Make cookie spoofing a little harder: we set the user's cookie to
10
+ (remember_token), but store digest(remember_token, request_IP). A CSRF cookie
11
+ spoofer has to then at least also spoof the user's originating IP
12
+ (see "Secure Programs HOWTO":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html)
13
+
14
+ * Log HTTP request on authentication / authorization failures
15
+ http://palisade.plynt.com/issues/2004Jul/safe-auth-practices
data/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), "lib", "authorization")
2
+ require File.join(File.dirname(__FILE__), "lib", "authorization", "aasm_roles")
3
+ require File.join(File.dirname(__FILE__), "lib", "authentication")
4
+ require File.join(File.dirname(__FILE__), "lib", "authentication", "by_password")
5
+ require File.join(File.dirname(__FILE__), "lib", "authentication", "by_cookie_token")
@@ -0,0 +1,40 @@
1
+ module Authentication
2
+ mattr_accessor :login_regex, :bad_login_message,
3
+ :name_regex, :bad_name_message,
4
+ :email_name_regex, :domain_head_regex, :domain_tld_regex, :email_regex, :bad_email_message
5
+
6
+ self.login_regex = /\A\w[\w\.\-_@]+\z/ # ASCII, strict
7
+ # self.login_regex = /\A[[:alnum:]][[:alnum:]\.\-_@]+\z/ # Unicode, strict
8
+ # self.login_regex = /\A[^[:cntrl:]\\<>\/&]*\z/ # Unicode, permissive
9
+
10
+ self.bad_login_message = "use only letters, numbers, and .-_@ please.".freeze
11
+
12
+ self.name_regex = /\A[^[:cntrl:]\\<>\/&]*\z/ # Unicode, permissive
13
+ self.bad_name_message = "avoid non-printing characters and \\&gt;&lt;&amp;/ please.".freeze
14
+
15
+ self.email_name_regex = '[\w\.%\+\-]+'.freeze
16
+ self.domain_head_regex = '(?:[A-Z0-9\-]+\.)+'.freeze
17
+ self.domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'.freeze
18
+ self.email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
19
+ self.bad_email_message = "should look like an email address.".freeze
20
+
21
+ def self.included(recipient)
22
+ recipient.extend(ModelClassMethods)
23
+ recipient.class_eval do
24
+ include ModelInstanceMethods
25
+ end
26
+ end
27
+
28
+ module ModelClassMethods
29
+ def secure_digest(*args)
30
+ Digest::SHA1.hexdigest(args.flatten.join('--'))
31
+ end
32
+
33
+ def make_token
34
+ secure_digest(Time.now, (1..10).map{ rand.to_s })
35
+ end
36
+ end # class methods
37
+
38
+ module ModelInstanceMethods
39
+ end # instance methods
40
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Authentication
3
+ module ByCookieToken
4
+ # Stuff directives into including module
5
+ def self.included(recipient)
6
+ recipient.extend(ModelClassMethods)
7
+ recipient.class_eval do
8
+ include ModelInstanceMethods
9
+ end
10
+ end
11
+
12
+ #
13
+ # Class Methods
14
+ #
15
+ module ModelClassMethods
16
+ end # class methods
17
+
18
+ #
19
+ # Instance Methods
20
+ #
21
+ module ModelInstanceMethods
22
+ def remember_token?
23
+ (!remember_token.blank?) &&
24
+ remember_token_expires_at && (Time.now.utc < remember_token_expires_at.utc)
25
+ end
26
+
27
+ # These create and unset the fields required for remembering users between browser closes
28
+ def remember_me
29
+ remember_me_for 2.weeks
30
+ end
31
+
32
+ def remember_me_for(time)
33
+ remember_me_until time.from_now.utc
34
+ end
35
+
36
+ def remember_me_until(time)
37
+ self.remember_token_expires_at = time
38
+ self.remember_token = self.class.make_token
39
+ save(:validate => false)
40
+ end
41
+
42
+ # refresh token (keeping same expires_at) if it exists
43
+ def refresh_token
44
+ if remember_token?
45
+ self.remember_token = self.class.make_token
46
+ save(:validate => false)
47
+ end
48
+ end
49
+
50
+ #
51
+ # Deletes the server-side record of the authentication token. The
52
+ # client-side (browser cookie) and server-side (this remember_token) must
53
+ # always be deleted together.
54
+ #
55
+ def forget_me
56
+ self.remember_token_expires_at = nil
57
+ self.remember_token = nil
58
+ save(:validate => false)
59
+ end
60
+ end # instance methods
61
+ end
62
+
63
+ module ByCookieTokenController
64
+ # Stuff directives into including module
65
+ def self.included( recipient )
66
+ recipient.extend( ControllerClassMethods )
67
+ recipient.class_eval do
68
+ include ControllerInstanceMethods
69
+ end
70
+ end
71
+
72
+ #
73
+ # Class Methods
74
+ #
75
+ module ControllerClassMethods
76
+ end # class methods
77
+
78
+ module ControllerInstanceMethods
79
+ end # instance methods
80
+ end
81
+ end
82
+