Commit e56e2fd3d93bb0cc99bdd17de977c63d3f5c83a0

Authored by Gabriel Silva
1 parent f919a26e

Adds federation behavior to OAuthClient plugin

- Logs in with different providers without creating a Noosfero user
- Overrides user info based on the service
- Adds option to enable the plugin federation

Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com>
Signed-off-by: Sabryna Sousa <sabryna.sousa1323@gmail.com>
Signed-off-by: Victor Navarro <victor.matias.navarro@gmail.com>
Signed-off-by: Vitor Barbosa <vitornga15@gmail.com>
Signed-off-by: Artur Bersan de Faria <artur_bersan@hotmail.com>
Signed-off-by: Matheus Miranda <matheusmirandalacerda@gmail.com>
Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com>
Signed-off-by: Dylan Guedes <djmgguedes@gmail.com>
Showing 33 changed files with 534 additions and 87 deletions   Show diff stats
app/controllers/public/account_controller.rb
... ... @@ -154,7 +154,7 @@ class AccountController &lt; ApplicationController
154 154  
155 155 # action to perform logout from the application
156 156 def logout
157   - if logged_in?
  157 + if logged_in? && self.current_user.id.present?
158 158 self.current_user.forget_me
159 159 end
160 160 reset_session
... ...
app/models/external_person.rb
... ... @@ -122,6 +122,10 @@ class ExternalPerson &lt; ActiveRecord::Base
122 122 "#{jid(options)}/#{self.name}"
123 123 end
124 124  
  125 + def name
  126 + "#{self[:name]}@#{self.source}"
  127 + end
  128 +
125 129 class ExternalPerson::Image
126 130 def initialize(path)
127 131 @path = path
... ... @@ -198,7 +202,10 @@ class ExternalPerson &lt; ActiveRecord::Base
198 202 relationships_cache_key: '', is_member_of?: false, follows?: false,
199 203 each_friend: nil, is_last_admin?: false, is_last_admin_leaving?: false,
200 204 leave: nil, last_notification: nil, notification_time: 0, notifier: nil,
201   - remove_suggestion: nil, allow_invitation_from?: false
  205 + remove_suggestion: nil, allow_invitation_from?: false,
  206 + tracked_actions: ActionTracker::Record.none, follow: [],
  207 + update_profile_circles: ProfileFollower.none, unfollow: ProfileFollower.none,
  208 + remove_profile_from_circle: ProfileFollower.none, followed_profiles: Profile.none
202 209 }
203 210  
204 211 derivated_methods = generate_derivated_methods(methods_and_responses)
... ... @@ -255,7 +262,8 @@ class ExternalPerson &lt; ActiveRecord::Base
255 262 {}, followed_by?: false, display_private_info_to?: true, can_view_field?:
256 263 true, remove_from_suggestion_list: nil, layout_template: 'default',
257 264 is_admin?: false, add_friend: false, follows?: false, is_a_friend?: false,
258   - already_request_friendship?: false
  265 + already_request_friendship?: false, allow_followers: false,
  266 + in_social_circle: false, in_circle: false
259 267 }
260 268  
261 269 derivated_methods = generate_derivated_methods(methods_and_responses)
... ...
features/external_login.feature
... ... @@ -7,8 +7,8 @@ Feature: external login
7 7 Scenario: login from portal homepage
8 8 Given feature "allow_change_of_redirection_after_login" is disabled on environment
9 9 And the following external environments
10   - | identifier | name | url |
11   - | test | Test | http://federated.noosfero.org |
  10 + | identifier | name | url |
  11 + | test | Test | http://federated.noosfero.org/ |
12 12 And the following external users
13 13 | login |
14 14 | joaosilva@federated.noosfero.org |
... ... @@ -26,8 +26,8 @@ Feature: external login
26 26 Scenario: not login from portal homepage
27 27 Given feature "allow_change_of_redirection_after_login" is disabled on environment
28 28 And the following external environments
29   - | identifier | name | url |
30   - | test | Test | http://federated.noosfero.org |
  29 + | identifier | name | url |
  30 + | test | Test | http://federated.noosfero.org/ |
31 31 And I am not logged in
32 32 And I go to the homepage
33 33 And I follow "Login"
... ...
plugins/oauth_client/controllers/oauth_client_plugin_admin_controller.rb
1 1 class OauthClientPluginAdminController < AdminController
2 2  
3 3 def index
  4 + @config = OauthClientPlugin::Config.instance
4 5 end
5 6  
6 7 def new
... ... @@ -13,6 +14,11 @@ class OauthClientPluginAdminController &lt; AdminController
13 14 redirect_to :action => 'index'
14 15 end
15 16  
  17 + def update_configs
  18 + OauthClientPlugin::Config.instance.update_attributes(params[:oauth_client_config])
  19 + redirect_to :action => 'index'
  20 + end
  21 +
