diff --git a/app/controllers/public/account_controller.rb b/app/controllers/public/account_controller.rb index 4b04572..6d0cb94 100644 --- a/app/controllers/public/account_controller.rb +++ b/app/controllers/public/account_controller.rb @@ -25,11 +25,13 @@ class AccountController < ApplicationController # action to perform login to the application def login - @user = User.new - @person = @user.build_person store_location(request.referer) unless session[:return_to] return unless request.post? - self.current_user = User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] + + self.current_user = plugins_alternative_authentication + + self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] + if logged_in? if params[:remember_me] == "1" self.current_user.remember_me @@ -41,7 +43,6 @@ class AccountController < ApplicationController end else session[:notice] = _('Incorrect username or password') if redirect? - redirect_to :back if redirect? end end @@ -56,6 +57,10 @@ class AccountController < ApplicationController # action to register an user to the application def signup + if @plugins.dispatch(:allow_user_registration).include?(false) + redirect_back_or_default(:controller => 'home') + end + @invitation_code = params[:invitation_code] begin if params[:user] @@ -125,6 +130,9 @@ class AccountController < ApplicationController # # Posts back. def forgot_password + if @plugins.dispatch(:allow_password_recovery).include?(false) + redirect_back_or_default(:controller => 'home') + end @change_password = ChangePassword.new(params[:change_password]) if request.post? @@ -316,4 +324,13 @@ class AccountController < ApplicationController end end + def plugins_alternative_authentication + user = nil + @plugins.each do |plugin| + user = plugin.alternative_authentication + break unless user.nil? + end + user + end + end diff --git a/app/models/person.rb b/app/models/person.rb index 378ad3a..37c5f27 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -71,10 +71,7 @@ class Person < Profile Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } end - after_destroy :destroy_user - def destroy_user - self.user.destroy if self.user - end + belongs_to :user, :dependent => :delete def can_control_scrap?(scrap) begin diff --git a/app/models/user.rb b/app/models/user.rb index 307b69d..da9b5f0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,7 +30,7 @@ class User < ActiveRecord::Base after_create do |user| user.person ||= Person.new - user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id) + user.person.attributes = user.person_data.merge(:identifier => user.login, :user => user, :environment_id => user.environment_id) user.person.name ||= user.login user.person.visible = false unless user.activated? user.person.save! @@ -88,13 +88,13 @@ class User < ActiveRecord::Base attr_protected :activated_at # Virtual attribute for the unencrypted password - attr_accessor :password + attr_accessor :password, :name validates_presence_of :login, :email validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) validates_presence_of :password, :if => :password_required? - validates_presence_of :password_confirmation, :if => :password_required?, :if => (lambda {|user| !user.password.blank?}) - validates_length_of :password, :within => 4..40, :if => :password_required?, :if => (lambda {|user| !user.password.blank?}) + validates_presence_of :password_confirmation, :if => :password_required? + validates_length_of :password, :within => 4..40, :if => :password_required? validates_confirmation_of :password, :if => :password_required? validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?}) validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?}) @@ -228,7 +228,12 @@ class User < ActiveRecord::Base end def name - person ? person.name : login + name = (self[:name] || login) + person.nil? ? name : (person.name || name) + end + + def name= name + self[:name] = name end def enable_email! @@ -274,6 +279,11 @@ class User < ActiveRecord::Base 15 # in minutes end + + def not_require_password! + @is_password_required = false + end + protected # before filter def encrypt_password @@ -282,9 +292,13 @@ class User < ActiveRecord::Base self.password_type ||= User.system_encryption_method.to_s self.crypted_password = encrypt(password) end - + def password_required? - crypted_password.blank? || !password.blank? + (crypted_password.blank? || !password.blank?) && is_password_required? + end + + def is_password_required? + @is_password_required.nil? ? true : @is_password_required end def make_activation_code diff --git a/app/views/account/login.rhtml b/app/views/account/login.rhtml index 69ec0fc..5ab7e8c 100644 --- a/app/views/account/login.rhtml +++ b/app/views/account/login.rhtml @@ -13,6 +13,8 @@ <%= f.password_field :password %> + <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %> + <% button_bar do %> <%= submit_button( 'login', _('Log in') )%> <% if is_thickbox %> @@ -23,8 +25,13 @@ <% end %> <% button_bar do %> - <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %> - <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> + <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %> + <% end %> + + <% unless @plugins.dispatch(:allow_password_recovery).include?(false) %> + <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> + <% end %> <% end %> diff --git a/app/views/layouts/application-ng.rhtml b/app/views/layouts/application-ng.rhtml index 838fb19..480e3f9 100644 --- a/app/views/layouts/application-ng.rhtml +++ b/app/views/layouts/application-ng.rhtml @@ -56,10 +56,18 @@ <%= usermenu_logged_in %>
diff --git a/config/routes.rb b/config/routes.rb index 207529c..c80bb6a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,6 +19,7 @@ ActionController::Routing::Routes.draw do |map| # -- just remember to delete public/index.html. # You can have the root of your site routed by hooking up '' + map.root :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } map.connect '', :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } map.home 'site/:action', :controller => 'home' diff --git a/lib/noosfero/plugin.rb b/lib/noosfero/plugin.rb index b193d5e..3868559 100644 --- a/lib/noosfero/plugin.rb +++ b/lib/noosfero/plugin.rb @@ -320,6 +320,37 @@ class Noosfero::Plugin nil end + # -> Add an alternative authentication method. + # Your plugin have to make the access control and return the logged user. + # returns = User + def alternative_authentication + nil + end + + # -> Adds adicional link to make the user authentication + # returns = lambda block that creates html code + def alternative_authentication_link + nil + end + + # -> Allow or not user registration + # returns = boolean + def allow_user_registration + true + end + + # -> Allow or not password recovery by users + # returns = boolean + def allow_password_recovery + true + end + + # -> Adds fields to the login form + # returns = lambda block that creates html code + def login_extra_contents + nil + end + def method_missing(method, *args, &block) # This is a generic hotspot for all controllers on Noosfero. # If any plugin wants to define filters to run on any controller, the name of diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index 647b7ef..c732664 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -11,6 +11,10 @@ class AccountControllerTest < ActionController::TestCase all_fixtures + def teardown + Thread.current[:enabled_plugins] = nil + end + def setup @controller = AccountController.new @request = ActionController::TestRequest.new @@ -31,13 +35,11 @@ class AccountControllerTest < ActionController::TestCase assert_response :redirect end - should 'redirect to where user was on login' do - @request.env["HTTP_REFERER"] = '/bli' - u = new_user + should 'display notice message if the login fail' do @controller.stubs(:logged_in?).returns(false) post :login, :user => {:login => 'quire', :password => 'quire'} - assert_redirected_to '/bli' + assert session[:notice].include?('Incorrect') end should 'authenticate on the current environment' do @@ -46,23 +48,11 @@ class AccountControllerTest < ActionController::TestCase post :login, :user => { :login => 'fake', :password => 'fake' } end - should 'redirect to where was when login on other environment' do - e = fast_create(Environment, :name => 'other_environment') - e.domains << Domain.new(:name => 'other.environment') - e.save! - u = create_user('test_user', :environment => e).person - - @request.env["HTTP_REFERER"] = '/bli' - post :login, :user => {:login => 'test_user', :password => 'test_user'} - - assert_redirected_to '/bli' - end - def test_should_fail_login_and_not_redirect @request.env["HTTP_REFERER"] = 'bli' post :login, :user => {:login => 'johndoe', :password => 'bad password'} assert_nil session[:user] - assert_response :redirect + assert_response :success end def test_should_allow_signup @@ -697,7 +687,6 @@ class AccountControllerTest < ActionController::TestCase assert_nil assigns(:message) post :login, :user => {:login => 'testuser', :password => 'test123'} assert_nil session[:user] - assert_redirected_to '/bli' end should 'not activate user when activation code is incorrect' do @@ -707,7 +696,6 @@ class AccountControllerTest < ActionController::TestCase assert_nil assigns(:message) post :login, :user => {:login => 'testuser', :password => 'test123'} assert_nil session[:user] - assert_redirected_to '/bli' end should 'be able to upload an image' do @@ -777,6 +765,122 @@ class AccountControllerTest < ActionController::TestCase assert_tag :tag => 'strong', :content => 'Plugin2 text' end + should 'login with an alternative authentication defined by plugin' do + class Plugin1 < Noosfero::Plugin + def alternative_authentication + User.new(:login => 'testuser') + end + end + Environment.default.enable_plugin(Plugin1.name) + + post :login, :user => {:login => "testuser"} + + assert_equal 'testuser', assigns(:current_user).login + assert_response :redirect + end + + should "login with the default autentication if the alternative authentication method doesn't login the user" do + class Plugin1 < Noosfero::Plugin + def alternative_authentication + nil + end + end + Environment.default.enable_plugin(Plugin1.name) + post :login, :user => {:login => 'johndoe', :password => 'test'} + assert session[:user] + assert_equal 'johndoe', assigns(:current_user).login + assert_response :redirect + end + + should "redirect user on signup if a plugin doesn't allow user registration" do + class TestRegistrationPlugin < Noosfero::Plugin + def allow_user_registration + false + end + end + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestRegistrationPlugin.new]) + + post :signup, :user => { :login => 'testuser', :password => '123456', :password_confirmation => '123456', :email => 'testuser@example.com' } + assert_response :redirect + end + + should "not display the new user button on login page if not allowed by any plugin" do + class Plugin1 < Noosfero::Plugin + def allow_user_registration + false + end + end + + class Plugin2 < Noosfero::Plugin + def allow_user_registration + true + end + end + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new]) + + get :login + + assert_no_tag :tag => 'a', :attributes => {:href => '/account/signup'} + end + + should "redirect user on forgot_password action if a plugin doesn't allow user to recover its password" do + class TestRegistrationPlugin < Noosfero::Plugin + def allow_password_recovery + false + end + end + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestRegistrationPlugin.new]) + + #Redirect on get action + get :forgot_password + assert_response :redirect + + #Redirect on post action + post :forgot_password, :change_password => { :login => 'test', :email => 'test@localhost.localdomain' } + assert_response :redirect + end + + should "not display the forgot password button on login page if not allowed by any plugin" do + class Plugin1 < Noosfero::Plugin + def allow_password_recovery + false + end + end + + class Plugin2 < Noosfero::Plugin + def allow_password_recovery + true + end + end + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new]) + + get :login + + assert_no_tag :tag => 'a', :attributes => {:href => '/account/forgot_password'} + end + + should 'add extra content on login form from plugins' do + class Plugin1 < Noosfero::Plugin + def login_extra_contents + lambda {"Plugin1 text"} + end + end + class Plugin2 < Noosfero::Plugin + def login_extra_contents + lambda {"Plugin2 text"} + end + end + + Environment.default.enable_plugin(Plugin1.name) + Environment.default.enable_plugin(Plugin2.name) + + get :login + + assert_tag :tag => 'strong', :content => 'Plugin1 text' + assert_tag :tag => 'strong', :content => 'Plugin2 text' + end + + protected def new_user(options = {}, extra_options ={}) data = {:profile_data => person_data} diff --git a/test/functional/home_controller_test.rb b/test/functional/home_controller_test.rb index b9b78f7..99233ef 100644 --- a/test/functional/home_controller_test.rb +++ b/test/functional/home_controller_test.rb @@ -6,8 +6,11 @@ class HomeController; def rescue_action(e) raise e end; end class HomeControllerTest < ActionController::TestCase -# all_fixtures:profiles, :environments, :domains -all_fixtures + def teardown + Thread.current[:enabled_plugins] = nil + end + + all_fixtures def setup @controller = HomeController.new @request = ActionController::TestRequest.new @@ -93,4 +96,44 @@ all_fixtures assert_tag :content => /Noosfero terms of use/ end + should 'provide a link to make the user authentication' do + class Plugin1 < Noosfero::Plugin + def alternative_authentication_link + lambda {"Plugin1 link"} + end + end + class Plugin2 < Noosfero::Plugin + def alternative_authentication_link + lambda {"Plugin2 link"} + end + end + + Environment.default.enable_plugin(Plugin1) + Environment.default.enable_plugin(Plugin2) + + get :index + + assert_tag :tag => 'a', :content => 'Plugin1 link' + assert_tag :tag => 'a', :content => 'Plugin2 link' + end + + should "not display the new user button on login page if now allowed by any plugin" do + class Plugin1 < Noosfero::Plugin + def allow_user_registration + false + end + end + + class Plugin2 < Noosfero::Plugin + def allow_user_registration + true + end + end + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new]) + + get :index + + assert_no_tag :tag => 'a', :attributes => {:href => '/account/signup'} + end + end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 2863dea..88d9cb1 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -403,12 +403,29 @@ class UserTest < ActiveSupport::TestCase assert_equal 'Test User', user.name end - should 'respond name with login, if there is no person related' do + should 'respond name with login, if there is no person related and name defined' do user = create_user('testuser') user.person = nil + user.name = nil assert_equal 'testuser', user.name end + should 'respond name with user name attribute' do + user = create_user('testuser') + user.person = nil + user.name = 'Another User' + user.login = 'Login User' + assert_equal 'Another User', user.name + end + + should 'respond name with related person name although user name attribute is defined' do + user = create_user('testuser') + user.person.name = 'Person Name' + user.name = 'Another User' + user.login = 'Login User' + assert_equal 'Person Name', user.name + end + should 'have activation code' do user = create_user('testuser') assert_respond_to user, :activation_code @@ -499,6 +516,12 @@ class UserTest < ActiveSupport::TestCase assert !user.activate end + should 'be able to skip the password requirement' do + user = User.new(:login => 'quire', :email => 'quire@example.com') + user.not_require_password! + assert user.save! + end + protected def new_user(options = {}) user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options)) -- libgit2 0.21.2