Commit 22a9fad0d7025507b1f0b055fa021bcb5b43c2ed
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 < ApplicationController | @@ -154,7 +154,7 @@ class AccountController < ApplicationController | ||
154 | 154 | ||
155 | # action to perform logout from the application | 155 | # action to perform logout from the application |
156 | def logout | 156 | def logout |
157 | - if logged_in? | 157 | + if logged_in? && self.current_user.id.present? |
158 | self.current_user.forget_me | 158 | self.current_user.forget_me |
159 | end | 159 | end |
160 | reset_session | 160 | reset_session |
app/models/external_person.rb
@@ -122,6 +122,10 @@ class ExternalPerson < ActiveRecord::Base | @@ -122,6 +122,10 @@ class ExternalPerson < ActiveRecord::Base | ||
122 | "#{jid(options)}/#{self.name}" | 122 | "#{jid(options)}/#{self.name}" |
123 | end | 123 | end |
124 | 124 | ||
125 | + def name | ||
126 | + "#{self[:name]}@#{self.source}" | ||
127 | + end | ||
128 | + | ||
125 | class ExternalPerson::Image | 129 | class ExternalPerson::Image |
126 | def initialize(path) | 130 | def initialize(path) |
127 | @path = path | 131 | @path = path |
@@ -198,7 +202,10 @@ class ExternalPerson < ActiveRecord::Base | @@ -198,7 +202,10 @@ class ExternalPerson < ActiveRecord::Base | ||
198 | relationships_cache_key: '', is_member_of?: false, follows?: false, | 202 | relationships_cache_key: '', is_member_of?: false, follows?: false, |
199 | each_friend: nil, is_last_admin?: false, is_last_admin_leaving?: false, | 203 | each_friend: nil, is_last_admin?: false, is_last_admin_leaving?: false, |
200 | leave: nil, last_notification: nil, notification_time: 0, notifier: nil, | 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 | derivated_methods = generate_derivated_methods(methods_and_responses) | 211 | derivated_methods = generate_derivated_methods(methods_and_responses) |
@@ -255,7 +262,8 @@ class ExternalPerson < ActiveRecord::Base | @@ -255,7 +262,8 @@ class ExternalPerson < ActiveRecord::Base | ||
255 | {}, followed_by?: false, display_private_info_to?: true, can_view_field?: | 262 | {}, followed_by?: false, display_private_info_to?: true, can_view_field?: |
256 | true, remove_from_suggestion_list: nil, layout_template: 'default', | 263 | true, remove_from_suggestion_list: nil, layout_template: 'default', |
257 | is_admin?: false, add_friend: false, follows?: false, is_a_friend?: false, | 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 | derivated_methods = generate_derivated_methods(methods_and_responses) | 269 | derivated_methods = generate_derivated_methods(methods_and_responses) |
features/external_login.feature
@@ -7,8 +7,8 @@ Feature: external login | @@ -7,8 +7,8 @@ Feature: external login | ||
7 | Scenario: login from portal homepage | 7 | Scenario: login from portal homepage |
8 | Given feature "allow_change_of_redirection_after_login" is disabled on environment | 8 | Given feature "allow_change_of_redirection_after_login" is disabled on environment |
9 | And the following external environments | 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 | And the following external users | 12 | And the following external users |
13 | | login | | 13 | | login | |
14 | | joaosilva@federated.noosfero.org | | 14 | | joaosilva@federated.noosfero.org | |
@@ -26,8 +26,8 @@ Feature: external login | @@ -26,8 +26,8 @@ Feature: external login | ||
26 | Scenario: not login from portal homepage | 26 | Scenario: not login from portal homepage |
27 | Given feature "allow_change_of_redirection_after_login" is disabled on environment | 27 | Given feature "allow_change_of_redirection_after_login" is disabled on environment |
28 | And the following external environments | 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 | And I am not logged in | 31 | And I am not logged in |
32 | And I go to the homepage | 32 | And I go to the homepage |
33 | And I follow "Login" | 33 | And I follow "Login" |
plugins/oauth_client/controllers/oauth_client_plugin_admin_controller.rb
1 | class OauthClientPluginAdminController < AdminController | 1 | class OauthClientPluginAdminController < AdminController |
2 | 2 | ||
3 | def index | 3 | def index |
4 | + @config = OauthClientPlugin::Config.instance | ||
4 | end | 5 | end |
5 | 6 | ||
6 | def new | 7 | def new |
@@ -13,6 +14,11 @@ class OauthClientPluginAdminController < AdminController | @@ -13,6 +14,11 @@ class OauthClientPluginAdminController < AdminController | ||
13 | redirect_to :action => 'index' | 14 | redirect_to :action => 'index' |
14 | end | 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 | def edit | 22 | def edit |
17 | @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new | 23 | @provider = params[:id] ? environment.oauth_providers.find(params[:id]) : environment.oauth_providers.new |
18 | if request.post? | 24 | if request.post? |
@@ -24,4 +30,8 @@ class OauthClientPluginAdminController < AdminController | @@ -24,4 +30,8 @@ class OauthClientPluginAdminController < AdminController | ||
24 | end | 30 | end |
25 | end | 31 | end |
26 | 32 | ||
33 | + def edit_login_option | ||
34 | + option = params['oauth_client_plugin_option'] | ||
35 | + end | ||
36 | + | ||
27 | end | 37 | end |
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb
@@ -3,9 +3,15 @@ class OauthClientPluginPublicController < PublicController | @@ -3,9 +3,15 @@ class OauthClientPluginPublicController < PublicController | ||
3 | skip_before_filter :login_required | 3 | skip_before_filter :login_required |
4 | 4 | ||
5 | def callback | 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 | end | 15 | end |
10 | 16 | ||
11 | def failure | 17 | def failure |
@@ -20,12 +26,45 @@ class OauthClientPluginPublicController < PublicController | @@ -20,12 +26,45 @@ class OauthClientPluginPublicController < PublicController | ||
20 | 26 | ||
21 | protected | 27 | protected |
22 | 28 | ||
23 | - def login person | 29 | + def external_person_login(auth_data) |
24 | provider = OauthClientPlugin::Provider.find(session[:provider_id]) | 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 | else | 68 | else |
30 | session[:notice] = _("Can't login with %s") % provider.name | 69 | session[:notice] = _("Can't login with %s") % provider.name |
31 | end | 70 | end |
@@ -33,12 +72,4 @@ class OauthClientPluginPublicController < PublicController | @@ -33,12 +72,4 @@ class OauthClientPluginPublicController < PublicController | ||
33 | redirect_to :controller => :account, :action => :login | 72 | redirect_to :controller => :account, :action => :login |
34 | end | 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 | end | 75 | end |
plugins/oauth_client/db/migrate/20160714113820_create_oauth_client_plugin_config.rb
0 → 100644
plugins/oauth_client/db/migrate/20160720165808_add_external_profile_to_oauth_auth.rb
0 → 100644
@@ -0,0 +1,21 @@ | @@ -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
plugins/oauth_client/lib/ext/environment.rb
1 | require_dependency 'environment' | 1 | require_dependency 'environment' |
2 | 2 | ||
3 | class Environment | 3 | class Environment |
4 | - | 4 | + has_one :oauth_client_plugin_configs, :class_name => 'OauthClientPlugin::Config' |
5 | has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider' | 5 | has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider' |
6 | - | ||
7 | end | 6 | end |
plugins/oauth_client/lib/ext/profile.rb
@@ -2,7 +2,7 @@ require_dependency 'profile' | @@ -2,7 +2,7 @@ require_dependency 'profile' | ||
2 | 2 | ||
3 | class Profile | 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 | has_many :oauth_providers, through: :oauth_auths, source: :provider | 6 | has_many :oauth_providers, through: :oauth_auths, source: :provider |
7 | 7 | ||
8 | end | 8 | end |
plugins/oauth_client/lib/oauth_client_plugin.rb
@@ -90,6 +90,7 @@ class OauthClientPlugin < Noosfero::Plugin | @@ -90,6 +90,7 @@ class OauthClientPlugin < Noosfero::Plugin | ||
90 | def account_controller_filters | 90 | def account_controller_filters |
91 | { | 91 | { |
92 | :type => 'before_filter', :method_name => 'signup', | 92 | :type => 'before_filter', :method_name => 'signup', |
93 | + :options => { :only => 'signup' }, | ||
93 | :block => proc { | 94 | :block => proc { |
94 | auth = session[:oauth_data] | 95 | auth = session[:oauth_data] |
95 | 96 | ||
@@ -104,7 +105,7 @@ class OauthClientPlugin < Noosfero::Plugin | @@ -104,7 +105,7 @@ class OauthClientPlugin < Noosfero::Plugin | ||
104 | end | 105 | end |
105 | 106 | ||
106 | def js_files | 107 | def js_files |
107 | - ["script.js"] | 108 | + ["script.js", "provider.js"] |
108 | end | 109 | end |
109 | 110 | ||
110 | end | 111 | end |
plugins/oauth_client/models/oauth_client_plugin/auth.rb
1 | class OauthClientPlugin::Auth < ApplicationRecord | 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 | belongs_to :provider, class_name: 'OauthClientPlugin::Provider' | 8 | belongs_to :provider, class_name: 'OauthClientPlugin::Provider' |
8 | 9 | ||
9 | - validates_presence_of :profile | ||
10 | validates_presence_of :provider | 10 | validates_presence_of :provider |
11 | + validates_presence_of :profile | ||
11 | validates_uniqueness_of :profile_id, scope: :provider_id | 12 | validates_uniqueness_of :profile_id, scope: :provider_id |
12 | 13 | ||
13 | extend ActsAsHavingSettings::ClassMethods | 14 | extend ActsAsHavingSettings::ClassMethods |
@@ -27,4 +28,34 @@ class OauthClientPlugin::Auth < ApplicationRecord | @@ -27,4 +28,34 @@ class OauthClientPlugin::Auth < ApplicationRecord | ||
27 | not self.expired? | 28 | not self.expired? |
28 | end | 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 | end | 61 | end |
plugins/oauth_client/models/oauth_client_plugin/config.rb
0 → 100644
@@ -0,0 +1,15 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 < ApplicationRecord | @@ -4,6 +4,8 @@ class OauthClientPlugin::Provider < ApplicationRecord | ||
4 | 4 | ||
5 | validates_presence_of :name, :strategy | 5 | validates_presence_of :name, :strategy |
6 | 6 | ||
7 | + validate :noosfero_provider_must_have_a_site | ||
8 | + | ||
7 | extend ActsAsHavingImage::ClassMethods | 9 | extend ActsAsHavingImage::ClassMethods |
8 | acts_as_having_image | 10 | acts_as_having_image |
9 | 11 | ||
@@ -19,4 +21,9 @@ class OauthClientPlugin::Provider < ApplicationRecord | @@ -19,4 +21,9 @@ class OauthClientPlugin::Provider < ApplicationRecord | ||
19 | 21 | ||
20 | scope :enabled, -> { where enabled: true } | 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 | end | 29 | end |
plugins/oauth_client/models/oauth_client_plugin/twitter_auth.rb
0 → 100644
@@ -0,0 +1,23 @@ | @@ -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 |
@@ -0,0 +1,12 @@ | @@ -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 @@ | @@ -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 < ActionController::TestCase | @@ -5,76 +5,97 @@ class OauthClientPluginPublicControllerTest < ActionController::TestCase | ||
5 | def setup | 5 | def setup |
6 | @auth = mock | 6 | @auth = mock |
7 | @auth.stubs(:info).returns(mock) | 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 | request.env["omniauth.auth"] = @auth | 15 | request.env["omniauth.auth"] = @auth |
9 | @environment = Environment.default | 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 | end | 20 | end |
12 | attr_reader :auth, :environment, :provider | 21 | attr_reader :auth, :environment, :provider |
13 | 22 | ||
14 | should 'redirect to signup when user is not found' do | 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 | get :callback | 24 | get :callback |
20 | assert_match /.*\/account\/signup/, @response.redirect_url | 25 | assert_match /.*\/account\/signup/, @response.redirect_url |
21 | end | 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 | get :callback | 31 | get :callback |
30 | - assert_redirected_to :controller => :account, :action => :login | ||
31 | - assert_equal user.id, session[:user] | 32 | + assert session[:user].present? |
32 | end | 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 | provider.update_attribute(:enabled, false) | 37 | provider.update_attribute(:enabled, false) |
40 | 38 | ||
41 | get :callback | 39 | get :callback |
42 | - assert_redirected_to :controller => :account, :action => :login | ||
43 | - assert_equal nil, session[:user] | 40 | + assert session[:user].nil? |
44 | end | 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 | get :callback | 47 | get :callback |
54 | - assert_redirected_to :controller => :account, :action => :login | ||
55 | - assert_equal nil, session[:user] | 48 | + assert session[:user].nil? |
56 | end | 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 | get :callback | 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 | end | 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 | get :callback | 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 | end | 73 | end |
78 | end | 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 | end | 101 | end |
@@ -0,0 +1,60 @@ | @@ -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 @@ | @@ -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 |
@@ -0,0 +1,17 @@ | @@ -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
plugins/oauth_client/views/auth/_generate_providers_links.html.erb
0 → 100644
@@ -0,0 +1,5 @@ | @@ -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 | <div class="oauth-login"> | 1 | <div class="oauth-login"> |
2 | <% unless providers.empty? %> | 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 | <% end %> | 15 | <% end %> |
10 | 16 | ||
11 | <span class="provider"> | 17 | <span class="provider"> |
plugins/oauth_client/views/oauth_client_plugin_admin/_noosfero_oauth2.html.erb
plugins/oauth_client/views/oauth_client_plugin_admin/edit.html.erb
@@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
8 | </div> | 8 | </div> |
9 | 9 | ||
10 | <div class="name"> | 10 | <div class="name"> |
11 | - <%= labelled_form_field _('Name'), f.text_field(:name) %> | 11 | + <%= required labelled_form_field _('Name'), f.text_field(:name) %> |
12 | </div> | 12 | </div> |
13 | 13 | ||
14 | <div class="strategy"> | 14 | <div class="strategy"> |
@@ -27,8 +27,10 @@ | @@ -27,8 +27,10 @@ | ||
27 | <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %> | 27 | <%= labelled_form_field _('Client Secret'), f.text_field(:client_secret) %> |
28 | </div> | 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 | <% end %> | 34 | <% end %> |
33 | 35 | ||
34 | <div class="image-icon"> | 36 | <div class="image-icon"> |
plugins/oauth_client/views/oauth_client_plugin_admin/index.html.erb
1 | <h1><%= _('Oauth Client Settings') %></h1> | 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 | <h3><%= _('Providers') %></h3> | 20 | <h3><%= _('Providers') %></h3> |
3 | <%= button :add, _('New'), {:action => 'new'} %> | 21 | <%= button :add, _('New'), {:action => 'new'} %> |
4 | <table> | 22 | <table> |
test/unit/external_person_test.rb
@@ -31,7 +31,9 @@ class ExternalPersonTest < ActiveSupport::TestCase | @@ -31,7 +31,9 @@ class ExternalPersonTest < ActiveSupport::TestCase | ||
31 | 31 | ||
32 | should 'not be a member of any communities' do | 32 | should 'not be a member of any communities' do |
33 | community = fast_create(Community) | 33 | community = fast_create(Community) |
34 | - refute community.add_member(@external_person) | 34 | + assert_raise do |
35 | + community.add_member(@external_person) | ||
36 | + end | ||
35 | assert_equivalent [], @external_person.memberships | 37 | assert_equivalent [], @external_person.memberships |
36 | end | 38 | end |
37 | 39 |