jashmenn-restful-authentication 2.0.0.beta1

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 +176 -0
  3. data/Rakefile +32 -0
  4. data/TODO +15 -0
  5. data/init.rb +3 -0
  6. data/lib/authentication.rb +44 -0
  7. data/lib/authentication/by_cookie_token.rb +82 -0
  8. data/lib/authentication/by_password.rb +64 -0
  9. data/lib/authorization.rb +14 -0
  10. data/lib/authorization/aasm_roles.rb +63 -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 +101 -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 +127 -0
  42. data/lib/generators/authenticated/templates/spec/controllers/users_controller_spec.rb +131 -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 +227 -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 +103 -0
@@ -0,0 +1,8 @@
1
+ <%% if logged_in? -%>
2
+ <div id="<%= file_name %>-bar-greeting">Logged in as <%%= link_to_current_<%= file_name %> :content_method => :login %></div>
3
+ <div id="<%= file_name %>-bar-action" >(<%%= link_to "Log out", logout_path, { :title => "Log out" } %>)</div>
4
+ <%% else -%>
5
+ <div id="<%= file_name %>-bar-greeting"><%%= link_to_login_with_IP 'Not logged in', :style => 'border: none;' %></div>
6
+ <div id="<%= file_name %>-bar-action" ><%%= link_to "Log in", login_path, { :title => "Log in" } %> /
7
+ <%%= link_to "Sign up", signup_path, { :title => "Create an account" } %></div>
8
+ <%% end -%>
@@ -0,0 +1,3 @@
1
+ <%%=h @<%= file_name %>.login %>, your account has been activated. Welcome aboard!
2
+
3
+ <%%=h @url %>
@@ -0,0 +1,189 @@
1
+ module AuthenticatedSystem
2
+ protected
3
+ # Returns true or false if the <%= file_name %> is logged in.
4
+ # Preloads @current_<%= file_name %> with the <%= file_name %> model if they're logged in.
5
+ def logged_in?
6
+ !!current_<%= file_name %>
7
+ end
8
+
9
+ # Accesses the current <%= file_name %> from the session.
10
+ # Future calls avoid the database because nil is not equal to false.
11
+ def current_<%= file_name %>
12
+ @current_<%= file_name %> ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_<%= file_name %> == false
13
+ end
14
+
15
+ # Store the given <%= file_name %> id in the session.
16
+ def current_<%= file_name %>=(new_<%= file_name %>)
17
+ session[:<%= file_name %>_id] = new_<%= file_name %> ? new_<%= file_name %>.id : nil
18
+ @current_<%= file_name %> = new_<%= file_name %> || false
19
+ end
20
+
21
+ # Check if the <%= file_name %> is authorized
22
+ #
23
+ # Override this method in your controllers if you want to restrict access
24
+ # to only a few actions or if you want to check if the <%= file_name %>
25
+ # has the correct rights.
26
+ #
27
+ # Example:
28
+ #
29
+ # # only allow nonbobs
30
+ # def authorized?
31
+ # current_<%= file_name %>.login != "bob"
32
+ # end
33
+ #
34
+ def authorized?(action = action_name, resource = nil)
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? || 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 <%= file_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
+ respond_to do |format|
66
+ format.html do
67
+ store_location
68
+ redirect_to new_<%= controller_routing_name %>_path
69
+ end
70
+ # format.any doesn't work in rails version < http://dev.rubyonrails.org/changeset/8987
71
+ # Add any other API formats here. (Some browsers, notably IE6, send Accept: */* and trigger
72
+ # the 'format.any' block incorrectly. See http://bit.ly/ie6_borken or http://bit.ly/ie6_borken2
73
+ # for a workaround.)
74
+ format.any(:json, :xml) do
75
+ request_http_basic_authentication 'Web Password'
76
+ end
77
+ end
78
+ end
79
+
80
+ # Store the URI of the current request in the session.
81
+ #
82
+ # We can return to this location by calling #redirect_back_or_default.
83
+ def store_location
84
+ session[:return_to] = request.fullpath
85
+ end
86
+
87
+ # Redirect to the URI stored by the most recent store_location call or
88
+ # to the passed default. Set an appropriately modified
89
+ # after_filter :store_location, :only => [:index, :new, :show, :edit]
90
+ # for any controller you want to be bounce-backable.
91
+ def redirect_back_or_default(default, options = {})
92
+ redirect_to((session[:return_to] || default), options)
93
+ session[:return_to] = nil
94
+ end
95
+
96
+ # Inclusion hook to make #current_<%= file_name %> and #logged_in?
97
+ # available as ActionView helper methods.
98
+ def self.included(base)
99
+ base.send :helper_method, :current_<%= file_name %>, :logged_in?, :authorized? if base.respond_to? :helper_method
100
+ end
101
+
102
+ #
103
+ # Login
104
+ #
105
+
106
+ # Called from #current_<%= file_name %>. First attempt to login by the <%= file_name %> id stored in the session.
107
+ def login_from_session
108
+ self.current_<%= file_name %> = <%= class_name %>.find_by_id(session[:<%= file_name %>_id]) if session[:<%= file_name %>_id]
109
+ end
110
+
111
+ # Called from #current_<%= file_name %>. Now, attempt to login by basic authentication information.
112
+ def login_from_basic_auth
113
+ authenticate_with_http_basic do |login, password|
114
+ self.current_<%= file_name %> = <%= class_name %>.authenticate(login, password)
115
+ end
116
+ end
117
+
118
+ #
119
+ # Logout
120
+ #
121
+
122
+ # Called from #current_<%= file_name %>. Finaly, attempt to login by an expiring token in the cookie.
123
+ # for the paranoid: we _should_ be storing <%= file_name %>_token = hash(cookie_token, request IP)
124
+ def login_from_cookie
125
+ <%= file_name %> = cookies[:auth_token] && <%= class_name %>.find_by_remember_token(cookies[:auth_token])
126
+ if <%= file_name %> && <%= file_name %>.remember_token?
127
+ self.current_<%= file_name %> = <%= file_name %>
128
+ handle_remember_cookie! false # freshen cookie token (keeping date)
129
+ self.current_<%= file_name %>
130
+ end
131
+ end
132
+
133
+ # This is ususally what you want; resetting the session willy-nilly wreaks
134
+ # havoc with forgery protection, and is only strictly necessary on login.
135
+ # However, **all session state variables should be unset here**.
136
+ def logout_keeping_session!
137
+ # Kill server-side auth cookie
138
+ @current_<%= file_name %>.forget_me if @current_<%= file_name %>.is_a? <%= class_name %>
139
+ # @current_<%= file_name %> = false # not logged in, and don't do it for me
140
+ kill_remember_cookie! # Kill client-side auth cookie
141
+ session[:<%= file_name %>_id] = nil # keeps the session but kill our variable
142
+ # explicitly kill any other session variables you set
143
+ end
144
+
145
+ # The session should only be reset at the tail end of a form POST --
146
+ # otherwise the request forgery protection fails. It's only really necessary
147
+ # when you cross quarantine (logged-out to logged-in).
148
+ def logout_killing_session!
149
+ logout_keeping_session!
150
+ reset_session
151
+ end
152
+
153
+ #
154
+ # Remember_me Tokens
155
+ #
156
+ # Cookies shouldn't be allowed to persist past their freshness date,
157
+ # and they should be changed at each login
158
+
159
+ # Cookies shouldn't be allowed to persist past their freshness date,
160
+ # and they should be changed at each login
161
+
162
+ def valid_remember_cookie?
163
+ return nil unless @current_<%= file_name %>
164
+ (@current_<%= file_name %>.remember_token?) &&
165
+ (cookies[:auth_token] == @current_<%= file_name %>.remember_token)
166
+ end
167
+
168
+ # Refresh the cookie auth token if it exists, create it otherwise
169
+ def handle_remember_cookie!(new_cookie_flag)
170
+ return unless @current_<%= file_name %>
171
+ case
172
+ when valid_remember_cookie? then @current_<%= file_name %>.refresh_token # keeping same expiry date
173
+ when new_cookie_flag then @current_<%= file_name %>.remember_me
174
+ else @current_<%= file_name %>.forget_me
175
+ end
176
+ send_remember_cookie!
177
+ end
178
+
179
+ def kill_remember_cookie!
180
+ cookies.delete :auth_token
181
+ end
182
+
183
+ def send_remember_cookie!
184
+ cookies[:auth_token] = {
185
+ :value => @current_<%= file_name %>.remember_token,
186
+ :expires => @current_<%= file_name %>.remember_token_expires_at }
187
+ end
188
+
189
+ end
@@ -0,0 +1,22 @@
1
+ module AuthenticatedTestHelper
2
+ # Sets the current <%= file_name %> in the session from the <%= file_name %> fixtures.
3
+ def login_as(<%= file_name %>)
4
+ @request.session[:<%= file_name %>_id] = <%= file_name %> ? (<%= file_name %>.is_a?(<%= file_name.camelize %>) ? <%= file_name %>.id : <%= table_name %>(<%= file_name %>).id) : nil
5
+ end
6
+
7
+ def authorize_as(<%= file_name %>)
8
+ @request.env["HTTP_AUTHORIZATION"] = <%= file_name %> ? ActionController::HttpAuthentication::Basic.encode_credentials(<%= table_name %>(<%= file_name %>).login, 'monkey') : nil
9
+ end
10
+
11
+ <% if options.rspec? -%>
12
+ # rspec
13
+ def mock_<%= file_name %>
14
+ <%= file_name %> = mock_model(<%= class_name %>, :id => 1,
15
+ :login => 'user_name',
16
+ :name => 'U. Surname',
17
+ :to_xml => "<%= class_name %>-in-XML", :to_json => "<%= class_name %>-in-JSON",
18
+ :errors => [])
19
+ <%= file_name %>
20
+ end
21
+ <% end -%>
22
+ end
@@ -0,0 +1,41 @@
1
+ # This controller handles the login/logout function of the site.
2
+ class <%= controller_class_name %>Controller < ApplicationController
3
+ # Be sure to include AuthenticationSystem in Application Controller instead
4
+ include AuthenticatedSystem
5
+
6
+ # render new.rhtml
7
+ def new
8
+ end
9
+
10
+ def create
11
+ logout_keeping_session!
12
+ <%= file_name %> = <%= class_name %>.authenticate(params[:login], params[:password])
13
+ if <%= file_name %>
14
+ # Protects against session fixation attacks, causes request forgery
15
+ # protection if user resubmits an earlier form using back
16
+ # button. Uncomment if you understand the tradeoffs.
17
+ # reset_session
18
+ self.current_<%= file_name %> = <%= file_name %>
19
+ new_cookie_flag = (params[:remember_me] == "1")
20
+ handle_remember_cookie! new_cookie_flag
21
+ redirect_back_or_default('/', :notice => "Logged in successfully")
22
+ else
23
+ note_failed_signin
24
+ @login = params[:login]
25
+ @remember_me = params[:remember_me]
26
+ render :action => 'new'
27
+ end
28
+ end
29
+
30
+ def destroy
31
+ logout_killing_session!
32
+ redirect_back_or_default('/', :notice => "You have been logged out.")
33
+ end
34
+
35
+ protected
36
+ # Track failed login attempts
37
+ def note_failed_signin
38
+ flash.now[:error] = "Couldn't log you in as '#{params[:login]}'"
39
+ logger.warn "Failed login for '#{params[:login]}' from #{request.remote_ip} at #{Time.now.utc}"
40
+ end
41
+ end
@@ -0,0 +1,109 @@
1
+ Visitors should be in control of creating an account and of proving their
2
+ essential humanity/accountability or whatever it is people think the
3
+ id-validation does. We should be fairly skeptical about this process, as the
4
+ identity+trust chain starts here.
5
+
6
+ Story: Creating an account
7
+ As an anonymous user
8
+ I want to be able to create an account
9
+ So that I can be one of the cool kids
10
+
11
+ #
12
+ # Account Creation: Get entry form
13
+ #
14
+ Scenario: Anonymous user can start creating an account
15
+ Given an anonymous user
16
+ When she goes to /signup
17
+ Then she should be at the 'users/new' page
18
+ And the page should look AWESOME
19
+ And she should see a <form> containing a textfield: Login, textfield: Email, password: Password, password: 'Confirm Password', submit: 'Sign up'
20
+
21
+ #
22
+ # Account Creation
23
+ #
24
+ Scenario: Anonymous user can create an account
25
+ Given an anonymous user
26
+ And no user with login: 'Oona' exists
27
+ When she registers an account as the preloaded 'Oona'
28
+ Then she should be redirected to the home page
29
+ When she follows that redirect!
30
+ Then she should see a notice message 'Thanks for signing up!'
31
+ And a user with login: 'oona' should exist
32
+ And the user should have login: 'oona', and email: 'unactivated@example.com'
33
+
34
+ And oona should be logged in
35
+
36
+
37
+ #
38
+ # Account Creation Failure: Account exists
39
+ #
40
+
41
+
42
+ Scenario: Anonymous user can not create an account replacing an activated account
43
+ Given an anonymous user
44
+ And an activated user named 'Reggie'
45
+ And we try hard to remember the user's updated_at, and created_at
46
+ When she registers an account with login: 'reggie', password: 'monkey', and email: 'reggie@example.com'
47
+ Then she should be at the 'users/new' page
48
+ And she should see an errorExplanation message 'Login has already been taken'
49
+ And she should not see an errorExplanation message 'Email has already been taken'
50
+ And a user with login: 'reggie' should exist
51
+ And the user should have email: 'registered@example.com'
52
+
53
+ And the user's created_at should stay the same under to_s
54
+ And the user's updated_at should stay the same under to_s
55
+ And she should not be logged in
56
+
57
+ #
58
+ # Account Creation Failure: Incomplete input
59
+ #
60
+ Scenario: Anonymous user can not create an account with incomplete or incorrect input
61
+ Given an anonymous user
62
+ And no user with login: 'Oona' exists
63
+ When she registers an account with login: '', password: 'monkey', password_confirmation: 'monkey' and email: 'unactivated@example.com'
64
+ Then she should be at the 'users/new' page
65
+ And she should see an errorExplanation message 'Login can't be blank'
66
+ And no user with login: 'oona' should exist
67
+
68
+ Scenario: Anonymous user can not create an account with no password
69
+ Given an anonymous user
70
+ And no user with login: 'Oona' exists
71
+ When she registers an account with login: 'oona', password: '', password_confirmation: 'monkey' and email: 'unactivated@example.com'
72
+ Then she should be at the 'users/new' page
73
+ And she should see an errorExplanation message 'Password can't be blank'
74
+ And no user with login: 'oona' should exist
75
+
76
+ Scenario: Anonymous user can not create an account with no password_confirmation
77
+ Given an anonymous user
78
+ And no user with login: 'Oona' exists
79
+ When she registers an account with login: 'oona', password: 'monkey', password_confirmation: '' and email: 'unactivated@example.com'
80
+ Then she should be at the 'users/new' page
81
+ And she should see an errorExplanation message 'Password confirmation can't be blank'
82
+ And no user with login: 'oona' should exist
83
+
84
+ Scenario: Anonymous user can not create an account with mismatched password & password_confirmation
85
+ Given an anonymous user
86
+ And no user with login: 'Oona' exists
87
+ When she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkeY' and email: 'unactivated@example.com'
88
+ Then she should be at the 'users/new' page
89
+ And she should see an errorExplanation message 'Password doesn't match confirmation'
90
+ And no user with login: 'oona' should exist
91
+
92
+ Scenario: Anonymous user can not create an account with bad email
93
+ Given an anonymous user
94
+ And no user with login: 'Oona' exists
95
+ When she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkey' and email: ''
96
+ Then she should be at the 'users/new' page
97
+ And she should see an errorExplanation message 'Email can't be blank'
98
+ And no user with login: 'oona' should exist
99
+ When she registers an account with login: 'oona', password: 'monkey', password_confirmation: 'monkey' and email: 'unactivated@example.com'
100
+ Then she should be redirected to the home page
101
+ When she follows that redirect!
102
+ Then she should see a notice message 'Thanks for signing up!'
103
+ And a user with login: 'oona' should exist
104
+ And the user should have login: 'oona', and email: 'unactivated@example.com'
105
+
106
+ And oona should be logged in
107
+
108
+
109
+
@@ -0,0 +1,134 @@
1
+ Users want to know that nobody can masquerade as them. We want to extend trust
2
+ only to visitors who present the appropriate credentials. Everyone wants this
3
+ identity verification to be as secure and convenient as possible.
4
+
5
+ Story: Logging in
6
+ As an anonymous user with an account
7
+ I want to log in to my account
8
+ So that I can be myself
9
+
10
+ #
11
+ # Log in: get form
12
+ #
13
+ Scenario: Anonymous user can get a login form.
14
+ Given an anonymous user
15
+ When she goes to /login
16
+ Then she should be at the new sessions page
17
+ And the page should look AWESOME
18
+ And she should see a <form> containing a textfield: Login, password: Password, and submit: 'Log in'
19
+
20
+ #
21
+ # Log in successfully, but don't remember me
22
+ #
23
+ Scenario: Anonymous user can log in
24
+ Given an anonymous user
25
+ And an activated user named 'reggie'
26
+ When she creates a singular sessions with login: 'reggie', password: 'monkey', remember me: ''
27
+ Then she should be redirected to the home page
28
+ When she follows that redirect!
29
+ Then she should see a notice message 'Logged in successfully'
30
+ And reggie should be logged in
31
+ And she should not have an auth_token cookie
32
+
33
+ Scenario: Logged-in user who logs in should be the new one
34
+ Given an activated user named 'reggie'
35
+ And an activated user logged in as 'oona'
36
+ When she creates a singular sessions with login: 'reggie', password: 'monkey', remember me: ''
37
+ Then she should be redirected to the home page
38
+ When she follows that redirect!
39
+ Then she should see a notice message 'Logged in successfully'
40
+ And reggie should be logged in
41
+ And she should not have an auth_token cookie
42
+
43
+ #
44
+ # Log in successfully, remember me
45
+ #
46
+ Scenario: Anonymous user can log in and be remembered
47
+ Given an anonymous user
48
+ And an activated user named 'reggie'
49
+ When she creates a singular sessions with login: 'reggie', password: 'monkey', remember me: '1'
50
+ Then she should be redirected to the home page
51
+ When she follows that redirect!
52
+ Then she should see a notice message 'Logged in successfully'
53
+ And reggie should be logged in
54
+ And she should have an auth_token cookie
55
+ # assumes fixtures were run sometime
56
+ And her session store should have user_id: 4
57
+
58
+ #
59
+ # Log in unsuccessfully
60
+ #
61
+
62
+ Scenario: Logged-in user who fails logs in should be logged out
63
+ Given an activated user named 'oona'
64
+ When she creates a singular sessions with login: 'oona', password: '1234oona', remember me: '1'
65
+ Then she should be redirected to the home page
66
+ When she follows that redirect!
67
+ Then she should see a notice message 'Logged in successfully'
68
+ And oona should be logged in
69
+ And she should have an auth_token cookie
70
+ When she creates a singular sessions with login: 'reggie', password: 'i_haxxor_joo'
71
+ Then she should be at the new sessions page
72
+ Then she should see an error message 'Couldn't log you in as 'reggie''
73
+ And she should not be logged in
74
+ And she should not have an auth_token cookie
75
+ And her session store should not have user_id
76
+
77
+ Scenario: Log-in with bogus info should fail until it doesn't
78
+ Given an activated user named 'reggie'
79
+ When she creates a singular sessions with login: 'reggie', password: 'i_haxxor_joo'
80
+ Then she should be at the new sessions page
81
+ Then she should see an error message 'Couldn't log you in as 'reggie''
82
+ And she should not be logged in
83
+ And she should not have an auth_token cookie
84
+ And her session store should not have user_id
85
+ When she creates a singular sessions with login: 'reggie', password: ''
86
+ Then she should be at the new sessions page
87
+ Then she should see an error message 'Couldn't log you in as 'reggie''
88
+ And she should not be logged in
89
+ And she should not have an auth_token cookie
90
+ And her session store should not have user_id
91
+ When she creates a singular sessions with login: '', password: 'monkey'
92
+ Then she should be at the new sessions page
93
+ Then she should see an error message 'Couldn't log you in as '''
94
+ And she should not be logged in
95
+ And she should not have an auth_token cookie
96
+ And her session store should not have user_id
97
+ When she creates a singular sessions with login: 'leonard_shelby', password: 'monkey'
98
+ Then she should be at the new sessions page
99
+ Then she should see an error message 'Couldn't log you in as 'leonard_shelby''
100
+ And she should not be logged in
101
+ And she should not have an auth_token cookie
102
+ And her session store should not have user_id
103
+ When she creates a singular sessions with login: 'reggie', password: 'monkey', remember me: '1'
104
+ Then she should be redirected to the home page
105
+ When she follows that redirect!
106
+ Then she should see a notice message 'Logged in successfully'
107
+ And reggie should be logged in
108
+ And she should have an auth_token cookie
109
+ # assumes fixtures were run sometime
110
+ And her session store should have user_id: 4
111
+
112
+
113
+ #
114
+ # Log out successfully (should always succeed)
115
+ #
116
+ Scenario: Anonymous (logged out) user can log out.
117
+ Given an anonymous user
118
+ When she goes to /logout
119
+ Then she should be redirected to the home page
120
+ When she follows that redirect!
121
+ Then she should see a notice message 'You have been logged out'
122
+ And she should not be logged in
123
+ And she should not have an auth_token cookie
124
+ And her session store should not have user_id
125
+
126
+ Scenario: Logged in user can log out.
127
+ Given an activated user logged in as 'reggie'
128
+ When she goes to /logout
129
+ Then she should be redirected to the home page
130
+ When she follows that redirect!
131
+ Then she should see a notice message 'You have been logged out'
132
+ And she should not be logged in
133
+ And she should not have an auth_token cookie
134
+ And her session store should not have user_id