16 22 def edit
17 23 @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new
18 24 if request.post?
... ... @@ -24,4 +30,8 @@ class OauthClientPluginAdminController &lt; AdminController
24 30 end
25 31 end
26 32  
  33 + def edit_login_option
  34 + option = params['oauth_client_plugin_option']
  35 + end
  36 +
27 37 end
... ...
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb
... ... @@ -3,9 +3,15 @@ class OauthClientPluginPublicController &lt; PublicController
3 3 skip_before_filter :login_required
4 4  
5 5 def callback
6   - auth = request.env["omniauth.auth"]
7   - auth_user = environment.users.where(email: auth.info.email).first
8   - if auth_user then login auth_user.person else signup auth end
  6 + auth_data = request.env["omniauth.auth"]
  7 + oauth_params = request.env["omniauth.params"]
  8 +
  9 + if oauth_params && oauth_params["action"] == "external_login"
  10 + external_person_login(auth_data)
  11 + else
  12 + auth_user = environment.users.where(email: auth_data.info.email).first
  13 + if auth_user then login(auth_user.person) else signup(auth_data) end
  14 + end
9 15 end
10 16  
11 17 def failure
... ... @@ -20,12 +26,45 @@ class OauthClientPluginPublicController &lt; PublicController
20 26  
21 27 protected
22 28  
23   - def login person
  29 + def external_person_login(auth_data)
24 30 provider = OauthClientPlugin::Provider.find(session[:provider_id])
25   - auth = person.oauth_auths.where(provider_id: provider.id).first
26   - auth ||= person.oauth_auths.create! profile: person, provider: provider, enabled: true
27   - if auth.enabled? && provider.enabled?
28   - self.current_user = person.user
  31 +
  32 + user = User.new(email: auth_data.info.email, login: auth_data.info.name.to_slug)
  33 + person = OauthClientPlugin::OauthExternalPerson.find_or_create_by(
  34 + identifier: auth_data.info.nickname || user.login,
  35 + name: auth_data.info.name,
  36 + created_at: Time.now,
  37 + source: provider.site || auth_data.provider,
  38 + email: user.email
  39 + )
  40 + user.external_person_id = person.id
  41 +
  42 + oauth_auth = person.oauth_auth
  43 + oauth_data = { profile: person, provider: provider, enabled: true,
  44 + external_person_uid: auth_data.uid, external_person_image_url: auth_data.info.image }
  45 + oauth_auth ||= OauthClientPlugin::Auth.create_for_strategy(provider.strategy, oauth_data)
  46 + create_session(user, oauth_auth)
  47 + end
  48 +
  49 + def signup(auth_data)
  50 + session[:oauth_data] = auth_data
  51 + username = auth_data.info.email.split('@').first
  52 + name = auth_data.info.name
  53 + name ||= auth_data.extra && auth_data.extra.raw_info ? auth_data.extra.raw_info.name : ''
  54 + redirect_to :controller => :account, :action => :signup, :user => {:login => username, :email => auth_data.info.email}, :profile_data => {:name => name}
  55 + end
  56 +
  57 + def login(person)
  58 + auth = person.oauth_auths.find_or_create_by(profile: person,
  59 + provider_id: session[:provider_id])
  60 + create_session(person.user, auth)
  61 + end
  62 +
  63 + def create_session(user, oauth_auth)
  64 + provider = OauthClientPlugin::Provider.find(session[:provider_id])
  65 +
  66 + if oauth_auth.allow_login?
  67 + self.current_user = user
29 68 else
30 69 session[:notice] = _("Can't login with %s") % provider.name
31 70 end
... ... @@ -33,12 +72,4 @@ class OauthClientPluginPublicController &lt; PublicController
33 72 redirect_to :controller => :account, :action => :login
34 73 end
35 74  
36   - def signup(auth)
37   - login = auth.info.email.split('@').first
38   - session[:oauth_data] = auth
39   - name = auth.info.name
40   - name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : ''
41   - redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name}
42   - end
43   -
44 75 end
... ...
plugins/oauth_client/db/migrate/20160714113820_create_oauth_client_plugin_config.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class CreateOauthClientPluginConfig < ActiveRecord::Migration
  2 +
  3 + def change
  4 + create_table :oauth_client_plugin_configs do |t|
  5 + t.belongs_to :environment
  6 + t.boolean :allow_external_login, :default => false
  7 + end
  8 + end
  9 +end
