Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-29 00:10:57 +00:00
parent 9037472904
commit e064cd3f07
45 changed files with 762 additions and 224 deletions

View File

@ -283,7 +283,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/timezone.md @axil
/doc/administration/troubleshooting/ @axil
/doc/administration/troubleshooting/elasticsearch.md @sselhorn
/doc/administration/troubleshooting/group_saml_scim.md @eread
/doc/administration/troubleshooting/postgresql.md @aqualls
/doc/administration/uploads.md @axil
/doc/administration/user_settings.md @eread
@ -710,6 +709,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/group/saml_sso/group_managed_accounts.md @eread
/doc/user/group/saml_sso/index.md @eread
/doc/user/group/saml_sso/scim_setup.md @eread
/doc/user/group/saml_sso/example_saml_config.md @eread
/doc/user/group/settings/group_access_tokens.md @eread
/doc/user/group/settings/import_export.md @eread
/doc/user/group/subgroups/index.md @fneill

View File

@ -0,0 +1,71 @@
<script>
import { GlTable, GlFormInput } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
GlTable,
GlFormInput,
},
props: {
fields: {
type: Array,
required: true,
},
items: {
type: Array,
required: true,
},
hasFilter: {
type: Boolean,
required: false,
default: false,
},
caption: {
type: String,
required: false,
default: __('Generated with JSON data'),
},
},
data() {
return {
filterInput: '',
};
},
computed: {
cleanedFields() {
return this.fields.map((field) => {
if (typeof field === 'string') {
return field;
}
return {
key: field.key,
label: field.label,
sortable: field.sortable || false,
};
});
},
},
};
</script>
<template>
<div class="gl-display-inline-block">
<gl-form-input
v-if="hasFilter"
v-model="filterInput"
:placeholder="__('Type to search')"
class="gl-mb-2!"
/>
<gl-table
:fields="cleanedFields"
:items="items"
:filter="filterInput"
show-empty
class="gl-mt-0!"
>
<template v-if="caption" #table-caption>
<small>{{ caption }}</small>
</template>
</gl-table>
</div>
</template>

View File

