Skip to content

Commit

Permalink
Minor changes to make specs and stories pass. About to start adding t…
Browse files Browse the repository at this point in the history
…hose in
  • Loading branch information
Philip (flip) Kromer committed May 16, 2008
1 parent bd6934d commit 215673b
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 32 deletions.
24 changes: 18 additions & 6 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ h3. authenticated_system

h3. Changes to model

* recently_activated? belongs only if stateful

* Gave migration a 40-char limit on remember_token & an index on users by login

h4. Token generation

The salt and the remember_token should be generated from completely
Expand Down Expand Up @@ -79,10 +83,18 @@ commented out.
I'd like to get the advice of someone who understands CSRF better than I on this
change.

h3. Specs

git ci -m "Backported changes to model and model_controller:
* Token generation now different than password digest'ing, and all use same method call.
* added remember_token refresh
* making logout / session_reset'ing uniform across controllers
* made the implicit login only happen for non-activationed sites
* On a failed signup, kick you back to the signin screen (but strip out the password & confirmation"
h3. Stories


h3. Views

* Used escapes <%= %> in email templates (among other reasons, so courtenay's
"'dumbass' test":http://tinyurl.com/684g9t doesn't complain)

echo git ci -m '* Used escapes <%= %> in email templates (among other reasons, so courtenays
"dumbass test":http://tinyurl.com/684g9t doesn\'t complain)" generators/authenticated/templates/{activation.html.erb,signup.html.erb,signup_notification.html.erb}


controller.rb,
55 changes: 51 additions & 4 deletions generators/authenticated/authenticated_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def manifest
m.directory File.join('spec/models', class_path)
m.directory File.join('spec/helpers', model_controller_class_path)
m.directory File.join('spec/fixtures', class_path)
m.directory File.join('stories', class_path, table_name)
m.directory File.join('stories', 'steps')
else
m.directory File.join('test/functional', controller_class_path)
m.directory File.join('test/functional', model_controller_class_path)
Expand Down Expand Up @@ -122,22 +124,66 @@ def manifest
m.template 'functional_spec.rb',
File.join('spec/controllers',
controller_class_path,
"#{controller_file_name}_controller_spec.rb")
"old_#{controller_file_name}_controller_spec.rb")
m.template 'model_functional_spec.rb',
File.join('spec/controllers',
model_controller_class_path,
"old_#{model_controller_file_name}_controller_spec.rb")
m.template 'unit_spec.rb',
File.join('spec/models',
class_path,
"old_#{file_name}_spec.rb")
m.template 'fixtures.yml',
File.join('spec/fixtures',
"old_#{table_name}.yml")

# RSpec Specs
m.file 'spec/controllers/users_controller_spec.rb',
File.join('spec/controllers',
model_controller_class_path,
"#{model_controller_file_name}_controller_spec.rb")
m.template 'model_helper_spec.rb',
m.file 'spec/controllers/sessions_controller_spec.rb',
File.join('spec/controllers',
controller_class_path,
"#{controller_file_name}_controller_spec.rb")
m.file 'spec/controllers/access_control_spec.rb',
File.join('spec/controllers',
controller_class_path,
"access_control_spec.rb")
m.file 'spec/controllers/authenticated_system_spec.rb',
File.join('spec/controllers',
controller_class_path,
"authenticated_system_spec.rb")
m.file 'spec/helpers/users_helper_spec.rb',
File.join('spec/helpers',
model_controller_class_path,
"#{table_name}_helper_spec.rb")
m.template 'unit_spec.rb',
m.file 'spec/models/user_spec.rb',
File.join('spec/models',
class_path,
"#{file_name}_spec.rb")
m.template 'fixtures.yml',
m.template 'spec/fixtures/users.yml',
File.join('spec/fixtures',
"#{table_name}.yml")

# RSpec Stories
m.file 'stories/steps/ra_navigation_steps.rb',
File.join('stories/steps/ra_navigation_steps.rb')
m.file 'stories/steps/ra_response_steps.rb',
File.join('stories/steps/ra_response_steps.rb')
m.file 'stories/steps/ra_resource_steps.rb',
File.join('stories/steps/ra_resource_steps.rb')
m.file 'stories/steps/user_steps.rb',
File.join('stories/steps/', "#{file_name}_steps.rb")
m.file 'stories/users/accounts.story',
File.join('stories', table_name, 'accounts.story')
m.file 'stories/users/sessions.story',
File.join('stories', table_name, 'sessions.story')
m.file 'stories/helper_rest_auth_stories.rb',
File.join('stories', 'helper_rest_auth_stories.rb')
m.file 'stories/rest_auth_stories.rb',
File.join('stories', 'rest_auth_stories.rb')

else
m.template 'functional_test.rb',
File.join('test/functional',
Expand Down Expand Up @@ -173,6 +219,7 @@ def manifest
# Controller templates
m.template 'login.html.erb', File.join('app/views', controller_class_path, controller_file_name, "new.html.erb")
m.template 'signup.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.html.erb")
m.template '_model_partial.html.erb', File.join('app/views', model_controller_class_path, model_controller_file_name, "_#{file_name}_bar.html.erb")

if options[:include_activation]
# Mailer templates
Expand Down
14 changes: 12 additions & 2 deletions generators/authenticated/templates/authenticated_system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def logged_in?
!!current_<%= file_name %>
end

# Accesses the current <%= file_name %> from the session.
# Accesses the current <%= file_name %> from the session.
# Future calls avoid the database because nil is not equal to false.
def current_<%= file_name %>
@current_<%= file_name %> ||= (login_from_session || login_from_basic_auth || login_from_cookie) unless @current_<%= file_name %> == false
Expand Down Expand Up @@ -98,7 +98,7 @@ def self.included(base)
end

#
# Login routines
# Login
#

# Called from #current_<%= file_name %>. First attempt to login by the <%= file_name %> id stored in the session.
Expand All @@ -112,6 +112,10 @@ def login_from_basic_auth
self.current_<%= file_name %> = <%= class_name %>.authenticate(login, password)
end
end

#
# Logout
#

# Called from #current_<%= file_name %>. Finaly, attempt to login by an expiring token in the cookie.
# for the paranoid: we _should_ be storing <%= file_name %>_token = hash(cookie_token, request IP)
Expand Down Expand Up @@ -142,6 +146,12 @@ def logout_killing_session!
logout_keeping_session!
reset_session
end

#
# Remember_me Tokens
#
# Cookies shouldn't be allowed to persist past their freshness date,
# and they should be changed at each login

# Cookies shouldn't be allowed to persist past their freshness date,
# and they should be changed at each login
Expand Down
22 changes: 22 additions & 0 deletions generators/authenticated/templates/authenticated_test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,26 @@ def login_as(<%= file_name %>)
def authorize_as(user)
@request.env["HTTP_AUTHORIZATION"] = user ? ActionController::HttpAuthentication::Basic.encode_credentials(users(user).login, 'test') : nil
end
<% if options[:include_activation] -%>
# For tests that include a mailer
def set_mailer_in_test
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
<% end -%>
<% if options[:rspec] -%>
# rspec
def mock_<%= file_name %>
<%= file_name %> = mock_model(<%= class_name %>, :id => 1,
:login => 'user_name',
:name => 'U. Surname',
:to_xml => "XML", :to_json => "JSON",
:errors => [])
<%= file_name %>
end
<% end -%>

end
6 changes: 2 additions & 4 deletions generators/authenticated/templates/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ def new
def create
logout_keeping_session!
<%= file_name %> = <%= class_name %>.authenticate(params[:login], params[:password])
if <%= file_name %>
if <%= file_name %>
# Protects against session fixation attacks, causes request forgery
# protection if user resubmits an earlier form using back
# button. Uncomment if you understand the tradeoffs.
# reset_session
# reset_session
self.current_<%= file_name %> = <%= file_name %>
if params[:remember_me] == "1"
make_or_refresh_remember_cookie!
Expand All @@ -38,11 +38,9 @@ def destroy
end

protected

# Track failed login attempts
def note_failed_signin
flash[:error] = "Couldn't log you in as '#{params[:login]}'"
logger.warn "Failed login for '#{params[:login]}' from #{request.remote_ip} at #{Time.now.utc}"
end

end
5 changes: 3 additions & 2 deletions generators/authenticated/templates/functional_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@
end

it 'does not remember me' do
<%= table_name %>(:quentin).forget_me
post :create, :login => 'quentin', :password => 'test', :remember_me => "0"
response.cookies["auth_token"].should be_nil
response.cookies["auth_token"].should be_blank
end

it 'deletes token on logout' do
login_as :quentin
get :destroy
response.cookies["auth_token"].should == []
response.cookies["auth_token"].should be_blank
end

it 'logs in with cookie' do
Expand Down
5 changes: 4 additions & 1 deletion generators/authenticated/templates/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,12 @@ def forget_me
save(false)
end

<% if options[:stateful] -%>
# Returns true if the user has just been activated.
def recently_activated?
@activated
end
<% end -%>

protected
# before filter
Expand All @@ -130,7 +132,8 @@ def password_required?
end
<% if options[:include_activation] %>
def make_activation_code
<% if options[:stateful] %> self.deleted_at = nil<% end %>
<% if options[:stateful] -%>
self.deleted_at = nil<% end %>
self.activation_code = self.class.make_token
end<% end %>
<% if options[:stateful] %>
Expand Down
5 changes: 2 additions & 3 deletions generators/authenticated/templates/model_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def new
end
def create
logout_keeping_session!
logout_keeping_session!
@<%= file_name %> = <%= class_name %>.new(params[:<%= file_name %>])
<% if options[:stateful] -%>
@<%= file_name %>.register! if @<%= file_name %> && @<%= file_name %>.valid?
Expand Down Expand Up @@ -51,7 +51,6 @@ def activate
flash[:error] = "We couldn't find a user with that activation code -- check your email? Or maybe you've already activated -- try signing in."
redirect_back_or_default('/')
end
redirect_back_or_default('/') # shouldn't get here
end
<% end %><% if options[:stateful] %>
def suspend
Expand Down Expand Up @@ -82,5 +81,5 @@ def purge
def find_<%= file_name %>
@<%= file_name %> = <%= class_name %>.find(params[:id])
end
<% end %>
<% end -%>
end
4 changes: 2 additions & 2 deletions generators/authenticated/templates/model_functional_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
it 'activates user' do
<%= class_name %>.authenticate('aaron', 'test').should be_nil
get :activate, :activation_code => <%= table_name %>(:aaron).activation_code
response.should redirect_to('/')
response.should redirect_to('/session/new')
flash[:notice].should_not be_nil
<%= class_name %>.authenticate('aaron', 'test').should == <%= table_name %>(:aaron)
end
Expand All @@ -83,4 +83,4 @@ def create_<%= file_name %>(options = {})
post :create, :<%= file_name %> => { :login => 'quire', :email => 'quire@example.com',
:password => 'quire', :password_confirmation => 'quire' }.merge(options)
end
end
end
23 changes: 15 additions & 8 deletions generators/authenticated/templates/model_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,22 @@ module <%= model_controller_class_name %>Helper
# !! Note: this is an *interface*, not *security* feature !!
# You need to do all access control at the controller level.
#
def if_authorized(action, resource, &block)
# Example:
# <%%= if_authorized?(:index, User) do link_to('List all users', users_path) end %> |
# <%%= if_authorized?(:edit, @user) do link_to('Edit this user', edit_user_path) end %> |
# <%%= if_authorized?(:destroy, @user) do link_to 'Destroy', @user, :confirm => 'Are you sure?', :method => :delete end %>
#
#
def if_authorized?(action, resource, &block)
if authorized?(action, resource)
yield action, resource
end
end

#
# Link to user's page ('<%= table_name %>/1') with their login as text. Their login will
# appear as the link title (its tooltip) and a 'nickname' class attribute
# (useful for microformats) will be inserted.
# Link to user's page ('<%= table_name %>/1')
#
# By default, their login is used as link text and link title (tooltip)
#
# Takes options
# * :content_text => 'Content text in place of <%= file_name %>.login', escaped with
Expand All @@ -25,13 +31,14 @@ def if_authorized(action, resource, &block)
#
# Examples:
# link_to_<%= file_name %> @<%= file_name %>
# # => <a href="/<%= table_name %>/3" title="barmy" class="nickname">barmy</a>
# # => <a href="/<%= table_name %>/3" title="barmy">barmy</a>
#
# # if you've added a .name attribute:
# content_tag :span, :class => :vcard do
# link_to_<%= file_name %> @<%= file_name %>, :class => 'fn n' :title_method => :login, :content_method => :name
# content_tag :span, :class => :vcard do
# (link_to_<%= file_name %> <%= file_name %>, :class => 'fn n', :title_method => :login, :content_method => :name) +
# ': ' + (content_tag :span, <%= file_name %>.email, :class => 'email')
# end
# # => <span class="vcard"><a href="/<%= table_name %>/3" title="barmy" class="fn n">Cyril Fotheringay-Phipps</a></span>
# # => <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>
#
# link_to_<%= file_name %> @<%= file_name %>, :content_text => 'Your user page'
# # => <a href="/<%= table_name %>/3" title="barmy" class="nickname">Your user page</a>
Expand Down

0 comments on commit 215673b

Please sign in to comment.