... ...
plugins/oauth_client/db/migrate/20160720165808_add_external_profile_to_oauth_auth.rb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +class AddExternalProfileToOauthAuth < ActiveRecord::Migration
  2 + def up
  3 + add_column :oauth_client_plugin_auths, :profile_type, :string
  4 + add_index :oauth_client_plugin_auths, :profile_type
  5 +
  6 + add_column :oauth_client_plugin_auths, :external_person_uid, :string
  7 + add_column :oauth_client_plugin_auths, :external_person_image_url, :string
  8 +
  9 + change_column_default :oauth_client_plugin_auths, :enabled, true
  10 + end
  11 +
  12 + def down
  13 + remove_index :oauth_client_plugin_auths, :profile_type
  14 + remove_column :oauth_client_plugin_auths, :profile_type
  15 +
  16 + remove_column :oauth_client_plugin_auths, :external_person_uid
  17 + remove_column :oauth_client_plugin_auths, :external_person_image_url
  18 +
  19 + change_column_default :oauth_client_plugin_auths, :enabled, nil
  20 + end
  21 +end
... ...
plugins/oauth_client/db/migrate/20160809181708_adds_type_to_external_person.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddsTypeToExternalPerson < ActiveRecord::Migration
  2 + def up
  3 + add_column :external_people, :type, :string
  4 + end
  5 +
  6 + def down
  7 + remove_column :external_people, :type
  8 + end
  9 +end
... ...
plugins/oauth_client/lib/ext/environment.rb
1 1 require_dependency 'environment'
2 2  
3 3 class Environment
4   -
  4 + has_one :oauth_client_plugin_configs, :class_name => 'OauthClientPlugin::Config'
5 5 has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider'
6   -
7 6 end
... ...
plugins/oauth_client/lib/ext/profile.rb
... ... @@ -2,7 +2,7 @@ require_dependency &#39;profile&#39;
2 2  
3 3 class Profile
4 4  
5   - has_many :oauth_auths, foreign_key: :profile_id, class_name: 'OauthClientPlugin::Auth', dependent: :destroy
  5 + has_many :oauth_auths, as: :profile, class_name: 'OauthClientPlugin::Auth', dependent: :destroy