@ -5,6 +5,7 @@ import { renderKroki } from './render_kroki';
import renderMath from './render_math';
import renderSandboxedMermaid from './render_sandboxed_mermaid';
import renderMetrics from './render_metrics';
import { renderJSONTable } from './render_json_table';
// Render GitLab flavoured Markdown
//
@ -15,6 +16,9 @@ $.fn.renderGFM = function renderGFM() {
renderKroki(this.find('.js-render-kroki[hidden]').get());
renderMath(this.find('.js-render-math'));
renderSandboxedMermaid(this.find('.js-render-mermaid'));
renderJSONTable(
Array.from(this.find('[lang="json"][data-lang-params="table"]').get()).map((e) => e.parentNode),
);
highlightCurrentUser(this.find('.gfm-project_member').get());

View File

@ -0,0 +1,70 @@
import { memoize } from 'lodash';
import Vue from 'vue';
import { __ } from '~/locale';
import { createAlert } from '~/flash';
// Async import component since we might not need it...
const JSONTable = memoize(() =>
import(/* webpackChunkName: 'gfm_json_table' */ '../components/json_table.vue'),
);
const mountParseError = (element) => {
// Let the error container be a sibling to the element.
// Otherwise, dismissing the alert causes the copy button to be misplaced.
const container = document.createElement('div');
element.insertAdjacentElement('beforebegin', container);
// We need to create a child element with a known selector for `createAlert`
const el = document.createElement('div');
el.classList.add('js-json-table-error');
container.insertAdjacentElement('afterbegin', el);
return createAlert({
message: __('Unable to parse JSON'),
variant: 'warning',
parent: container,
containerSelector: '.js-json-table-error',
});
};
const mountJSONTableVueComponent = (userData, element) => {
const { fields = [], items = [], filter, caption } = userData;
const container = document.createElement('div');
element.innerHTML = '';
element.appendChild(container);
return new Vue({
el: container,
render(h) {
return h(JSONTable, {
props: {
fields,
items,
hasFilter: filter,
caption,
},
});
},
});
};
const renderTable = (element) => {
// Avoid rendering multiple times
if (!element || element.classList.contains('js-json-table')) {
return;
}
element.classList.add('js-json-table');
try {
mountJSONTableVueComponent(JSON.parse(element.textContent), element);
} catch (e) {
mountParseError(element);
}
};
export const renderJSONTable = (elements) => {
elements.forEach(renderTable);
};

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class AddUniqueProjectDownloadLimitAllowlistToNamespaceSettings < Gitlab::Database::Migration[2.0]
def change
add_column :namespace_settings, :unique_project_download_limit_allowlist,
:text,
array: true,
default: [],
null: false
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddNamespaceSettingsUniqueProjectDownloadLimitAllowlistSizeConstraint < Gitlab::Database::Migration[2.0]
CONSTRAINT_NAME = 'namespace_settings_unique_project_download_limit_allowlist_size'
disable_ddl_transaction!
def up
add_check_constraint :namespace_settings,
'CARDINALITY(unique_project_download_limit_allowlist) <= 100',
CONSTRAINT_NAME
end
def down
remove_check_constraint :namespace_settings, CONSTRAINT_NAME
end
end

View File

@ -0,0 +1 @@
42b601de66244f527b8c40182b7c9c8ba3a6ea9863582be3c499ffe2491c8d4f

View File

@ -0,0 +1 @@
326acd1c7e562056d29d5727869a0d0e5a5e9c387b0f54238c79c89f3947808b

View File

@ -17613,7 +17613,9 @@ CREATE TABLE namespace_settings (
unique_project_download_limit_interval_in_seconds integer DEFAULT 0 NOT NULL,
project_import_level smallint DEFAULT 50 NOT NULL,
include_for_free_user_cap_preview boolean DEFAULT false NOT NULL,
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255))
unique_project_download_limit_allowlist text[] DEFAULT '{}'::text[] NOT NULL,
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)),
CONSTRAINT namespace_settings_unique_project_download_limit_allowlist_size CHECK ((cardinality(unique_project_download_limit_allowlist) <= 100))
);
CREATE TABLE namespace_statistics (

View File

@ -241,4 +241,4 @@ who are aware of the risks.
- [Testing with OpenSSL](https://www.feistyduck.com/library/openssl-cookbook/online/testing-with-openssl/index.html)
- [`strace` zine](https://wizardzines.com/zines/strace/)
- GitLab.com-specific resources:
- [Group SAML/SCIM setup](troubleshooting/group_saml_scim.md)
- [Example group SAML and SCIM configurations](../user/group/saml_sso/example_saml_config.md)

View File

@ -1,207 +1,11 @@
---
stage: Manage
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
type: reference
redirect_to: '../../user/group/saml_sso/example_saml_config.md'
remove_date: '2022-10-29'
---
# Troubleshooting Group SAML and SCIM **(PREMIUM SAAS)**
This document was moved to [another location](../../user/group/saml_sso/example_saml_config.md).
These are notes and screenshots regarding Group SAML and SCIM that the GitLab Support Team sometimes uses while troubleshooting, but which do not fit into the official documentation. GitLab is making this public, so that anyone can make use of the Support team's collected knowledge.
Please refer to the GitLab [Group SAML](../../user/group/saml_sso/index.md) docs for information on the feature and how to set it up.
When troubleshooting a SAML configuration, GitLab team members will frequently start with the [SAML troubleshooting section](../../user/group/saml_sso/index.md#troubleshooting).
They may then set up a test configuration of the desired identity provider. We include example screenshots in this section.
## SAML and SCIM screenshots
This section includes relevant screenshots of the following example configurations of [Group SAML](../../user/group/saml_sso/index.md) and [Group SCIM](../../user/group/saml_sso/scim_setup.md):
- [Azure Active Directory](#azure-active-directory)
- [Google Workspace](#google-workspace)
- [Okta](#okta)
- [OneLogin](#onelogin)
WARNING:
These screenshots are updated only as needed by GitLab Support. They are **not** official documentation.
If you are currently having an issue with GitLab, you may want to check your [support options](https://about.gitlab.com/support/).
## Azure Active Directory
Basic SAML app configuration:
![Azure AD basic SAML](img/AzureAD-basic_SAML.png)
User claims and attributes:
![Azure AD user claims](img/AzureAD-claims.png)
SCIM mapping:
![Azure AD SCIM Provisioning](img/AzureAD-scim_provisioning.png)
![Azure AD SCIM Attribute Mapping](img/AzureAD-scim_attribute_mapping.png)
Group Sync:
![Azure Group Claims](img/azure_configure_group_claim.png)
## Google Workspace
Basic SAML app configuration:
![Google Workspace basic SAML](img/GoogleWorkspace-basic-SAML_v14_10.png)
User claims and attributes:
![Google Workspace user claims](img/GoogleWorkspace-claims_v14_10.png)
IdP links and certificate:
NOTE:
Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint required by GitLab for configuring SAML, download the certificate and calculate the SHA1 certificate
fingerprint.
![Google Workspace Links and Certificate](img/GoogleWorkspace-linkscert_v14_10.png)
## Okta
Basic SAML app configuration:
![Okta basic SAML](img/Okta-SAMLsetup.png)
User claims and attributes:
![Okta Attributes](img/Okta-attributes.png)
Advanced SAML app settings (defaults):
![Okta Advanced Settings](img/Okta-advancedsettings.png)
IdP Links and Certificate:
![Okta Links and Certificate](img/Okta-linkscert.png)
Sign on settings:
![Okta SAML settings](img/okta_saml_settings.png)
Self-managed instance example:
![Okta admin panel view](img/okta_admin_panel_v13_9.png)
Setting the username for the newly provisioned users when assigning them the SCIM app:
![Assigning SCIM app to users on Okta](img/okta_setting_username.png)
## OneLogin
Application details:
![OneLogin application details](img/OneLogin-app_details.png)
Parameters:
![OneLogin application details](img/OneLogin-parameters.png)
Adding a user:
![OneLogin user add](img/OneLogin-userAdd.png)
SSO settings:
![OneLogin SSO settings](img/OneLogin-SSOsettings.png)
## SAML response example
When a user signs in using SAML, GitLab receives a SAML response. The SAML response can be found in `production.log` logs as a base64-encoded message. Locate the response by
searching for `SAMLResponse`. The decoded SAML response is in XML format. For example:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://gitlabexample/-/saml/callback" ID="id4898983630840142426821432" InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id4898983630840142426821432">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id489" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id48989836309833801859473359">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==<</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">useremail@domain.com</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" NotOnOrAfter="2022-05-30T21:35:35.696Z" Recipient="https://gitlab.example.com/-/saml/callback"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2022-05-30T21:25:35.696Z" NotOnOrAfter="2022-05-30T21:35:35.696Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://gitlab.example.com/</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2022-05-30T21:30:35.696Z" SessionIndex="_c65e4c88-9425-4472-b42c-37f4186ac0ee">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">useremail@domain.com</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="firtname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">John</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="lastname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Doe</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="Groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Super-awesome-group</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
```
<!-- This redirect file can be deleted after <2022-10-29>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View File

@ -16,7 +16,7 @@ installation.
- [Elasticsearch](elasticsearch.md)
- [Sidekiq](sidekiq.md)
- [GitLab Rails console cheat sheet](gitlab_rails_cheat_sheet.md)
- [Group SAML and SCIM troubleshooting](group_saml_scim.md) **(PREMIUM SAAS)**
- [Example group SAML and SCIM configurations](../../user/group/saml_sso/example_saml_config.md)
- [Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html)
- [Linux cheat sheet](linux_cheat_sheet.md)
- [Parsing GitLab logs with `jq`](../logs/log_parsing.md)

View File

@ -901,6 +901,13 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
## Update group
> `unique_project_download_limit`, `unique_project_download_limit_interval_in_seconds`, and `unique_project_download_limit_allowlist` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92970) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `limit_unique_project_downloads_per_namespace_user`. Disabled by default.
FLAG:
On self-managed GitLab, by default `unique_project_download_limit`, `unique_project_download_limit_interval_in_seconds`, and `unique_project_download_limit_allowlist` are not available.
To make them available, ask an administrator to [enable the feature flag](../administration/feature_flags.md)
named `limit_unique_project_downloads_per_namespace_user`.
Updates the project group. Only available to group owners and administrators.
```plaintext
@ -933,6 +940,9 @@ PUT /groups/:id
| `membership_lock` **(PREMIUM)** | boolean | no | Users cannot be added to projects in this group. |
| `prevent_forking_outside_group` **(PREMIUM)** | boolean | no | When enabled, users can **not** fork projects from this group to external namespaces. |
| `shared_runners_minutes_limit` **(PREMIUM)** | integer | no | Can be set by administrators only. Maximum number of monthly CI/CD minutes for this group. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. |
| `unique_project_download_limit` **(ULTIMATE)** | integer | no | Maximum number of unique projects a user can download in the specified time period before they are banned. Available only on top-level groups. Default: 0, Maximum: 10,000. |
| `unique_project_download_limit_interval_in_seconds` **(ULTIMATE)** | integer | no | Time period during which a user can download a maximum amount of projects before they are banned. Available only on top-level groups. Default: 0, Maximum: 864,000 seconds (10 days). |
| `unique_project_download_limit_allowlist` **(ULTIMATE)** | array of strings | no | List of usernames excluded from the unique project download limit. Available only on top-level groups. Default: `[]`, Maximum: 100 usernames. |
NOTE:
The `projects` and `shared_projects` attributes in the response are deprecated and [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797).

View File

@ -15,6 +15,9 @@ to create a project. The project includes cluster applications that integrate wi
and extend GitLab functionality. You can use the pattern shown in the project to extend
your custom cluster applications.
NOTE:
The project template works on GitLab.com without modifications. If you're on a self-managed instance, you must modify the `.gitlab-ci.yml` file.
## Use one project for the agent and your manifests
If you **have not yet** used the agent to connect your cluster with GitLab:
@ -47,10 +50,7 @@ To create a project from the cluster management project template:
1. From the list of templates, next to **GitLab Cluster Management**, select **Use template**.
1. Enter the project details.
1. Select **Create project**.
If you use self-managed GitLab, your instance might not include the latest version of the template.
In that case, select **Import project**, **Repository by URL** and for the **Git repository URL**, enter
`https://gitlab.com/gitlab-org/project-templates/cluster-management.git`.
1. In the new project, [configure the files](#configure-the-project) as needed.
## Configure the project
@ -73,6 +73,11 @@ The base image used in the pipeline is built by the
[cluster-applications](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications) project.
This image contains a set of Bash utility scripts to support [Helm v3 releases](https://helm.sh/docs/intro/using_helm/#three-big-concepts).
If you are on a self-managed instance of GitLab, you must modify the `.gitlab-ci.yml` file.
Specifically, the section that starts with the comment `Automatic package upgrades` will not
work on a self-managed instance, because the `include` refers to a GitLab.com project.
If you remove everything below this comment, the pipeline will succeed.
### The main `helmfile.yml` file
The template contains a [Helmfile](https://github.com/roboll/helmfile) you can use to manage

View File

@ -0,0 +1,207 @@
---
stage: Manage
group: Authentication and Authorization
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
type: reference
---
# Example group SAML and SCIM configurations **(PREMIUM SAAS)**
These are notes and screenshots regarding Group SAML and SCIM that the GitLab Support Team sometimes uses while troubleshooting, but which do not fit into the official documentation. GitLab is making this public, so that anyone can make use of the Support team's collected knowledge.
Please refer to the GitLab [Group SAML](index.md) docs for information on the feature and how to set it up.
When troubleshooting a SAML configuration, GitLab team members will frequently start with the [SAML troubleshooting section](index.md#troubleshooting).
They may then set up a test configuration of the desired identity provider. We include example screenshots in this section.
## SAML and SCIM screenshots
This section includes relevant screenshots of the following example configurations of [Group SAML](index.md) and [Group SCIM](scim_setup.md):
- [Azure Active Directory](#azure-active-directory)
- [Google Workspace](#google-workspace)
- [Okta](#okta)
- [OneLogin](#onelogin)
WARNING:
These screenshots are updated only as needed by GitLab Support. They are **not** official documentation.
If you are currently having an issue with GitLab, you may want to check your [support options](https://about.gitlab.com/support/).
## Azure Active Directory
Basic SAML app configuration:
![Azure AD basic SAML](img/AzureAD-basic_SAML.png)
User claims and attributes:
![Azure AD user claims](img/AzureAD-claims.png)
SCIM mapping:
![Azure AD SCIM Provisioning](img/AzureAD-scim_provisioning.png)
![Azure AD SCIM Attribute Mapping](img/AzureAD-scim_attribute_mapping.png)
Group Sync:
![Azure Group Claims](img/azure_configure_group_claim.png)
## Google Workspace
Basic SAML app configuration:
![Google Workspace basic SAML](img/GoogleWorkspace-basic-SAML_v14_10.png)
User claims and attributes:
![Google Workspace user claims](img/GoogleWorkspace-claims_v14_10.png)
IdP links and certificate:
NOTE:
Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint required by GitLab for configuring SAML, download the certificate and calculate the SHA1 certificate
fingerprint.
![Google Workspace Links and Certificate](img/GoogleWorkspace-linkscert_v14_10.png)
## Okta
Basic SAML app configuration:
![Okta basic SAML](img/Okta-SAMLsetup.png)
User claims and attributes:
![Okta Attributes](img/Okta-attributes.png)
Advanced SAML app settings (defaults):
![Okta Advanced Settings](img/Okta-advancedsettings.png)
IdP Links and Certificate:
![Okta Links and Certificate](img/Okta-linkscert.png)
Sign on settings:
![Okta SAML settings](img/okta_saml_settings.png)
Self-managed instance example:
![Okta admin panel view](img/okta_admin_panel_v13_9.png)
Setting the username for the newly provisioned users when assigning them the SCIM app:
![Assigning SCIM app to users on Okta](img/okta_setting_username.png)
## OneLogin
Application details:
![OneLogin application details](img/OneLogin-app_details.png)
Parameters:
![OneLogin application details](img/OneLogin-parameters.png)
Adding a user:
![OneLogin user add](img/OneLogin-userAdd.png)
SSO settings:
![OneLogin SSO settings](img/OneLogin-SSOsettings.png)
## SAML response example
When a user signs in using SAML, GitLab receives a SAML response. The SAML response can be found in `production.log` logs as a base64-encoded message. Locate the response by
searching for `SAMLResponse`. The decoded SAML response is in XML format. For example:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://gitlabexample/-/saml/callback" ID="id4898983630840142426821432" InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id4898983630840142426821432">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id489" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#id48989836309833801859473359">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==<</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">useremail@domain.com</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" NotOnOrAfter="2022-05-30T21:35:35.696Z" Recipient="https://gitlab.example.com/-/saml/callback"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2022-05-30T21:25:35.696Z" NotOnOrAfter="2022-05-30T21:35:35.696Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://gitlab.example.com/</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2022-05-30T21:30:35.696Z" SessionIndex="_c65e4c88-9425-4472-b42c-37f4186ac0ee">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">useremail@domain.com</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="firtname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">John</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="lastname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Doe</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="Groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Super-awesome-group</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</saml2p:Response>
```

View File

@ -28,7 +28,7 @@ To configure SAML Group Sync:
1. Ensure your SAML identity provider sends an attribute statement with the same name as the value of the `groups_attribute` setting.
- For GitLab.com:
1. See [SAML SSO for GitLab.com groups](index.md).
1. Ensure your SAML identity provider sends an attribute statement named `Groups` or `groups`.
1. Ensure your SAML identity provider sends an attribute statement named `Groups` or `groups`.
NOTE:
The value for `Groups` or `groups` in the SAML response can be either the group name or the group ID.
@ -44,8 +44,8 @@ The value for `Groups` or `groups` in the SAML response can be either the group
Other attribute names such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups`
are not accepted as a source of groups.
See the [SAML troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md)
for examples on configuring the required attribute name in the SAML identity provider's settings.
See [examples](../../../user/group/saml_sso/example_saml_config.md)
for configuring the required attribute name in the SAML identity provider's settings.
## Configure SAML Group Links

View File

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -174,7 +174,7 @@ The recommended attributes and claims settings are:
If using [Group Sync](#group-sync), customize the name of the group claim to match the required attribute.
See the [troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md#azure-active-directory) for an example configuration.
See our [example configuration page](example_saml_config.md#azure-active-directory).
### Google Workspace setup notes
@ -206,7 +206,7 @@ For NameID, the following settings are recommended:
When selecting **Verify SAML Configuration** on the GitLab SAML SSO page, disregard the warning recommending setting the NameID format to "persistent".
See the [troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md#google-workspace) for an example configuration.
See our [example configuration page](example_saml_config.md#google-workspace).
### Okta setup notes
@ -445,7 +445,7 @@ To generate a SAML Response:
### Verifying configuration
For convenience, we've included some [example resources](../../../administration/troubleshooting/group_saml_scim.md) used by our Support Team. While they may help you verify the SAML app configuration, they are not guaranteed to reflect the current state of third-party products.
For convenience, we've included some [example resources](../../../user/group/saml_sso/example_saml_config.md) used by our Support Team. While they may help you verify the SAML app configuration, they are not guaranteed to reflect the current state of third-party products.
### Verifying NameID

View File

@ -82,7 +82,7 @@ For a list of required attributes, refer to the [SCIM API documentation](../../.
| `userPrincipalName` | `emails[type eq "work"].value` | |
| `mailNickname` | `userName` | |
For guidance, you can view [an example configuration in the troubleshooting reference](../../../administration/troubleshooting/group_saml_scim.md#azure-active-directory).
For guidance, you can view [an example configuration](example_saml_config.md#azure-active-directory).
1. Below the mapping list select **Show advanced options > Edit attribute list for AppName**.
1. Ensure the `id` is the primary and required field, and `externalId` is also required.

View File

@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Use deploy keys to access repositories that are hosted in GitLab. In most cases, you use deploy keys
to access a repository from an external host, like a build server or Continuous Integration (CI) server.
Depending on your needs, you might want to use a [deploy token](../deploy_tokens/) to access a repository instead.
Depending on your needs, you might want to use a [deploy token](../deploy_tokens/index.md) to access a repository instead.
| Attribute | Deploy key | Deploy token |
|------------------|-------------|--------------|

View File

@ -7,7 +7,8 @@ module API
SharedGroupWithGroup.represent(group.shared_with_group_links_visible_to_user(options[:current_user]))
end
expose :runners_token, if: ->(_, options) { options[:user_can_admin_group] }
expose :prevent_sharing_groups_outside_hierarchy, if: ->(group) { group.root? }
expose :prevent_sharing_groups_outside_hierarchy,
if: ->(group) { group.root? && group.namespace_settings.present? }
expose :projects,
if: ->(_, options) { options[:with_projects] },

View File

@ -16816,6 +16816,9 @@ msgstr ""
msgid "Generate site and private keys at"
msgstr ""
msgid "Generated with JSON data"
msgstr ""
msgid "Generic"
msgstr ""
@ -41281,6 +41284,9 @@ msgstr ""
msgid "Type"
msgstr ""
msgid "Type to search"
msgstr ""
msgid "U2F Devices (%{length})"
msgstr ""
@ -41401,6 +41407,9 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
msgid "Unable to parse JSON"
msgstr ""
msgid "Unable to parse the vulnerability report's options."
msgstr ""

View File

@ -42,10 +42,6 @@ module QA
expect(project.asset_exists?(expected_badge_image_url)).to be_truthy
end
end
after do
project&.remove_via_api!
end
end
end
end

View File

@ -0,0 +1,40 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Rendering json:table code block in markdown', :js do
let_it_be(:project) { create(:project, :public) }
it 'creates table correctly' do
description = <<~JSONTABLE
Hello world!
```json:table
{
"fields" : [
{"key": "a", "label": "AA"},
{"key": "b", "label": "BB"}
],
"items" : [
{"a": "11", "b": "22"},
{"a": "211", "b": "222"}
]
}
```
JSONTABLE
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
wait_for_requests
within ".js-json-table table" do
headers = all("thead th").collect { |column| column.text.strip }
data = all("tbody td").collect { |column| column.text.strip }
expect(headers).to eql(%w[AA BB])
expect(data).to eql(%w[11 22 211 222])
end
end
end

View File

@ -22,6 +22,14 @@ const createStubbedMethods = (methods = {}) => {
);
};
export const RENDER_ALL_SLOTS_TEMPLATE = `<div>
<template v-for="(_, name) in $scopedSlots">
<div :data-testid="'slot-' + name">
<slot :name="name" />
</div>
</template>
</div>`;
export function stubComponent(Component, options = {}) {
return {
props: Component.props,

View File

@ -0,0 +1,162 @@
import { GlTable, GlFormInput } from '@gitlab/ui';
import { nextTick } from 'vue';
import { merge } from 'lodash';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component';
import JSONTable from '~/behaviors/components/json_table.vue';
const TEST_FIELDS = [
'A',
{
key: 'B',
label: 'Second',
sortable: true,
other: 'foo',
},
{
key: 'C',
label: 'Third',
},
'D',
];
const TEST_ITEMS = [
{ A: 1, B: 'lorem', C: 2, D: null, E: 'dne' },
{ A: 2, B: 'ipsum', C: 2, D: null, E: 'dne' },
{ A: 3, B: 'dolar', C: 2, D: null, E: 'dne' },
];
describe('behaviors/components/json_table', () => {
let wrapper;
const buildWrapper = ({
fields = [],
items = [],
filter = undefined,
caption = undefined,
} = {}) => {
wrapper = shallowMountExtended(JSONTable, {
propsData: {
fields,
items,
hasFilter: filter,
caption,
},
stubs: {
GlTable: merge(stubComponent(GlTable), {
props: {
fields: {
type: Array,
required: true,
},
items: {
type: Array,
required: true,
},
},
template: RENDER_ALL_SLOTS_TEMPLATE,
}),
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findTable = () => wrapper.findComponent(GlTable);
const findTableCaption = () => wrapper.findByTestId('slot-table-caption');
const findFilterInput = () => wrapper.findComponent(GlFormInput);
describe('default', () => {
beforeEach(() => {
buildWrapper();
});
it('renders gltable', () => {
expect(findTable().props()).toEqual({
fields: [],
items: [],
});
expect(findTable().attributes()).toMatchObject({
filter: '',
'show-empty': '',
});
});
it('does not render filter input', () => {
expect(findFilterInput().exists()).toBe(false);
});
it('renders caption', () => {
expect(findTableCaption().text()).toBe('Generated with JSON data');
});
});
describe('with filter', () => {
beforeEach(() => {
buildWrapper({
filter: true,
});
});
it('renders filter input', () => {
expect(findFilterInput().attributes()).toMatchObject({
value: '',
placeholder: 'Type to search',
});
});
it('when input is changed, updates table filter', async () => {
findFilterInput().vm.$emit('input', 'New value!');
await nextTick();
expect(findTable().attributes('filter')).toBe('New value!');
});
});
describe('with fields', () => {
beforeEach(() => {
buildWrapper({
fields: TEST_FIELDS,
items: TEST_ITEMS,
});
});
it('passes cleaned fields and items to table', () => {
expect(findTable().props()).toEqual({
fields: [
'A',
{
key: 'B',
label: 'Second',
sortable: true,
},
{
key: 'C',
label: 'Third',
sortable: false,
},
'D',
],
items: TEST_ITEMS,
});
});
});
describe('with full mount', () => {
beforeEach(() => {
wrapper = mountExtended(JSONTable, {
propsData: {
fields: [],
items: [],
},
});
});
// We want to make sure all the props are passed down nicely in integration
it('renders table without errors', () => {
expect(findTable().exists()).toBe(true);
});
});
});

View File

@ -0,0 +1,119 @@
import { nextTick } from 'vue';
import { renderJSONTable } from '~/behaviors/markdown/render_json_table';
describe('behaviors/markdown/render_json_table', () => {
let element;
const TEST_DATA = {
fields: [
{ label: 'Field 1', key: 'a' },
{ label: 'F 2', key: 'b' },
{ label: 'F 3', key: 'c' },
],
items: [
{
a: '1',
b: 'b',
c: 'c',
},
{
a: '2',
b: 'd',
c: 'e',
},
],
};
const TEST_LABELS = TEST_DATA.fields.map((x) => x.label);
const tableAsData = (table) => ({
head: Array.from(table.querySelectorAll('thead th')).map((td) => td.textContent),
body: Array.from(table.querySelectorAll('tbody > tr')).map((tr) =>
Array.from(tr.querySelectorAll('td')).map((x) => x.textContent),
),
});
const createTestSubject = async (json) => {
if (element) {
throw new Error('element has already been initialized');
}
const parent = document.createElement('div');
const pre = document.createElement('pre');
pre.textContent = json;
parent.appendChild(pre);
document.body.appendChild(parent);
renderJSONTable([parent]);
element = parent;
jest.runAllTimers();
await nextTick();
};
const findPres = () => document.querySelectorAll('pre');
const findTables = () => document.querySelectorAll('table');
const findAlerts = () => document.querySelectorAll('.gl-alert');
const findInputs = () => document.querySelectorAll('.gl-form-input');
afterEach(() => {
document.body.innerHTML = '';
element = null;
});
describe('default', () => {
beforeEach(async () => {
await createTestSubject(JSON.stringify(TEST_DATA, null, 2));
});
it('removes pre', () => {
expect(findPres()).toHaveLength(0);
});
it('replaces pre with table', () => {
const tables = findTables();
expect(tables).toHaveLength(1);
expect(tableAsData(tables[0])).toEqual({
head: TEST_LABELS,
body: [
['1', 'b', 'c'],
['2', 'd', 'e'],
],
});
});
it('does not show filter', () => {
expect(findInputs()).toHaveLength(0);
});
});
describe('with invalid json', () => {
beforeEach(() => {
createTestSubject('funky but not json');
});
it('preserves pre', () => {
expect(findPres()).toHaveLength(1);
});
it('shows alert', () => {
const alerts = findAlerts();
expect(alerts).toHaveLength(1);
expect(alerts[0].textContent).toMatchInterpolatedText('Unable to parse JSON');
});
});
describe('with filter set', () => {
beforeEach(() => {
createTestSubject(JSON.stringify({ ...TEST_DATA, filter: true }));
});
it('shows filter', () => {
expect(findInputs()).toHaveLength(1);
});
});
});