At the moment you've got to install the authlogic gem -- we will eventually need to package it as an RPM and add it as a dependency in the specfile.
Right now any user can create an account and access all pages. We aren't doing any access control beyond requiring a login account.
Signed-off-by: Scott Seago sseago@redhat.com --- src/app/controllers/application_controller.rb | 39 ++++++++++++++++ src/app/controllers/instance_controller.rb | 2 + src/app/controllers/portal_pool_controller.rb | 2 + src/app/controllers/provider_controller.rb | 2 + src/app/controllers/user_sessions_controller.rb | 24 ++++++++++ src/app/controllers/users_controller.rb | 36 +++++++++++++++ src/app/helpers/user_sessions_helper.rb | 2 + src/app/helpers/users_helper.rb | 2 + src/app/models/user.rb | 3 + src/app/models/user_session.rb | 8 +++ src/app/views/layouts/_header.rhtml | 8 +++- src/app/views/layouts/dcloud.rhtml | 2 +- src/app/views/user_sessions/login.html.erb | 18 ++++++++ src/app/views/users/_form.erb | 10 ++++ src/app/views/users/edit.html.erb | 11 +++++ src/app/views/users/new.html.erb | 9 ++++ src/app/views/users/show.html.erb | 40 +++++++++++++++++ src/config/environment.rb | 1 + src/config/routes.rb | 9 +++- src/db/migrate/20090917192602_create_users.rb | 30 ++++++++++++ src/test/fixtures/users.yml | 15 ++++++ src/test/functional/task_controller_test.rb | 47 -------------------- .../functional/user_sessions_controller_test.rb | 23 ++++++++++ src/test/functional/users_controller_test.rb | 38 ++++++++++++++++ src/test/test_helper.rb | 5 ++ src/test/unit/helpers/user_sessions_helper_test.rb | 4 ++ src/test/unit/helpers/users_helper_test.rb | 4 ++ src/test/unit/user_test.rb | 8 +++ 28 files changed, 350 insertions(+), 52 deletions(-) create mode 100644 src/app/controllers/user_sessions_controller.rb create mode 100644 src/app/controllers/users_controller.rb create mode 100644 src/app/helpers/user_sessions_helper.rb create mode 100644 src/app/helpers/users_helper.rb create mode 100644 src/app/models/user.rb create mode 100644 src/app/models/user_session.rb create mode 100644 src/app/views/user_sessions/login.html.erb create mode 100644 src/app/views/users/_form.erb create mode 100644 src/app/views/users/edit.html.erb create mode 100644 src/app/views/users/new.html.erb create mode 100644 src/app/views/users/show.html.erb create mode 100644 src/db/migrate/20090917192602_create_users.rb create mode 100644 src/test/fixtures/users.yml delete mode 100644 src/test/functional/task_controller_test.rb create mode 100644 src/test/functional/user_sessions_controller_test.rb create mode 100644 src/test/functional/users_controller_test.rb create mode 100644 src/test/unit/helpers/user_sessions_helper_test.rb create mode 100644 src/test/unit/helpers/users_helper_test.rb create mode 100644 src/test/unit/user_test.rb
diff --git a/src/app/controllers/application_controller.rb b/src/app/controllers/application_controller.rb index d32f1de..c417641 100644 --- a/src/app/controllers/application_controller.rb +++ b/src/app/controllers/application_controller.rb @@ -24,6 +24,8 @@ class ApplicationController < ActionController::Base # FIXME: not sure what we're doing aobut service layer w/ deltacloud include ApplicationService + filter_parameter_logging :password, :password_confirmation + helper_method :current_user_session, :current_user
init_gettext "ovirt" layout :choose_layout @@ -186,4 +188,41 @@ class ApplicationController < ActionController::Base end return hash end + + def current_user_session + return @current_user_session unless @current_user_session.nil? + @current_user_session = UserSession.find + end + + def current_user + return @current_user unless @current_user.nil? + @current_user = current_user_session && current_user_session.user + end + + def require_user + unless current_user + store_location + flash[:notice] = "You must be logged in to access this page" + redirect_to login_url + return false + end + end + + def require_no_user + if current_user + store_location + flash[:notice] = "You must be logged out to access this page" + redirect_to account_url + return false + end + end + + def store_location + session[:return_to] = request.request_uri + end + + def redirect_back_or_default(default) + redirect_to(session[:return_to] || default) + session[:return_to] = nil + end end diff --git a/src/app/controllers/instance_controller.rb b/src/app/controllers/instance_controller.rb index 398fdde..59e19ed 100644 --- a/src/app/controllers/instance_controller.rb +++ b/src/app/controllers/instance_controller.rb @@ -1,4 +1,6 @@ class InstanceController < ApplicationController + before_filter :require_user + def index end
diff --git a/src/app/controllers/portal_pool_controller.rb b/src/app/controllers/portal_pool_controller.rb index 49c2d90..9f41cf6 100644 --- a/src/app/controllers/portal_pool_controller.rb +++ b/src/app/controllers/portal_pool_controller.rb @@ -1,4 +1,6 @@ class PortalPoolController < ApplicationController + before_filter :require_user + def index render :action => 'new' end diff --git a/src/app/controllers/provider_controller.rb b/src/app/controllers/provider_controller.rb index 9b5e841..e0a96b7 100644 --- a/src/app/controllers/provider_controller.rb +++ b/src/app/controllers/provider_controller.rb @@ -1,4 +1,6 @@ class ProviderController < ApplicationController + before_filter :require_user + def index render :action => 'new' end diff --git a/src/app/controllers/user_sessions_controller.rb b/src/app/controllers/user_sessions_controller.rb new file mode 100644 index 0000000..7320ed0 --- /dev/null +++ b/src/app/controllers/user_sessions_controller.rb @@ -0,0 +1,24 @@ +class UserSessionsController < ApplicationController + before_filter :require_no_user, :only => [:new, :create] + before_filter :require_user, :only => :destroy + + def login + @user_session = UserSession.new + end + + def create + @user_session = UserSession.new(params[:user_session]) + if @user_session.save + flash[:notice] = "Login successful!" + redirect_back_or_default account_url + else + render :action => :login + end + end + + def logout + current_user_session.destroy + flash[:notice] = "Logout successful!" + redirect_back_or_default login_url + end +end diff --git a/src/app/controllers/users_controller.rb b/src/app/controllers/users_controller.rb new file mode 100644 index 0000000..9fd4212 --- /dev/null +++ b/src/app/controllers/users_controller.rb @@ -0,0 +1,36 @@ +class UsersController < ApplicationController + before_filter :require_no_user, :only => [:new, :create] + before_filter :require_user, :only => [:show, :edit, :update] + + def new + @user = User.new + end + + def create + @user = User.new(params[:user]) + if @user.save + flash[:notice] = "User registered!" + redirect_back_or_default account_url + else + render :action => :new + end + end + + def show + @user = @current_user + end + + def edit + @user = @current_user + end + + def update + @user = @current_user # makes our views "cleaner" and more consistent + if @user.update_attributes(params[:user]) + flash[:notice] = "User updated!" + redirect_to account_url + else + render :action => :edit + end + end +end diff --git a/src/app/helpers/user_sessions_helper.rb b/src/app/helpers/user_sessions_helper.rb new file mode 100644 index 0000000..2018402 --- /dev/null +++ b/src/app/helpers/user_sessions_helper.rb @@ -0,0 +1,2 @@ +module UserSessionsHelper +end diff --git a/src/app/helpers/users_helper.rb b/src/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/src/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/src/app/models/user.rb b/src/app/models/user.rb new file mode 100644 index 0000000..04c7d17 --- /dev/null +++ b/src/app/models/user.rb @@ -0,0 +1,3 @@ +class User < ActiveRecord::Base + acts_as_authentic +end diff --git a/src/app/models/user_session.rb b/src/app/models/user_session.rb new file mode 100644 index 0000000..6f99d26 --- /dev/null +++ b/src/app/models/user_session.rb @@ -0,0 +1,8 @@ +class UserSession < Authlogic::Session::Base + # gettext_activerecord defines a gettext method for the activerecord + # Validations module. Authlogic uses these Validations also but does + # not define the gettext method. We define it here instead. + def gettext(str) + GetText._(str) + end +end diff --git a/src/app/views/layouts/_header.rhtml b/src/app/views/layouts/_header.rhtml index 76f9e73..3086620 100644 --- a/src/app/views/layouts/_header.rhtml +++ b/src/app/views/layouts/_header.rhtml @@ -1,10 +1,14 @@ <div class="header_logo"><%= image_tag "dcloud.png" %></div>
<div class="header_info"> - <div id="hi-username">Hi, <%= @user %></div> + <div id="hi-username"> + <%= link_to "Hi, " + @current_user.login, + { :controller => "users", :action => "show"} unless @current_user.nil? %> + </div> <form method="POST" id="search-form" action="<%= url_for :controller => "search", :action => 'results' %>"> <input id="textfield_effect" name="terms" value="Search" onkeypress="" onfocus="if( this.value == this.defaultValue ) this.value='';" type="text"> <input id="searchbox-button" src="<%= image_path "icon_search.png"%>" title="Search" type="image"> | </form> - <%= link_to 'Log out', { :controller => "login", :action => "logout"}%> + <%= link_to 'Log out', logout_url unless @current_user.nil? %> + <%= link_to 'Log in', login_url if @current_user.nil? %> </div> \ No newline at end of file diff --git a/src/app/views/layouts/dcloud.rhtml b/src/app/views/layouts/dcloud.rhtml index 725f630..60e0ad8 100644 --- a/src/app/views/layouts/dcloud.rhtml +++ b/src/app/views/layouts/dcloud.rhtml @@ -69,7 +69,7 @@ </div>
<div id="side"> - <%= render :partial => '/layouts/main_nav' %> + <%= render :partial => '/layouts/main_nav' unless @current_user.nil? %> </div>
<div id="tabs-and-content-container"> diff --git a/src/app/views/user_sessions/login.html.erb b/src/app/views/user_sessions/login.html.erb new file mode 100644 index 0000000..ee7da51 --- /dev/null +++ b/src/app/views/user_sessions/login.html.erb @@ -0,0 +1,18 @@ +<div class="dcloud_form"> + <h2>Login</h2> + + <% form_for @user_session, :url => user_session_path do |f| %> + <%= f.error_messages %> + <%= f.label :login %><br /> + <%= f.text_field :login %><br /> + <br /> + <%= f.label :password %><br /> + <%= f.password_field :password %><br /> + <br /> + <%= f.check_box :remember_me %><%= f.label :remember_me %><br /> + <br /> + <%= f.submit "Login" %> + <% end %> + <%= link_to 'Register', {:controller => 'users', :action => 'new'}, :class => 'actionlink' %> + +</div> diff --git a/src/app/views/users/_form.erb b/src/app/views/users/_form.erb new file mode 100644 index 0000000..a278d9a --- /dev/null +++ b/src/app/views/users/_form.erb @@ -0,0 +1,10 @@ +<%= form.label :login %><br /> +<%= form.text_field :login %><br /> +<%= form.label :email %><br /> +<%= form.text_field :email %><br /> +<br /> +<%= form.label :password, form.object.new_record? ? nil : "Change password" %><br /> +<%= form.password_field :password %><br /> +<br /> +<%= form.label :password_confirmation %><br /> +<%= form.password_field :password_confirmation %><br /> diff --git a/src/app/views/users/edit.html.erb b/src/app/views/users/edit.html.erb new file mode 100644 index 0000000..73fdedd --- /dev/null +++ b/src/app/views/users/edit.html.erb @@ -0,0 +1,11 @@ +<div class="dcloud_form"> + <h2>Edit My Profile</h2> + + <% form_for @user, :url => account_path do |f| %> + <%= f.error_messages %> + <%= render :partial => "form", :object => f %> + <%= f.submit "Update" %> + <% end %> + + <br /><%= link_to "My Profile", account_path, :class => 'actionlink' %> +</div> diff --git a/src/app/views/users/new.html.erb b/src/app/views/users/new.html.erb new file mode 100644 index 0000000..d6a35e4 --- /dev/null +++ b/src/app/views/users/new.html.erb @@ -0,0 +1,9 @@ +<div class="dcloud_form"> + <h2>Register</h2> + + <% form_for @user, :url => account_path do |f| %> + <%= f.error_messages %> + <%= render :partial => "form", :object => f %> + <%= f.submit "Register" %> + <% end %> +</div> diff --git a/src/app/views/users/show.html.erb b/src/app/views/users/show.html.erb new file mode 100644 index 0000000..632b630 --- /dev/null +++ b/src/app/views/users/show.html.erb @@ -0,0 +1,40 @@ +<div class="dcloud_form"> + <h2>User Profile for <%=h @user.login %></h2> +<p> + <b>Login:</b> + <%=h @user.login %> +</p> + +<p> + <b>Login count:</b> + <%=h @user.login_count %> +</p> + +<p> + <b>Last request at:</b> + <%=h @user.last_request_at %> +</p> + +<p> + <b>Last login at:</b> + <%=h @user.last_login_at %> +</p> + +<p> + <b>Current login at:</b> + <%=h @user.current_login_at %> +</p> + +<p> + <b>Last login ip:</b> + <%=h @user.last_login_ip %> +</p> + +<p> + <b>Current login ip:</b> + <%=h @user.current_login_ip %> +</p> + + +<%= link_to 'Edit', edit_account_path, :class => 'actionlink' %> +</div> diff --git a/src/config/environment.rb b/src/config/environment.rb index 5098306..9a3433d 100644 --- a/src/config/environment.rb +++ b/src/config/environment.rb @@ -42,6 +42,7 @@ Rails::Initializer.run do |config| # config.gem "aws-s3", :lib => "aws/s3" config.gem "gettext", :lib => "gettext_rails" config.gem "gettext", :lib => "gettext_activerecord" + config.gem "authlogic"
# Only load the plugins named here, in the order given. By default, all plugins # in vendor/plugins are loaded in alphabetical order. diff --git a/src/config/routes.rb b/src/config/routes.rb index ae9bc75..6e08af0 100644 --- a/src/config/routes.rb +++ b/src/config/routes.rb @@ -33,8 +33,13 @@ ActionController::Routing::Routes.draw do |map| # -- just remember to delete public/index.html. map.default '', :controller => 'provider'
- map.login '/login', :controller => 'resources', :action => 'list' - map.logout '/logout', :controller => 'resources', :action => 'list' + map.resource :user_session + map.root :controller => "user_sessions", :action => "login" + map.login 'login', :controller => "user_sessions", :action => "login" + map.logout 'logout', :controller => "user_sessions", :action => "logout" + map.resource :account, :controller => "users" + map.resources :users +
# Allow downloading Web Service WSDL as a file with an extension # instead of a file named 'wsdl' diff --git a/src/db/migrate/20090917192602_create_users.rb b/src/db/migrate/20090917192602_create_users.rb new file mode 100644 index 0000000..1bcf0d4 --- /dev/null +++ b/src/db/migrate/20090917192602_create_users.rb @@ -0,0 +1,30 @@ +class CreateUsers < ActiveRecord::Migration + def self.up + create_table :users do |t| + t.string :login, :null => false + t.string :email, :null => false + t.string :crypted_password, :null => false + t.string :password_salt, :null => false + t.string :persistence_token, :null => false + t.string :single_access_token, :null => false + t.string :perishable_token, :null => false + # Magic columns, just like ActiveRecord's created_at and updated_at. + # These are automatically maintained by Authlogic if they are present. + t.integer :login_count, :null => false, :default => 0 + t.integer :failed_login_count, :null => false, :default => 0 + t.datetime :last_request_at + t.datetime :current_login_at + t.datetime :last_login_at + t.string :current_login_ip + t.string :last_login_ip + t.timestamps + end + add_index :users, :login + add_index :users, :persistence_token + add_index :users, :last_request_at + end + + def self.down + drop_table :users + end +end diff --git a/src/test/fixtures/users.yml b/src/test/fixtures/users.yml new file mode 100644 index 0000000..3a3acb5 --- /dev/null +++ b/src/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value +test_user: + login: tuser + email: tuser@example.com + password_salt: <%= salt = Authlogic::Random.hex_token %> + crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("testpass" + salt) %> + persistence_token: 5136b29cb04a5b8840fe74451b8bdf83531f57c072826eaf63a5c05e71828ed58fc5359a2f22b02e54298d64e043a870bc03d898249dd7f577f6c5418d5ba5a6 + single_access_token: YxaPK0smnUj2t9Pq0xuK + perishable_token: XZO-3xU2OIqHAUJOkDMX diff --git a/src/test/functional/task_controller_test.rb b/src/test/functional/task_controller_test.rb deleted file mode 100644 index a2a6393..0000000 --- a/src/test/functional/task_controller_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (C) 2008 Red Hat, Inc. -# Written by Scott Seago sseago@redhat.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. A copy of the GNU General Public License is -# also available at http://www.gnu.org/copyleft/gpl.html. - -require File.dirname(__FILE__) + '/../test_helper' -require 'task_controller' - -# Re-raise errors caught by the controller. -class TaskController; def rescue_action(e) raise e end; end - -class TaskControllerTest < ActionController::TestCase - fixtures :tasks, :vms, :pools - - def setup - @controller = TaskController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - - @task_id = tasks(:shutdown_production_httpd_appliance_task).id - end - - def test_show - get :show, :id => @task_id - - assert_response :success - assert_template 'show' - - assert_not_nil assigns(:task) - assert assigns(:task).valid? - end - -end diff --git a/src/test/functional/user_sessions_controller_test.rb b/src/test/functional/user_sessions_controller_test.rb new file mode 100644 index 0000000..cac84a9 --- /dev/null +++ b/src/test/functional/user_sessions_controller_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class UserSessionsControllerTest < ActionController::TestCase + fixtures :users + test "should get new" do + get :login + assert_response :success + end + + test "should create user session" do + post :create, :user_session => { :login => "tuser", :password => "testpass" } + assert user_session = UserSession.find + assert_equal users(:test_user), user_session.user + assert_redirected_to account_path + end + + test "should destroy user session" do + post :create, :user_session => { :login => "tuser", :password => "testpass" } + delete :logout + assert_nil UserSession.find + assert_redirected_to login_path + end +end diff --git a/src/test/functional/users_controller_test.rb b/src/test/functional/users_controller_test.rb new file mode 100644 index 0000000..0f04dd2 --- /dev/null +++ b/src/test/functional/users_controller_test.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class UsersControllerTest < ActionController::TestCase + fixtures :users + + test "should get new" do + get :new + assert_response :success + end + + test "should create user" do + assert_difference('User.count') do + post :create, :user => { :login => "tuser2", :email => "tuser2@example.com", + :password => "testpass", + :password_confirmation => "testpass" } + end + + assert_redirected_to account_path + end + + test "should show user" do + UserSession.create(users(:test_user)) + get :show + assert_response :success + end + + test "should get edit" do + UserSession.create(users(:test_user)) + get :edit, :id => users(:test_user).id + assert_response :success + end + + test "should update user" do + UserSession.create(users(:test_user)) + put :update, :id => users(:test_user).id, :user => { } + assert_redirected_to account_path + end +end diff --git a/src/test/test_helper.rb b/src/test/test_helper.rb index 009dfc8..7d902b7 100644 --- a/src/test/test_helper.rb +++ b/src/test/test_helper.rb @@ -20,6 +20,7 @@ ENV["RAILS_ENV"] = "test" require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require 'test_help' +require 'authlogic/test_case'
class ActiveSupport::TestCase # Transactional fixtures accelerate your tests by wrapping each test method @@ -48,3 +49,7 @@ class ActiveSupport::TestCase RAILS_DEFAULT_LOGGER end end + +class ActionController::TestCase + setup :activate_authlogic +end diff --git a/src/test/unit/helpers/user_sessions_helper_test.rb b/src/test/unit/helpers/user_sessions_helper_test.rb new file mode 100644 index 0000000..20dabdf --- /dev/null +++ b/src/test/unit/helpers/user_sessions_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class UserSessionsHelperTest < ActionView::TestCase +end diff --git a/src/test/unit/helpers/users_helper_test.rb b/src/test/unit/helpers/users_helper_test.rb new file mode 100644 index 0000000..96af37a --- /dev/null +++ b/src/test/unit/helpers/users_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class UsersHelperTest < ActionView::TestCase +end diff --git a/src/test/unit/user_test.rb b/src/test/unit/user_test.rb new file mode 100644 index 0000000..a64d2d3 --- /dev/null +++ b/src/test/unit/user_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end
On Mon, Oct 5, 2009 at 4:15 PM, Scott Seago sseago@redhat.com wrote:
At the moment you've got to install the authlogic gem -- we will eventually need to package it as an RPM and add it as a dependency in the specfile.
Right now any user can create an account and access all pages. We aren't doing any access control beyond requiring a login account.
Signed-off-by: Scott Seago sseago@redhat.com
ACK, tests (yay!) all pass, issues I hit on previous revision are no longer present. However, I would still like to see a note in the README telling people of the fact that authlogic is not yet an rpm, and how to get around that. Note that we also have the option of putting it up in a personal repo on fedorapeople until we can get it into fedora proper.
Two things I noticed that do not need to be addressed here, but I wanted to mention. First, there is a minor style issue that does not need to be addressed here, just thought I would mention it - if you fail validation on the login form, the 'register' link gets wrapped down to the next line. Jeremy P, if you have time to fix this, that would be great, otherwise I'll get to it at some point.
Second, I noticed when I ran rake:test, I got failures on VmTaskTest. When I looked at this, it is because there is no such thing as a VmTask currently. Not sure if this was added and dropped, or just an error, but we should get rid of this class if there is no need for it.
deltacloud-devel@lists.fedorahosted.org