Commit 1ce6af4a authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 24256212
# frozen_string_literal: true # frozen_string_literal: true
class Import::BaseController < ApplicationController class Import::BaseController < ApplicationController
before_action :import_rate_limit, only: [:create]
private private
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -37,4 +39,18 @@ class Import::BaseController < ApplicationController ...@@ -37,4 +39,18 @@ class Import::BaseController < ApplicationController
def project_save_error(project) def project_save_error(project)
project.errors.full_messages.join(', ') project.errors.full_messages.join(', ')
end end
def import_rate_limit
key = "project_import".to_sym
if rate_limiter.throttled?(key, scope: [current_user, key])
rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
redirect_back_or_default(options: { alert: _('This endpoint has been requested too many times. Try again later.') })
end
end
def rate_limiter
::Gitlab::ApplicationRateLimiter
end
end end
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Clusters module Clusters
module Applications module Applications
class Runner < ApplicationRecord class Runner < ApplicationRecord
VERSION = '0.12.0' VERSION = '0.13.0'
self.table_name = 'clusters_applications_runners' self.table_name = 'clusters_applications_runners'
......
...@@ -76,6 +76,7 @@ class Event < ApplicationRecord ...@@ -76,6 +76,7 @@ class Event < ApplicationRecord
# Scopes # Scopes
scope :recent, -> { reorder(id: :desc) } scope :recent, -> { reorder(id: :desc) }
scope :code_push, -> { where(action: PUSHED) } scope :code_push, -> { where(action: PUSHED) }
scope :merged, -> { where(action: MERGED) }
scope :with_associations, -> do scope :with_associations, -> do
# We're using preload for "push_event_payload" as otherwise the association # We're using preload for "push_event_payload" as otherwise the association
......
---
title: Expose current and last IPs to /users endpoint
merge_request: 19781
author:
type: added
---
title: Remove the OpenSSL include within SMIME email signing
merge_request: 23642
author: Roger Meier
type: fixed
---
title: Add rate limiter to Project Imports
merge_request: 22644
author:
type: other
---
title: Update GitLab Runner Helm Chart to 0.13.0/12.7.0
merge_request: 23308
author:
type: other
...@@ -35,6 +35,7 @@ unless Gitlab::Runtime.sidekiq? ...@@ -35,6 +35,7 @@ unless Gitlab::Runtime.sidekiq?
::Gitlab::InstrumentationHelper.add_instrumentation_data(payload) ::Gitlab::InstrumentationHelper.add_instrumentation_data(payload)
payload[:response] = event.payload[:response] if event.payload[:response] payload[:response] = event.payload[:response] if event.payload[:response]
payload[:etag_route] = event.payload[:etag_route] if event.payload[:etag_route]
payload[Labkit::Correlation::CorrelationId::LOG_KEY] = Labkit::Correlation::CorrelationId.current_id payload[Labkit::Correlation::CorrelationId::LOG_KEY] = Labkit::Correlation::CorrelationId.current_id
if cpu_s = Gitlab::Metrics::System.thread_cpu_duration(::Gitlab::RequestContext.instance.start_thread_cpu_time) if cpu_s = Gitlab::Metrics::System.thread_cpu_duration(::Gitlab::RequestContext.instance.start_thread_cpu_time)
......
...@@ -8,7 +8,7 @@ Managing a large number of users in GitLab can become a burden for system admini ...@@ -8,7 +8,7 @@ Managing a large number of users in GitLab can become a burden for system admini
In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems. In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems.
GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/blog/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](../how_to_configure_ldap_gitlab_ee/index.html#group-sync) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/blog/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab. GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/releases/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](../how_to_configure_ldap_gitlab_ee/index.md#group-sync) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/releases/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab.
## Getting started ## Getting started
......
...@@ -111,7 +111,9 @@ GET /users ...@@ -111,7 +111,9 @@ GET /users
"can_create_project": true, "can_create_project": true,
"two_factor_enabled": true, "two_factor_enabled": true,
"external": false, "external": false,
"private_profile": false "private_profile": false,
"current_sign_in_ip": "196.165.1.102",
"last_sign_in_ip": "172.127.2.22"
}, },
{ {
"id": 2, "id": 2,
...@@ -142,7 +144,9 @@ GET /users ...@@ -142,7 +144,9 @@ GET /users
"can_create_project": true, "can_create_project": true,
"two_factor_enabled": true, "two_factor_enabled": true,
"external": false, "external": false,
"private_profile": false "private_profile": false,
"current_sign_in_ip": "10.165.1.102",
"last_sign_in_ip": "172.127.2.22"
} }
] ]
``` ```
...@@ -294,7 +298,9 @@ Example Responses: ...@@ -294,7 +298,9 @@ Example Responses:
"can_create_project": true, "can_create_project": true,
"two_factor_enabled": true, "two_factor_enabled": true,
"external": false, "external": false,
"private_profile": false "private_profile": false,
"current_sign_in_ip": "196.165.1.102",
"last_sign_in_ip": "172.127.2.22"
} }
``` ```
...@@ -534,7 +540,9 @@ GET /user ...@@ -534,7 +540,9 @@ GET /user
"can_create_project": true, "can_create_project": true,
"two_factor_enabled": true, "two_factor_enabled": true,
"external": false, "external": false,
"private_profile": false "private_profile": false,
"current_sign_in_ip": "196.165.1.102",
"last_sign_in_ip": "172.127.2.22"
} }
``` ```
......
...@@ -147,7 +147,7 @@ need to do for this: ...@@ -147,7 +147,7 @@ need to do for this:
For the scope of this article, we've defined an additional [CI/CD stage](../../yaml/README.md#stages) For the scope of this article, we've defined an additional [CI/CD stage](../../yaml/README.md#stages)
`confidence-check` that is executed _after_ the stage that deploys the review app. It uses the `node:latest` [Docker `confidence-check` that is executed _after_ the stage that deploys the review app. It uses the `node:latest` [Docker
image](../../docker/using_docker_images.html). However, WebdriverIO fires up actual browsers image](../../docker/using_docker_images.md). However, WebdriverIO fires up actual browsers
to interact with your application, so we need to install and run them. to interact with your application, so we need to install and run them.
Furthermore, WebdriverIO uses Selenium as a common interface to control different browsers, Furthermore, WebdriverIO uses Selenium as a common interface to control different browsers,
so we need to install and run Selenium as well. Luckily, the Selenium project provides the Docker images so we need to install and run Selenium as well. Luckily, the Selenium project provides the Docker images
...@@ -187,7 +187,7 @@ option as an argument to `npm run confidence-check` on the command line. ...@@ -187,7 +187,7 @@ option as an argument to `npm run confidence-check` on the command line.
However, we still need to tell WebdriverIO which browser is available for it to use. However, we still need to tell WebdriverIO which browser is available for it to use.
[GitLab CI/CD makes [GitLab CI/CD makes
a number of variables available](../../variables/README.html#predefined-environment-variables) a number of variables available](../../variables/README.md#predefined-environment-variables)
with information about the current CI job. We can use this information to dynamically set with information about the current CI job. We can use this information to dynamically set
up our WebdriverIO configuration according to the job that is running. More specifically, we can up our WebdriverIO configuration according to the job that is running. More specifically, we can
tell WebdriverIO what browser to execute the test on depending on the name of the currently running tell WebdriverIO what browser to execute the test on depending on the name of the currently running
......
...@@ -62,7 +62,7 @@ rspec: ...@@ -62,7 +62,7 @@ rspec:
Artifacts may work a bit differently than you've used them with Jenkins. In GitLab, any job can define Artifacts may work a bit differently than you've used them with Jenkins. In GitLab, any job can define
a set of artifacts to be saved by using the `artifacts:` keyword. This can be configured to point to a file a set of artifacts to be saved by using the `artifacts:` keyword. This can be configured to point to a file
or set of files that can then be persisted from job to job. Read more on our detailed [artifacts documentation](../../user/project/pipelines/job_artifacts.html) or set of files that can then be persisted from job to job. Read more on our detailed [artifacts documentation](../../user/project/pipelines/job_artifacts.md)
```yaml ```yaml
pdf: pdf:
...@@ -129,7 +129,7 @@ stages: ...@@ -129,7 +129,7 @@ stages:
- test - test
- deploy - deploy
- after_pipeline - after_pipeline
``` ```
Setting a step to be performed before and after any job can be done via the [`before_script` and `after_script` keywords](../yaml/README.md#before_script-and-after_script). Setting a step to be performed before and after any job can be done via the [`before_script` and `after_script` keywords](../yaml/README.md#before_script-and-after_script).
......
...@@ -736,7 +736,7 @@ This means the `only:changes` policy is useful for pipelines where: ...@@ -736,7 +736,7 @@ This means the `only:changes` policy is useful for pipelines where:
- `$CI_PIPELINE_SOURCE == 'external_pull_request_event'` - `$CI_PIPELINE_SOURCE == 'external_pull_request_event'`
If there is no Git push event, such as for pipelines with If there is no Git push event, such as for pipelines with
[sources other than the three above](../variables/predefined_variables.html#variables-reference), [sources other than the three above](../variables/predefined_variables.md#variables-reference),
`changes` cannot determine if a given file is new or old, and will always `changes` cannot determine if a given file is new or old, and will always
return true. return true.
......
...@@ -196,13 +196,12 @@ Every GitLab instance includes the documentation, which is available at `/help` ...@@ -196,13 +196,12 @@ Every GitLab instance includes the documentation, which is available at `/help`
There are [plans](https://gitlab.com/groups/gitlab-org/-/epics/693) to end this There are [plans](https://gitlab.com/groups/gitlab-org/-/epics/693) to end this
practice and instead link out from the GitLab application to <https://docs.gitlab.com> URLs. practice and instead link out from the GitLab application to <https://docs.gitlab.com> URLs.
The documentation available online on <https://docs.gitlab.com> is continuously The documentation available online on <https://docs.gitlab.com> is deployed every four hours from the `master` branch of GitLab, Omnibus, and Runner. Therefore,
deployed every hour from the `master` branch of GitLab, Omnibus, and Runner. Therefore, after a merge request gets merged, it will be available online on the same day.
once a merge request gets merged, it will be available online on the same day. However, it will be shipped (and available on `/help`) within the milestone assigned
However, they will be shipped (and available on `/help`) within the milestone assigned
to the MR. to the MR.
For instance, let's say your merge request has a milestone set to 11.3, which For example, let's say your merge request has a milestone set to 11.3, which
will be released on 2018-09-22. If it gets merged on 2018-09-15, it will be will be released on 2018-09-22. If it gets merged on 2018-09-15, it will be
available online on 2018-09-15, but, as the feature freeze date has passed, if available online on 2018-09-15, but, as the feature freeze date has passed, if
the MR does not have a "pick into 11.3" label, the milestone has to be changed the MR does not have a "pick into 11.3" label, the milestone has to be changed
......
...@@ -769,6 +769,74 @@ nicely on different mobile devices. ...@@ -769,6 +769,74 @@ nicely on different mobile devices.
- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers) is available for many languages. - [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers) is available for many languages.
- For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks). - For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks).
## GitLab SVG icons
> [Introduced](https://gitlab.com/gitlab-org/gitlab-docs/issues/384) in GitLab 12.7.
You can use icons from the [GitLab SVG library](https://gitlab-org.gitlab.io/gitlab-svgs/) directly
in the documentation.
This way, you can achieve a consistent look when writing about interacting with GitLab UI elements.
Usage examples:
- Icon with default size (16px): `**{icon-name}**`
Example: `**{tanuki}**` renders as: **{tanuki}**.
- Icon with custom size: `**{icon-name, size}**`
Available sizes (in px): 8, 10, 12, 14, 16, 18, 24, 32, 48, and 72
Example: `**{tanuki, 24}**` renders as: **{tanuki, 24}**.
- Icon with custom size and class: `**{icon-name, size, class-name}**`.
You can access any class available to this element in GitLab docs CSS.
Example with `float-right`, a
[Bootstrap utility class](https://getbootstrap.com/docs/4.4/utilities/float/):
`**{tanuki, 32, float-right}**` renders as: **{tanuki, 32, float-right}**
### Using GitLab SVGs to describe UI elements
When using GitLab SVGs to describe screen elements, also include the name or tooltip of the element as text.
For example, for references to the Admin Area:
- Correct: `**{admin}** **Admin Area > Settings**` (**{admin}** **Admin Area > Settings**)
- Incorrect: `**{admin}** **> Settings**` (**{admin}** **> Settings**)
This will ensure that the source Markdown remains readable and should help with accessibility.
The following are examples of source Markdown for menu items with their published output:
```md
1. Go to **{home}** **Project overview > Details**
1. Go to **{doc-text}** **Repository > Branches**
1. Go to **{issues}** **Issues > List**
1. Go to **{merge-request}** **Merge Requests**
1. Go to **{rocket}** **CI/CD > Pipelines**
1. Go to **{shield}** **Security & Compliance > Configuration**
1. Go to **{cloud-gear}** **Operations > Metrics**
1. Go to **{package}** **Packages > Container Registry**
1. Go to **{chart}** **Project Analytics > Code Review**
1. Go to **{book}** **Wiki**
1. Go to **{snippet}** **Snippets**
1. Go to **{users}** **Members**
```
1. Go to **{home}** **Project overview > Details**
1. Go to **{doc-text}** **Repository > Branches**
1. Go to **{issues}** **Issues > List**
1. Go to **{merge-request}** **Merge Requests**
1. Go to **{rocket}** **CI/CD > Pipelines**
1. Go to **{shield}** **Security & Compliance > Configuration**
1. Go to **{cloud-gear}** **Operations > Metrics**
1. Go to **{package}** **Packages > Container Registry**
1. Go to **{chart}** **Project Analytics > Code Review**
1. Go to **{book}** **Wiki**
1. Go to **{snippet}** **Snippets**
1. Go to **{users}** **Members**
## Alert boxes ## Alert boxes
Whenever you need to call special attention to particular sentences, Whenever you need to call special attention to particular sentences,
......
...@@ -77,6 +77,24 @@ Or: ...@@ -77,6 +77,24 @@ Or:
hello = _("Hello world!") hello = _("Hello world!")
``` ```
Be careful when translating strings at the class or module level since these would only be
evaluated once at class load time.
For example:
```ruby
validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") }
```
This would be translated when the class is loaded and result in the error message
always being in the default locale.
Active Record's `:message` option accepts a `Proc`, so we can do this instead:
```ruby
validates :group_id, uniqueness: { scope: [:project_id], message: -> (object, data) { _("already shared with this group") } }
```
NOTE: **Note:** Messages in the API (`lib/api/` or `app/graphql`) do NOTE: **Note:** Messages in the API (`lib/api/` or `app/graphql`) do
not need to be externalised. not need to be externalised.
......
...@@ -59,7 +59,7 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server: ...@@ -59,7 +59,7 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server:
**Replace `https://github.example.com/` with your GitHub URL.** **Replace `https://github.example.com/` with your GitHub URL.**
1. Save the file and [reconfigure](../administration/restart_gitlab.html#omnibus-gitlab-reconfigure) GitLab for the changes to take effect. 1. Save the file and [reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
--- ---
...@@ -86,7 +86,7 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server: ...@@ -86,7 +86,7 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server:
**Replace `https://github.example.com/` with your GitHub URL.** **Replace `https://github.example.com/` with your GitHub URL.**
1. Save the file and [restart](../administration/restart_gitlab.html#installations-from-source) GitLab for the changes to take effect. 1. Save the file and [restart](../administration/restart_gitlab.md#installations-from-source) GitLab for the changes to take effect.
--- ---
......
...@@ -549,7 +549,7 @@ GitLab will sign the request with the provided private key. GitLab will include ...@@ -549,7 +549,7 @@ GitLab will sign the request with the provided private key. GitLab will include
If you need to troubleshoot, [a complete GitLab+SAML testing environment using Docker compose](https://gitlab.com/gitlab-com/support/toolbox/replication/tree/master/compose_files) is available. If you need to troubleshoot, [a complete GitLab+SAML testing environment using Docker compose](https://gitlab.com/gitlab-com/support/toolbox/replication/tree/master/compose_files) is available.
If you only need a SAML provider for testing, a [quick start guide to start a Docker container](../administration/troubleshooting/test_environments.html#saml) with a plug and play SAML 2.0 Identity Provider (IdP) is available. If you only need a SAML provider for testing, a [quick start guide to start a Docker container](../administration/troubleshooting/test_environments.md#saml) with a plug and play SAML 2.0 Identity Provider (IdP) is available.
### 500 error after login ### 500 error after login
......
...@@ -38,7 +38,7 @@ Please note that for the deactivation option to be visible to an admin, the user ...@@ -38,7 +38,7 @@ Please note that for the deactivation option to be visible to an admin, the user
- Must be currently active. - Must be currently active.
- Should not have any activity in the last 180 days. - Should not have any activity in the last 180 days.
Users can also be deactivated using the [GitLab API](../../api/users.html#deactivate-user). Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
NOTE: **Note:** NOTE: **Note:**
A deactivated user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions). A deactivated user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
...@@ -56,7 +56,7 @@ To do this: ...@@ -56,7 +56,7 @@ To do this:
1. Select a user. 1. Select a user.
1. Under the **Account** tab, click **Activate user**. 1. Under the **Account** tab, click **Activate user**.
Users can also be activated using the [GitLab API](../../api/users.html#activate-user). Users can also be activated using the [GitLab API](../../api/users.md#activate-user).
NOTE: **Note:** NOTE: **Note:**
Activating a user will change the user's state to active and it consumes a Activating a user will change the user's state to active and it consumes a
......
...@@ -27,7 +27,7 @@ A blocked user: ...@@ -27,7 +27,7 @@ A blocked user:
Personal projects, and group and user history of the blocked user will be left intact. Personal projects, and group and user history of the blocked user will be left intact.
Users can also be blocked using the [GitLab API](../../api/users.html#block-user). Users can also be blocked using the [GitLab API](../../api/users.md#block-user).
NOTE: **Note:** NOTE: **Note:**
A blocked user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions). A blocked user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
...@@ -41,7 +41,7 @@ A blocked user can be unblocked from the Admin Area. To do this: ...@@ -41,7 +41,7 @@ A blocked user can be unblocked from the Admin Area. To do this:
1. Select a user. 1. Select a user.
1. Under the **Account** tab, click **Unblock user**. 1. Under the **Account** tab, click **Unblock user**.
Users can also be unblocked using the [GitLab API](../../api/users.html#unblock-user). Users can also be unblocked using the [GitLab API](../../api/users.md#unblock-user).
NOTE: **Note:** NOTE: **Note:**
Unblocking a user will change the user's state to active and it consumes a Unblocking a user will change the user's state to active and it consumes a
......
...@@ -6,7 +6,9 @@ type: reference, howto ...@@ -6,7 +6,9 @@ type: reference, howto
> Introduced in [GitLab.com Silver](https://about.gitlab.com/pricing/) 11.0. > Introduced in [GitLab.com Silver](https://about.gitlab.com/pricing/) 11.0.
SAML on GitLab.com allows users to be automatically added to a group, and then allows those users to sign into GitLab.com. Users should already have an account on the GitLab instance, or can create one when logging in for the first time. SAML on GitLab.com allows users to be added to a group. Those users can then sign in to GitLab.com. If such users don't already have an account on the GitLab instance, they can create one when signing in for the first time.
If you follow our guidance to automate user provisioning using [SCIM](scim_setup.md) or [group managed accounts](#group-managed-accounts), you do not need to create such accounts manually.
User synchronization for GitLab.com is partially supported using [SCIM](scim_setup.md). User synchronization for GitLab.com is partially supported using [SCIM](scim_setup.md).
...@@ -91,7 +93,7 @@ assertions to be able to create a user. ...@@ -91,7 +93,7 @@ assertions to be able to create a user.
| First Name | `first_name`, `firstname`, `firstName` | | First Name | `first_name`, `firstname`, `firstName` |
| Last Name | `last_name`, `lastname`, `lastName` | | Last Name | `last_name`, `lastname`, `lastName` |
## Metadata configuration ### Metadata configuration
GitLab provides metadata XML that can be used to configure your Identity Provider. GitLab provides metadata XML that can be used to configure your Identity Provider.
...@@ -111,6 +113,37 @@ Once you've set up your identity provider to work with GitLab, you'll need to co ...@@ -111,6 +113,37 @@ Once you've set up your identity provider to work with GitLab, you'll need to co
![Group SAML Settings for GitLab.com](img/group_saml_settings.png) ![Group SAML Settings for GitLab.com](img/group_saml_settings.png)
## User access and management
Once Group SSO is configured and enabled, users can access the GitLab.com group through the identity provider's dashboard. If [SCIM](scim_setup.md) is configured, please see the [user access and linking setup section on the SCIM page](scim_setup.md#user-access-and-linking-setup).
When a user tries to sign in with Group SSO, they'll need an account that's configured with one of the following:
- [SCIM](scim_setup.md).
- [Group-managed accounts](#group-managed-accounts).
- A GitLab.com account.
1. Click on the GitLab app in the identity provider's dashboard, or visit the Group's GitLab SSO URL.
1. Sign in to GitLab.com. The next time you connect on the same browser, you won't have to sign in again provided the active session has not expired.
1. Click on the **Authorize** button.
On subsequent visits, users can access the group through the identify provider's dashboard or by visiting links directly. With the **enforce SSO** option turned on, users will be redirected to log in through the identity provider as required.
### Role
Upon first sign in, a new user is added to the parent group with the Guest role. Existing members with an appropriate role will have to elevate users to a higher role where relevant.
If a user is already a member of the group, linking the SAML identity does not change their role.
### Blocking access
To rescind access to the group:
1. Remove the user from the identity provider or users list for the specific app.
1. Remove the user from the GitLab.com group.
Even when **enforce SSO** is active, we recommend removing the user from the group. Otherwise, the user can sign in through the identity provider if they do not have an active session.
## Providers ## Providers
NOTE: **Note:** GitLab is unable to provide support for IdPs that are not listed here. NOTE: **Note:** GitLab is unable to provide support for IdPs that are not listed here.
......
...@@ -117,6 +117,28 @@ bottom of the **Provisioning** screen, together with a link to the audit logs. ...@@ -117,6 +117,28 @@ bottom of the **Provisioning** screen, together with a link to the audit logs.
CAUTION: **Warning:** CAUTION: **Warning:**
Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group. Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group.
## User access and linking setup
As long as [Group SAML](index.md) has been configured, prior to turning on sync, existing GitLab.com users can link to their accounts in one of the following ways, before synchronization is active:
- By updating their *primary* email address in their GitLab.com user account to match their identity provider's user profile email address.
- By following these steps:
1. Sign in to GitLab.com if needed.
1. Click on the GitLab app in the identity provider's dashboard or visit the **GitLab single sign on URL**.
1. Click on the **Authorize** button.
New users and existing users on subsequent visits can access the group through the identify provider's dashboard or by visiting links directly.
For role information, please see the [Group SAML page](index.md#user-access-and-management)
### Blocking access
To rescind access to the group, we recommend removing the user from the identity
provider or users list for the specific app.
Upon the next sync, the user will be deprovisioned, which means that the user will be removed from the group. The user account will not be deleted unless using [group managed accounts](index.md#group-managed-accounts).
## Troubleshooting ## Troubleshooting
This section contains possible solutions for problems you might encounter. This section contains possible solutions for problems you might encounter.
......
...@@ -425,7 +425,7 @@ for details about the pipelines security model. ...@@ -425,7 +425,7 @@ for details about the pipelines security model.
## LDAP users permissions ## LDAP users permissions
Since GitLab 8.15, LDAP user permissions can now be manually overridden by an admin user. Since GitLab 8.15, LDAP user permissions can now be manually overridden by an admin user.
Read through the documentation on [LDAP users permissions](../administration/auth/how_to_configure_ldap_gitlab_ee/index.html) to learn more. Read through the documentation on [LDAP users permissions](../administration/auth/how_to_configure_ldap_gitlab_ee/index.md) to learn more.
## Project aliases ## Project aliases
......
...@@ -123,3 +123,13 @@ NOTE: **Note:** ...@@ -123,3 +123,13 @@ NOTE: **Note:**
If use of the `Internal` visibility level If use of the `Internal` visibility level
[is restricted](../../../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects), [is restricted](../../../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects),
all imported projects are given the visibility of `Private`. all imported projects are given the visibility of `Private`.
## Rate limits
To help avoid abuse, users are rate limited to:
| Request Type | Limit |
| ---------------- | --------------------------- |
| Export | 1 project per 5 minutes |
| Download export | 10 projects per 10 minutes |
| Import | 30 projects per 10 minutes |
...@@ -115,6 +115,8 @@ module API ...@@ -115,6 +115,8 @@ module API
class UserDetailsWithAdmin < UserWithAdmin class UserDetailsWithAdmin < UserWithAdmin
expose :highest_role expose :highest_role
expose :current_sign_in_ip
expose :last_sign_in_ip
end end
class UserStatus < Grape::Entity class UserStatus < Grape::Entity
......
...@@ -22,6 +22,7 @@ module Gitlab ...@@ -22,6 +22,7 @@ module Gitlab
project_export: { threshold: 1, interval: 5.minutes }, project_export: { threshold: 1, interval: 5.minutes },
project_download_export: { threshold: 10, interval: 10.minutes }, project_download_export: { threshold: 10, interval: 10.minutes },
project_generate_new_export: { threshold: 1, interval: 5.minutes }, project_generate_new_export: { threshold: 1, interval: 5.minutes },
project_import: { threshold: 30, interval: 10.minutes },
play_pipeline_schedule: { threshold: 1, interval: 1.minute }, play_pipeline_schedule: { threshold: 1, interval: 1.minute },
show_raw_controller: { threshold: -> { Gitlab::CurrentSettings.current_application_settings.raw_blob_request_limit }, interval: 1.minute } show_raw_controller: { threshold: -> { Gitlab::CurrentSettings.current_application_settings.raw_blob_request_limit }, interval: 1.minute }
}.freeze }.freeze
......
...@@ -4,8 +4,6 @@ module Gitlab ...@@ -4,8 +4,6 @@ module Gitlab
module Email module Email
module Smime module Smime
class Certificate class Certificate
include OpenSSL
attr_reader :key, :cert attr_reader :key, :cert
def key_string def key_string
...@@ -17,8 +15,8 @@ module Gitlab ...@@ -17,8 +15,8 @@ module Gitlab
end end
def self.from_strings(key_string, cert_string) def self.from_strings(key_string, cert_string)
key = PKey::RSA.new(key_string) key = OpenSSL::PKey::RSA.new(key_string)
cert = X509::Certificate.new(cert_string) cert = OpenSSL::X509::Certificate.new(cert_string)
new(key, cert) new(key, cert)
end end
......
...@@ -7,20 +7,18 @@ module Gitlab ...@@ -7,20 +7,18 @@ module Gitlab
module Smime module Smime
# Tooling for signing and verifying data with SMIME # Tooling for signing and verifying data with SMIME
class Signer class Signer
include OpenSSL
def self.sign(cert:, key:, data:) def self.sign(cert:, key:, data:)
signed_data = PKCS7.sign(cert, key, data, nil, PKCS7::DETACHED) signed_data = OpenSSL::PKCS7.sign(cert, key, data, nil, OpenSSL::PKCS7::DETACHED)
PKCS7.write_smime(signed_data) OpenSSL::PKCS7.write_smime(signed_data)
end end
# return nil if data cannot be verified, otherwise the signed content data # return nil if data cannot be verified, otherwise the signed content data
def self.verify_signature(cert:, ca_cert: nil, signed_data:) def self.verify_signature(cert:, ca_cert: nil, signed_data:)
store = X509::Store.new store = OpenSSL::X509::Store.new
store.set_default_paths store.set_default_paths
store.add_cert(ca_cert) if ca_cert store.add_cert(ca_cert) if ca_cert
signed_smime = PKCS7.read_smime(signed_data) signed_smime = OpenSSL::PKCS7.read_smime(signed_data)
signed_smime if signed_smime.verify([cert], store) signed_smime if signed_smime.verify([cert], store)
end end
end end
......
...@@ -18,7 +18,7 @@ module Gitlab ...@@ -18,7 +18,7 @@ module Gitlab
if_none_match = env['HTTP_IF_NONE_MATCH'] if_none_match = env['HTTP_IF_NONE_MATCH']
if if_none_match == etag if if_none_match == etag
handle_cache_hit(etag, route) handle_cache_hit(etag, route, request)
else else
track_cache_miss(if_none_match, cached_value_present, route) track_cache_miss(if_none_match, cached_value_present, route)
...@@ -47,11 +47,13 @@ module Gitlab ...@@ -47,11 +47,13 @@ module Gitlab
%Q{W/"#{value}"} %Q{W/"#{value}"}
end end
def handle_cache_hit(etag, route) def handle_cache_hit(etag, route, request)
track_event(:etag_caching_cache_hit, route) track_event(:etag_caching_cache_hit, route)
status_code = Gitlab::PollingInterval.polling_enabled? ? 304 : 429 status_code = Gitlab::PollingInterval.polling_enabled? ? 304 : 429
add_instrument_for_cache_hit(status_code, route, request)
[status_code, { 'ETag' => etag, 'X-Gitlab-From-Cache' => 'true' }, []] [status_code, { 'ETag' => etag, 'X-Gitlab-From-Cache' => 'true' }, []]
end end
...@@ -68,6 +70,21 @@ module Gitlab ...@@ -68,6 +70,21 @@ module Gitlab
def track_event(name, route) def track_event(name, route)
Gitlab::Metrics.add_event(name, endpoint: route.name) Gitlab::Metrics.add_event(name, endpoint: route.name)
end end
def add_instrument_for_cache_hit(status, route, request)
payload = {
etag_route: route.name,
params: request.filtered_parameters,
headers: request.headers,
format: request.format.ref,
method: request.request_method,
path: request.filtered_path,
status: status
}
ActiveSupport::Notifications.instrument(
"process_action.action_controller", payload)
end
end end
end end
end end
...@@ -2098,6 +2098,9 @@ msgstr "" ...@@ -2098,6 +2098,9 @@ msgstr ""
msgid "Approve the current merge request." msgid "Approve the current merge request."
msgstr "" msgstr ""
msgid "Approved by: "
msgstr ""
msgid "Approved the current merge request." msgid "Approved the current merge request."
msgstr "" msgstr ""
...@@ -4897,6 +4900,12 @@ msgstr "" ...@@ -4897,6 +4900,12 @@ msgstr ""
msgid "Complete" msgid "Complete"
msgstr "" msgstr ""
msgid "Compliance"
msgstr ""
msgid "Compliance Dashboard"
msgstr ""
msgid "Confidence: %{confidence}" msgid "Confidence: %{confidence}"
msgstr "" msgstr ""
...@@ -22490,6 +22499,9 @@ msgid_plural "merge requests" ...@@ -22490,6 +22499,9 @@ msgid_plural "merge requests"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "merged %{time_ago}"
msgstr ""
msgid "milestone should belong either to a project or a group." msgid "milestone should belong either to a project or a group."
msgstr "" msgstr ""
......
...@@ -136,6 +136,8 @@ describe Import::BitbucketController do ...@@ -136,6 +136,8 @@ describe Import::BitbucketController do
expect(response).to have_gitlab_http_status(422) expect(response).to have_gitlab_http_status(422)
end end
it_behaves_like 'project import rate limiter'
context "when the repository owner is the Bitbucket user" do context "when the repository owner is the Bitbucket user" do
context "when the Bitbucket user and GitLab user's usernames match" do context "when the Bitbucket user and GitLab user's usernames match" do
it "takes the current user's namespace" do it "takes the current user's namespace" do
......
...@@ -102,6 +102,8 @@ describe Import::BitbucketServerController do ...@@ -102,6 +102,8 @@ describe Import::BitbucketServerController do
expect(response).to have_gitlab_http_status(422) expect(response).to have_gitlab_http_status(422)
end end
it_behaves_like 'project import rate limiter'
end end
describe 'POST configure' do describe 'POST configure' do
......
...@@ -75,4 +75,8 @@ describe Import::FogbugzController do ...@@ -75,4 +75,8 @@ describe Import::FogbugzController do
expect(assigns(:repos)).to eq([]) expect(assigns(:repos)).to eq([])
end end
end end
describe 'POST create' do
it_behaves_like 'project import rate limiter'
end
end end
...@@ -41,6 +41,8 @@ describe Import::GiteaController do ...@@ -41,6 +41,8 @@ describe Import::GiteaController do
assign_host_url assign_host_url
end end
end end
it_behaves_like 'project import rate limiter'
end end
describe "GET realtime_changes" do describe "GET realtime_changes" do
......
...@@ -71,6 +71,8 @@ describe Import::GithubController do ...@@ -71,6 +71,8 @@ describe Import::GithubController do
describe "POST create" do describe "POST create" do
it_behaves_like 'a GitHub-ish import controller: POST create' it_behaves_like 'a GitHub-ish import controller: POST create'
it_behaves_like 'project import rate limiter'
end end
describe "GET realtime_changes" do describe "GET realtime_changes" do
......
...@@ -282,6 +282,8 @@ describe Import::GitlabController do ...@@ -282,6 +282,8 @@ describe Import::GitlabController do
expect(response).to have_gitlab_http_status(422) expect(response).to have_gitlab_http_status(422)
end end
end end
it_behaves_like 'project import rate limiter'
end end
end end
end end
...@@ -36,5 +36,7 @@ describe Import::GitlabProjectsController do ...@@ -36,5 +36,7 @@ describe Import::GitlabProjectsController do
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
end end
end end
it_behaves_like 'project import rate limiter'
end end
end end
...@@ -58,4 +58,8 @@ describe Import::GoogleCodeController do ...@@ -58,4 +58,8 @@ describe Import::GoogleCodeController do
expect(assigns(:incompatible_repos)).to eq([@repo]) expect(assigns(:incompatible_repos)).to eq([@repo])
end end
end end
describe "POST create" do
it_behaves_like 'project import rate limiter'
end
end end
...@@ -88,5 +88,7 @@ describe Import::PhabricatorController do ...@@ -88,5 +88,7 @@ describe Import::PhabricatorController do
expect { post_create }.not_to change { current_user.namespace.projects.reload.size } expect { post_create }.not_to change { current_user.namespace.projects.reload.size }
end end
end end
it_behaves_like 'project import rate limiter'
end end
end end
...@@ -94,6 +94,11 @@ describe 'lograge', type: :request do ...@@ -94,6 +94,11 @@ describe 'lograge', type: :request do
let(:logger) do let(:logger) do
Logger.new(log_output).tap { |logger| logger.formatter = ->(_, _, _, msg) { msg } } Logger.new(log_output).tap { |logger| logger.formatter = ->(_, _, _, msg) { msg } }
end end
let(:log_data) { JSON.parse(log_output.string) }
before do
Lograge.logger = logger
end
describe 'with an exception' do describe 'with an exception' do
let(:exception) { RuntimeError.new('bad request') } let(:exception) { RuntimeError.new('bad request') }
...@@ -102,18 +107,29 @@ describe 'lograge', type: :request do ...@@ -102,18 +107,29 @@ describe 'lograge', type: :request do
before do before do
allow(exception).to receive(:backtrace).and_return(backtrace) allow(exception).to receive(:backtrace).and_return(backtrace)
event.payload[:exception_object] = exception event.payload[:exception_object] = exception
Lograge.logger = logger
end end
it 'adds exception data to log' do it 'adds exception data to log' do
subscriber.process_action(event) subscriber.process_action(event)
log_data = JSON.parse(log_output.string)
expect(log_data['exception.class']).to eq('RuntimeError') expect(log_data['exception.class']).to eq('RuntimeError')
expect(log_data['exception.message']).to eq('bad request') expect(log_data['exception.message']).to eq('bad request')
expect(log_data['exception.backtrace']).to eq(Gitlab::BacktraceCleaner.clean_backtrace(backtrace)) expect(log_data['exception.backtrace']).to eq(Gitlab::BacktraceCleaner.clean_backtrace(backtrace))
end end
end end
describe 'with etag_route' do
let(:etag_route) { 'etag route' }
before do
event.payload[:etag_route] = etag_route
end
it 'adds etag_route to log' do
subscriber.process_action(event)
expect(log_data['etag_route']).to eq(etag_route)
end
end
end end
end end
...@@ -8,6 +8,7 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -8,6 +8,7 @@ describe Gitlab::EtagCaching::Middleware do
let(:app_status_code) { 200 } let(:app_status_code) { 200 }
let(:if_none_match) { nil } let(:if_none_match) { nil }
let(:enabled_path) { '/gitlab-org/gitlab-foss/noteable/issue/1/notes' } let(:enabled_path) { '/gitlab-org/gitlab-foss/noteable/issue/1/notes' }
let(:endpoint) { 'issue_notes' }
context 'when ETag caching is not enabled for current route' do context 'when ETag caching is not enabled for current route' do
let(:path) { '/gitlab-org/gitlab-foss/tree/master/noteable/issue/1/notes' } let(:path) { '/gitlab-org/gitlab-foss/tree/master/noteable/issue/1/notes' }
...@@ -50,9 +51,9 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -50,9 +51,9 @@ describe Gitlab::EtagCaching::Middleware do
it 'tracks "etag_caching_key_not_found" event' do it 'tracks "etag_caching_key_not_found" event' do
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_middleware_used, endpoint: 'issue_notes') .with(:etag_caching_middleware_used, endpoint: endpoint)
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_key_not_found, endpoint: 'issue_notes') .with(:etag_caching_key_not_found, endpoint: endpoint)
middleware.call(build_request(path, if_none_match)) middleware.call(build_request(path, if_none_match))
end end
...@@ -74,6 +75,37 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -74,6 +75,37 @@ describe Gitlab::EtagCaching::Middleware do
end end
end end
shared_examples 'sends a process_action.action_controller notification' do |status_code|
let(:expected_items) do
{
etag_route: endpoint,
params: {},
format: :html,
method: 'GET',
path: enabled_path,
status: status_code
}
end
it 'sends the expected payload' do
payload = payload_for('process_action.action_controller') do
middleware.call(build_request(path, if_none_match))
end
expect(payload).to include(expected_items)
expect(payload[:headers].env['HTTP_IF_NONE_MATCH']).to eq('W/"123"')
end
it 'log subscriber processes action' do
expect_any_instance_of(ActionController::LogSubscriber).to receive(:process_action)
.with(instance_of(ActiveSupport::Notifications::Event))
.and_call_original
middleware.call(build_request(path, if_none_match))
end
end
context 'when If-None-Match header matches ETag in store' do context 'when If-None-Match header matches ETag in store' do
let(:path) { enabled_path } let(:path) { enabled_path }
let(:if_none_match) { 'W/"123"' } let(:if_none_match) { 'W/"123"' }
...@@ -94,6 +126,8 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -94,6 +126,8 @@ describe Gitlab::EtagCaching::Middleware do
expect(status).to eq 304 expect(status).to eq 304
end end
it_behaves_like 'sends a process_action.action_controller notification', 304
it 'returns empty body' do it 'returns empty body' do
_, _, body = middleware.call(build_request(path, if_none_match)) _, _, body = middleware.call(build_request(path, if_none_match))
...@@ -102,9 +136,9 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -102,9 +136,9 @@ describe Gitlab::EtagCaching::Middleware do
it 'tracks "etag_caching_cache_hit" event' do it 'tracks "etag_caching_cache_hit" event' do
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_middleware_used, endpoint: 'issue_notes') .with(:etag_caching_middleware_used, endpoint: endpoint)
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_cache_hit, endpoint: 'issue_notes') .with(:etag_caching_cache_hit, endpoint: endpoint)
middleware.call(build_request(path, if_none_match)) middleware.call(build_request(path, if_none_match))
end end
...@@ -120,6 +154,8 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -120,6 +154,8 @@ describe Gitlab::EtagCaching::Middleware do
expect(status).to eq 429 expect(status).to eq 429
end end
it_behaves_like 'sends a process_action.action_controller notification', 429
end end
end end
...@@ -141,9 +177,9 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -141,9 +177,9 @@ describe Gitlab::EtagCaching::Middleware do
mock_app_response mock_app_response
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_middleware_used, endpoint: 'issue_notes') .with(:etag_caching_middleware_used, endpoint: endpoint)
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_resource_changed, endpoint: 'issue_notes') .with(:etag_caching_resource_changed, endpoint: endpoint)
middleware.call(build_request(path, if_none_match)) middleware.call(build_request(path, if_none_match))
end end
...@@ -159,9 +195,9 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -159,9 +195,9 @@ describe Gitlab::EtagCaching::Middleware do
it 'tracks "etag_caching_header_missing" event' do it 'tracks "etag_caching_header_missing" event' do
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_middleware_used, endpoint: 'issue_notes') .with(:etag_caching_middleware_used, endpoint: endpoint)
expect(Gitlab::Metrics).to receive(:add_event) expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_header_missing, endpoint: 'issue_notes') .with(:etag_caching_header_missing, endpoint: endpoint)
middleware.call(build_request(path, if_none_match)) middleware.call(build_request(path, if_none_match))
end end
...@@ -197,6 +233,21 @@ describe Gitlab::EtagCaching::Middleware do ...@@ -197,6 +233,21 @@ describe Gitlab::EtagCaching::Middleware do
end end
def build_request(path, if_none_match) def build_request(path, if_none_match)
{ 'PATH_INFO' => path, 'HTTP_IF_NONE_MATCH' => if_none_match } { 'PATH_INFO' => path,
'HTTP_IF_NONE_MATCH' => if_none_match,
'rack.input' => '',
'REQUEST_METHOD' => 'GET' }
end
def payload_for(event)
payload = nil
subscription = ActiveSupport::Notifications.subscribe event do |_, _, _, _, extra_payload|
payload = extra_payload
end
yield
ActiveSupport::Notifications.unsubscribe(subscription)
payload
end end
end end
...@@ -77,6 +77,14 @@ describe API::Users do ...@@ -77,6 +77,14 @@ describe API::Users do
expect(json_response.first.keys).not_to include 'highest_role' expect(json_response.first.keys).not_to include 'highest_role'
end end
it "does not return the current or last sign-in ip addresses" do
get api("/users"), params: { username: user.username }
expect(response).to match_response_schema('public_api/v4/user/basics')
expect(json_response.first.keys).not_to include 'current_sign_in_ip'
expect(json_response.first.keys).not_to include 'last_sign_in_ip'
end
context "when public level is restricted" do context "when public level is restricted" do
before do before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
...@@ -314,6 +322,14 @@ describe API::Users do ...@@ -314,6 +322,14 @@ describe API::Users do
expect(json_response.keys).not_to include 'highest_role' expect(json_response.keys).not_to include 'highest_role'
end end
it "does not return the user's sign in IPs" do
get api("/users/#{user.id}", user)
expect(response).to match_response_schema('public_api/v4/user/basic')
expect(json_response.keys).not_to include 'current_sign_in_ip'
expect(json_response.keys).not_to include 'last_sign_in_ip'
end
context 'when authenticated as admin' do context 'when authenticated as admin' do
it 'includes the `is_admin` field' do it 'includes the `is_admin` field' do
get api("/users/#{user.id}", admin) get api("/users/#{user.id}", admin)
...@@ -328,12 +344,34 @@ describe API::Users do ...@@ -328,12 +344,34 @@ describe API::Users do
expect(response).to match_response_schema('public_api/v4/user/admin') expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response.keys).to include 'created_at' expect(json_response.keys).to include 'created_at'
end end
it 'includes the `highest_role` field' do it 'includes the `highest_role` field' do
get api("/users/#{user.id}", admin) get api("/users/#{user.id}", admin)
expect(response).to match_response_schema('public_api/v4/user/admin') expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response['highest_role']).to be(0) expect(json_response['highest_role']).to be(0)
end end
context 'when user has not logged in' do
it 'does not include the sign in IPs' do
get api("/users/#{user.id}", admin)
expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response).to include('current_sign_in_ip' => nil, 'last_sign_in_ip' => nil)
end
end
context 'when user has logged in' do
let_it_be(:signed_in_user) { create(:user, :with_sign_ins) }
it 'includes the sign in IPs' do
get api("/users/#{signed_in_user.id}", admin)
expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response['current_sign_in_ip']).to eq('127.0.0.1')
expect(json_response['last_sign_in_ip']).to eq('127.0.0.1')
end
end
end end
context 'for an anonymous user' do context 'for an anonymous user' do
......
# frozen_string_literal: true
shared_examples 'project import rate limiter' do
let(:user) { create(:user) }
before do
sign_in(user)
end
context 'when limit exceeds' do
before do
allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
end
it 'notifies and redirects user' do
post :create, params: {}
expect(flash[:alert]).to eq('This endpoint has been requested too many times. Try again later.')
expect(response).to have_gitlab_http_status(302)
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
module SmimeHelper module SmimeHelper
include OpenSSL
INFINITE_EXPIRY = 1000.years INFINITE_EXPIRY = 1000.years
SHORT_EXPIRY = 30.minutes SHORT_EXPIRY = 30.minutes
...@@ -20,12 +18,12 @@ module SmimeHelper ...@@ -20,12 +18,12 @@ module SmimeHelper
public_key = key.public_key public_key = key.public_key
subject = if certificate_authority subject = if certificate_authority
X509::Name.parse("/CN=EU") OpenSSL::X509::Name.parse("/CN=EU")
else else
X509::Name.parse("/CN=#{email_address}") OpenSSL::X509::Name.parse("/CN=#{email_address}")
end end
cert = X509::Certificate.new cert = OpenSSL::X509::Certificate.new
cert.subject = subject cert.subject = subject
cert.issuer = signed_by&.fetch(:cert, nil)&.subject || subject cert.issuer = signed_by&.fetch(:cert, nil)&.subject || subject
...@@ -36,7 +34,7 @@ module SmimeHelper ...@@ -36,7 +34,7 @@ module SmimeHelper
cert.serial = 0x0 cert.serial = 0x0
cert.version = 2 cert.version = 2
extension_factory = X509::ExtensionFactory.new extension_factory = OpenSSL::X509::ExtensionFactory.new
if certificate_authority if certificate_authority
extension_factory.subject_certificate = cert extension_factory.subject_certificate = cert
extension_factory.issuer_certificate = cert extension_factory.issuer_certificate = cert
...@@ -50,7 +48,7 @@ module SmimeHelper ...@@ -50,7 +48,7 @@ module SmimeHelper
cert.add_extension(extension_factory.create_extension('extendedKeyUsage', 'clientAuth,emailProtection', false)) cert.add_extension(extension_factory.create_extension('extendedKeyUsage', 'clientAuth,emailProtection', false))
end end
cert.sign(signed_by&.fetch(:key, nil) || key, Digest::SHA256.new) cert.sign(signed_by&.fetch(:key, nil) || key, OpenSSL::Digest::SHA256.new)
{ key: key, cert: cert } { key: key, cert: cert }
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