Commit 2b3661a1 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'jej/settings-for-saml-sso-per-group' into 'master'

Settings page for Per Group SAML

Closes #4513

See merge request gitlab-org/gitlab-ee!4549
parents c2e52a68 d80e28c8
......@@ -12,6 +12,10 @@
border-bottom: 1px solid $well-inner-border;
}
&.borderless {
border-bottom: 0;
}
&.branch-info {
.commit-sha,
.commit-info {
......
......@@ -297,6 +297,12 @@
}
}
.saml-settings.info-well {
.form-control[readonly] {
background: $white-light;
}
}
.modal-doorkeepr-auth,
.doorkeeper-app-form {
.scope-description {
......
......@@ -638,6 +638,8 @@ production: &base
# name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
# } }
#
# - { name: 'group_saml' }
#
# - { name: 'crowd',
# args: {
# crowd_server_url: 'CROWD SERVER URL',
......
......@@ -26,5 +26,6 @@ end
module OmniAuth
module Strategies
autoload :Bitbucket, Rails.root.join('lib', 'omni_auth', 'strategies', 'bitbucket')
autoload :GroupSaml, Rails.root.join('ee', 'lib', 'omni_auth', 'strategies', 'group_saml')
end
end
......@@ -67,6 +67,10 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resources :ldap_group_links, only: [:index, :create, :destroy]
resource :saml_providers, path: 'saml', only: [:show, :create, :update] do
get :sso, to: 'sso#saml'
end
resource :notification_setting, only: [:update]
resources :audit_events, only: [:index]
resources :pipeline_quota, only: [:index]
......
......@@ -2202,6 +2202,15 @@ ActiveRecord::Schema.define(version: 20180327101207) do
add_index "routes", ["path"], name: "index_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
add_index "routes", ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree
create_table "saml_providers", force: :cascade do |t|
t.integer "group_id", null: false
t.boolean "enabled", null: false
t.string "certificate_fingerprint", null: false
t.string "sso_url", null: false
end
add_index "saml_providers", ["group_id"], name: "index_saml_providers_on_group_id", using: :btree
create_table "sent_notifications", force: :cascade do |t|
t.integer "project_id"
t.integer "noteable_id"
......@@ -2779,6 +2788,7 @@ ActiveRecord::Schema.define(version: 20180327101207) do
add_foreign_key "push_rules", "projects", name: "fk_83b29894de", on_delete: :cascade
add_foreign_key "releases", "projects", name: "fk_47fe2a0596", on_delete: :cascade
add_foreign_key "remote_mirrors", "projects", name: "fk_43a9aa4ca8", on_delete: :cascade
add_foreign_key "saml_providers", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "services", "projects", name: "fk_71cce407f9", on_delete: :cascade
add_foreign_key "slack_integrations", "services", on_delete: :cascade
add_foreign_key "snippets", "projects", name: "fk_be41fd4bb7", on_delete: :cascade
......
# SAML SSO for Groups (Beta)
> Introduced in [GitLab Premium][https://about.gitlab.com/products/] 10.7.
This allows SAML to be used for adding users to a group on GitLab.com and other instances where using [site-wide SAML](../../../integration/saml.md) is not possible.
## Enable the beta
Enable the beta by setting the `enable_group_saml` cookie. This can be done with the below JavaScript snippet:
```javascript
javascript:void((function(d){document.cookie='enable_group_saml=' + (document.cookie.indexOf('enable_group_saml=true') >= 0 ? 'false' : 'true') + ';domain=.' + window.location.hostname + ';path=/;expires=' + new Date(Date.now() + 31536000000).toUTCString(); location.reload();})(document));
```
## How to configure
1. Navigate to the group and click Settings -> SAML SSO.
1. Configure your SAML server using the **Assertion consumer service URL** and **Issuer**. See [your identity provider's documentation](#providers) for more details.
1. Configure required assertions using the table below.
1. Find the SSO URL from your Identity Provider and enter it on GitLab.
1. Find and enter the fingerprint for the SAML token signing certificate.
## Assertions
| Field | Supported keys | Notes |
|-|----------------|-------------|
| Email | `email`, `mail` | (required) |
| Full Name | `name` | |
| First Name | `first_name`, `firstname`, `firstName` | |
| Last Name | `last_name`, `lastname`, `firstName` | |
## Providers
| Provider | Documentation |
|----------|---------------|
| ADFS (Active Directory Federation Services) | [Create a Relying Party Trust](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-relying-party-trust) |
| Azure | [Configuring single sign-on to applications](https://docs.microsoft.com/en-us/azure/active-directory/active-directory-saas-custom-apps) |
| Auth0 | [Auth0 as Identity Provider](https://auth0.com/docs/protocols/saml/saml-idp-generic) |
| G Suite | [Set up your own custom SAML application](https://support.google.com/a/answer/6087519?hl=en) |
| Okta | [Setting up a SAML application in Okta](https://developer.okta.com/standards/SAML/setting_up_a_saml_application_in_okta) |
| OneLogin | [How to Use the OneLogin SAML Test Connector](https://support.onelogin.com/hc/en-us/articles/202673944-How-to-Use-the-OneLogin-SAML-Test-Connector) |
| Ping Identity | [Add and configure a new SAML application](https://docs.pingidentity.com/bundle/p1_enterpriseConfigSsoSaml_cas/page/enableAppWithoutURL.html) |
## Glossary
| Term | Description |
|------|-------------|
| Identity Provider | The service which manages your user identities such as ADFS, Okta, Onelogin or Ping Identity. |
| Service Provider | SAML considers GitLab to be a service provider. |
| Assertion | A piece of information about a user's identity, such as their name or role. Also know as claims or attributes. |
| SSO | Single Sign On. |
| Assertion consumer service URL | The callback on GitLab where users will be redirected after successfully authenticating with the identity provider. |
| Issuer | How GitLab identifies itself to the identity provider. Also known as a "Relying party trust identifier". |
| Certificate fingerprint | Used to confirm that communications over SAML are secure by checking that the server is signing communications with the correct certificate. Also known as a certificate thumbprint. |
class Groups::SamlProvidersController < Groups::ApplicationController
before_action :require_top_level_group
before_action :authorize_manage_saml!
before_action :check_group_saml_available!
before_action :check_group_saml_configured
before_action :check_group_saml_beta_enabled
def show
@saml_provider = @group.saml_provider || @group.build_saml_provider
end
def create
@saml_provider = @group.build_saml_provider(saml_provider_params)
@saml_provider.save
render :show
end
def update
@saml_provider = @group.saml_provider
@saml_provider.update(saml_provider_params)
render :show
end
private
def authorize_manage_saml!
render_404 unless can?(current_user, :admin_group_saml, @group)
end
def check_group_saml_configured
render_404 unless Gitlab::Auth::GroupSaml::Config.enabled?
end
def check_group_saml_beta_enabled
render_404 unless Gitlab::Utils.to_boolean(cookies['enable_group_saml'])
end
def require_top_level_group
render_404 if @group.subgroup?
end
def saml_provider_params
allowed_params = %i[sso_url certificate_fingerprint enabled]
params.require(:saml_provider).permit(allowed_params)
end
end
......@@ -5,7 +5,7 @@ module EE
override :group_nav_link_paths
def group_nav_link_paths
if ::Gitlab::CurrentSettings.should_check_namespace_plan? && can?(current_user, :admin_group, @group)
super + %w[billings#index]
super + %w[billings#index saml_providers#show]
else
super
end
......
module EE
module SamlProvidersHelper
def group_saml_enabled?
group_saml_beta_enabled? && ::Gitlab::Auth::GroupSaml::Config.enabled?
end
def group_saml_beta_enabled?
::Gitlab::Utils.to_boolean(cookies['enable_group_saml'])
end
def show_saml_in_sidebar?(group)
group_saml_enabled? && !group.subgroup? && can?(current_user, :admin_group_saml, group)
end
def saml_link(text, group_id, redirect: nil, html_class: 'btn')
redirect ||= group_path(group_id)
url = omniauth_authorize_path(:user, :group_saml, group_id: group_id, redirect_to: redirect)
link_to(text, url, method: :post, class: html_class)
end
end
end
......@@ -10,6 +10,8 @@ module EE
included do
has_many :epics
has_one :saml_provider
state_machine :ldap_sync_status, namespace: :ldap_sync, initial: :ready do
state :ready
state :started
......
......@@ -50,6 +50,7 @@ class License < ActiveRecord::Base
multiple_group_issue_boards
merge_request_performance_metrics
object_storage
group_saml
service_desk
variable_environment_scope
reject_unsigned_commits
......
class SamlProvider < ActiveRecord::Base
belongs_to :group
validates :group, presence: true, top_level_group: true
validates :sso_url, presence: true, url: { protocols: %w(https) }
validates :certificate_fingerprint, presence: true, certificate_fingerprint: true
after_initialize :set_defaults, if: :new_record?
NAME_IDENTIFIER_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'.freeze
def assertion_consumer_service_url
"#{full_group_path}/-/saml/callback"
end
def issuer
full_group_path
end
def name_identifier_format
NAME_IDENTIFIER_FORMAT
end
def settings
{
assertion_consumer_service_url: assertion_consumer_service_url,
issuer: issuer,
idp_cert_fingerprint: certificate_fingerprint,
idp_sso_target_url: sso_url,
name_identifier_format: name_identifier_format
}
end
private
def full_group_path
"#{host}/groups/#{group.full_path}"
end
def set_defaults
self.enabled = true
end
def host
@host ||= Gitlab.config.gitlab.url
end
end
......@@ -49,6 +49,8 @@ module EE
rule { admin }.enable :read_epic
rule { has_projects }.enable :read_epic
rule { admin | owner }.enable :admin_group_saml
rule { admin | (can_owners_manage_ldap & owner) }.enable :admin_ldap_group_links
rule { ldap_synced }.prevent :admin_group_member
......
......@@ -4,6 +4,12 @@
%span
LDAP Synchronization
- if show_saml_in_sidebar?(@group)
= nav_link(path: 'saml_providers#show') do
= link_to group_saml_providers_path(@group), title: 'SAML SSO' do
%span
SAML SSO
- if @group.feature_available?(:group_webhooks) || show_promotions?
= nav_link(path: 'hooks#index') do
= link_to group_hooks_path(@group), title: 'Webhooks' do
......
%section.saml_provider
= form_for [group, saml_provider], url: group_saml_providers_path, html: { class: 'form-horizontal' } do |f|
.form-group.row
= form_errors(saml_provider)
= f.label :enabled, _("Enabled"), class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :enabled do
= f.check_box :enabled
= _("Enable SAML authentication for this group")
.form-group.row
= f.label :sso_url, class: 'control-label col-sm-2' do
= _("Identity provider single sign on URL")
.col-sm-10
= f.text_field :sso_url, placeholder: 'e.g. https://example.com/adfs/ls', class: 'form-control'
.help-block
= _('Members will be forwarded here when signing in to your group. Get this from your identity provider, where it can also be called "SSO Service Location", "SAML Token Issuance Endpoint", or "SAML 2.0/W-Federation URL".')
.form-group.row
= f.label :certificate_fingerprint, class: 'control-label col-sm-2' do
= _("Certificate fingerprint")
.col-sm-10
= f.text_field :certificate_fingerprint, placeholder: 'e.g. 0a:1b:2c:3d:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff', class: 'form-control'
.help-block
= _('SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called "Thumbprint".')
.form-actions
= f.submit _("Save changes"), class: 'btn btn-success'
%section.saml-settings.info-well.append-bottom-20
.well-segment
%p= _("To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:")
%ol
%li
= _('Review the process for configuring service providers in your identity provider — in this case, GitLab is the "service provider" or "relying party".')
= link_to help_page_path('user/group/saml_sso/index', anchor: 'providers'), target: '_blank' do
= _("Documentation for popular identity providers")
= icon('external-link')
%li
= _("During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below.")
%li
= (_("Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}") % { icon: icon('external-link'), docsLinkStart: "<a href='#{help_page_path('user/group/saml_sso/index', anchor: 'assertions')}' target='_blank'>", docsLinkEnd: '</a>' }).html_safe
%li
= (_("Fill in the fields below, turn on <strong>%{enable_label}</strong>, and press <strong>%{save_changes}</strong>") % { enable_label: _('Enable SAML authentication for this group'), save_changes: _('Save changes') }).html_safe
%li
= (_("Share the <strong>%{sso_label}</strong> with members so they can sign in to your group through your identity provider") % { sso_label: _('GitLab single sign on URL') }).html_safe
.well-segment.borderless
= render 'info_row', field: :assertion_consumer_service_url, label_text: _('Assertion consumer service URL')
.help-block= _('Also called "Relying party service URL" or "Reply URL"')
.well-segment.borderless
= render 'info_row', field: :issuer, label_text: 'Identifier'
.help-block= _('Also called "Issuer" or "Relying party trust identifier"')
- if @saml_provider.persisted?
.well-segment.borderless
%label= _("GitLab single sign on URL")
- user_login_url = sso_group_saml_providers_url(@group)
%div= link_to user_login_url, user_login_url
.help-block= _("Used by members to sign in to your group in GitLab")
- value = local_assigns[:value] || @saml_provider.send(field)
= label_tag field, label_text
.clipboard-input-group.input-group
= text_field_tag field, value, class: "js-select-on-focus form-control", readonly: true, aria: { label: label_text }
.input-group-btn
= clipboard_button(target: "##{field}", title: _("Copy URL to clipboard"), class: "btn-default btn-gray")
- page_title _('SAML Single Sign On Settings')
%section.row.prepend-top-default
.col-lg-3.append-bottom-default
%h4.page-title
= _("SAML Single Sign On")
%p
= _("Manage your group’s membership while adding another level of security with SAML.")
= link_to help_page_path('user/group/saml_sso/index'), target: '_blank' do
= _("Learn more")
= icon('external-link')
.col-lg-9
= render 'info'
= render 'form', group: @group, saml_provider: @saml_provider
---
title: Per group SAML settings added behind cookie beta restriction
merge_request: 4549
author:
type: added
class CreateSamlProviders < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :saml_providers do |t|
t.references :group, null: false, index: true
t.boolean :enabled, null: false
t.string :certificate_fingerprint, null: false
t.string :sso_url, null: false
end
add_foreign_key(:saml_providers, :namespaces, column: :group_id, on_delete: :cascade) # rubocop: disable Migration/AddConcurrentForeignKey
end
end
module Gitlab
module Auth
module GroupSaml
class Config < Gitlab::Auth::Saml::Config
def self.options
{}
end
def self.enabled?
Gitlab::Auth::OAuth::Provider.enabled?(:group_saml)
end
end
end
end
end
module OmniAuth
module Strategies
class GroupSaml < SAML
option :name, 'group_saml'
end
end
end
require 'spec_helper'
describe Groups::SamlProvidersController do
let(:saml_provider) { create(:saml_provider, group: group) }
let(:group) { create(:group, :private) }
let(:user) { create(:user) }
before do
request.cookies['enable_group_saml'] = 'true'
sign_in(user)
end
def stub_saml_config(enabled:)
providers = enabled ? %i(group_saml) : []
allow(Devise).to receive(:omniauth_providers).and_return(providers)
end
shared_examples '404 status' do
it 'returns 404 status' do
group.add_owner(user)
subject
expect(response).to have_gitlab_http_status(404)
end
end
shared_examples 'configuration is prevented' do
describe 'GET #show' do
subject { get :show, group_id: group }
it_behaves_like '404 status'
end
describe 'POST #create' do
subject { post :create, group_id: group, saml_provider: { enabled: 'false' } }
it_behaves_like '404 status'
end
describe 'PUT #update' do
subject { put :update, group_id: group, saml_provider: { enabled: 'false' } }
it_behaves_like '404 status'
end
end
context 'when per group saml is unlicensed' do
before do
stub_licensed_features(group_saml: false)
stub_saml_config(enabled: true)
end
it_behaves_like 'configuration is prevented'
end
context 'when per group saml is unconfigured' do
before do
stub_licensed_features(group_saml: true)
stub_saml_config(enabled: false)
end
it_behaves_like 'configuration is prevented'
end
context 'when per group saml feature is enabled' do
before do
stub_saml_config(enabled: true)
stub_licensed_features(group_saml: true)
end
describe 'GET #show' do
subject { get :show, group_id: group }
it 'shows configuration page' do
group.add_owner(user)
subject
expect(response).to render_template 'groups/saml_providers/show'
end
context 'not on a top level group', :nested_groups do
let(:group) { create(:group, :nested) }
it_behaves_like '404 status'
end
context 'with unauthorized user' do
it 'responds with 404' do
group.add_developer(user)
subject
expect(response).to have_http_status(404)
end
end
end
end
end
FactoryBot.define do
factory :saml_provider do
group
certificate_fingerprint '55:44:33:22:11:aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99'
sso_url 'https://saml.example.com/adfs/ls'
end
end
require 'spec_helper'
feature 'SAML provider settings' do
include CookieHelper
let(:user) { create(:user) }
let(:group) { create(:group) }
before do
set_beta_cookie
stub_config_setting(url: 'https://localhost')
stub_saml_config
group.add_owner(user)
end
def set_beta_cookie
set_cookie('enable_group_saml', 'true')
end
def submit
click_button('Save changes')
end
def stub_saml_config
stub_saml_authorize_path_helpers
stub_licensed_features(group_saml: true)
allow(Devise).to receive(:omniauth_providers).and_return(%i(group_saml))
end
describe 'settings' do
before do
sign_in(user)
end
it 'displays required information to user' do
visit group_saml_providers_path(group)
within '.saml-settings' do
expect(find_field('Assertion consumer service URL').value).to eq group.build_saml_provider.assertion_consumer_service_url
expect(find_field('Identifier').value).to eq "https://localhost/groups/#{group.full_path}"
end
end
it 'allows creation of new provider' do
visit group_saml_providers_path(group)
fill_in 'Identity provider single sign on URL', with: 'https://localhost:9999/adfs/ls'
fill_in 'Certificate fingerprint', with: 'aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99:0a:1b:2c:3d:00'
expect { submit }.to change(SamlProvider, :count).by(1)
end
it 'shows errors if fields missing' do
visit group_saml_providers_path(group)
submit
expect(find('#error_explanation')).to have_text("Certificate fingerprint can't be blank")
end
context 'with existing SAML provider' do
let!(:saml_provider) { create(:saml_provider, group: group) }
it 'allows provider to be disabled' do
visit group_saml_providers_path(group)
find('input#saml_provider_enabled').click
expect { submit }.to change { saml_provider.reload.enabled }.to false
end
it 'displays user login URL' do
visit group_saml_providers_path(group)
login_url = find('label', text: 'GitLab single sign on URL').find('~* a').text
expect(login_url).to end_with "/groups/#{group.full_path}/-/saml/sso"
end
end
end
end
require 'spec_helper'
describe SamlProvider do
describe "Associations" do
it { is_expected.to belong_to :group }
end
describe 'Validations' do
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:sso_url) }
it { is_expected.to validate_presence_of(:certificate_fingerprint) }
it 'expects sso_url to be an https URL' do
expect(subject).to allow_value('https://example.com').for(:sso_url)
expect(subject).not_to allow_value('http://example.com').for(:sso_url)
end
it 'expects certificate_fingerprint to be in an accepted format' do
expect(subject).to allow_value('000030EDC285E01D6B5EA33010A79ADD142F5004').for(:certificate_fingerprint)
expect(subject).to allow_value('00:00:30:ED:C2:85:E0:1D:6B:5E:A3:30:10:A7:9A:DD:14:2F:50:04').for(:certificate_fingerprint)
expect(subject).to allow_value('00-00-30-ED-C2-85-E0-1D-6B-5E-A3-30-10-A7-9A-DD-14-2F-50-04').for(:certificate_fingerprint)
expect(subject).to allow_value('00 00 30 ED C2 85 E0 1D 6B 5E A3 30 10 A7 9A DD 14 2F 50 04').for(:certificate_fingerprint)
sha512 = 'a12bc3d4567ef89ba97f4d1904815d56a497ffc2fe9d5b0f13439a5da73f4f1afde03b1c1b213128e173da24e75cadf224286696f5171540eedf59b684a5f8dd'
expect(subject).to allow_value(sha512).for(:certificate_fingerprint)
too_short = '00:00:30'
invalid_characters = '00@0030EDC285E01D6B5EA33010A79ADD142F5004'
expect(subject).not_to allow_value(too_short).for(:certificate_fingerprint)
expect(subject).not_to allow_value(invalid_characters).for(:certificate_fingerprint)
end
it 'requires group to be top-level' do
group = create(:group)
nested_group = create(:group, :nested)
expect(subject).to allow_value(group).for(:group)
expect(subject).not_to allow_value(nested_group).for(:group)
end
end
describe 'Default values' do
subject(:saml_provider) { described_class.new }
it 'defaults enabled to true' do
expect(subject).to be_enabled
end
end
describe '#settings' do
let(:group) { create(:group, path: 'foo-group')}
let(:settings) { subject.settings }
subject(:saml_provider) { create(:saml_provider, group: group) }
before do
stub_config_setting(url: 'https://localhost')
end
it 'generates callback URL' do
expect(settings[:assertion_consumer_service_url]).to eq "https://localhost/groups/foo-group/-/saml/callback"
end
it 'generates issuer from group' do
expect(settings[:issuer]).to eq "https://localhost/groups/foo-group"
end
it 'includes NameID format' do
expect(settings[:name_identifier_format]).to start_with 'urn:oasis:names:tc:'
end
it 'includes fingerprint' do
expect(settings[:idp_cert_fingerprint]).to eq saml_provider.certificate_fingerprint
end
it 'includes SSO URL' do
expect(settings[:idp_sso_target_url]).to eq saml_provider.sso_url
end
end
end
......@@ -36,6 +36,24 @@ describe GroupPolicy do
it { is_expected.to be_allowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
describe 'per group SAML' do
let(:current_user) { master }
it { is_expected.to be_disallowed(:admin_group_saml) }
context 'owner' do
let(:current_user) { owner }
it { is_expected.to be_allowed(:admin_group_saml) }
end
context 'admin' do
let(:current_user) { admin }
it { is_expected.to be_allowed(:admin_group_saml) }
end
end
context 'when LDAP sync is not enabled' do
context 'owner' do
let(:current_user) { owner }
......
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-30 17:57+0200\n"
"PO-Revision-Date: 2018-03-30 17:57+0200\n"
"POT-Creation-Date: 2018-04-03 12:44+0100\n"
"PO-Revision-Date: 2018-04-03 12:44+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -256,6 +256,12 @@ msgstr ""
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
msgid "Also called \"Relying party service URL\" or \"Reply URL\""
msgstr ""
msgid "Alternatively, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the <code>repo</code> scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
......@@ -376,6 +382,9 @@ msgstr ""
msgid "Artifacts"
msgstr ""
msgid "Assertion consumer service URL"
msgstr ""
msgid "Assign custom color like #FF0000"
msgstr ""
......@@ -466,6 +475,12 @@ msgstr ""
msgid "Average per day: %{average}"
msgstr ""
msgid "Background Color"
msgstr ""
msgid "Background jobs"
msgstr ""
msgid "Begin with the selected commit"
msgstr ""
......@@ -711,6 +726,9 @@ msgstr ""
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
msgid "Certificate fingerprint"
msgstr ""
msgid "Change Weight"
msgstr ""
......@@ -1276,6 +1294,9 @@ msgstr ""
msgid "Compare changes with the last commit"
msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
msgstr ""
......@@ -1297,6 +1318,9 @@ msgstr ""
msgid "Confidentiality"
msgstr ""
msgid "Configure Sidekiq job throttling."
msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
......@@ -1501,6 +1525,9 @@ msgstr ""
msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
msgstr ""
msgid "Customize colors"
msgstr ""
msgid "Cycle Analytics"
msgstr ""
......@@ -1584,6 +1611,9 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
msgid "Documentation for popular identity providers"
msgstr ""
msgid "Don't show again"
msgstr ""
......@@ -1623,6 +1653,9 @@ msgstr ""
msgid "Due date"
msgstr ""
msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below."
msgstr ""
msgid "Edit"
msgstr ""
......@@ -1644,6 +1677,9 @@ msgstr ""
msgid "Enable Auto DevOps"
msgstr ""
msgid "Enable SAML authentication for this group"
msgstr ""
msgid "Enable and configure InfluxDB metrics."
msgstr ""
......@@ -1653,6 +1689,15 @@ msgstr ""
msgid "Enable classification control using an external service"
msgstr ""
msgid "Enable reCAPTCHA or Akismet and set IP limits."
msgstr ""
msgid "Enable the Performance Bar for a given group."
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
......@@ -1839,6 +1884,9 @@ msgstr ""
msgid "Files (%{human_size})"
msgstr ""
msgid "Fill in the fields below, turn on <strong>%{enable_label}</strong>, and press <strong>%{save_changes}</strong>"
msgstr ""
msgid "Filter by commit message"
msgstr ""
......@@ -1857,6 +1905,12 @@ msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
msgid "Font Color"
msgstr ""
msgid "Footer message"
msgstr ""
msgid "Fork"
msgid_plural "Forks"
msgstr[0] ""
......@@ -2069,6 +2123,9 @@ msgstr ""
msgid "GitLab Runner section"
msgstr ""
msgid "GitLab single sign on URL"
msgstr ""
msgid "Gitaly Servers"
msgstr ""
......@@ -2171,6 +2228,9 @@ msgstr ""
msgid "Have your users email"
msgstr ""
msgid "Header message"
msgstr ""
msgid "Health Check"
msgstr ""
......@@ -2209,6 +2269,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr ""
msgid "Identity provider single sign on URL"
msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
......@@ -2477,6 +2540,9 @@ msgstr ""
msgid "Manage project labels"
msgstr ""
msgid "Manage your group’s membership while adding another level of security with SAML."
msgstr ""
msgid "Mar"
msgstr ""
......@@ -2498,6 +2564,9 @@ msgstr ""
msgid "Members"
msgstr ""
msgid "Members will be forwarded here when signing in to your group. Get this from your identity provider, where it can also be called \"SSO Service Location\", \"SAML Token Issuance Endpoint\", or \"SAML 2.0/W-Federation URL\"."
msgstr ""
msgid "Merge Requests"
msgstr ""
......@@ -2510,9 +2579,6 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
msgid "MergeRequest|Approved"
msgstr ""
msgid "Merged"
msgstr ""
......@@ -2902,6 +2968,9 @@ msgstr ""
msgid "Pagination|« First"
msgstr ""
msgid "Part of merge request changes"
msgstr ""
msgid "Password"
msgstr ""
......@@ -3121,6 +3190,9 @@ msgstr ""
msgid "Profiles|your account"
msgstr ""
msgid "Profiling - Performance bar"
msgstr ""
msgid "Programming languages used in this repository"
msgstr ""
......@@ -3447,9 +3519,15 @@ msgstr ""
msgid "Revert this merge request"
msgstr ""
msgid "Review the process for configuring service providers in your identity provider — in this case, GitLab is the \"service provider\" or \"relying party\"."
msgstr ""
msgid "Reviewing"
msgstr ""
msgid "Reviewing (merge request !%{mergeRequestId})"
msgstr ""
msgid "Roadmap"
msgstr ""
......@@ -3462,6 +3540,15 @@ msgstr ""
msgid "Running"
msgstr ""
msgid "SAML Single Sign On"
msgstr ""
msgid "SAML Single Sign On Settings"
msgstr ""
msgid "SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
msgstr ""
msgid "SSH Keys"
msgstr ""
......@@ -3573,6 +3660,9 @@ msgstr ""
msgid "Set up Koding"
msgstr ""
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
msgid "SetPasswordToCloneLink|set a password"
msgstr ""
......@@ -3582,6 +3672,9 @@ msgstr ""
msgid "Setup a specific Runner automatically"
msgstr ""
msgid "Share the <strong>%{sso_label}</strong> with members so they can sign in to your group through your identity provider"
msgstr ""
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr ""
......@@ -3773,6 +3866,9 @@ msgstr ""
msgid "Spam Logs"
msgstr ""
msgid "Spam and Anti-bot Protection"
msgstr ""
msgid "Specify the following URL during the Runner setup:"
msgstr ""
......@@ -3797,6 +3893,9 @@ msgstr ""
msgid "Started"
msgstr ""
msgid "State your message to activate"
msgstr ""
msgid "Status"
msgstr ""
......@@ -3818,6 +3917,9 @@ msgstr ""
msgid "System Hooks"
msgstr ""
msgid "System header and footer:"
msgstr ""
msgid "Tag (%{tag_count})"
msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
......@@ -4286,6 +4388,9 @@ msgstr ""
msgid "To only use CI/CD features for an external repository, choose <strong>CI/CD for external repo</strong>."
msgstr ""
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr ""
msgid "To validate your GitLab CI configurations, go to 'CI/CD → Pipelines' inside your project, and click on the 'CI Lint' button."
msgstr ""
......@@ -4388,6 +4493,9 @@ msgstr ""
msgid "Use your global notification setting"
msgstr ""
msgid "Used by members to sign in to your group in GitLab"
msgstr ""
msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
msgstr ""
......@@ -4884,6 +4992,9 @@ msgstr ""
msgid "mrWidget|Approve"
msgstr ""
msgid "mrWidget|Approved"
msgstr ""
msgid "mrWidget|Approved by"
msgstr ""
......@@ -5016,6 +5127,9 @@ msgstr ""
msgid "mrWidget|This project is archived, write access has been disabled"
msgstr ""
msgid "mrWidget|Web IDE"
msgstr ""
msgid "mrWidget|You can merge this merge request manually using the"
msgstr ""
......
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