caleb-restful-authentication 1.1.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 (54) hide show
  1. data/CHANGELOG +68 -0
  2. data/README.textile +240 -0
  3. data/Rakefile +32 -0
  4. data/TODO +15 -0
  5. data/generators/authenticated/USAGE +1 -0
  6. data/generators/authenticated/authenticated_generator.rb +508 -0
  7. data/generators/authenticated/lib/insert_routes.rb +54 -0
  8. data/generators/authenticated/templates/_model_partial.html.erb +8 -0
  9. data/generators/authenticated/templates/activation.erb +3 -0
  10. data/generators/authenticated/templates/authenticated_system.rb +189 -0
  11. data/generators/authenticated/templates/authenticated_test_helper.rb +22 -0
  12. data/generators/authenticated/templates/controller.rb +43 -0
  13. data/generators/authenticated/templates/helper.rb +2 -0
  14. data/generators/authenticated/templates/login.html.erb +21 -0
  15. data/generators/authenticated/templates/mailer.rb +33 -0
  16. data/generators/authenticated/templates/migration.rb +29 -0
  17. data/generators/authenticated/templates/model.rb +101 -0
  18. data/generators/authenticated/templates/model_controller.rb +117 -0
  19. data/generators/authenticated/templates/model_helper.rb +93 -0
  20. data/generators/authenticated/templates/model_helper_spec.rb +158 -0
  21. data/generators/authenticated/templates/observer.rb +14 -0
  22. data/generators/authenticated/templates/signup.html.erb +21 -0
  23. data/generators/authenticated/templates/signup_notification.erb +8 -0
  24. data/generators/authenticated/templates/site_keys.rb +38 -0
  25. data/generators/authenticated/templates/spec/controllers/access_control_spec.rb +90 -0
  26. data/generators/authenticated/templates/spec/controllers/authenticated_system_spec.rb +102 -0
  27. data/generators/authenticated/templates/spec/controllers/sessions_controller_spec.rb +139 -0
  28. data/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +200 -0
  29. data/generators/authenticated/templates/spec/fixtures/users.yml +66 -0
  30. data/generators/authenticated/templates/spec/helpers/users_helper_spec.rb +141 -0
  31. data/generators/authenticated/templates/spec/models/user_spec.rb +295 -0
  32. data/generators/authenticated/templates/stories/rest_auth_stories.rb +22 -0
  33. data/generators/authenticated/templates/stories/rest_auth_stories_helper.rb +81 -0
  34. data/generators/authenticated/templates/stories/steps/ra_navigation_steps.rb +49 -0
  35. data/generators/authenticated/templates/stories/steps/ra_resource_steps.rb +179 -0
  36. data/generators/authenticated/templates/stories/steps/ra_response_steps.rb +171 -0
  37. data/generators/authenticated/templates/stories/steps/user_steps.rb +153 -0
  38. data/generators/authenticated/templates/stories/users/accounts.story +194 -0
  39. data/generators/authenticated/templates/stories/users/sessions.story +134 -0
  40. data/generators/authenticated/templates/test/functional_test.rb +82 -0
  41. data/generators/authenticated/templates/test/mailer_test.rb +31 -0
  42. data/generators/authenticated/templates/test/model_functional_test.rb +95 -0
  43. data/generators/authenticated/templates/test/unit_test.rb +166 -0
  44. data/init.rb +1 -0
  45. data/lib/authentication.rb +40 -0
  46. data/lib/authentication/by_cookie_token.rb +82 -0
  47. data/lib/authentication/by_password.rb +64 -0
  48. data/lib/authorization.rb +14 -0
  49. data/lib/authorization/aasm_roles.rb +64 -0
  50. data/lib/authorization/stateful_roles.rb +63 -0
  51. data/lib/trustification.rb +14 -0
  52. data/lib/trustification/email_validation.rb +20 -0
  53. data/rails/init.rb +6 -0
  54. metadata +115 -0
@@ -0,0 +1,117 @@
1
+ class <%= model_controller_class_name %>Controller < ApplicationController
2
+ # Be sure to include AuthenticationSystem in Application Controller instead
3
+ include AuthenticatedSystem
4
+ <% if options[:stateful] %>
5
+ # Protect these actions behind an admin login
6
+ # before_filter :admin_required, :only => [:suspend, :unsuspend, :destroy, :purge]
7
+ before_filter :find_<%= file_name %>, :only => [:suspend, :unsuspend, :destroy, :purge]
8
+ <% end %>
9
+
10
+ # render new.rhtml
11
+ def new
12
+ @<%= file_name %> = <%= class_name %>.new
13
+ end
14
+
15
+ def create
16
+ logout_keeping_session!
17
+ @<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
18
+ <% if options[:stateful] -%>
19
+ @<%= file_name %>.register! if @<%= file_name %> && @<%= file_name %>.valid?
20
+ success = @<%= file_name %> && @<%= file_name %>.valid?
21
+ <% else -%>
22
+ success = @<%= file_name %> && @<%= file_name %>.save
23
+ <% end -%>
24
+ if success && @<%= file_name %>.errors.empty?
25
+ <% if !options[:include_activation] -%>
26
+ # Protects against session fixation attacks, causes request forgery
27
+ # protection if visitor resubmits an earlier form using back
28
+ # button. Uncomment if you understand the tradeoffs.
29
+ # reset session
30
+ self.current_<%= file_name %> = @<%= file_name %> # !! now logged in
31
+ <% end -%>redirect_back_or_default('/')
32
+ flash[:notice] = "Thanks for signing up! We're sending you an email with your activation code."
33
+ else
34
+ flash[:error] = "We couldn't set up that account, sorry. Please try again, or contact an admin (link is above)."
35
+ render :action => 'new'
36
+ end
37
+ end
38
+ <% if options[:include_activation] %>
39
+ def activate
40
+ logout_keeping_session!
41
+ <%= file_name %> = <%= class_name %>.find_by_activation_code(params[:activation_code]) unless params[:activation_code].blank?
42
+ case
43
+ when (!params[:activation_code].blank?) && <%= file_name %> && !<%= file_name %>.active?
44
+ <%= file_name %>.activate!
45
+ flash[:notice] = "Signup complete! Please sign in to continue."
46
+ redirect_to '/login'
47
+ when params[:activation_code].blank?
48
+ flash[:error] = "The activation code was missing. Please follow the URL from your email."
49
+ redirect_back_or_default('/')
50
+ else
51
+ flash[:error] = "We couldn't find a <%= file_name %> with that activation code -- check your email? Or maybe you've already activated -- try signing in."
52
+ redirect_back_or_default('/')
53
+ end
54
+ end
55
+ <% end %><% if options[:include_forgot_password] %>
56
+ def forgot
57
+ if request.post?
58
+ <%= file_name %> = <%= class_name %>.find_by_email(params[:<%= file_name %>][:email]) unless params[:<%= file_name %>][:email].blank?
59
+ case
60
+ when (!params[:<%= file_name %>][:email].blank?) && <%= file_name %> && <%= file_name %>.active?
61
+ <%= file_name %>.make_reset_code!
62
+ flash[:notice] = "A password reset link was sent to #{<%= file_name %>.email}"
63
+ redirect_back_or_default('/')
64
+ when params[:<%= file_name %>][:email].blank?
65
+ flash[:error] = "The email address was missing. Please enter your email address."
66
+ redirect_back_or_default('/')
67
+ else
68
+ flash[:error] = "We couldn't find a <%= file_name %> with the email address, '#{params[:<%= file_name %>][:email]}' or the <%= file_name %> is suspended, deleted, or not activated."
69
+ redirect_back_or_default('/')
70
+ end
71
+ end
72
+ end
73
+
74
+ def reset
75
+ if request.post?
76
+ @<%= file_name %> = <%= class_name %>.find_by_email_and_reset_code(params[:<%= file_name %>][:email], params[:reset_code])
77
+ if @<%= file_name %>.update_attributes(:password => params[:<%= file_name %>][:password], :password_confirmation => params[:<%= file_name %>][:password_confirmation])
78
+ @<%= file_name %>.clear_reset_code!
79
+ self.current_user = @<%= file_name %>
80
+ flash[:notice] = "Password reset successfully for #{@<%= file_name %>.email}"
81
+ redirect_back_or_default("/")
82
+ else
83
+ render :action => :reset
84
+ end
85
+ end
86
+ end
87
+ <% end %><% if options[:stateful] %>
88
+ def suspend
89
+ @<%= file_name %>.suspend!
90
+ redirect_to <%= model_controller_routing_name %>_path
91
+ end
92
+
93
+ def unsuspend
94
+ @<%= file_name %>.unsuspend!
95
+ redirect_to <%= model_controller_routing_name %>_path
96
+ end
97
+
98
+ def destroy
99
+ @<%= file_name %>.delete!
100
+ redirect_to <%= model_controller_routing_name %>_path
101
+ end
102
+
103
+ def purge
104
+ @<%= file_name %>.destroy
105
+ redirect_to <%= model_controller_routing_name %>_path
106
+ end
107
+
108
+ # There's no page here to update or destroy a <%= file_name %>. If you add those, be
109
+ # smart -- make sure you check that the visitor is authorized to do so, that they
110
+ # supply their old password along with a new one to update it, etc.
111
+
112
+ protected
113
+ def find_<%= file_name %>
114
+ @<%= file_name %> = <%= class_name %>.find(params[:id])
115
+ end
116
+ <% end -%>
117
+ end
@@ -0,0 +1,93 @@
1
+ module <%= model_controller_class_name %>Helper
2
+
3
+ #
4
+ # Use this to wrap view elements that the user can't access.
5
+ # !! Note: this is an *interface*, not *security* feature !!
6
+ # You need to do all access control at the controller level.
7
+ #
8
+ # Example:
9
+ # <%%= if_authorized?(:index, User) do link_to('List all users', users_path) end %> |
10
+ # <%%= if_authorized?(:edit, @user) do link_to('Edit this user', edit_user_path) end %> |
11
+ # <%%= if_authorized?(:destroy, @user) do link_to 'Destroy', @user, :confirm => 'Are you sure?', :method => :delete end %>
12
+ #
13
+ #
14
+ def if_authorized?(action, resource, &block)
15
+ if authorized?(action, resource)
16
+ yield action, resource
17
+ end
18
+ end
19
+
20
+ #
21
+ # Link to user's page ('<%= table_name %>/1')
22
+ #
23
+ # By default, their <%= options[:login_field_name] -%> is used as link text and link title (tooltip)
24
+ #
25
+ # Takes options
26
+ # * :content_text => 'Content text in place of <%= file_name %>.<%= options[:login_field_name] -%>', escaped with
27
+ # the standard h() function.
28
+ # * :content_method => :<%= file_name %>_instance_method_to_call_for_content_text
29
+ # * :title_method => :<%= file_name %>_instance_method_to_call_for_title_attribute
30
+ # * as well as link_to()'s standard options
31
+ #
32
+ # Examples:
33
+ # link_to_<%= file_name %> @<%= file_name %>
34
+ # # => <a href="/<%= table_name %>/3" title="barmy">barmy</a>
35
+ #
36
+ # # if you've added a .name attribute:
37
+ # content_tag :span, :class => :vcard do
38
+ # (link_to_<%= file_name %> <%= file_name %>, :class => 'fn n', :title_method => :<%= options[:login_field_name] -%>, :content_method => :name) +
39
+ # ': ' + (content_tag :span, <%= file_name %>.email, :class => 'email')
40
+ # end
41
+ # # => <span class="vcard"><a href="/<%= table_name %>/3" title="barmy" class="fn n">Cyril Fotheringay-Phipps</a>: <span class="email">barmy@blandings.com</span></span>
42
+ #
43
+ # link_to_<%= file_name %> @<%= file_name %>, :content_text => 'Your user page'
44
+ # # => <a href="/<%= table_name %>/3" title="barmy" class="nickname">Your user page</a>
45
+ #
46
+ def link_to_<%= file_name %>(<%= file_name %>, options={})
47
+ raise "Invalid <%= file_name %>" unless <%= file_name %>
48
+ options.reverse_merge! :content_method => :<%= options[:login_field_name] -%>, :title_method => :<%= options[:login_field_name] -%>, :class => :nickname
49
+ content_text = options.delete(:content_text)
50
+ content_text ||= <%= file_name %>.send(options.delete(:content_method))
51
+ options[:title] ||= <%= file_name %>.send(options.delete(:title_method))
52
+ link_to h(content_text), <%= model_controller_routing_name.singularize %>_path(<%= file_name %>), options
53
+ end
54
+
55
+ #
56
+ # Link to login page using remote ip address as link content
57
+ #
58
+ # The :title (and thus, tooltip) is set to the IP address
59
+ #
60
+ # Examples:
61
+ # link_to_login_with_IP
62
+ # # => <a href="/login" title="169.69.69.69">169.69.69.69</a>
63
+ #
64
+ # link_to_login_with_IP :content_text => 'not signed in'
65
+ # # => <a href="/login" title="169.69.69.69">not signed in</a>
66
+ #
67
+ def link_to_login_with_IP content_text=nil, options={}
68
+ ip_addr = request.remote_ip
69
+ content_text ||= ip_addr
70
+ options.reverse_merge! :title => ip_addr
71
+ if tag = options.delete(:tag)
72
+ content_tag tag, h(content_text), options
73
+ else
74
+ link_to h(content_text), login_path, options
75
+ end
76
+ end
77
+
78
+ #
79
+ # Link to the current user's page (using link_to_<%= file_name %>) or to the login page
80
+ # (using link_to_login_with_IP).
81
+ #
82
+ def link_to_current_<%= file_name %>(options={})
83
+ if current_<%= file_name %>
84
+ link_to_<%= file_name %> current_<%= file_name %>, options
85
+ else
86
+ content_text = options.delete(:content_text) || 'not signed in'
87
+ # kill ignored options from link_to_<%= file_name %>
88
+ [:content_method, :title_method].each{|opt| options.delete(opt)}
89
+ link_to_login_with_IP content_text, options
90
+ end
91
+ end
92
+
93
+ end
@@ -0,0 +1,158 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ include ApplicationHelper
3
+ include <%= model_controller_class_name %>Helper
4
+
5
+ describe "<%= model_controller_class_name %>Helper.link_to_<%= file_name %>" do
6
+ before do
7
+ @<%= file_name %> = <%= class_name %>.new({
8
+ :name => '<%= class_name %> Name',
9
+ :<%= options[:login_field_name] -%> => '<%= file_name %>_name',
10
+ })
11
+ @<%= file_name %>.id = 1 # set non-attr_accessible specifically
12
+ end
13
+
14
+ it "should give an error on a nil <%= file_name %>" do
15
+ lambda { link_to_<%= file_name %>(nil) }.should raise_error('Invalid <%= file_name %>')
16
+ end
17
+
18
+ it "should link to the given <%= file_name %>" do
19
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[href='/<%= table_name %>/1']")
20
+ end
21
+
22
+ it "should use given link text if :content_text is specified" do
23
+ link_to_<%= file_name %>(@<%= file_name %>, :content_text => 'Hello there!').should have_tag("a", 'Hello there!')
24
+ end
25
+
26
+ it "should use the <%= options[:login_field_name] -%> as link text with no :content_method specified" do
27
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a", '<%= file_name %>_name')
28
+ end
29
+
30
+ it "should use the name as link text with :content_method => :name" do
31
+ link_to_<%= file_name %>(@<%= file_name %>, :content_method => :name).should have_tag("a", '<%= class_name %> Name')
32
+ end
33
+
34
+ it "should use the <%= options[:login_field_name] -%> as title with no :title_method specified" do
35
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a[title='<%= file_name %>_name']")
36
+ end
37
+
38
+ it "should use the name as link title with :content_method => :name" do
39
+ link_to_<%= file_name %>(@<%= file_name %>, :title_method => :name).should have_tag("a[title='<%= class_name %> Name']")
40
+ end
41
+
42
+ it "should have nickname as a class by default" do
43
+ link_to_<%= file_name %>(@<%= file_name %>).should have_tag("a.nickname")
44
+ end
45
+
46
+ it "should take other classes and no longer have the nickname class" do
47
+ result = link_to_<%= file_name %>(@<%= file_name %>, :class => 'foo bar')
48
+ result.should have_tag("a.foo")
49
+ result.should have_tag("a.bar")
50
+ end
51
+ end
52
+
53
+ describe "<%= model_controller_class_name %>Helper.link_to_signin_with_IP" do
54
+ before do
55
+ end
56
+
57
+ it "should link to the signin_path" do
58
+ link_to_signin_with_IP().should have_tag("a[href='/signin']")
59
+ end
60
+
61
+ it "should use given link text if :content_text is specified" do
62
+ link_to_signin_with_IP(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
63
+ end
64
+
65
+ it "should use the <%= options[:login_field_name] -%> as link text with no :content_method specified" do
66
+ link_to_signin_with_IP().should have_tag("a", '0.0.0.0')
67
+ end
68
+
69
+ it "should use the ip address as title" do
70
+ link_to_signin_with_IP().should have_tag("a[title='0.0.0.0']")
71
+ end
72
+
73
+ it "should by default be like school in summer and have no class" do
74
+ link_to_signin_with_IP().should_not have_tag("a.nickname")
75
+ end
76
+
77
+ it "should have some class if you tell it to" do
78
+ result = link_to_signin_with_IP(:class => 'foo bar')
79
+ result.should have_tag("a.foo")
80
+ result.should have_tag("a.bar")
81
+ end
82
+ end
83
+
84
+ describe "<%= model_controller_class_name %>Helper.link_to_current_<%= file_name %>, When logged in" do
85
+ fixtures :<%= table_name %>
86
+ include AuthenticatedTestHelper
87
+ before do
88
+ login_as(:quentin)
89
+ end
90
+
91
+ it "should link to the given <%= file_name %>" do
92
+ link_to_current_<%= file_name %>().should have_tag("a[href='/<%= table_name %>/1']")
93
+ end
94
+
95
+ it "should use given link text if :content_text is specified" do
96
+ link_to_current_user(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
97
+ end
98
+
99
+ it "should use the <%= options[:login_field_name] -%> as link text with no :content_method specified" do
100
+ link_to_current_user().should have_tag("a", 'quentin')
101
+ end
102
+
103
+ it "should use the name as link text with :content_method => :name" do
104
+ link_to_current_user(:content_method => :name).should have_tag("a", 'Quentin')
105
+ end
106
+
107
+ it "should use the <%= options[:login_field_name] -%> as title with no :title_method specified" do
108
+ link_to_current_user().should have_tag("a[title='quentin']")
109
+ end
110
+
111
+ it "should use the name as link title with :content_method => :name" do
112
+ link_to_current_user(:title_method => :name).should have_tag("a[title='Quentin']")
113
+ end
114
+
115
+ it "should have nickname as a class" do
116
+ link_to_current_user().should have_tag("a.nickname")
117
+ end
118
+
119
+ it "should take other classes and no longer have the nickname class" do
120
+ result = link_to_current_user(:class => 'foo bar')
121
+ result.should have_tag("a.foo")
122
+ result.should have_tag("a.bar")
123
+ end
124
+ end
125
+
126
+
127
+
128
+ describe "<%= model_controller_class_name %>Helper.link_to_current_user, When logged out" do
129
+ include AuthenticatedTestHelper
130
+ before do
131
+ end
132
+
133
+ it "should link to the signin_path" do
134
+ link_to_current_user().should have_tag("a[href='/signin']")
135
+ end
136
+
137
+ it "should use given link text if :content_text is specified" do
138
+ link_to_current_user(:content_text => 'Hello there!').should have_tag("a", 'Hello there!')
139
+ end
140
+
141
+ it "should use the IP address as link text with no :content_method specified" do
142
+ link_to_current_user().should have_tag("a", '0.0.0.0')
143
+ end
144
+
145
+ it "should use the ip address as title" do
146
+ link_to_current_user().should have_tag("a[title='0.0.0.0']")
147
+ end
148
+
149
+ it "should by default be like school in summer and have no class" do
150
+ link_to_current_user().should_not have_tag("a.nickname")
151
+ end
152
+
153
+ it "should have some class if you tell it to" do
154
+ result = link_to_current_user(:class => 'foo bar')
155
+ result.should have_tag("a.foo")
156
+ result.should have_tag("a.bar")
157
+ end
158
+ end
@@ -0,0 +1,14 @@
1
+ class <%= class_name %>Observer < ActiveRecord::Observer
2
+ def after_create(<%= file_name %>)
3
+ <%= class_name %>Mailer.deliver_signup_notification(<%= file_name %>)
4
+ end
5
+
6
+ def after_save(<%= file_name %>)
7
+ <% if options[:include_activation] -%>
8
+ <%= class_name %>Mailer.deliver_activation(<%= file_name %>) if <%= file_name %>.recently_activated?
9
+ <% end -%>
10
+ <% if options[:include_forgot_password] -%>
11
+ <%= class_name %>Mailer.deliver_reset_password(<%= file_name %>) if <%= file_name %>.recently_reset_password?
12
+ <% end -%>
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ <h1>Sign up as a new user</h1>
2
+ <%% @<%= file_name %>.password = @<%= file_name %>.password_confirmation = nil %>
3
+
4
+ <%%= error_messages_for :<%= file_name %> %>
5
+ <%% form_for :<%= file_name %>, :url => <%= model_controller_routing_name %>_path do |f| -%>
6
+ <% unless options[:email_as_login] -%>
7
+ <p><%%= label_tag 'login' %><br/>
8
+ <%%= f.text_field :login %></p>
9
+ <% end -%>
10
+
11
+ <p><%%= label_tag 'email' %><br/>
12
+ <%%= f.text_field :email %></p>
13
+
14
+ <p><%%= label_tag 'password' %><br/>
15
+ <%%= f.password_field :password %></p>
16
+
17
+ <p><%%= label_tag 'password_confirmation', 'Confirm Password' %><br/>
18
+ <%%= f.password_field :password_confirmation %></p>
19
+
20
+ <p><%%= submit_tag 'Sign up' %></p>
21
+ <%% end -%>
@@ -0,0 +1,8 @@
1
+ Your account has been created.
2
+
3
+ Username: <%%=h @<%= file_name %>.<%= options[:login_field_name] -%> %>
4
+ Password: <%%=h @<%= file_name %>.password %>
5
+
6
+ Visit this url to activate your account:
7
+
8
+ <%%=h @url %>
@@ -0,0 +1,38 @@
1
+
2
+ # A Site key gives additional protection against a dictionary attack if your
3
+ # DB is ever compromised. With no site key, we store
4
+ # DB_password = hash(user_password, DB_user_salt)
5
+ # If your database were to be compromised you'd be vulnerable to a dictionary
6
+ # attack on all your stupid users' passwords. With a site key, we store
7
+ # DB_password = hash(user_password, DB_user_salt, Code_site_key)
8
+ # That means an attacker needs access to both your site's code *and* its
9
+ # database to mount an "offline dictionary attack.":http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/web-authentication.html
10
+ #
11
+ # It's probably of minor importance, but recommended by best practices: 'defense
12
+ # in depth'. Needless to say, if you upload this to github or the youtubes or
13
+ # otherwise place it in public view you'll kinda defeat the point. Your users'
14
+ # passwords are still secure, and the world won't end, but defense_in_depth -= 1.
15
+ #
16
+ # Please note: if you change this, all the passwords will be invalidated, so DO
17
+ # keep it someplace secure. Use the random value given or type in the lyrics to
18
+ # your favorite Jay-Z song or something; any moderately long, unpredictable text.
19
+ REST_AUTH_SITE_KEY = '<%= $rest_auth_site_key_from_generator %>'
20
+
21
+ # Repeated applications of the hash make brute force (even with a compromised
22
+ # database and site key) harder, and scale with Moore's law.
23
+ #
24
+ # bq. "To squeeze the most security out of a limited-entropy password or
25
+ # passphrase, we can use two techniques [salting and stretching]... that are
26
+ # so simple and obvious that they should be used in every password system.
27
+ # There is really no excuse not to use them." http://tinyurl.com/37lb73
28
+ # Practical Security (Ferguson & Scheier) p350
29
+ #
30
+ # A modest 10 foldings (the default here) adds 3ms. This makes brute forcing 10
31
+ # times harder, while reducing an app that otherwise serves 100 reqs/s to 78 signin
32
+ # reqs/s, an app that does 10reqs/s to 9.7 reqs/s
33
+ #
34
+ # More:
35
+ # * http://www.owasp.org/index.php/Hashing_Java
36
+ # * "An Illustrated Guide to Cryptographic Hashes":http://www.unixwiz.net/techtips/iguide-crypto-hashes.html
37
+
38
+ REST_AUTH_DIGEST_STRETCHES = <%= $rest_auth_digest_stretches_from_generator %>