6 6 has_many :oauth_providers, through: :oauth_auths, source: :provider
7 7  
8 8 end
... ...
plugins/oauth_client/lib/oauth_client_plugin.rb
... ... @@ -90,6 +90,7 @@ class OauthClientPlugin &lt; Noosfero::Plugin
90 90 def account_controller_filters
91 91 {
92 92 :type => 'before_filter', :method_name => 'signup',
  93 + :options => { :only => 'signup' },
93 94 :block => proc {
94 95 auth = session[:oauth_data]
95 96  
... ... @@ -104,7 +105,7 @@ class OauthClientPlugin &lt; Noosfero::Plugin
104 105 end
105 106  
106 107 def js_files
107   - ["script.js"]
  108 + ["script.js", "provider.js"]
108 109 end
109 110  
110 111 end
... ...
plugins/oauth_client/models/oauth_client_plugin/auth.rb
1 1 class OauthClientPlugin::Auth < ApplicationRecord
2 2  
3   - attr_accessible :profile, :provider, :enabled,
4   - :access_token, :expires_in
  3 + attr_accessible :profile, :provider, :provider_id, :enabled,
  4 + :access_token, :expires_in, :type, :external_person_uid,
  5 + :external_person_image_url
5 6  
6   - belongs_to :profile, class_name: 'Profile'
  7 + belongs_to :profile, polymorphic: true
7 8 belongs_to :provider, class_name: 'OauthClientPlugin::Provider'
8 9  
9   - validates_presence_of :profile
10 10 validates_presence_of :provider
  11 + validates_presence_of :profile
11 12 validates_uniqueness_of :profile_id, scope: :provider_id
12 13  
13 14 extend ActsAsHavingSettings::ClassMethods
... ... @@ -27,4 +28,34 @@ class OauthClientPlugin::Auth &lt; ApplicationRecord
27 28 not self.expired?
28 29 end
29 30  
  31 + def allow_login?
  32 + self.enabled? && self.provider.enabled?
  33 + end
  34 +
  35 + def self.create_for_strategy(strategy, args = {})
  36 + namespace = self.name.split("::")[0]
  37 + class_name = "#{namespace}::#{strategy.camelize}Auth"
  38 + OauthClientPlugin::Auth.create!(args.merge(type: class_name))
  39 + end
  40 +
  41 + IMAGE_SIZES = {
  42 + :big => "150",
  43 + :thumb => "100",
  44 + :portrait => "64",
  45 + :minor => "50",
  46 + :icon => "18"
  47 + }
  48 +
  49 + # The following methods should be implemented by
  50 + # the Provider specific Auth classes
  51 + def image_url(size = nil)
  52 + nil
  53 + end
  54 + def profile_url
  55 + nil
  56 + end
  57 + def settings_url
  58 + nil
  59 + end
  60 +
30 61 end
... ...
plugins/oauth_client/models/oauth_client_plugin/config.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class OauthClientPlugin::Config < ApplicationRecord
  2 +
  3 + belongs_to :environment
  4 + attr_accessible :allow_external_login, :environment_id
  5 +
  6 + class << self
  7 + def instance
  8 + environment = Environment.default
  9 + environment.oauth_client_plugin_configs || create(environment_id: environment.id)
  10 + end
  11 +
  12 + private :new
  13 + end
  14 +
  15 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/facebook_auth.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class OauthClientPlugin::FacebookAuth < OauthClientPlugin::Auth
  2 +
  3 + def image_url(size = nil)
  4 + size = IMAGE_SIZES[size] || IMAGE_SIZES[:icon]
  5 + "#{self.external_person_image_url}?width=#{size}"
  6 + end
  7 +
  8 + def profile_url
  9 + "https://www.facebook.com/#{self.external_person_uid}"
  10 + end
  11 +
  12 + def settings_url
  13 + "https://www.facebook.com/settings"
  14 + end
  15 +
  16 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/github_auth.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class OauthClientPlugin::GithubAuth < OauthClientPlugin::Auth
  2 +
  3 + def image_url(size = nil)
  4 + size = IMAGE_SIZES[size] || IMAGE_SIZES[:icon]
  5 + "#{self.external_person_image_url}&size=#{size}"
  6 + end
  7 +
  8 + def profile_url
  9 + "https://www.github.com/#{self.profile.identifier}"
  10 + end
  11 +
  12 + def settings_url
  13 + "https://www.github.com/settings"
  14 + end
  15 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/google_oauth2_auth.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class OauthClientPlugin::GoogleOauth2Auth < OauthClientPlugin::Auth
  2 +
  3 + def image_url(size = nil)
  4 + size = IMAGE_SIZES[size] || IMAGE_SIZES[:icon]
  5 + "#{self.external_person_image_url}?sz=#{size}"
  6 + end
  7 +
  8 + def profile_url
  9 + "https://plus.google.com/#{self.external_person_uid}"
  10 + end
  11 +
  12 + def settings_url
  13 + "https://plus.google.com/u/0/settings"
  14 + end
  15 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/noosfero_oauth2_auth.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class OauthClientPlugin::NoosferoOauth2Auth < OauthClientPlugin::Auth
  2 +
  3 + def image_url(size = "")
  4 + URI.join("http://#{self.provider.client_options[:site]}/profile/#{self.profile.identifier}/icon/", size)
  5 + end
  6 +
  7 + def profile_url
  8 + "http://#{self.profile.source}/profile/#{self.profile.identifier}"
  9 + end
  10 +
  11 + def settings_url
  12 + "http://#{self.profile.source}/myprofile/#{self.profile.identifier}"
  13 + end
  14 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/oauth_external_person.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +class OauthClientPlugin::OauthExternalPerson < ExternalPerson
  2 +
  3 + has_one :oauth_auth, as: :profile, class_name: 'OauthClientPlugin::Auth', dependent: :destroy
  4 + has_one :oauth_provider, through: :oauth_auth, source: :provider
  5 +
  6 + def avatar
  7 + self.oauth_auth.image_url
  8 + end
  9 +
  10 + def image
  11 + OauthClientPlugin::OauthExternalPerson::Image.new(self.oauth_auth)
  12 + end
  13 +
  14 + def public_profile_url
  15 + self.oauth_auth.profile_url
  16 + end
  17 +
  18 + def url
  19 + self.oauth_auth.profile_url
  20 + end
  21 +
  22 + def admin_url
  23 + self.oauth_auth.settings_url
  24 + end
  25 +
  26 + class OauthClientPlugin::OauthExternalPerson::Image < ExternalPerson::Image
  27 + def initialize(oauth_auth)
  28 + @oauth_auth = oauth_auth
  29 + end
  30 +
  31 + def public_filename(size = nil)
  32 + URI(@oauth_auth.image_url(size))
  33 + end
  34 + end
  35 +end
... ...
plugins/oauth_client/models/oauth_client_plugin/provider.rb
... ... @@ -4,6 +4,8 @@ class OauthClientPlugin::Provider &lt; ApplicationRecord
4 4  
5 5 validates_presence_of :name, :strategy
6 6  
  7 + validate :noosfero_provider_must_have_a_site
  8 +
7 9 extend ActsAsHavingImage::ClassMethods
8 10 acts_as_having_image
9 11  
... ... @@ -19,4 +21,9 @@ class OauthClientPlugin::Provider &lt; ApplicationRecord
19 21  
20 22 scope :enabled, -> { where enabled: true }
21 23  
  24 + def noosfero_provider_must_have_a_site
  25 + if self.strategy == 'noosfero_oauth2' && (self.client_options.nil? || self.client_options[:site].blank?)
  26 + self.errors.add(:site, "A Noosfero provider must have a site")
  27 + end
  28 + end
22 29 end
... ...
plugins/oauth_client/models/oauth_client_plugin/twitter_auth.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +class OauthClientPlugin::TwitterAuth < OauthClientPlugin::Auth
  2 +
  3 + IMAGE_SIZES = {
  4 + :big => "",
  5 + :thumb => "_bigger",
  6 + :portrait => "_normal",
  7 + :minor => "_normal",
  8 + :icon => "_mini"
  9 + }
  10 +
  11 + def image_url(size = nil)
  12 + size = IMAGE_SIZES[size] || IMAGE_SIZES[:icon]
  13 + self.external_person_image_url.gsub("_normal", size)
  14 + end
  15 +
  16 + def profile_url
  17 + "https://twitter.com/#{self.profile.identifier}"
  18 + end
  19 +
  20 + def settings_url
  21 + "https://twitter.com/settings"
  22 + end
  23 +end
... ...
plugins/oauth_client/public/provider.js 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +function toggle_strategy(strategyName) {
  2 + if (strategyName == "noosfero_oauth2") {
  3 + $(".client-url").addClass("required-field");
  4 + } else {
  5 + $(".client-url").removeClass("required-field");
  6 + }
  7 +}
  8 +
  9 +$(document).on("change", "select#oauth_client_plugin_provider_strategy", function() {
  10 + var selectedOption = $(this).find(":selected").text();
  11 + toggle_strategy(selectedOption);
  12 +});
... ...
plugins/oauth_client/test/functional/account_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +require 'test_helper'
  2 +
  3 +class AccountControllerTest < ActionController::TestCase
  4 + def setup
  5 + external_person = ExternalPerson.create!(identifier: 'johnlock',
  6 + name: 'John Locke',
  7 + source: 'anerenvironment.org',
  8 + email: 'john@locke.org',
  9 + created_at: Date.yesterday
  10 + )
  11 + session[:external] = external_person.id
  12 + end
  13 +
  14 + should "not create an User when logging out" do
  15 + assert_no_difference 'User.count' do
  16 + get :logout
  17 + end
  18 + end
  19 +end
... ...
plugins/oauth_client/test/functional/oauth_client_plugin_public_controller_test.rb
... ... @@ -5,76 +5,97 @@ class OauthClientPluginPublicControllerTest &lt; ActionController::TestCase
5 5 def setup
6 6 @auth = mock
7 7 @auth.stubs(:info).returns(mock)
  8 + @auth.info.stubs(:email).returns("user@email.com")
  9 + @auth.info.stubs(:name).returns("User")
  10 + @auth.info.stubs(:nickname).returns("user")
  11 + @auth.info.stubs(:image).returns("url.to.image.com")
  12 + @auth.stubs(:provider).returns("testprovider")
  13 + @auth.stubs(:uid).returns("jh12j3h12kjh312")
  14 +
8 15 request.env["omniauth.auth"] = @auth
9 16 @environment = Environment.default
10   - @provider = OauthClientPlugin::Provider.create!(:name => 'provider', :strategy => 'provider', :enabled => true)
  17 + @provider = OauthClientPlugin::Provider.create!(:name => 'provider', :strategy => 'github', :enabled => true)
  18 +
  19 + session[:provider_id] = provider.id
11 20 end
12 21 attr_reader :auth, :environment, :provider
13 22  
14 23 should 'redirect to signup when user is not found' do
15   - auth.info.stubs(:email).returns("xyz123@noosfero.org")
16   - auth.info.stubs(:name).returns('xyz123')
17   - session[:provider_id] = provider.id
18   -
19 24 get :callback
20 25 assert_match /.*\/account\/signup/, @response.redirect_url
21 26 end
22 27  
23   - should 'redirect to login when user is found' do
24   - user = create_user
25   - auth.info.stubs(:email).returns(user.email)
26   - auth.info.stubs(:name).returns(user.name)
27   - session[:provider_id] = provider.id
  28 + should 'login when user already signed up' do
  29 + create_user(@auth.info.name, email: @auth.info.email)
28 30  
29 31 get :callback
30   - assert_redirected_to :controller => :account, :action => :login
31   - assert_equal user.id, session[:user]
  32 + assert session[:user].present?
32 33 end
33 34  
34   - should 'do not login when the provider is disabled' do
35   - user = create_user
36   - auth.info.stubs(:email).returns(user.email)
37   - auth.info.stubs(:name).returns(user.name)
38   - session[:provider_id] = provider.id
  35 + should 'not login when user already signed up and the provider is disabled' do
  36 + create_user(@auth.info.name, email: @auth.info.email)
39 37 provider.update_attribute(:enabled, false)
40 38  
41 39 get :callback
42   - assert_redirected_to :controller => :account, :action => :login
43   - assert_equal nil, session[:user]
  40 + assert session[:user].nil?
44 41 end
45 42  
46   - should 'do not login when the provider is disabled for a user' do
47   - user = create_user
48   - auth.info.stubs(:email).returns(user.email)
49   - auth.info.stubs(:name).returns(user.name)
50   - session[:provider_id] = provider.id
51   - user.person.oauth_auths.create!(profile: user.person, provider: provider, enabled: false)
  43 + should 'not login when user already signed up and the provider is disabled for him' do
  44 + create_user(@auth.info.name, email: @auth.info.email)
  45 + OauthClientPlugin::Auth.any_instance.stubs(:enabled?).returns(false)
52 46  
53 47 get :callback
54   - assert_redirected_to :controller => :account, :action => :login
55   - assert_equal nil, session[:user]
  48 + assert session[:user].nil?
56 49 end
57 50  
58   - should 'save provider when an user login with it' do
59   - user = create_user
60   - auth.info.stubs(:email).returns(user.email)
61   - auth.info.stubs(:name).returns(user.name)
62   - session[:provider_id] = provider.id
  51 + should 'not duplicate oauth_auths when the same provider is used several times' do
  52 + user = create_user(@auth.info.name, email: @auth.info.email)
63 53  
64 54 get :callback
65   - assert_equal [provider], user.oauth_providers
  55 + assert_no_difference 'user.oauth_auths.count' do
  56 + 3.times { get :callback }
  57 + end
66 58 end
67 59  
68   - should 'do not duplicate relations between an user and a provider when the same provider was used again in a login' do
69   - user = create_user
70   - auth.info.stubs(:email).returns(user.email)
71   - auth.info.stubs(:name).returns(user.name)
72   - session[:provider_id] = provider.id
  60 + should 'perform external login using provider when url param is present' do
  61 + request.env["omniauth.params"] = {"action" => "external_login"}
73 62  
74 63 get :callback
75   - assert_no_difference 'user.oauth_auths.count' do
76   - 3.times { get :callback }
  64 + assert_redirected_to :controller => :account, :action => :login
  65 + assert session[:external].present?
  66 + end
  67 +
  68 + should 'not create an user when performing external login' do
  69 + request.env["omniauth.params"] = {"action" => "external_login"}
  70 +
  71 + assert_no_difference 'User.count' do
  72 + get :callback
77 73 end
78 74 end
79 75  
  76 + should 'not perform external login when the provider is disabled' do
  77 + request.env["omniauth.params"] = {"action" => "external_login"}
  78 + provider.update_attribute(:enabled, false)
  79 +
  80 + get :callback
  81 + assert_redirected_to :controller => :account, :action => :login
  82 + assert session[:external].nil?
  83 + end
  84 +
  85 + should 'not perform external login when the provider is disabled for a user' do
  86 + request.env["omniauth.params"] = {"action" => "external_login"}
  87 + OauthClientPlugin::GithubAuth.any_instance.stubs(:enabled?).returns(false)
  88 +
  89 + get :callback
  90 + assert_redirected_to :controller => :account, :action => :login
  91 + assert session[:external].nil?
  92 + end
  93 +
  94 + should 'save provider when an external person logs in with it' do
  95 + request.env["omniauth.params"] = {"action" => "external_login"}
  96 +
  97 + get :callback
  98 + external_person = OauthClientPlugin::OauthExternalPerson.find_by(identifier: auth.info.nickname)
  99 + assert_equal provider, external_person.oauth_auth.provider
  100 + end
80 101 end
... ...
plugins/oauth_client/test/unit/auth_test.rb 0 → 100644
... ... @@ -0,0 +1,60 @@
  1 +require 'test_helper'
  2 +
  3 +class AuthTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @person = fast_create(Person)
  7 + @provider = fast_create(OauthClientPlugin::Provider, name: "GitHub")
  8 + @external_person = fast_create(ExternalPerson, name: "testuser", email: "test@email.com",
  9 + identifier: "testuser")
  10 +
  11 + OauthClientPlugin::Auth.any_instance.stubs(:external_person_image_url).returns("http://some.host/image")
  12 + OauthClientPlugin::Auth.any_instance.stubs(:external_person_uid).returns("j4b25cj234hb5n235")
  13 + OauthClientPlugin::Provider.any_instance.stubs(:client_options).returns({site: "http://host.com"})
  14 + end
  15 +
  16 + should "not create an auth without a related profile or external person" do
  17 + auth = OauthClientPlugin::Auth.new(provider: @provider)
  18 + assert_not auth.valid?
  19 + end
  20 +
  21 + should "create an auth with an external person" do
  22 + auth = OauthClientPlugin::Auth.create!(profile: @external_person,
  23 + provider: @provider)
  24 + assert auth.id.present?
  25 + end
  26 +
  27 + should "create an auth with a profile" do
  28 + auth = OauthClientPlugin::Auth.create!(profile: @person, provider: @provider)
  29 + assert auth.id.present?
  30 + end
  31 +
  32 + should "create an auth for a custom provider" do
  33 + auth = OauthClientPlugin::Auth.create_for_strategy("github", provider: @provider,
  34 + profile: @person)
  35 + assert auth.id.present?
  36 + assert auth.is_a? OauthClientPlugin::GithubAuth
  37 + end
  38 +
  39 + STRATEGIES = %w[facebook github google_oauth2 noosfero_oauth2 twitter]
  40 + STRATEGIES.each do |strategy|
  41 + should "override the external person's image url for #{strategy} strategy" do
  42 + auth = OauthClientPlugin::Auth.create_for_strategy(strategy, provider: @provider,
  43 + profile: @external_person)
  44 + assert_not auth.image_url.nil?
  45 + end
  46 +
  47 + should "override the external person's profile url for #{strategy} strategy" do
  48 + auth = OauthClientPlugin::Auth.create_for_strategy(strategy, provider: @provider,
  49 + profile: @external_person)
  50 + assert_not auth.profile_url.nil?
  51 + end
  52 +
  53 + should "override the external person's profile settings url for #{strategy} strategy" do
  54 + auth = OauthClientPlugin::Auth.create_for_strategy(strategy, provider: @provider,
  55 + profile: @external_person)
  56 + assert_not auth.settings_url.nil?
  57 + end
  58 + end
  59 +
  60 +end
... ...
plugins/oauth_client/test/unit/oauth_external_person_test.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +
  2 +require 'test_helper'
  3 +
  4 +class OauthExternalPersonTest < ActiveSupport::TestCase
  5 +
  6 + def setup
  7 + provider = fast_create(OauthClientPlugin::Provider, name: "GitHub")
  8 + @external_person = fast_create(ExternalPerson, name: "testuser", email: "test@email.com",
  9 + identifier: "testuser")
  10 + OauthClientPlugin::GithubAuth.create!(profile: @external_person, provider: provider)
  11 +
  12 + @oauth_external_person = fast_create(OauthClientPlugin::OauthExternalPerson,
  13 + name: "testuser", email: "test@email.com",
  14 + identifier: "testuser")
  15 + OauthClientPlugin::GithubAuth.create!(profile: @oauth_external_person,
  16 + provider: provider)
  17 + end
  18 +
  19 + should "not orverride info from a regular external person" do
  20 + assert_not_equal @external_person.avatar, @oauth_external_person.avatar
  21 + assert_not_equal @external_person.url, @oauth_external_person.url
  22 + assert_not_equal @external_person.admin_url, @oauth_external_person.admin_url
  23 + assert_not_equal @external_person.public_profile_url,
  24 + @oauth_external_person.public_profile_url
  25 + end
  26 +
  27 + should "not override the Image class from a regular external person" do
  28 + assert @external_person.image.is_a? ExternalPerson::Image
  29 + assert @oauth_external_person.image.is_a? OauthClientPlugin::OauthExternalPerson::Image
  30 + end
  31 +end
... ...
plugins/oauth_client/test/unit/provider_test.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +require 'test_helper'
  2 +
  3 +class ProviderTest < ActiveSupport::TestCase
  4 +
  5 + should "only create a noosfero provider with a site" do
  6 + provider = OauthClientPlugin::Provider.new(:name => 'noosfero', :strategy => 'noosfero_oauth2')
  7 + assert_not provider.valid?
  8 +
  9 + provider.client_options = { :site => "http://noosfero.org" }
  10 + assert provider.valid?
  11 + end
  12 +
  13 + should "create a regular provider without a site" do
  14 + provider = OauthClientPlugin::Provider.new(:name => 'github', :strategy => 'github')
  15 + assert provider.valid?
  16 + end
  17 +end
... ...
plugins/oauth_client/views/account/_oauth_signup.html.erb
1 1 <%= hidden_field_tag 'return_to', '/' %>
2 2  
3 3 <style>
4   - #signup-password, #signup-password-confirmation, #signup-email {
  4 + #signup-email {
5 5 display: none;
6 6 }
7 7 </style>
... ...
plugins/oauth_client/views/auth/_generate_providers_links.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<% providers.each do |provider| %>
  2 + <span class="provider">
  3 + <%= link_to provider.image ? image_tag(provider.image.public_filename) : provider.name, "/plugin/oauth_client/#{provider.strategy}?id=#{provider.id}&action=#{action}", :class => provider.strategy, :title => provider.name %>
  4 + </span>
  5 +<% end %>
... ...
plugins/oauth_client/views/auth/_oauth_login.html.erb
1 1 <div class="oauth-login">
2 2 <% unless providers.empty? %>
3   - <%= _('Login with:') %>
4   - <% end %>
5   - <% providers.each do |provider| %>
6   - <span class="provider">
7   - <%= link_to provider.image ? image_tag(provider.image.public_filename) : provider.name, "/plugin/oauth_client/#{provider.strategy}?id=#{provider.id}", :class => provider.strategy, :title => provider.name %>
8   - </span>
  3 + <div class="providers-links">
  4 + <%= _('Create an account from:') %>
  5 + <div>
  6 + <%= render :partial => 'auth/generate_providers_links', :locals => {:providers => providers, :action => ""} %>
  7 + </div>
  8 + <% if OauthClientPlugin::Config.instance.allow_external_login %>
  9 + <%= _('Login with:') %>
  10 + <div>
  11 + <%= render :partial => 'auth/generate_providers_links', :locals => {:providers => providers, :action => "external_login"} %>
  12 + </div>
  13 + <% end %>
  14 + </div>
9 15 <% end %>
10 16  
11 17 <span class="provider">
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/_noosfero_oauth2.html.erb
... ... @@ -1,5 +0,0 @@
1   -<%= f.fields_for :client_options, OpenStruct.new(provider.options[:client_options]) do |c| %>
2   - <div class="client-url">
3   - <%= labelled_form_field _('Client Url'), c.text_field(:site) %>
4   - </div>
5   -<% end %>
plugins/oauth_client/views/oauth_client_plugin_admin/edit.html.erb
... ... @@ -8,7 +8,7 @@
8 8 </div>
9 9  
10 10 <div class="name">
11   - <%= labelled_form_field _('Name'), f.text_field(:name) %>
  11 + <%= required labelled_form_field _('Name'), f.text_field(:name) %>
12 12 </div>
13 13  
14 14 <div class="strategy">
... ... @@ -27,8 +27,10 @@
27 27 <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %>
28 28 </div>
29 29  
30   - <% if File.exists?(File.join(File.dirname(__FILE__), "_#{@provider.strategy}.html.erb")) %>
31   - <%= render :partial => "#{@provider.strategy}", :locals => {:f => f, :provider => @provider} %>
  30 + <%= f.fields_for :client_options, OpenStruct.new(@provider.options[:client_options]) do |c| %>
  31 + <div class="client-url <%= "required-field" if @provider.strategy == "noosfero_oauth2" %>" title="<%= _("The service URL. If this value is informed, it will be used to identify the users, replacing the provider name") %>">
  32 + <%= labelled_form_field _('Client Url'), c.text_field(:site) %>
  33 + </div>
32 34 <% end %>
33 35  
34 36 <div class="image-icon">
... ...
plugins/oauth_client/views/oauth_client_plugin_admin/index.html.erb
1 1 <h1><%= _('Oauth Client Settings') %></h1>
  2 +
  3 +<%= labelled_form_for @config, url: { action: "update_configs" } do |f| %>
  4 + <table>
  5 + <tr>
  6 + <%= hidden_field_tag "oauth_client_config[allow_external_login]", false %>
  7 + <td><%= _('Allow external login') %></td>
  8 + <td><%= check_box_tag "oauth_client_config[allow_external_login]", true, @config.allow_external_login %></td>
  9 + </tr>
  10 + </table>
  11 +
  12 + <div>
  13 + <%= button_bar do %>
  14 + <%= submit_button('save', _('Save changes')) %>
  15 + <%= button :back, _('Back to plugins panel'), :controller => 'plugins', :action => 'index' %>
  16 + <% end %>
  17 + </div>
  18 +<% end %>
  19 +
2 20 <h3><%= _('Providers') %></h3>
3 21 <%= button :add, _('New'), {:action => 'new'} %>
4 22 <table>
... ...
test/unit/external_person_test.rb
... ... @@ -31,7 +31,9 @@ class ExternalPersonTest &lt; ActiveSupport::TestCase
31 31  
32 32 should 'not be a member of any communities' do
33 33 community = fast_create(Community)
34   - refute community.add_member(@external_person)
  34 + assert_raise ActiveRecord::AssociationTypeMismatch do
  35 + community.add_member(@external_person)
  36 + end
35 37 assert_equivalent [], @external_person.memberships
36 38 end
37 39  
... ...