Commit 6f8cc02c authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 3d1be386 b15a78df
...@@ -49,7 +49,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController ...@@ -49,7 +49,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def set_index_vars def set_index_vars
@scopes = Gitlab::Auth.available_scopes(current_user) @scopes = Gitlab::Auth.available_scopes_for(current_user)
@impersonation_token ||= finder.build @impersonation_token ||= finder.build
@inactive_impersonation_tokens = finder(state: 'inactive').execute @inactive_impersonation_tokens = finder(state: 'inactive').execute
......
...@@ -22,7 +22,7 @@ class JwtController < ApplicationController ...@@ -22,7 +22,7 @@ class JwtController < ApplicationController
private private
def authenticate_project_or_user def authenticate_project_or_user
@authentication_result = Gitlab::Auth::Result.new(nil, nil, :none, Gitlab::Auth.read_authentication_abilities) @authentication_result = Gitlab::Auth::Result.new(nil, nil, :none, Gitlab::Auth.read_only_authentication_abilities)
authenticate_with_http_basic do |login, password| authenticate_with_http_basic do |login, password|
@authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip) @authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip)
......
...@@ -42,7 +42,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController ...@@ -42,7 +42,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def set_index_vars def set_index_vars
@scopes = Gitlab::Auth.available_scopes(current_user) @scopes = Gitlab::Auth.available_scopes_for(current_user)
@inactive_personal_access_tokens = finder(state: 'inactive').execute @inactive_personal_access_tokens = finder(state: 'inactive').execute
@active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at) @active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at)
......
...@@ -83,7 +83,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController ...@@ -83,7 +83,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
def render_missing_personal_access_token def render_missing_personal_access_token
render plain: "HTTP Basic: Access denied\n" \ render plain: "HTTP Basic: Access denied\n" \
"You must use a personal access token with 'api' scope for Git over HTTP.\n" \ "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}", "You can generate one at #{profile_personal_access_tokens_url}",
status: :unauthorized status: :unauthorized
end end
......
...@@ -56,7 +56,7 @@ class PersonalAccessToken < ApplicationRecord ...@@ -56,7 +56,7 @@ class PersonalAccessToken < ApplicationRecord
protected protected
def validate_scopes def validate_scopes
unless revoked || scopes.all? { |scope| Gitlab::Auth.available_scopes.include?(scope.to_sym) } unless revoked || scopes.all? { |scope| Gitlab::Auth.all_available_scopes.include?(scope.to_sym) }
errors.add :scopes, "can only contain available scopes" errors.add :scopes, "can only contain available scopes"
end end
end end
......
---
title: Added write_repository scope for personal access token
merge_request: 26021
author: Horatiu Eugen Vlad
type: added
...@@ -60,7 +60,8 @@ en: ...@@ -60,7 +60,8 @@ en:
scopes: scopes:
api: Access the authenticated user's API api: Access the authenticated user's API
read_user: Read the authenticated user's personal information read_user: Read the authenticated user's personal information
read_repository: Allows read-access to the repository read_repository: Allows read-only access to the repository
write_repository: Allows read-write access to the repository
read_registry: Grants permission to read container registry images read_registry: Grants permission to read container registry images
openid: Authenticate using OpenID Connect openid: Authenticate using OpenID Connect
sudo: Perform API actions as any user in the system sudo: Perform API actions as any user in the system
...@@ -73,6 +74,8 @@ en: ...@@ -73,6 +74,8 @@ en:
Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users. Grants read-only access to the authenticated user's profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users.
read_repository: read_repository:
Grants read-only access to repositories on private projects using Git-over-HTTP (not using the API). Grants read-only access to repositories on private projects using Git-over-HTTP (not using the API).
write_repository:
Grants read-write access to repositories on private projects using Git-over-HTTP (not using the API).
read_registry: read_registry:
Grants read-only access to container registry images on private projects. Grants read-only access to container registry images on private projects.
openid: openid:
......
...@@ -40,10 +40,11 @@ the following table. ...@@ -40,10 +40,11 @@ the following table.
| Scope | Description | | Scope | Description |
| ----- | ----------- | | ----- | ----------- |
|`read_user` | Allows access to the read-only endpoints under `/users`. Essentially, any of the `GET` requests in the [Users API][users] are allowed ([introduced][ce-5951] in GitLab 8.15). | |`read_user` | Allows access to the read-only endpoints under `/users`. Essentially, any of the `GET` requests in the [Users API][users] are allowed ([introduced][ce-5951] in GitLab 8.15). |
| `api` | Grants complete access to the API and Container Registry (read/write) ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5951) in GitLab 8.15). Required for accessing Git repositories over HTTP when 2FA is enabled. | | `api` | Grants complete access to the API and Container Registry (read/write) ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5951) in GitLab 8.15). |
| `read_registry` | Allows to read (pull) [container registry] images if a project is private and authorization is required ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11845) in GitLab 9.3). | | `read_registry` | Allows to read (pull) [container registry] images if a project is private and authorization is required ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11845) in GitLab 9.3). |
| `sudo` | Allows performing API actions as any user in the system (if the authenticated user is an admin) ([introduced][ce-14838] in GitLab 10.2). | | `sudo` | Allows performing API actions as any user in the system (if the authenticated user is an admin) ([introduced][ce-14838] in GitLab 10.2). |
| `read_repository` | Allows read-access (pull) to the repository through git clone. | | `read_repository` | Allows read-only access (pull) to the repository through git clone. |
| `write_repository` | Allows read-write access (pull, push) to the repository through git clone. Required for accessing Git repositories over HTTP when 2FA is enabled. |
[2fa]: ../account/two_factor_authentication.md [2fa]: ../account/two_factor_authentication.md
[api]: ../../api/README.md [api]: ../../api/README.md
......
...@@ -8,7 +8,9 @@ last_updated: 2019-03-05 ...@@ -8,7 +8,9 @@ last_updated: 2019-03-05
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/80) in GitLab Enterprise Edition 8.3. > - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/80) in GitLab Enterprise Edition 8.3.
> - Custom CNAMEs with TLS support were [introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/173) in GitLab Enterprise Edition 8.5. > - Custom CNAMEs with TLS support were [introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/173) in GitLab Enterprise Edition 8.5.
> - [Ported](https://gitlab.com/gitlab-org/gitlab-ce/issues/14605) to GitLab Community Edition in GitLab 8.17. > - [Ported](https://gitlab.com/gitlab-org/gitlab-ce/issues/14605) to GitLab Community Edition in GitLab 8.17.
> Support for subgroup project's websites was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/30548) in GitLab 11.8. > - Support for subgroup project's websites was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/30548) in GitLab 11.8.
> - Bundled project templates were [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/47857) in GitLab 11.8.
**GitLab Pages is a feature that allows you to publish static websites **GitLab Pages is a feature that allows you to publish static websites
directly from a repository in GitLab.** directly from a repository in GitLab.**
...@@ -67,14 +69,6 @@ publish any website written directly in plain HTML, CSS, and JavaScript.</p> ...@@ -67,14 +69,6 @@ publish any website written directly in plain HTML, CSS, and JavaScript.</p>
<div class="col-md-3"><img src="img/ssgs_pages.png" alt="Examples of SSGs supported by Pages" class="image-noshadow middle display-block"></div> <div class="col-md-3"><img src="img/ssgs_pages.png" alt="Examples of SSGs supported by Pages" class="image-noshadow middle display-block"></div>
</div> </div>
### Availability
If you're using GitLab.com, your website will be publicly available to the internet.
If you're using self-managed instances (Core, Starter, Premium, or Ultimate),
your websites will be published on your own server, according to the
[Pages admin settings](../../../administration/pages/index.md) chosen by your sysadmin,
who can opt for making them public or internal to your server.
### How it works ### How it works
To use GitLab Pages, first you need to create a project in GitLab to upload your website's To use GitLab Pages, first you need to create a project in GitLab to upload your website's
...@@ -84,7 +78,7 @@ repository. Note that when you create a new project in GitLab, a [repository](.. ...@@ -84,7 +78,7 @@ repository. Note that when you create a new project in GitLab, a [repository](..
becomes available automatically. becomes available automatically.
To deploy your site, GitLab will use its built-in tool called [GitLab CI/CD](../../../ci/README.md), To deploy your site, GitLab will use its built-in tool called [GitLab CI/CD](../../../ci/README.md),
that will build your site and publish it to the GitLab Pages server. The sequence of to build your site and publish it to the GitLab Pages server. The sequence of
scripts that GitLab CI/CD runs to accomplish this task is created from a file named scripts that GitLab CI/CD runs to accomplish this task is created from a file named
`.gitlab-ci.yml`, which you can [create and modify](getting_started_part_four.md) at will. `.gitlab-ci.yml`, which you can [create and modify](getting_started_part_four.md) at will.
...@@ -95,14 +89,13 @@ need admin access to your domain's registrar (or control panel) to set it up wit ...@@ -95,14 +89,13 @@ need admin access to your domain's registrar (or control panel) to set it up wit
Optionally, when adding your own domain, you can add an SSL/TLS certificate to secure your Optionally, when adding your own domain, you can add an SSL/TLS certificate to secure your
site under the HTTPS protocol. site under the HTTPS protocol.
## Getting started ### Getting started
To get started with GitLab Pages, you can either: To get started with GitLab Pages, you can either:
- [Create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch). - [Create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch).
- [Copy an existing example project](getting_started_part_two.md#fork-a-project-to-get-started-from). - [Copy an existing example project](getting_started_part_two.md#fork-a-project-to-get-started-from).
- Use a bundled project template that is ready to go ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/47857) - Use a bundled project template ready to go:
in GitLab 11.8), as follows:
1. From the top navigation, click the **+** button and select **New project**. 1. From the top navigation, click the **+** button and select **New project**.
1. Select **Create from Template**. 1. Select **Create from Template**.
...@@ -125,34 +118,37 @@ _Advanced options:_ ...@@ -125,34 +118,37 @@ _Advanced options:_
- [Use a custom domain](getting_started_part_three.md#adding-your-custom-domain-to-gitlab-pages) - [Use a custom domain](getting_started_part_three.md#adding-your-custom-domain-to-gitlab-pages)
- Apply [SSL/TLS certification](getting_started_part_three.md#ssltls-certificates) to your custom domain - Apply [SSL/TLS certification](getting_started_part_three.md#ssltls-certificates) to your custom domain
## Explore GitLab Pages ## Availability
To learn more about GitLab Pages, read the following tutorials:
- [Static websites and GitLab Pages domains](getting_started_part_one.md): Understand what is a static website, and how GitLab Pages default domains work If you're using GitLab.com, your website will be publicly available to the internet.
- [Projects for GitLab Pages and URL structure](getting_started_part_two.md): Forking projects and creating new ones from scratch, understanding URLs structure and baseurls If you're using self-managed instances (Core, Starter, Premium, or Ultimate),
- [GitLab Pages custom domains and SSL/TLS Certificates](getting_started_part_three.md): How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates your websites will be published on your own server, according to the
- [Creating and Tweaking GitLab CI/CD for GitLab Pages](getting_started_part_four.md): Understand how to create your own `.gitlab-ci.yml` for your site [Pages admin settings](../../../administration/pages/index.md) chosen by your sysadmin,
- [Exploring GitLab Pages](introduction.md): Technical aspects, specific configuration options, custom 404 pages, limitations who can opt for making them public or internal to your server.
### GitLab Pages with Static Site Generators (SSGs)
To understand more about SSGs, their advantages, and how to get the most from them
with Pages, read through this series:
- [SSGs part 1: Static vs dynamic websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/)
- [SSGs part 2: Modern static site generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/)
- [SSGs part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/)
### GitLab Pages with SSL/TLS certificates Note that, if you're using GitLab Pages default domain (`.gitlab.io`),
your website will be automatically secure and available under
HTTPS. If you're using your own custom domain, you can
optionally secure it with SSL/TLS certificates.
If you're using GitLab Pages default domain (`.gitlab.io`), your website will be ## Explore GitLab Pages
automatically secure and available under HTTPS. If you're using your own domain, you can
optionally secure it with SSL/TLS certificates. You can read the following
tutorials to learn how to use these third-party certificates with GitLab Pages:
- [CloudFlare](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) To learn more about configuration options for GitLab Pages, read the following:
- [Let's Encrypt](lets_encrypt_for_gitlab_pages.md)
| Document | Description |
| --- | --- |
| [Static websites and Pages domains](getting_started_part_one.md) | Understand what is a static website, and how GitLab Pages default domains work. |
| [Projects and URL structure](getting_started_part_two.md) | Forking projects and creating new ones from scratch, understanding URLs structure and baseurls. |
| [GitLab CI/CD for GitLab Pages](getting_started_part_four.md) | Understand how to create your own `.gitlab-ci.yml` for your site. |
| [Exploring GitLab Pages](introduction.md) | Technical aspects, specific configuration options, custom 404 pages, limitations. |
|---+---|
| [Custom domains and SSL/TLS Certificates](getting_started_part_three.md) | How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates. |
| [CloudFlare certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Secure your Pages site with CloudFlare certificates. |
| [Let's Encrypt certificates](lets_encrypt_for_gitlab_pages.md) | Secure your Pages site with Let's Encrypt certificates. |
|---+---|
| [Static vs dynamic websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/) | A conceptual overview on static versus dynamic sites. |
| [Modern static site generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/) | A conceptual overview on SSGs. |
| [Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) | An overview on using SSGs for GitLab Pages. |
## Advanced use ## Advanced use
...@@ -160,13 +156,13 @@ There are quite some great examples of GitLab Pages websites built for some ...@@ -160,13 +156,13 @@ There are quite some great examples of GitLab Pages websites built for some
specific reasons. These examples can teach you some advanced techniques specific reasons. These examples can teach you some advanced techniques
to use and adapt to your own needs: to use and adapt to your own needs:
- [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/) - [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/).
- [GitLab CI: Run jobs sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/2016/07/29/the-basics-of-gitlab-ci/) - [GitLab CI: Run jobs sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/2016/07/29/the-basics-of-gitlab-ci/).
- [GitLab CI: Deployment & environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) - [GitLab CI: Deployment & environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/).
- [Building a new GitLab docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) - [Building a new GitLab docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/).
- [Publish code coverage reports with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/) - [Publish code coverage reports with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/).
## Admin GitLab Pages for CE and EE ## Admin GitLab Pages for self-managed instances
Enable and configure GitLab Pages on your own instance (GitLab Community Edition and Enterprise Editions) with Enable and configure GitLab Pages on your own instance (GitLab Community Edition and Enterprise Editions) with
the [admin guide](../../../administration/pages/index.md). the [admin guide](../../../administration/pages/index.md).
......
...@@ -4,10 +4,17 @@ module Gitlab ...@@ -4,10 +4,17 @@ module Gitlab
module Auth module Auth
MissingPersonalAccessTokenError = Class.new(StandardError) MissingPersonalAccessTokenError = Class.new(StandardError)
# Scopes used for GitLab API access
API_SCOPES = [:api, :read_user].freeze
# Scopes used for GitLab Repository access
REPOSITORY_SCOPES = [:read_repository, :write_repository].freeze
# Scopes used for GitLab Docker Registry access
REGISTRY_SCOPES = [:read_registry].freeze REGISTRY_SCOPES = [:read_registry].freeze
# Scopes used for GitLab API access # Scopes used for GitLab as admin
API_SCOPES = [:api, :read_user, :sudo, :read_repository].freeze ADMIN_SCOPES = [:sudo].freeze
# Scopes used for OpenID Connect # Scopes used for OpenID Connect
OPENID_SCOPES = [:openid].freeze OPENID_SCOPES = [:openid].freeze
...@@ -161,7 +168,7 @@ module Gitlab ...@@ -161,7 +168,7 @@ module Gitlab
token = PersonalAccessTokensFinder.new(state: 'active').find_by_token(password) token = PersonalAccessTokensFinder.new(state: 'active').find_by_token(password)
if token && valid_scoped_token?(token, available_scopes) if token && valid_scoped_token?(token, all_available_scopes)
Gitlab::Auth::Result.new(token.user, nil, :personal_access_token, abilities_for_scopes(token.scopes)) Gitlab::Auth::Result.new(token.user, nil, :personal_access_token, abilities_for_scopes(token.scopes))
end end
end end
...@@ -178,7 +185,8 @@ module Gitlab ...@@ -178,7 +185,8 @@ module Gitlab
abilities_by_scope = { abilities_by_scope = {
api: full_authentication_abilities, api: full_authentication_abilities,
read_registry: [:read_container_image], read_registry: [:read_container_image],
read_repository: [:download_code] read_repository: [:download_code],
write_repository: [:download_code, :push_code]
} }
scopes.flat_map do |scope| scopes.flat_map do |scope|
...@@ -198,7 +206,7 @@ module Gitlab ...@@ -198,7 +206,7 @@ module Gitlab
scopes = abilities_for_scopes(token.scopes) scopes = abilities_for_scopes(token.scopes)
if valid_scoped_token?(token, available_scopes) if valid_scoped_token?(token, all_available_scopes)
Gitlab::Auth::Result.new(token, token.project, :deploy_token, scopes) Gitlab::Auth::Result.new(token, token.project, :deploy_token, scopes)
end end
end end
...@@ -224,7 +232,7 @@ module Gitlab ...@@ -224,7 +232,7 @@ module Gitlab
elsif token_handler.deploy_key_pushable?(project) elsif token_handler.deploy_key_pushable?(project)
read_write_authentication_abilities read_write_authentication_abilities
else else
read_authentication_abilities read_only_authentication_abilities
end end
if token_handler.token_valid?(encoded_token) if token_handler.token_valid?(encoded_token)
...@@ -260,7 +268,7 @@ module Gitlab ...@@ -260,7 +268,7 @@ module Gitlab
] ]
end end
def read_authentication_abilities def read_only_authentication_abilities
[ [
:read_project, :read_project,
:download_code, :download_code,
...@@ -269,7 +277,7 @@ module Gitlab ...@@ -269,7 +277,7 @@ module Gitlab
end end
def read_write_authentication_abilities def read_write_authentication_abilities
read_authentication_abilities + [ read_only_authentication_abilities + [
:push_code, :push_code,
:create_container_image :create_container_image
] ]
...@@ -281,15 +289,19 @@ module Gitlab ...@@ -281,15 +289,19 @@ module Gitlab
] ]
end end
def available_scopes(current_user = nil) def available_scopes_for(current_user)
scopes = API_SCOPES + registry_scopes scopes = non_admin_available_scopes
scopes.delete(:sudo) if current_user && !current_user.admin? scopes += ADMIN_SCOPES if current_user.admin?
scopes scopes
end end
def all_available_scopes
non_admin_available_scopes + ADMIN_SCOPES
end
# Other available scopes # Other available scopes
def optional_scopes def optional_scopes
available_scopes + OPENID_SCOPES + PROFILE_SCOPES - DEFAULT_SCOPES all_available_scopes + OPENID_SCOPES + PROFILE_SCOPES - DEFAULT_SCOPES
end end
def registry_scopes def registry_scopes
...@@ -300,6 +312,10 @@ module Gitlab ...@@ -300,6 +312,10 @@ module Gitlab
private private
def non_admin_available_scopes
API_SCOPES + REPOSITORY_SCOPES + registry_scopes
end
def find_build_by_token(token) def find_build_by_token(token)
::Ci::Build.running.find_by_token(token) ::Ci::Build.running.find_by_token(token)
end end
......
...@@ -5,7 +5,15 @@ describe Gitlab::Auth do ...@@ -5,7 +5,15 @@ describe Gitlab::Auth do
describe 'constants' do describe 'constants' do
it 'API_SCOPES contains all scopes for API access' do it 'API_SCOPES contains all scopes for API access' do
expect(subject::API_SCOPES).to eq %i[api read_user sudo read_repository] expect(subject::API_SCOPES).to eq %i[api read_user]
end
it 'ADMIN_SCOPES contains all scopes for ADMIN access' do
expect(subject::ADMIN_SCOPES).to eq %i[sudo]
end
it 'REPOSITORY_SCOPES contains all scopes for REPOSITORY access' do
expect(subject::REPOSITORY_SCOPES).to eq %i[read_repository write_repository]
end end
it 'OPENID_SCOPES contains all scopes for OpenID Connect' do it 'OPENID_SCOPES contains all scopes for OpenID Connect' do
...@@ -19,7 +27,29 @@ describe Gitlab::Auth do ...@@ -19,7 +27,29 @@ describe Gitlab::Auth do
it 'optional_scopes contains all non-default scopes' do it 'optional_scopes contains all non-default scopes' do
stub_container_registry_config(enabled: true) stub_container_registry_config(enabled: true)
expect(subject.optional_scopes).to eq %i[read_user sudo read_repository read_registry openid profile email] expect(subject.optional_scopes).to eq %i[read_user read_repository write_repository read_registry sudo openid profile email]
end
end
context 'available_scopes' do
it 'contains all non-default scopes' do
stub_container_registry_config(enabled: true)
expect(subject.all_available_scopes).to eq %i[api read_user read_repository write_repository read_registry sudo]
end
it 'contains for non-admin user all non-default scopes without ADMIN access' do
stub_container_registry_config(enabled: true)
user = create(:user, admin: false)
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_repository write_repository read_registry]
end
it 'contains for admin user all non-default scopes with ADMIN access' do
stub_container_registry_config(enabled: true)
user = create(:user, admin: true)
expect(subject.available_scopes_for(user)).to eq %i[api read_user read_repository write_repository read_registry sudo]
end end
context 'registry_scopes' do context 'registry_scopes' do
...@@ -122,7 +152,7 @@ describe Gitlab::Auth do ...@@ -122,7 +152,7 @@ describe Gitlab::Auth do
token = Gitlab::LfsToken.new(key).token token = Gitlab::LfsToken.new(key).token
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}") expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities)) expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_only_authentication_abilities))
end end
it 'does not try password auth before oauth' do it 'does not try password auth before oauth' do
...@@ -150,7 +180,7 @@ describe Gitlab::Auth do ...@@ -150,7 +180,7 @@ describe Gitlab::Auth do
token = Gitlab::LfsToken.new(key).token token = Gitlab::LfsToken.new(key).token
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}") expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities)) expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_only_authentication_abilities))
end end
end end
...@@ -182,8 +212,19 @@ describe Gitlab::Auth do ...@@ -182,8 +212,19 @@ describe Gitlab::Auth do
it 'succeeds for personal access tokens with the `api` scope' do it 'succeeds for personal access tokens with the `api` scope' do
personal_access_token = create(:personal_access_token, scopes: ['api']) personal_access_token = create(:personal_access_token, scopes: ['api'])
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') expect_results_with_abilities(personal_access_token, full_authentication_abilities)
expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_access_token, full_authentication_abilities)) end
it 'succeeds for personal access tokens with the `read_repository` scope' do
personal_access_token = create(:personal_access_token, scopes: ['read_repository'])
expect_results_with_abilities(personal_access_token, [:download_code])
end
it 'succeeds for personal access tokens with the `write_repository` scope' do
personal_access_token = create(:personal_access_token, scopes: ['write_repository'])
expect_results_with_abilities(personal_access_token, [:download_code, :push_code])
end end
context 'when registry is enabled' do context 'when registry is enabled' do
...@@ -194,28 +235,24 @@ describe Gitlab::Auth do ...@@ -194,28 +235,24 @@ describe Gitlab::Auth do
it 'succeeds for personal access tokens with the `read_registry` scope' do it 'succeeds for personal access tokens with the `read_registry` scope' do
personal_access_token = create(:personal_access_token, scopes: ['read_registry']) personal_access_token = create(:personal_access_token, scopes: ['read_registry'])
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') expect_results_with_abilities(personal_access_token, [:read_container_image])
expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_access_token, [:read_container_image]))
end end
end end
it 'succeeds if it is an impersonation token' do it 'succeeds if it is an impersonation token' do
impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api']) impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') expect_results_with_abilities(impersonation_token, full_authentication_abilities)
expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(impersonation_token.user, nil, :personal_access_token, full_authentication_abilities))
end end
it 'limits abilities based on scope' do it 'limits abilities based on scope' do
personal_access_token = create(:personal_access_token, scopes: %w[read_user sudo]) personal_access_token = create(:personal_access_token, scopes: %w[read_user sudo])
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '') expect_results_with_abilities(personal_access_token, [])
expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_access_token, []))
end end
it 'fails if password is nil' do it 'fails if password is nil' do
expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '') expect_results_with_abilities(nil, nil, false)
expect(gl_auth.find_for_git_client('', nil, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
end end
end end
...@@ -479,7 +516,7 @@ describe Gitlab::Auth do ...@@ -479,7 +516,7 @@ describe Gitlab::Auth do
] ]
end end
def read_authentication_abilities def read_only_authentication_abilities
[ [
:read_project, :read_project,
:download_code, :download_code,
...@@ -488,7 +525,7 @@ describe Gitlab::Auth do ...@@ -488,7 +525,7 @@ describe Gitlab::Auth do
end end
def read_write_authentication_abilities def read_write_authentication_abilities
read_authentication_abilities + [ read_only_authentication_abilities + [
:push_code, :push_code,
:create_container_image :create_container_image
] ]
...@@ -499,4 +536,10 @@ describe Gitlab::Auth do ...@@ -499,4 +536,10 @@ describe Gitlab::Auth do
:admin_container_image :admin_container_image
] ]
end end
def expect_results_with_abilities(personal_access_token, abilities, success = true)
expect(gl_auth).to receive(:rate_limit!).with('ip', success: success, login: '')
expect(gl_auth.find_for_git_client('', personal_access_token&.token, project: nil, ip: 'ip'))
.to eq(Gitlab::Auth::Result.new(personal_access_token&.user, nil, personal_access_token.nil? ? nil : :personal_access_token, abilities))
end
end end
...@@ -549,14 +549,14 @@ describe 'Git HTTP requests' do ...@@ -549,14 +549,14 @@ describe 'Git HTTP requests' do
it 'rejects pulls with personal access token error message' do it 'rejects pulls with personal access token error message' do
download(path, user: user.username, password: user.password) do |response| download(path, user: user.username, password: user.password) do |response|
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'read_repository\' or \'write_repository\' scope for Git over HTTP')
end end
end end
it 'rejects the push attempt with personal access token error message' do it 'rejects the push attempt with personal access token error message' do
upload(path, user: user.username, password: user.password) do |response| upload(path, user: user.username, password: user.password) do |response|
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'read_repository\' or \'write_repository\' scope for Git over HTTP')
end end
end end
end end
...@@ -566,6 +566,47 @@ describe 'Git HTTP requests' do ...@@ -566,6 +566,47 @@ describe 'Git HTTP requests' do
it_behaves_like 'pulls are allowed' it_behaves_like 'pulls are allowed'
it_behaves_like 'pushes are allowed' it_behaves_like 'pushes are allowed'
it 'rejects the push attempt for read_repository scope' do
read_access_token = create(:personal_access_token, user: user, scopes: [:read_repository])
upload(path, user: user.username, password: read_access_token.token) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to include('You are not allowed to upload code')
end
end
it 'accepts the push attempt for write_repository scope' do
write_access_token = create(:personal_access_token, user: user, scopes: [:write_repository])
upload(path, user: user.username, password: write_access_token.token) do |response|
expect(response).to have_gitlab_http_status(:ok)
end
end
it 'accepts the pull attempt for read_repository scope' do
read_access_token = create(:personal_access_token, user: user, scopes: [:read_repository])
download(path, user: user.username, password: read_access_token.token) do |response|
expect(response).to have_gitlab_http_status(:ok)
end
end
it 'accepts the pull attempt for api scope' do
read_access_token = create(:personal_access_token, user: user, scopes: [:api])
download(path, user: user.username, password: read_access_token.token) do |response|
expect(response).to have_gitlab_http_status(:ok)
end
end
it 'accepts the push attempt for api scope' do
write_access_token = create(:personal_access_token, user: user, scopes: [:api])
upload(path, user: user.username, password: write_access_token.token) do |response|
expect(response).to have_gitlab_http_status(:ok)
end
end
end end
end end
...@@ -577,14 +618,14 @@ describe 'Git HTTP requests' do ...@@ -577,14 +618,14 @@ describe 'Git HTTP requests' do
it 'rejects pulls with personal access token error message' do it 'rejects pulls with personal access token error message' do
download(path, user: 'foo', password: 'bar') do |response| download(path, user: 'foo', password: 'bar') do |response|
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'read_repository\' or \'write_repository\' scope for Git over HTTP')
end end
end end
it 'rejects pushes with personal access token error message' do it 'rejects pushes with personal access token error message' do
upload(path, user: 'foo', password: 'bar') do |response| upload(path, user: 'foo', password: 'bar') do |response|
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'read_repository\' or \'write_repository\' scope for Git over HTTP')
end end
end end
...@@ -598,7 +639,7 @@ describe 'Git HTTP requests' do ...@@ -598,7 +639,7 @@ describe 'Git HTTP requests' do
it 'does not display the personal access token error message' do it 'does not display the personal access token error message' do
upload(path, user: 'foo', password: 'bar') do |response| upload(path, user: 'foo', password: 'bar') do |response|
expect(response).to have_gitlab_http_status(:unauthorized) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).not_to include('You must use a personal access token with \'read_repository\' or \'write_repository\' scope for Git over HTTP')
end end
end end
end end
......
...@@ -142,7 +142,7 @@ describe JwtController do ...@@ -142,7 +142,7 @@ describe JwtController do
end end
it 'allows read access' do it 'allows read access' do
expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_authentication_abilities) expect(service).to receive(:execute).with(authentication_abilities: Gitlab::Auth.read_only_authentication_abilities)
get '/jwt/auth', params: parameters get '/jwt/auth', params: parameters
end end
......
...@@ -187,7 +187,7 @@ describe 'OpenID Connect requests' do ...@@ -187,7 +187,7 @@ describe 'OpenID Connect requests' do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
expect(json_response['issuer']).to eq('http://localhost') expect(json_response['issuer']).to eq('http://localhost')
expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys') expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
expect(json_response['scopes_supported']).to eq(%w[api read_user sudo read_repository openid profile email]) expect(json_response['scopes_supported']).to eq(%w[api read_user read_repository write_repository sudo openid profile email])
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment