diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | app/controllers/admin/application_settings_controller.rb | 3 | ||||
-rw-r--r-- | app/models/application_setting.rb | 24 | ||||
-rw-r--r-- | app/models/user.rb | 24 | ||||
-rw-r--r-- | app/views/admin/application_settings/_form.html.haml | 5 | ||||
-rw-r--r-- | config/initializers/1_settings.rb | 1 | ||||
-rw-r--r-- | db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb | 5 | ||||
-rw-r--r-- | db/schema.rb | 3 | ||||
-rw-r--r-- | spec/models/application_setting_spec.rb | 24 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 47 |
10 files changed, 133 insertions, 4 deletions
diff --git a/CHANGELOG b/CHANGELOG index 2c5c9c76ccf..dc3a6709222 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.11.0 (unreleased) + - Add application setting to restrict user signups to e-mail domains (Stan Hu) - Don't allow a merge request to be merged when its title starts with "WIP". - Add a page title to every page. - Get Gitorious importer to work again. diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 8f6a766635a..3975e30835e 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -41,7 +41,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :max_attachment_size, :default_project_visibility, :default_snippet_visibility, - restricted_visibility_levels: [] + :restricted_signup_domains_raw, + restricted_visibility_levels: [], ) end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 9406fb91939..f2cebde9705 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -18,11 +18,13 @@ # restricted_visibility_levels :text # max_attachment_size :integer default(10) # default_project_visibility :integer -# default_snippet_visibility :integer +# restricted_signup_domains :text # class ApplicationSetting < ActiveRecord::Base serialize :restricted_visibility_levels + serialize :restricted_signup_domains, Array + attr_accessor :restricted_signup_domains_raw validates :home_page_url, allow_blank: true, @@ -55,11 +57,29 @@ class ApplicationSetting < ActiveRecord::Base restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], max_attachment_size: Settings.gitlab['max_attachment_size'], default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], - default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'] + default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], + restricted_signup_domains: Settings.gitlab['restricted_signup_domains'] ) end def home_page_url_column_exist ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url) end + + def restricted_signup_domains_raw + self.restricted_signup_domains.join("\n") unless self.restricted_signup_domains.nil? + end + + def restricted_signup_domains_raw=(values) + self.restricted_signup_domains = [] + self.restricted_signup_domains = values.split( + /\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace + | # or + \s # any whitespace character + | # or + [\r\n] # any number of newline characters + /x) + self.restricted_signup_domains.reject! { |d| d.empty? } + end + end diff --git a/app/models/user.rb b/app/models/user.rb index d6b93afe739..f22fdc28435 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -142,6 +142,7 @@ class User < ActiveRecord::Base validates :avatar, file_size: { maximum: 200.kilobytes.to_i } before_validation :generate_password, on: :create + before_validation :restricted_signup_domains, on: :create before_validation :sanitize_attrs before_validation :set_notification_email, if: ->(user) { user.email_changed? } before_validation :set_public_email, if: ->(user) { user.public_email_changed? } @@ -611,4 +612,27 @@ class User < ActiveRecord::Base select(:project_id). uniq.map(&:project_id) end + + def restricted_signup_domains + email_domains = current_application_settings.restricted_signup_domains + + unless email_domains.blank? + match_found = email_domains.any? do |domain| + escaped = Regexp.escape(domain).gsub('\*','.*?') + regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE + email_domain = Mail::Address.new(self.email).domain + email_domain =~ regexp + end + + unless match_found + self.errors.add :email, + 'is not whitelisted. ' + + 'Email domains valid for registration are: ' + + email_domains.join(', ') + return false + end + end + + true + end end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 87e7c9634e9..f6eb00ea0bd 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -72,6 +72,11 @@ = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2' .col-sm-10 = f.number_field :max_attachment_size, class: 'form-control' + .form-group + = f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2' + .col-sm-10 + = f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control' + .help-block Ex: domain.com, *.domain.com. Wildcards allowed. Use separate lines for multiple entries. .form-actions = f.submit 'Save', class: 'btn btn-primary' diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 0abd34fc3e0..e5ac66a2323 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -132,6 +132,7 @@ Settings.gitlab.default_projects_features['wiki'] = true if Settings.g Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil? Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root) +Settings.gitlab['restricted_signup_domains'] ||= [] # # Gravatar diff --git a/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb b/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb new file mode 100644 index 00000000000..184e2653610 --- /dev/null +++ b/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddRestrictedSignupDomainsToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :restricted_signup_domains, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 02882186fc8..f0cccb8b749 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150429002313) do +ActiveRecord::Schema.define(version: 20150502064022) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -31,6 +31,7 @@ ActiveRecord::Schema.define(version: 20150429002313) do t.integer "max_attachment_size", default: 10, null: false t.integer "default_project_visibility" t.integer "default_snippet_visibility" + t.text "restricted_signup_domains" end create_table "broadcast_messages", force: true do |t| diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index b4f0b2c201a..876502d03c2 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -21,4 +21,28 @@ require 'spec_helper' describe ApplicationSetting, models: true do it { expect(ApplicationSetting.create_from_defaults).to be_valid } + + context 'restricted signup domains' do + let(:setting) { ApplicationSetting.create_from_defaults } + + it 'set single domain' do + setting.restricted_signup_domains_raw = 'example.com' + expect(setting.restricted_signup_domains).to eq(['example.com']) + end + + it 'set multiple domains with spaces' do + setting.restricted_signup_domains_raw = 'example.com *.example.com' + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + + it 'set multiple domains with newlines and a space' do + setting.restricted_signup_domains_raw = "example.com\n *.example.com" + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + + it 'set multiple domains with commas' do + setting.restricted_signup_domains_raw = "example.com, *.example.com" + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 24384e8bf22..441aa793133 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -54,6 +54,8 @@ require 'spec_helper' describe User do + include Gitlab::CurrentSettings + describe "Associations" do it { is_expected.to have_one(:namespace) } it { is_expected.to have_many(:snippets).class_name('Snippet').dependent(:destroy) } @@ -112,6 +114,51 @@ describe User do user = build(:user, email: "lol!'+=?><#$%^&*()@gmail.com") expect(user).to be_invalid end + + context 'when no signup domains listed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return([]) } + it 'accepts any email' do + user = build(:user, email: "info@example.com") + expect(user).to be_valid + end + end + + context 'when a signup domain is listed and subdomains are allowed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return(['example.com', '*.example.com']) } + it 'accepts info@example.com' do + user = build(:user, email: "info@example.com") + expect(user).to be_valid + end + + it 'accepts info@test.example.com' do + user = build(:user, email: "info@test.example.com") + expect(user).to be_valid + end + + it 'rejects example@test.com' do + user = build(:user, email: "example@test.com") + expect(user).to be_invalid + end + end + + context 'when a signup domain is listed and subdomains are not allowed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return(['example.com']) } + + it 'accepts info@example.com' do + user = build(:user, email: "info@example.com") + expect(user).to be_valid + end + + it 'rejects info@test.example.com' do + user = build(:user, email: "info@test.example.com") + expect(user).to be_invalid + end + + it 'rejects example@test.com' do + user = build(:user, email: "example@test.com") + expect(user).to be_invalid + end + end end end |