diff --git a/app/assets/locales/el.json b/app/assets/locales/el.json index c78670ced6..93cd8e9f7e 100644 --- a/app/assets/locales/el.json +++ b/app/assets/locales/el.json @@ -319,7 +319,10 @@ "open": "Ενεργοποίηση εγγραφών", "invite": "Συμμετοχή με πρόσκληση", "approval": "Έγκριση/Απόρριψη" - } + }, + "allowed_domains": "Επιτρέπονται τα email ονομάτων τομεα", + "allowed_domains_signup_description": "Επιτρέπονται συγκεκριμένα email ονομάτων τομεα για εγγραφή. Η μορφή πρέπει να είναι @test.com,domain.com", + "enter_allowed_domains_rule" : "Προσθηκη επιτρεπόμενου ονόματος τομέα " } }, "room_configuration": { @@ -420,7 +423,8 @@ "privacy_policy_updated": "Η πολιτική απορρήτου ενημερώθηκε.", "helpcenter_updated": "Ο σύνδεσμος για το Κέντρο βοήθειας ενημερώθηκε. ", "terms_of_service_updated": "Οι όριο χρήσης ενημερώθηκαν.", - "maintenance_updated": "Το μήνυμα της λειτουργίας συντήρησης ενημερώθηκε." + "maintenance_updated": "Το μήνυμα της λειτουργίας συντήρησης ενημερώθηκε.", + "allowed_domains_signup_updated": "Τα επιτρεπόμενα ονόματα τομέα ενημερώθηκαν" }, "recording": { "recording_visibility_updated": "Η εμφάνιση καταγραφής ενημερώθηκε.", diff --git a/app/assets/locales/en.json b/app/assets/locales/en.json index d3ddd9c7ab..665d511926 100644 --- a/app/assets/locales/en.json +++ b/app/assets/locales/en.json @@ -319,7 +319,10 @@ "open": "Open Registration", "invite": "Join by Invitation", "approval": "Approve/Decline" - } + }, + "allowed_domains": "Allowed Email Domains", + "allowed_domains_signup_description": "Allow specific email domains to sign up. Format must be: @test.com,domain.com", + "enter_allowed_domains_rule" : "Enter the allowed domains" } }, "room_configuration": { @@ -420,7 +423,8 @@ "privacy_policy_updated": "The privacy notice has been updated.", "helpcenter_updated": "The help center link has been updated.", "terms_of_service_updated": "The terms of service have been updated.", - "maintenance_updated": "The maintenance banner has been updated." + "maintenance_updated": "The maintenance banner has been updated.", + "allowed_domains_signup_updated": "The allowed email domains have been updated." }, "recording": { "recording_visibility_updated": "The recording visibility has been updated.", diff --git a/app/assets/locales/ja.json b/app/assets/locales/ja.json index c33dfe0a3a..41f1604f09 100644 --- a/app/assets/locales/ja.json +++ b/app/assets/locales/ja.json @@ -319,7 +319,10 @@ "open": "誰でも自由に登録", "invite": "招待制", "approval": "承認制" - } + }, + "allowed_domains": "許可するEmailのドメイン", + "allowed_domains_signup_description": "特定のEmailドメインのみからのサインアップを許可します。@test.com や domain.com のような形式で記入してください。", + "enter_allowed_domains_rule" : "許可するドメインを入力" } }, "room_configuration": { @@ -420,7 +423,8 @@ "privacy_policy_updated": "プライバシーに関する告知がアップデートされました。", "helpcenter_updated": "ヘルプセンターのリンクが更新されました。", "terms_of_service_updated": "利用規約が更新されました。", - "maintenance_updated": "メンテナンスバナーが更新されました。" + "maintenance_updated": "メンテナンスバナーが更新されました。", + "allowed_domains_signup_updated": "許可するEmailのドメインが更新されました。" }, "recording": { "recording_visibility_updated": "録画の公開度が更新されました。", diff --git a/app/controllers/api/v1/meetings_controller.rb b/app/controllers/api/v1/meetings_controller.rb index f0a68b5819..a0dddd6657 100644 --- a/app/controllers/api/v1/meetings_controller.rb +++ b/app/controllers/api/v1/meetings_controller.rb @@ -37,6 +37,7 @@ def start render_data data: BigBlueButtonApi.new(provider: current_provider).join_meeting( room: @room, name: current_user.name, + user_id: fetch_bbb_user_id, avatar_url: current_user.avatar.attached? ? url_for(current_user.avatar) : nil, role: 'Moderator' ), status: :created @@ -81,6 +82,7 @@ def status data[:joinUrl] = BigBlueButtonApi.new(provider: current_provider).join_meeting( room: @room, name: current_user ? current_user.name : params[:name], + user_id: fetch_bbb_user_id, avatar_url: current_user&.avatar&.attached? ? url_for(current_user.avatar) : nil, role: bbb_role ) @@ -145,6 +147,21 @@ def infer_bbb_role(mod_code:, viewer_code:, anyone_join_as_mod:) 'Viewer' end end + + def fetch_bbb_user_id + return "gl-#{current_user.id}" if current_user + + return cookies[:guest_id] if cookies[:guest_id].present? + + guest_id = "gl-guest-#{SecureRandom.hex(12)}" + + cookies[:guest_id] = { + value: guest_id, + expires: 1.day.from_now + } + + guest_id + end end end end diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index d28c0834a3..6661d71a91 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -61,6 +61,9 @@ def create # Users created by a user will have the creator language by default with a fallback to the server configured default_locale. create_user_params[:language] = current_user&.language || I18n.default_locale if create_user_params[:language].blank? + # renders an error if the user is signing up with an invalid domain based off site settings + return render_error errors: Rails.configuration.custom_error_msgs[:unauthorized], status: :forbidden unless valid_domain? + user = UserCreator.new(user_params: create_user_params.except(:invite_token), provider: current_provider, role: default_role).call smtp_enabled = ENV['SMTP_SERVER'].present? @@ -184,6 +187,17 @@ def valid_invite_token Invitation.destroy_by(email: create_user_params[:email].downcase, provider: current_provider, token: create_user_params[:invite_token]).present? end + + def valid_domain? + allowed_domains_emails = SettingGetter.new(setting_name: 'AllowedDomains', provider: current_provider).call + return true if allowed_domains_emails.blank? + + domains = allowed_domains_emails.split(',') + domains.each do |domain| + return true if create_user_params[:email].end_with?(domain) + end + false + end end end end diff --git a/app/controllers/external_controller.rb b/app/controllers/external_controller.rb index f1ad7f7232..702fd8633a 100644 --- a/app/controllers/external_controller.rb +++ b/app/controllers/external_controller.rb @@ -48,6 +48,8 @@ def create_user return redirect_to root_path(error: Rails.configuration.custom_error_msgs[:invite_token_invalid]) end + return render_error status: :forbidden unless valid_domain?(user_info[:email]) + # Create the user if they dont exist if new_user user = UserCreator.new(user_params: user_info, provider: current_provider, role: default_role).call @@ -171,4 +173,15 @@ def build_user_info(credentials) verified: true } end + + def valid_domain?(email) + allowed_domain_emails = SettingGetter.new(setting_name: 'AllowedDomains', provider: current_provider).call + return true if allowed_domain_emails.blank? + + domains = allowed_domain_emails.split(',') + domains.each do |domain| + return true if email.end_with?(domain) + end + false + end end diff --git a/app/javascript/components/admin/site_settings/registration/Registration.jsx b/app/javascript/components/admin/site_settings/registration/Registration.jsx index 6b75f888bc..7d9029666f 100644 --- a/app/javascript/components/admin/site_settings/registration/Registration.jsx +++ b/app/javascript/components/admin/site_settings/registration/Registration.jsx @@ -28,11 +28,12 @@ import useRoles from '../../../../hooks/queries/admin/roles/useRoles'; export default function Registration() { const { t } = useTranslation(); const { data: env } = useEnv(); - const { data: siteSettings } = useSiteSettings(['RoleMapping', 'DefaultRole', 'ResyncOnLogin', 'RegistrationMethod']); + const { data: siteSettings } = useSiteSettings(['RoleMapping', 'DefaultRole', 'ResyncOnLogin', 'RegistrationMethod', 'AllowedDomains']); const { data: roles } = useRoles(); const updateRegistrationMethod = useUpdateSiteSetting('RegistrationMethod'); const updateDefaultRole = useUpdateSiteSetting('DefaultRole'); const updateRoleMapping = useUpdateSiteSetting('RoleMapping'); + const updateDomainSignUp = useUpdateSiteSetting('AllowedDomains'); return ( <> @@ -99,6 +100,24 @@ export default function Registration() { + + + {t('admin.site_settings.registration.allowed_domains')} +

{t('admin.site_settings.registration.allowed_domains_signup_description')}

+ + + + +
); } diff --git a/app/javascript/hooks/mutations/admin/site_settings/useUpdateSiteSetting.jsx b/app/javascript/hooks/mutations/admin/site_settings/useUpdateSiteSetting.jsx index 9b3725952f..7e4f4e3c0c 100644 --- a/app/javascript/hooks/mutations/admin/site_settings/useUpdateSiteSetting.jsx +++ b/app/javascript/hooks/mutations/admin/site_settings/useUpdateSiteSetting.jsx @@ -63,6 +63,9 @@ export default function useUpdateSiteSetting(name) { case 'Maintenance': toast.success(t('toast.success.site_settings.maintenance_updated')); break; + case 'AllowedDomains': + toast.success(t('toast.success.site_settings.allowed_domains_signup_updated')); + break; default: toast.success(t('toast.success.site_settings.site_setting_updated')); } diff --git a/app/services/big_blue_button_api.rb b/app/services/big_blue_button_api.rb index 21493fdbb6..495e1dacdf 100644 --- a/app/services/big_blue_button_api.rb +++ b/app/services/big_blue_button_api.rb @@ -44,12 +44,13 @@ def start_meeting(room:, options: {}, presentation_url: nil) end end - def join_meeting(room:, role:, name: nil, avatar_url: nil) + def join_meeting(room:, role:, user_id:, name: nil, avatar_url: nil) bbb_server.join_meeting_url( room.meeting_id, name, '', # empty password -> use the role passed ing { + userId: user_id, role:, avatarURL: avatar_url, createTime: room.last_session&.to_datetime&.strftime('%Q') diff --git a/app/services/meeting_starter.rb b/app/services/meeting_starter.rb index 99d95e3ffc..63009ffd2a 100644 --- a/app/services/meeting_starter.rb +++ b/app/services/meeting_starter.rb @@ -69,9 +69,11 @@ def computed_options(access_code:) logoutURL: room_url, meta_endCallbackUrl: meeting_ended_url(host: @base_url), 'meta_bbb-recording-ready-url': recording_ready_url(host: @base_url), - 'meta_bbb-origin-version': ENV.fetch('VERSION_TAG', 'v3'), 'meta_bbb-origin': 'greenlight', - 'meta_bbb-origin-server-name': URI(@base_url).host + 'meta_bbb-origin-server-name': URI(@base_url).host, + 'meta_bbb-origin-version': ENV.fetch('VERSION_TAG', 'v3'), + 'meta_bbb-context-name': @room.name, + 'meta_bbb-context-id': @room.friendly_id } end diff --git a/app/services/tenant_setup.rb b/app/services/tenant_setup.rb index 47a8b8651f..2bad739f9c 100644 --- a/app/services/tenant_setup.rb +++ b/app/services/tenant_setup.rb @@ -56,7 +56,8 @@ def create_site_settings { setting: Setting.find_by(name: 'DefaultRole'), provider: @provider, value: 'User' }, { setting: Setting.find_by(name: 'DefaultRecordingVisibility'), provider: @provider, value: 'Published' }, { setting: Setting.find_by(name: 'Maintenance'), provider: @provider, value: '' }, - { setting: Setting.find_by(name: 'SessionTimeout'), provider: @provider, value: '1' } + { setting: Setting.find_by(name: 'SessionTimeout'), provider: @provider, value: '1' }, + { setting: Setting.find_by(name: 'AllowedDomains'), value: '', provider: @provider } ] end diff --git a/db/data/20240812210436_add_allowed_domains_to_site_settings.rb b/db/data/20240812210436_add_allowed_domains_to_site_settings.rb new file mode 100644 index 0000000000..5c1aa3f5bb --- /dev/null +++ b/db/data/20240812210436_add_allowed_domains_to_site_settings.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +class AddAllowedDomainsToSiteSettings < ActiveRecord::Migration[7.1] + def up + setting = Setting.find_or_create_by(name: 'AllowedDomains') + + SiteSetting.create!(setting:, value: '', provider: 'greenlight') unless SiteSetting.exists?(setting:, provider: 'greenlight') + + Tenant.find_each do |tenant| + SiteSetting.create!(setting:, value: '', provider: tenant.name) unless SiteSetting.exists?(setting:, provider: tenant.name) + end + end + + def down + Tenant.find_each do |tenant| + SiteSetting.find_by(setting: Setting.find_by(name: 'Maintenance'), provider: tenant.name)&.destroy + end + + SiteSetting.find_by(setting: Setting.find_by(name: 'Maintenance'), provider: 'greenlight')&.destroy + + Setting.find_by(name: 'AllowedDomains')&.destroy + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb index dd44530cd2..5f04068525 100644 --- a/db/data_schema.rb +++ b/db/data_schema.rb @@ -1 +1 @@ -DataMigrate::Data.define(version: 20240423162700) +DataMigrate::Data.define(version: 20240812210436) diff --git a/spec/controllers/admin/tenants_controller_spec.rb b/spec/controllers/admin/tenants_controller_spec.rb index dfd13e8e93..a54876a60d 100644 --- a/spec/controllers/admin/tenants_controller_spec.rb +++ b/spec/controllers/admin/tenants_controller_spec.rb @@ -18,7 +18,7 @@ require 'rails_helper' -RSpec.describe Api::V1::Admin::TenantsController, type: :controller do +RSpec.describe Api::V1::Admin::TenantsController do let(:user) { create(:user, :with_super_admin) } let(:valid_tenant_params) do { @@ -146,6 +146,7 @@ def create_settings_permissions_meetingoptions Setting.find_or_create_by(name: 'HelpCenter') Setting.find_or_create_by(name: 'Maintenance') Setting.find_or_create_by(name: 'SessionTimeout') + Setting.find_or_create_by(name: 'AllowedDomains') Permission.find_or_create_by(name: 'CreateRoom') Permission.find_or_create_by(name: 'ManageUsers') diff --git a/spec/controllers/external_controller_spec.rb b/spec/controllers/external_controller_spec.rb index 607dac434f..764690dbc1 100644 --- a/spec/controllers/external_controller_spec.rb +++ b/spec/controllers/external_controller_spec.rb @@ -18,7 +18,7 @@ require 'rails_helper' -RSpec.describe ExternalController, type: :controller do +RSpec.describe ExternalController do let(:fake_setting_getter) { instance_double(SettingGetter) } describe '#create_user' do @@ -80,7 +80,7 @@ expect do get :create_user, params: { provider: 'openid_connect' } - end.to change(User, :count).by(0) + end.not_to change(User, :count) end it 'looks the user up based on email' do @@ -90,7 +90,7 @@ expect do get :create_user, params: { provider: 'openid_connect' } - end.to change(User, :count).by(0) + end.not_to change(User, :count) end context 'redirect' do @@ -212,40 +212,52 @@ email: 'email@example.com') end - it 'overwrites the saved values with the values from the authentication provider if true' do - allow_any_instance_of(SettingGetter).to receive(:call).and_return(true) + context 'value is true' do + before do + reg_method = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'ResyncOnLogin', provider: 'greenlight').and_return(reg_method) + allow(reg_method).to receive(:call).and_return(true) + end - request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + it 'overwrites the saved values with the values from the authentication provider if true' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] - get :create_user, params: { provider: 'openid_connect' } + get :create_user, params: { provider: 'openid_connect' } - user.reload - expect(user.name).to eq(OmniAuth.config.mock_auth[:openid_connect]['info']['name']) - expect(user.email).to eq(OmniAuth.config.mock_auth[:openid_connect]['info']['email']) - end + user.reload + expect(user.name).to eq(OmniAuth.config.mock_auth[:openid_connect]['info']['name']) + expect(user.email).to eq(OmniAuth.config.mock_auth[:openid_connect]['info']['email']) + end - it 'does not overwrite the saved values with the values from the authentication provider if false' do - allow_any_instance_of(SettingGetter).to receive(:call).and_return(false) + it 'does not overwrite the role even if true' do + allow_any_instance_of(SettingGetter).to receive(:call).and_return(true) + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] - request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + new_role = create(:role) + user.update(role: new_role) - get :create_user, params: { provider: 'openid_connect' } + get :create_user, params: { provider: 'openid_connect' } - user.reload - expect(user.name).to eq('Example Name') - expect(user.email).to eq('email@example.com') + expect(user.reload.role).to eq(new_role) + end end - it 'does not overwrite the role even if true' do - allow_any_instance_of(SettingGetter).to receive(:call).and_return(true) - request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + context 'value is false' do + before do + reg_method = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'ResyncOnLogin', provider: 'greenlight').and_return(reg_method) + allow(reg_method).to receive(:call).and_return(false) + end - new_role = create(:role) - user.update(role: new_role) + it 'does not overwrite the saved values with the values from the authentication provider if false' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] - get :create_user, params: { provider: 'openid_connect' } + get :create_user, params: { provider: 'openid_connect' } - expect(user.reload.role).to eq(new_role) + user.reload + expect(user.name).to eq('Example Name') + expect(user.email).to eq('email@example.com') + end end end @@ -325,6 +337,79 @@ end end + context 'Allowed Domains' do + context 'restricted domain not set' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('') + end + + it 'creates the user' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + + expect { get :create_user, params: { provider: 'openid_connect' } }.to change(User, :count).from(0).to(1) + end + end + + context 'restricted domain set to 1 domain' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('@domain.com') + end + + it 'creates the user if the domain is allowed' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + request.env['omniauth.auth'][:info][:email] = 'email@domain.com' + + expect { get :create_user, params: { provider: 'openid_connect' } }.to change(User, :count).from(0).to(1) + end + + it 'does not create if the domain is not allowed' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + + expect { get :create_user, params: { provider: 'openid_connect' } }.not_to change(User, :count) + end + end + + context 'restricted domain set to multiple domain' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('@example.com,@test.com,@domain.com') + end + + it 'creates the user if the domain is allowed 1' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + request.env['omniauth.auth'][:info][:email] = 'email@example.com' + + expect { get :create_user, params: { provider: 'openid_connect' } }.to change(User, :count).from(0).to(1) + end + + it 'creates the user if the domain is allowed 2' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + request.env['omniauth.auth'][:info][:email] = 'email@test.com' + + expect { get :create_user, params: { provider: 'openid_connect' } }.to change(User, :count).from(0).to(1) + end + + it 'creates the user if the domain is allowed 3' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + request.env['omniauth.auth'][:info][:email] = 'email@domain.com' + + expect { get :create_user, params: { provider: 'openid_connect' } }.to change(User, :count).from(0).to(1) + end + + it 'does not create if the domain is not allowed' do + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect] + request.env['omniauth.auth'][:info][:email] = 'test@invaliddomain.com' + + expect { get :create_user, params: { provider: 'openid_connect' } }.not_to change(User, :count) + end + end + end + context 'Role mapping' do let!(:role1) { create(:role, name: 'role1') } diff --git a/spec/controllers/meetings_controller_spec.rb b/spec/controllers/meetings_controller_spec.rb index 48aeec11d8..a4d1c6f67a 100644 --- a/spec/controllers/meetings_controller_spec.rb +++ b/spec/controllers/meetings_controller_spec.rb @@ -25,6 +25,8 @@ let(:test_user) { create(:user) } let(:test_room) { create(:room, user: test_user) } let(:user_with_manage_rooms_permission) { create(:user, :with_manage_rooms_permission) } + let(:user_id) { "gl-#{user.id}" } + let(:guest_user_id) { "gl-#{guest_user.id}" } before do request.headers['ACCEPT'] = 'application/json' @@ -43,7 +45,7 @@ it 'makes a call to the MeetingStarter service with the right values and returns the join url' do expect(MeetingStarter).to receive(:new).with(room:, base_url: request.base_url, current_user: user, provider: 'greenlight').and_call_original expect_any_instance_of(MeetingStarter).to receive(:call) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, user_id:, avatar_url: nil, role: 'Moderator') post :start, params: { friendly_id: room.friendly_id } @@ -61,7 +63,7 @@ it 'makes a call to the BigBlueButtonApi to get the join url' do expect_any_instance_of(BigBlueButtonApi) .to receive(:join_meeting) - .with(room:, name: user.name, avatar_url: nil, role: 'Moderator') + .with(room:, name: user.name, user_id:, avatar_url: nil, role: 'Moderator') post :start, params: { friendly_id: room.friendly_id } end @@ -72,7 +74,7 @@ expect_any_instance_of(BigBlueButtonApi) .to receive(:join_meeting) - .with(room:, name: user.name, avatar_url:, role: 'Moderator') + .with(room:, name: user.name, user_id:, avatar_url:, role: 'Moderator') post :start, params: { friendly_id: room.friendly_id } end @@ -129,7 +131,8 @@ it 'allows a user who the room is shared with to start the meeting' do expect_any_instance_of(MeetingStarter).to receive(:call) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, user_id: guest_user_id, + avatar_url: nil, role: 'Moderator') post :start, params: { friendly_id: room.friendly_id } @@ -142,7 +145,8 @@ describe '#status' do it 'gets the joinUrl if the meeting is running' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, avatar_url: nil, role: 'Viewer') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, user_id:, avatar_url: nil, + role: 'Viewer') post :status, params: { friendly_id: test_room.friendly_id, name: user.name } expect(response).to have_http_status(:ok) @@ -161,14 +165,15 @@ it 'joins as viewer if no access code is required nor provided' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, avatar_url: nil, role: 'Viewer') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, user_id:, avatar_url: nil, + role: 'Viewer') post :status, params: { friendly_id: test_room.friendly_id, name: user.name } expect(response).to have_http_status(:ok) end it 'joins as moderator if user is joining his own room' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, user_id:, avatar_url: nil, role: 'Moderator') post :status, params: { friendly_id: room.friendly_id, name: user.name } expect(response).to have_http_status(:ok) end @@ -180,7 +185,7 @@ expect_any_instance_of(BigBlueButtonApi) .to receive(:join_meeting) - .with(room: test_room, name: user.name, avatar_url:, role: 'Viewer') + .with(room: test_room, name: user.name, user_id:, avatar_url:, role: 'Viewer') post :status, params: { friendly_id: test_room.friendly_id, name: user.name } end @@ -203,7 +208,8 @@ it 'joins as moderator' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, user_id: guest_user_id, + avatar_url: nil, role: 'Moderator') post :status, params: { friendly_id: room.friendly_id, name: guest_user.name } end end @@ -219,7 +225,8 @@ it 'joins as viewer if access code correspond to the viewer access code' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, avatar_url: nil, role: 'Viewer') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, user_id:, avatar_url: nil, + role: 'Viewer') expect(RoomSettingsGetter).to receive(:new).with( room_id: test_room.id, provider: 'greenlight', show_codes: true, current_user: user, settings: %w[glRequireAuthentication glViewerAccessCode glModeratorAccessCode glAnyoneCanStart glAnyoneJoinAsModerator] @@ -234,7 +241,7 @@ it 'joins as moderator if access code correspond to moderator access code' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, user_id:, avatar_url: nil, role: 'Moderator') expect(RoomSettingsGetter).to receive(:new).with( room_id: room.id, provider: 'greenlight', show_codes: true, current_user: user, settings: %w[glRequireAuthentication glViewerAccessCode glModeratorAccessCode glAnyoneCanStart glAnyoneJoinAsModerator] @@ -273,7 +280,8 @@ it 'user joins as a moderator' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, user_id: guest_user_id, + avatar_url: nil, role: 'Moderator') expect(RoomSettingsGetter).to receive(:new).with( room_id: room.id, provider: 'greenlight', show_codes: true, current_user: guest_user, settings: %w[glRequireAuthentication glViewerAccessCode glModeratorAccessCode glAnyoneCanStart glAnyoneJoinAsModerator] @@ -299,7 +307,8 @@ it 'user joins as moderator if an access code is needed and the input correspond the viewer access code' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, user_id: guest_user_id, + avatar_url: nil, role: 'Moderator') expect(RoomSettingsGetter).to receive(:new).with( room_id: room.id, provider: 'greenlight', show_codes: true, current_user: guest_user, settings: %w[glRequireAuthentication glViewerAccessCode glModeratorAccessCode glAnyoneCanStart glAnyoneJoinAsModerator] @@ -314,7 +323,8 @@ it 'user joins as moderator if an access code is needed and the input correspond the moderator access code' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, avatar_url: nil, role: 'Moderator') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: guest_user.name, user_id: guest_user_id, + avatar_url: nil, role: 'Moderator') expect(RoomSettingsGetter).to receive(:new).with( room_id: room.id, provider: 'greenlight', show_codes: true, current_user: guest_user, settings: %w[glRequireAuthentication glViewerAccessCode glModeratorAccessCode glAnyoneCanStart glAnyoneJoinAsModerator] @@ -387,7 +397,8 @@ it 'allows the user to join if they are signed in' do allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, avatar_url: nil, role: 'Viewer') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room: test_room, name: user.name, user_id:, avatar_url: nil, + role: 'Viewer') post :status, params: { friendly_id: test_room.friendly_id, name: user.name } @@ -406,10 +417,13 @@ end it 'allows access to an unauthenticated user' do + allow(SecureRandom).to receive(:hex).and_return('abc123456789') + session[:session_token] = nil allow_any_instance_of(BigBlueButtonApi).to receive(:meeting_running?).and_return(true) - expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, avatar_url: nil, role: 'Viewer') + expect_any_instance_of(BigBlueButtonApi).to receive(:join_meeting).with(room:, name: user.name, user_id: 'gl-guest-abc123456789', + avatar_url: nil, role: 'Viewer') post :status, params: { friendly_id: room.friendly_id, name: user.name } diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 81a9d594ec..d24017fc3b 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -301,6 +301,66 @@ expect(response.parsed_body['errors']).not_to be_nil end end + + context 'Allowed Domains' do + context 'restricted domain not set' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('') + end + + it 'creates the user' do + expect { post :create, params: user_params }.to change(User, :count).from(0).to(1) + end + end + + context 'restricted domain set to 1 domain' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('@domain.com') + end + + it 'creates the user if the domain is allowed' do + user_params[:user][:email] = 'test@domain.com' + expect { post :create, params: user_params }.to change(User, :count).from(0).to(1) + end + + it 'does not create if the domain is not allowed' do + user_params[:user][:email] = 'test@invaliddomain.com' + expect { post :create, params: user_params }.not_to change(User, :count) + end + end + + context 'restricted domain set to multiple domain' do + before do + site_settings = instance_double(SettingGetter) + allow(SettingGetter).to receive(:new).with(setting_name: 'AllowedDomains', provider: 'greenlight').and_return(site_settings) + allow(site_settings).to receive(:call).and_return('@example.com,@test.com,@domain.com') + end + + it 'creates the user if the domain is allowed 1' do + user_params[:user][:email] = 'test@example.com' + expect { post :create, params: user_params }.to change(User, :count).from(0).to(1) + end + + it 'creates the user if the domain is allowed 2' do + user_params[:user][:email] = 'test@test.com' + expect { post :create, params: user_params }.to change(User, :count).from(0).to(1) + end + + it 'creates the user if the domain is allowed 3' do + user_params[:user][:email] = 'test@domain.com' + expect { post :create, params: user_params }.to change(User, :count).from(0).to(1) + end + + it 'does not create if the domain is not allowed' do + user_params[:user][:email] = 'test@invaliddomain.com' + expect { post :create, params: user_params }.not_to change(User, :count) + end + end + end end describe '#show' do diff --git a/spec/services/meeting_starter_spec.rb b/spec/services/meeting_starter_spec.rb index 254c77e5ef..4fb0464bb0 100644 --- a/spec/services/meeting_starter_spec.rb +++ b/spec/services/meeting_starter_spec.rb @@ -46,6 +46,8 @@ 'meta_bbb-origin-version': 'v3', 'meta_bbb-origin': 'greenlight', 'meta_bbb-origin-server-name': URI(base_url).host, + 'meta_bbb-context-name': room.name, + 'meta_bbb-context-id': room.friendly_id, setting: 'value' } end