Commit 8ba690c6 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee into ce_upstream

parents 7c526cf6 84ff13a8
Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (Unreleased)
- Reduce UPDATE queries when moving between import states on projects
- [ES] Instrument Elasticsearch::Git::Repository
- Request only the LDAP attributes we need
- [ES] Instrument other Gitlab::Elastic classes
- [ES] Fix: Elasticsearch does not find partial matches in project names
v 8.11.6
- Exclude blocked users from potential MR approvers
- Add 'Sync now' to group members page !704
v 8.11.6
- Fix mirrored projects allowing empty import urls
v 8.11.5
- API: Restore backward-compatibility for POST /projects/:id/members when membership is locked
......
......@@ -2,9 +2,10 @@ class Groups::LdapsController < Groups::ApplicationController
before_action :group
before_action :authorize_admin_group!
def reset_access
LdapGroupResetService.new.execute(group, current_user)
def sync
@group.pending_ldap_sync
LdapGroupSyncWorker.perform_async(@group.id)
redirect_to group_group_members_path(@group), notice: 'Access reset complete'
redirect_to group_group_members_path(@group), notice: 'The group sync has been scheduled'
end
end
......@@ -13,14 +13,26 @@ module Elastic
analysis: {
analyzer: {
default: {
tokenizer: "standard",
filter: ["standard", "lowercase", "my_stemmer"]
tokenizer: 'standard',
filter: ['standard', 'lowercase', 'my_stemmer']
},
my_ngram_analyzer: {
tokenizer: 'my_ngram_tokenizer',
filter: ['lowercase']
}
},
filter: {
my_stemmer: {
type: "stemmer",
name: "light_english"
type: 'stemmer',
name: 'light_english'
}
},
tokenizer: {
my_ngram_tokenizer: {
type: 'nGram',
min_gram: 2,
max_gram: 3,
token_chars: [ 'letter', 'digit' ]
}
}
}
......
......@@ -12,7 +12,8 @@ module Elastic
indexes :path, type: :string,
index_options: 'offsets'
indexes :name_with_namespace, type: :string,
index_options: 'offsets'
index_options: 'offsets',
analyzer: :my_ngram_analyzer
indexes :path_with_namespace, type: :string,
index_options: 'offsets'
indexes :description, type: :string,
......
......@@ -10,10 +10,15 @@ module EE
state_machine :ldap_sync_status, namespace: :ldap_sync, initial: :ready do
state :ready
state :started
state :pending
state :failed
event :pending do
transition [:ready, :failed] => :pending
end
event :start do
transition [:ready, :failed] => :started
transition [:ready, :pending, :failed] => :started
end
event :finish do
......
......@@ -169,7 +169,6 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
validates :import_url, addressable_url: true, if: :external_import?
validates :mirror_user, presence: true, if: :mirror?
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
validate :avatar_type,
......@@ -183,6 +182,11 @@ class Project < ActiveRecord::Base
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
with_options if: :mirror? do |project|
project.validates :import_url, presence: true
project.validates :mirror_user, presence: true
end
add_authentication_token_field :runners_token
before_save :ensure_runners_token
before_validation :mark_remote_mirrors_for_removal
......@@ -237,12 +241,11 @@ class Project < ActiveRecord::Base
after_transition any => :finished, do: :reset_cache_and_import_attrs
after_transition started: :finished do |project, transaction|
before_transition started: :finished do |project, transaction|
if project.mirror?
timestamp = DateTime.now
project.mirror_last_update_at = timestamp
project.mirror_last_successful_update_at = timestamp
project.save
end
if current_application_settings.elasticsearch_indexing?
......@@ -250,10 +253,8 @@ class Project < ActiveRecord::Base
end
end
after_transition started: :failed do |project, transaction|
if project.mirror?
project.update(mirror_last_update_at: DateTime.now)
end
before_transition started: :failed do |project, transaction|
project.mirror_last_update_at = DateTime.now if project.mirror?
end
end
......
- if current_user && @group.ldap_synced?
.bs-callout.bs-callout-info
The members of this group are managed using LDAP and cannot be added, changed or removed here.
Because LDAP permissions in GitLab get updated one user at a time and because GitLab caches LDAP check results, changes on your LDAP server or in this group's LDAP sync settings may take up to #{Gitlab.config.ldap['sync_time']}s to show in the list below.
%ul
- @group.ldap_group_links.each do |ldap_group_link|
%li
People in cn
%code= ldap_group_link.cn
are given
%code= ldap_group_link.human_access
access.
- if can?(current_user, :admin_group, @group)
= render 'sync_button'
- if @group.ldap_sync_started?
%span.btn.disabled
= icon("refresh spin")
Syncing&hellip;
- elsif @group.ldap_sync_pending?
%span.btn.disabled
= icon("refresh spin")
Pending sync&hellip;
- else
= link_to sync_group_ldap_path(@group), method: :put, class: 'btn' do
= icon("refresh")
Sync now
- if @group.ldap_sync_ready? && @group.ldap_sync_last_successful_update_at
%p.inline.prepend-left-10
Successfully synced #{time_ago_with_tooltip(@group.ldap_sync_last_successful_update_at)}.
......@@ -13,23 +13,7 @@
= render 'shared/members/requests', membership_source: @group, requesters: @requesters
- if current_user && @group.ldap_synced?
.bs-callout.bs-callout-info
The members of this group are managed using LDAP and cannot be added, changed or removed here.
Because LDAP permissions in GitLab get updated one user at a time and because GitLab caches LDAP check results, changes on your LDAP server or in this group's LDAP sync settings may take up to #{Gitlab.config.ldap['sync_time']}s to show in the list below.
%ul
- @group.ldap_group_links.each do |ldap_group_link|
%li
People in cn
%code= ldap_group_link.cn
are given
%code= ldap_group_link.human_access
access.
- if can?(current_user, :admin_group_member, @group)
= form_tag(reset_access_group_ldap_path(@group), method: :put, class: 'inline') do
= button_to 'Clear LDAP permission cache', '#', class: "btn btn-remove js-confirm-danger",
data: { "confirm-danger-message" => clear_ldap_permission_cache_message,
'warning-message' => 'If you made manual permission tweaks for some group members they will be lost.' }
= render 'ldap_sync'
.panel.panel-default
.panel-heading
......@@ -51,5 +35,3 @@
event.preventDefault();
Turbolinks.visit(this.action + '?' + $(this).serialize());
});
= render 'shared/confirm_modal', phrase: 'reset'
......@@ -139,5 +139,8 @@
$('.import_git').click(function( event ) {
$projectImportUrl = $('#project_import_url')
$projectMirror = $('#project_mirror')
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'))
$projectMirror.attr('disabled', !$projectMirror.attr('disabled'))
});
......@@ -19,7 +19,7 @@
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :mirror do
= f.check_box :mirror
= f.check_box :mirror, disabled: true
%strong
Mirror repository
.help-block
......
......@@ -3,9 +3,21 @@ class LdapGroupSyncWorker
sidekiq_options retry: false
def perform
logger.info 'Started LDAP group sync'
EE::Gitlab::LDAP::Sync::Groups.execute
logger.info 'Finished LDAP group sync'
def perform(group_id = nil)
if group_id
group = Group.find_by(id: group_id)
unless group
logger.warn "Could not find group #{group_id} for LDAP group sync"
return
end
logger.info "Started LDAP group sync for group #{group.name} (#{group.id})"
EE::Gitlab::LDAP::Sync::Group.execute_all_providers(group)
logger.info "Finished LDAP group sync for group #{group.name} (#{group.id})"
else
logger.info 'Started LDAP group sync'
EE::Gitlab::LDAP::Sync::Groups.execute
logger.info 'Finished LDAP group sync'
end
end
end
......@@ -463,7 +463,7 @@ Rails.application.routes.draw do
resource :analytics, only: [:show]
resource :ldap, only: [] do
member do
put :reset_access
put :sync
end
end
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class UpdateMirrorWhenEmptyImportUrlInProjects < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
update_column_in_batches(:projects, :mirror, false) do |table, query|
query.where(table[:import_url].eq(nil).or(table[:import_url].eq('')))
end
end
end
......@@ -26,6 +26,7 @@
## Administrator documentation
- [Upload your GitLab License](user/admin_area/license.md) Upload the license you purchased for GitLab Enterprise Edition to unlock its features.
- [Audit Events](administration/audit_events.md) Check how user access changed in projects and groups.
- [Access restrictions](user/admin_area/settings/visibility_and_access_controls.md#enabled-git-access-protocols) Define which Git access protocols can be used to talk to GitLab
- [Authentication/Authorization](administration/auth/README.md) Configure
......@@ -36,7 +37,6 @@
- [Push Rules](push_rules/push_rules.md) Advanced push rules for your project.
- [Help message](customization/help_message.md) Set information about administrators of your GitLab instance.
- [Install](install/README.md) Requirements, directory structures and installation from source.
- [Installing your license](license/README.md)
- [Integration](integration/README.md) How to integrate with systems such as JIRA, Redmine, LDAP and Twitter.
- [Restart GitLab](administration/restart_gitlab.md) Learn how to restart GitLab and its components.
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
......
# Installing your license
To activate all GitLab Enterprise Edition functionality, you need to upload a
license. Once you've received your license from GitLab Inc., you can upload it
by signing into your GitLab instance as an admin, and navigating to
**Admin Area > License**.
If you've received a `.gitlab-license` file, you can upload it directly.
![upload.png](img/upload.png)
If you've received your license as plain text, you need to select the
"Enter license key" option, copy the license and paste it into the "License key"
field.
![enter.png](img/enter.png)
Once you've uploaded your license, all GitLab Enterprise Edition functionality
will be active until the end of the license period.
You can review the license details at any time in the License section of the
Admin Area.
![details.png](img/details.png)
## Notification before the license expires
One month before the license expires, a message informing when the expiration
is due to will be shown to GitLab admins. Make sure that you update your license
beforehand otherwise you will miss important features if it expires.
![License expiration](img/expire_message.png)
## What happens when my license expires?
In case your license expires, you will not be able to push any commits to
GitLab and creation of new issues and merge requests will be disabled.
A message to inform of the locked state of GitLab will be presented to
admins only.
![No license message](img/no_license_message.png)
This document was moved to [user/admin_area/license](../user/admin_area/license.md).
# Activate all GitLab Enterprise Edition functionality with a license
To activate all GitLab Enterprise Edition (EE) functionality, you need to upload
a license. The license has the form of a base64 encoded ASCII text with a
`.gitlab-license` extension and can be obtained when you [purchase one][pricing]
or when you sign up for a [free trial]. Once you've received your license from
GitLab Inc., you can upload it by signing into your GitLab instance as an admin.
## Uploading your license
The very first time you visit your GitLab EE installation, you should see a
notice urging you to upload a license with a link that takes you straight to the
License admin area. Otherwise, you can navigate manually to the **Admin Area**
by clicking the wrench icon in the upper right corner and the going to the
**License** tab.
![License admin area](img/license_admin_area.png)
---
If you've received a `.gitlab-license` file, you should have already downloaded
it in your local machine. You can then upload it directly by choosing the
license file and clicking the **Upload license** button. In the image below,
you can see that the selected license file is named `GitLab.gitlab-license`.
![Upload license](img/license_upload.png)
---
If you've received your license as plain text, you need to select the
"Enter license key" option, copy the license, paste it into the "License key"
field and click **Upload license**.
![Enter license](img/license_enter.png)
Once you've uploaded your license, all GitLab Enterprise Edition functionality
will be active until the end of the license period.
You can review the license details at any time in the License section of the
Admin Area.
![License details](img/license_details.png)
## License history
It's possible to upload more than one license, but only the last one will be
taken into account.
You can see your previous licenses' history at the bottom of the License page.
![License history](img/license_history.png)
## Notification before the license expires
One month before the license expires, a message informing when the expiration
is due to will be shown to GitLab admins. Make sure that you update your license
beforehand otherwise you will miss important features if it expires.
![License expiration](img/license_expire_message.png)
## What happens when your license expires
In case your license expires, you will not be able to push any commits to
GitLab and creation of new issues and merge requests will be disabled.
A message to inform of the locked state of GitLab will be presented to all
users and admins will be able to see a link to upload a license.
![No license message](img/license_no_license_message.png)
[free trial]: https://about.gitlab.com/free-trial/
[pricing]: https://about.gitlab.com/pricing/
......@@ -16,7 +16,8 @@ module EE
def groups(cn = "*", size = nil)
options = {
base: config.group_base,
filter: Net::LDAP::Filter.eq("cn", cn)
filter: Net::LDAP::Filter.eq("cn", cn),
attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
options.merge!(size: size) if size
......@@ -30,13 +31,13 @@ module EE
groups(*args).first
end
def dn_matches_filter?(dn, filter)
def dns_for_filter(filter)
ldap_search(
base: dn,
base: config.base,
filter: filter,
scope: Net::LDAP::SearchScope_BaseObject,
scope: Net::LDAP::SearchScope_WholeSubtree,
attributes: %w{dn}
).any?
).map(&:dn)
end
end
end
......
module EE
module Gitlab
module LDAP
module Person
def ssh_keys
if config.sync_ssh_keys? && entry.respond_to?(config.sync_ssh_keys)
entry[config.sync_ssh_keys.to_sym].
map { |key| key[/(ssh|ecdsa)-[^ ]+ [^\s]+/] }.
compact
else
[]
end
end
def kerberos_principal
# The following is only meaningful for Active Directory
return unless entry.respond_to?(:sAMAccountName)
entry[:sAMAccountName].first + '@' + windows_domain_name.upcase
end
def windows_domain_name
# The following is only meaningful for Active Directory
require 'net/ldap/dn'
dn_components = []
Net::LDAP::DN.new(dn).each_pair { |name, value| dn_components << { name: name, value: value } }
dn_components.
reverse.
take_while { |rdn| rdn[:name].casecmp('DC').zero? }. # Domain Component
map { |rdn| rdn[:value] }.
reverse.
join('.')
end
end
end
end
end
......@@ -44,13 +44,11 @@ module Gitlab
users(*args).first
end
def dns_for_filter(filter)
ldap_search(
base: config.base,
filter: filter,
scope: Net::LDAP::SearchScope_WholeSubtree,
attributes: %w{dn}
).map(&:dn)
def dn_matches_filter?(dn, filter)
ldap_search(base: dn,
filter: filter,
scope: Net::LDAP::SearchScope_BaseObject,
attributes: %w{dn}).any?
end
def ldap_search(*args)
......
module Gitlab
module LDAP
class Person
include EE::Gitlab::LDAP::Person
# Active Directory-specific LDAP filter that checks if bit 2 of the
# userAccountControl attribute is set.
# Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
......@@ -47,35 +49,6 @@ module Gitlab
entry.dn
end
def ssh_keys
if config.sync_ssh_keys? && entry.respond_to?(config.sync_ssh_keys)
entry[config.sync_ssh_keys.to_sym].
map { |key| key[/(ssh|ecdsa)-[^ ]+ [^\s]+/] }.
compact
else
[]
end
end
def kerberos_principal
# The following is only meaningful for Active Directory
return unless entry.respond_to?(:sAMAccountName)
entry[:sAMAccountName].first + '@' + windows_domain_name.upcase
end
def windows_domain_name
# The following is only meaningful for Active Directory
require 'net/ldap/dn'
dn_components = []
Net::LDAP::DN.new(dn).each_pair { |name, value| dn_components << { name: name, value: value } }
dn_components.
reverse.
take_while { |rdn| rdn[:name].casecmp('DC').zero? }. # Domain Component
map { |rdn| rdn[:value] }.
reverse.
join('.')
end
private
def entry
......
......@@ -9,6 +9,8 @@ module Gitlab
end
def self.valid?(url)
return false unless url
Addressable::URI.parse(url.strip)
true
......
......@@ -58,7 +58,7 @@ namespace :gitlab do
desc "GitLab | Elasticsearch | Index wiki repositories"
task index_wikis: :environment do
projects = apply_project_filters(Project.where(wiki_enabled: true))
projects = apply_project_filters(Project.with_wiki_enabled)
projects.find_each do |project|
unless project.wiki.empty?
......
require 'spec_helper'
# Test things specific to the EE mixin, but run the actual tests
# against the main adapter class to ensure it's properly included
describe Gitlab::LDAP::Adapter, lib: true do
subject { Gitlab::LDAP::Adapter.new 'ldapmain' }
include LdapHelpers
it { is_expected.to include_module(EE::Gitlab::LDAP::Adapter) }
it 'includes the EE module' do
expect(Gitlab::LDAP::Adapter).to include_module(EE::Gitlab::LDAP::Adapter)
end
describe '#groups' do
let(:adapter) { ldap_adapter('ldapmain') }
before do
stub_ldap_config(
group_base: 'ou=groups,dc=example,dc=com',
active_directory: false
)
end
it 'searches with the proper options' do
# Requires this expectation style to match the filter
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(cn=*)')
expect(arg[:base]).to eq('ou=groups,dc=example,dc=com')
expect(arg[:attributes]).to match(%w(dn cn memberuid member submember uniquemember memberof))
end.and_return({})
adapter.groups
end
it 'returns a group object if search returns a result' do
entry = ldap_group_entry(['john', 'mary'], cn: 'group1')
allow(adapter).to receive(:ldap_search).and_return([entry])
results = adapter.groups('group1')
expect(results.first).to be_a(EE::Gitlab::LDAP::Group)
expect(results.first.cn).to eq('group1')
expect(results.first.member_dns).to match_array(%w(john mary))
end
end
end
require 'spec_helper'
describe EE::Gitlab::LDAP::Group, lib: true do
include LdapHelpers
let(:adapter) { ldap_adapter }
describe '#member_dns' do
def ldif
Net::LDAP::Entry.from_single_ldif_string(
......@@ -17,10 +21,6 @@ describe EE::Gitlab::LDAP::Group, lib: true do
)
end
def adapter
@adapter ||= Gitlab::LDAP::Adapter.new('ldapmain')
end
let(:group) { described_class.new(ldif, adapter) }
let(:recursive_dns) do
%w(
......
require "spec_helper"
require 'spec_helper'
describe Gitlab::LDAP::Person do
describe "#kerberos_principal" do
it 'includes the EE module' do
expect(Gitlab::LDAP::Person).to include(EE::Gitlab::LDAP::Person)
end
describe '#kerberos_principal' do
let(:entry) do
ldif = "dn: cn=foo, dc=bar, dc=com\n"
ldif += "sAMAccountName: #{sam_account_name}\n" if sam_account_name
......@@ -10,25 +14,25 @@ describe Gitlab::LDAP::Person do
subject { Gitlab::LDAP::Person.new(entry, 'ldapmain') }
context "when sAMAccountName is not defined (non-AD LDAP server)" do
context 'when sAMAccountName is not defined (non-AD LDAP server)' do
let(:sam_account_name) { nil }
it "returns nil" do
it 'returns nil' do
expect(subject.kerberos_principal).to be_nil
end
end
context "when sAMAccountName is defined (AD server)" do
let(:sam_account_name) { "mylogin" }
context 'when sAMAccountName is defined (AD server)' do
let(:sam_account_name) { 'mylogin' }
it "returns the principal combining sAMAccountName and DC components of the distinguishedName" do
expect(subject.kerberos_principal).to eq("mylogin@BAR.COM")
it 'returns the principal combining sAMAccountName and DC components of the distinguishedName' do
expect(subject.kerberos_principal).to eq('mylogin@BAR.COM')
end
end
end
describe "#ssh_keys" do
let(:ssh_key) { "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrSQHff6a1rMqBdHFt+FwIbytMZ+hJKN3KLkTtOWtSvNIriGhnTdn4rs+tjD/w+z+revytyWnMDM9dS7J8vQi006B16+hc9Xf82crqRoPRDnBytgAFFQY1G/55ql2zdfsC5yvpDOFzuwIJq5dNGsojS82t6HNmmKPq130fzsenFnj5v1pl3OJvk513oduUyKiZBGTroWTn7H/eOPtu7s9MD7pAdEjqYKFLeaKmyidiLmLqQlCRj3Tl2U9oyFg4PYNc0bL5FZJ/Z6t0Ds3i/a2RanQiKxrvgu3GSnUKMx7WIX373baL4jeM7cprRGiOY/1NcS+1cAjfJ8oaxQF/1dYj" }
describe '#ssh_keys' do
let(:ssh_key) { 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrSQHff6a1rMqBdHFt+FwIbytMZ+hJKN3KLkTtOWtSvNIriGhnTdn4rs+tjD/w+z+revytyWnMDM9dS7J8vQi006B16+hc9Xf82crqRoPRDnBytgAFFQY1G/55ql2zdfsC5yvpDOFzuwIJq5dNGsojS82t6HNmmKPq130fzsenFnj5v1pl3OJvk513oduUyKiZBGTroWTn7H/eOPtu7s9MD7pAdEjqYKFLeaKmyidiLmLqQlCRj3Tl2U9oyFg4PYNc0bL5FZJ/Z6t0Ds3i/a2RanQiKxrvgu3GSnUKMx7WIX373baL4jeM7cprRGiOY/1NcS+1cAjfJ8oaxQF/1dYj' }
let(:ssh_key_attribute_name) { 'altSecurityIdentities' }
let(:entry) do
Net::LDAP::Entry.from_single_ldif_string("dn: cn=foo, dc=bar, dc=com\n#{keys}")
......@@ -40,53 +44,53 @@ describe Gitlab::LDAP::Person do
allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(sync_ssh_keys: ssh_key_attribute_name)
end
context "when the SSH key is literal" do
context 'when the SSH key is literal' do
let(:keys) { "#{ssh_key_attribute_name}: #{ssh_key}" }
it "includes the SSH key" do
it 'includes the SSH key' do
expect(subject.ssh_keys).to include(ssh_key)
end
end
context "when the SSH key is prefixed" do
context 'when the SSH key is prefixed' do
let(:keys) { "#{ssh_key_attribute_name}: SSHKey:#{ssh_key}" }
it "includes the SSH key" do
it 'includes the SSH key' do
expect(subject.ssh_keys).to include(ssh_key)
end
end
context "when the SSH key is suffixed" do
context 'when the SSH key is suffixed' do
let(:keys) { "#{ssh_key_attribute_name}: #{ssh_key} (SSH key)" }
it "includes the SSH key" do
it 'includes the SSH key' do
expect(subject.ssh_keys).to include(ssh_key)
end
end
context "when the SSH key is followed by a newline" do
context 'when the SSH key is followed by a newline' do
let(:keys) { "#{ssh_key_attribute_name}: #{ssh_key}\n" }
it "includes the SSH key" do
it 'includes the SSH key' do
expect(subject.ssh_keys).to include(ssh_key)
end
end
context "when the key is not an SSH key" do
context 'when the key is not an SSH key' do
let(:keys) { "#{ssh_key_attribute_name}: KerberosKey:bogus" }
it "is empty" do
it 'is empty' do
expect(subject.ssh_keys).to be_empty
end
end
context "when there are multiple keys" do
context 'when there are multiple keys' do
let(:keys) { "#{ssh_key_attribute_name}: #{ssh_key}\n#{ssh_key_attribute_name}: KerberosKey:bogus\n#{ssh_key_attribute_name}: ssh-rsa keykeykey" }
it "includes both SSH keys" do
it 'includes both SSH keys' do
expect(subject.ssh_keys).to include(ssh_key)
expect(subject.ssh_keys).to include("ssh-rsa keykeykey")
expect(subject.ssh_keys).not_to include("KerberosKey:bogus")
expect(subject.ssh_keys).to include('ssh-rsa keykeykey')
expect(subject.ssh_keys).not_to include('KerberosKey:bogus')
end
end
end
......
......@@ -3,6 +3,8 @@ require 'spec_helper'
describe EE::Gitlab::LDAP::Sync::AdminUsers, lib: true do
include LdapHelpers
let(:adapter) { ldap_adapter }
describe '#update_permissions' do
let(:sync_admin) { described_class.new(proxy(adapter)) }
......
......@@ -4,6 +4,7 @@ describe EE::Gitlab::LDAP::Sync::ExternalUsers, lib: true do
include LdapHelpers
describe '#update_permissions' do
let(:adapter) { ldap_adapter }
let(:sync_external) { described_class.new(proxy(adapter)) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
......
......@@ -3,6 +3,7 @@ require 'spec_helper'
describe EE::Gitlab::LDAP::Sync::Group, lib: true do
include LdapHelpers
let(:adapter) { ldap_adapter }
let(:sync_group) { described_class.new(group, proxy(adapter)) }
let(:user) { create(:user) }
......@@ -92,6 +93,24 @@ describe EE::Gitlab::LDAP::Sync::Group, lib: true do
include_examples :group_state_machine
end
describe '.ldap_sync_ready?' do
let(:ldap_group1) { nil }
it 'returns false when ldap sync started' do
group = create(:group)
group.start_ldap_sync
expect(described_class.ldap_sync_ready?(group)).to be_falsey
end
it 'returns true when ldap sync pending' do
group = create(:group)
group.pending_ldap_sync
expect(described_class.ldap_sync_ready?(group)).to be_truthy
end
end
describe '#update_permissions' do
before { group.start_ldap_sync }
after { group.finish_ldap_sync }
......
......@@ -3,6 +3,7 @@ require 'spec_helper'
describe EE::Gitlab::LDAP::Sync::Groups, lib: true do
include LdapHelpers
let(:adapter) { ldap_adapter }
let(:group_sync) { described_class.new(proxy(adapter)) }
describe '#update_permissions' do
......
......@@ -4,6 +4,7 @@ require 'net/ldap/dn'
describe EE::Gitlab::LDAP::Sync::Proxy, lib: true do
include LdapHelpers
let(:adapter) { ldap_adapter }
let(:sync_proxy) { EE::Gitlab::LDAP::Sync::Proxy.new('ldapmain', adapter) }
before do
......
......@@ -70,4 +70,12 @@ describe Gitlab::UrlSanitizer, lib: true do
expect(sanitizer.full_url).to eq('user@server:project.git')
end
end
describe '.valid?' do
it 'validates url strings' do
expect(described_class.valid?(nil)).to be(false)
expect(described_class.valid?('valid@project:url.git')).to be(true)
expect(described_class.valid?('123://invalid:url')).to be(false)
end
end
end
......@@ -11,7 +11,7 @@ describe Project, elastic: true do
stub_application_setting(elasticsearch_search: false, elasticsearch_indexing: false)
end
it "searches projects" do
it "finds projects" do
project_ids = []
Sidekiq::Testing.inline! do
......@@ -29,6 +29,20 @@ describe Project, elastic: true do
expect(described_class.elastic_search('someone_elses_project', options: { pids: project_ids }).total_count).to eq(0)
end
it "finds partial matches in project names" do
project_ids = []
Sidekiq::Testing.inline! do
project = create :empty_project, name: 'tesla-model-s'
project1 = create :empty_project, name: 'tesla_model_s'
project_ids += [project.id, project1.id]
Gitlab::Elastic::Helper.refresh_index
end
expect(described_class.elastic_search('tesla', options: { pids: project_ids }).total_count).to eq(2)
end
it "returns json with all needed elements" do
project = create :empty_project
......
......@@ -134,6 +134,13 @@ describe Project, models: true do
end
end
context 'mirror' do
subject { build(:project, mirror: true) }
it { is_expected.to validate_presence_of(:import_url) }
it { is_expected.to validate_presence_of(:mirror_user) }
end
it 'does not allow an invalid URI as import_url' do
project2 = build(:project, import_url: 'invalid://')
......
module EE
module LdapHelpers
def proxy(adapter, provider = 'ldapmain')
EE::Gitlab::LDAP::Sync::Proxy.new(provider, adapter)
end
# Stub an LDAP group search and provide the return entry. Specify `nil` for
# `entry` to simulate when an LDAP group is not found
#
# Example:
# adapter = ::Gitlab::LDAP::Adapter.new('ldapmain', double(:ldap))
# ldap_group1 = ldap_group_entry('uid=user,ou=users,dc=example,dc=com')
#
# stub_ldap_group_find_by_cn('ldap_group1', ldap_group1, adapter)
def stub_ldap_group_find_by_cn(cn, entry, adapter = nil)
if entry.present?
return_value = EE::Gitlab::LDAP::Group.new(entry, adapter)
end
allow(EE::Gitlab::LDAP::Group)
.to receive(:find_by_cn)
.with(cn, kind_of(::Gitlab::LDAP::Adapter)).and_return(return_value)
end
# Create an LDAP group entry with any number of members. By default, creates
# a groupOfNames style entry. Change the style by specifying the object class
# and member attribute name. The last example below shows how to specify a
# posixGroup (Apple Open Directory) entry. `members` can be nil to create
# an empty group.
#
# Example:
# ldap_group_entry('uid=user,ou=users,dc=example,dc=com')
#
# ldap_group_entry(
# 'uid=user1,ou=users,dc=example,dc=com',
# 'uid=user2,ou=users,dc=example,dc=com'
# )
#
# ldap_group_entry(
# [ 'user1', 'user2' ],
# cn: 'my_group'
# objectclass: 'posixGroup',
# member_attr: 'memberUid'
# )
def ldap_group_entry(
members,
cn: 'ldap_group1',
objectclass: 'groupOfNames',
member_attr: 'uniqueMember'
)
entry = Net::LDAP::Entry.from_single_ldif_string(<<-EOS.strip_heredoc)
dn: cn=#{cn},ou=groups,dc=example,dc=com
cn: #{cn}
description: LDAP Group #{cn}
objectclass: top
objectclass: #{objectclass}
EOS
members = [members].flatten
entry[member_attr] = members if members.any?
entry
end
end
end
module LdapHelpers
<<<<<<< HEAD
def adapter(provider = 'ldapmain')
::Gitlab::LDAP::Adapter.new(provider, double(:ldap))
end
include EE::LdapHelpers
def proxy(adapter, provider = 'ldapmain')
EE::Gitlab::LDAP::Sync::Proxy.new(provider, adapter)
=======
def ldap_adapter(provider = 'ldapmain', ldap = double(:ldap))
::Gitlab::LDAP::Adapter.new(provider, ldap)
>>>>>>> 13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f
end
def user_dn(uid)
......@@ -39,90 +32,18 @@ module LdapHelpers
#
# stub_ldap_person_find_by_uid('john_doe', ldap_user_entry, adapter)
def stub_ldap_person_find_by_uid(uid, entry, provider = 'ldapmain')
<<<<<<< HEAD
return_value = if entry.present?
::Gitlab::LDAP::Person.new(entry, provider)
else
nil
end
=======
return_value = ::Gitlab::LDAP::Person.new(entry, provider) if entry.present?
>>>>>>> 13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f
allow(::Gitlab::LDAP::Person)
.to receive(:find_by_uid).with(uid, any_args).and_return(return_value)
end
<<<<<<< HEAD
# Stub an LDAP group search and provide the return entry. Specify `nil` for
# `entry` to simulate when an LDAP group is not found
#
# Example:
# adapter = ::Gitlab::LDAP::Adapter.new('ldapmain', double(:ldap))
# ldap_group1 = ldap_group_entry('uid=user,ou=users,dc=example,dc=com')
#
# stub_ldap_group_find_by_cn('ldap_group1', ldap_group1, adapter)
def stub_ldap_group_find_by_cn(cn, entry, adapter = nil)
return_value = if entry.present?
EE::Gitlab::LDAP::Group.new(entry, adapter)
else
nil
end
allow(EE::Gitlab::LDAP::Group)
.to receive(:find_by_cn)
.with(cn, kind_of(::Gitlab::LDAP::Adapter)).and_return(return_value)
end
# Create a simple LDAP user entry.
def ldap_user_entry(uid)
Net::LDAP::Entry.from_single_ldif_string("dn: #{user_dn(uid)}")
end
# Create an LDAP group entry with any number of members. By default, creates
# a groupOfNames style entry. Change the style by specifying the object class
# and member attribute name. The last example below shows how to specify a
# posixGroup (Apple Open Directory) entry. `members` can be nil to create
# an empty group.
#
# Example:
# ldap_group_entry('uid=user,ou=users,dc=example,dc=com')
#
# ldap_group_entry(
# 'uid=user1,ou=users,dc=example,dc=com',
# 'uid=user2,ou=users,dc=example,dc=com'
# )
#
# ldap_group_entry(
# [ 'user1', 'user2' ],
# cn: 'my_group'
# objectclass: 'posixGroup',
# member_attr: 'memberUid'
# )
def ldap_group_entry(
members,
cn: 'ldap_group1',
objectclass: 'groupOfNames',
member_attr: 'uniqueMember'
)
entry = Net::LDAP::Entry.from_single_ldif_string(<<-EOS.strip_heredoc)
dn: cn=#{cn},ou=groups,dc=example,dc=com
cn: #{cn}
description: LDAP Group #{cn}
objectclass: top
objectclass: #{objectclass}
EOS
members = [members].flatten
entry[member_attr] = members if members.any?
=======
# Create a simple LDAP user entry.
def ldap_user_entry(uid)
entry = Net::LDAP::Entry.new
entry['dn'] = user_dn(uid)
entry['uid'] = uid
>>>>>>> 13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f
entry
end
end
require 'spec_helper'
describe LdapGroupSyncWorker do
describe '#perform' do
it 'syncs all groups when group_id is nil' do
expect(EE::Gitlab::LDAP::Sync::Groups).to receive(:execute)
described_class.new.perform
end
it 'syncs a single group when group_id is present' do
group = create(:group)
expect(EE::Gitlab::LDAP::Sync::Group)
.to receive(:execute_all_providers).with(group)
described_class.new.perform(group.id)
end
it 'logs an error when group cannot be found' do
expect(EE::Gitlab::LDAP::Sync::Group).not_to receive(:execute_all_providers)
expect(Sidekiq.logger)
.to receive(:warn).with('Could not find group 9999 for LDAP group sync')
described_class.new.perform(9999)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment