Commit aba93fe2 authored by Steve Abrams's avatar Steve Abrams Committed by Dmitriy Zaporozhets

OAuth2 support for GitLab personal access tokens

PATs are accepted using the OAuth2 compliant header
"Authorization: Bearer {token}" in order to allow for
OAuth requests while 2FA is enabled.
parent 30a0d460
......@@ -7,6 +7,7 @@ class PersonalAccessToken < ApplicationRecord
add_authentication_token_field :token, digest: true
REDIS_EXPIRY_TIME = 3.minutes
TOKEN_LENGTH = 20
serialize :scopes, Array # rubocop:disable Cop/ActiveRecordSerialize
......
---
title: Personal access tokens are accepted using OAuth2 header format
merge_request: 30277
author:
type: added
......@@ -272,6 +272,12 @@ Example of using the personal access token in a header:
curl --header "Private-Token: <your_access_token>" https://gitlab.example.com/api/v4/projects
```
You can also use personal access tokens with OAuth-compliant headers:
```shell
curl --header "Authorization: Bearer <your_access_token>" https://gitlab.example.com/api/v4/projects
```
Read more about [personal access tokens][pat].
### Session cookie
......
......@@ -49,35 +49,32 @@ Registry.
## Authenticating to the GitLab NPM Registry
If a project is private or you want to upload an NPM package to GitLab,
credentials will need to be provided for authentication. Support is available
only for [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow).
credentials will need to be provided for authentication. Support is available for [OAuth tokens](../../../api/oauth2.md#resource-owner-password-credentials-flow) or [personal access tokens](../../profile/personal_access_tokens.md).
CAUTION: **2FA not supported:**
Authentication for personal access tokens is not yet supported
([#9140](https://gitlab.com/gitlab-org/gitlab-ee/issues/9140)). If you have 2FA
enabled, you won't be able to authenticate to the GitLab NPM Registry.
CAUTION: **2FA is only supported with personal access tokens:**
If you have 2FA enabled, you need to use a [personal access token](../../profile/personal_access_tokens.md) with OAuth headers. Standard OAuth tokens won't be able to authenticate to the GitLab NPM Registry.
### Authenticating with an OAuth token
To authenticate with an [OAuth token](../../../api/oauth2.md#resource-owner-password-credentials-flow),
add a corresponding section to your `.npmrc` file:
To authenticate with an [OAuth token](../../../api/oauth2.md#resource-owner-password-credentials-flow)
or [personal access token](../../profile/personal_access_tokens.md), add a corresponding section to your `.npmrc` file:
```ini
; Set URL for your scoped packages.
; For example package with name `@foo/bar` will use this URL for download
@foo:registry=https://gitlab.com/api/v4/packages/npm/
; Add the OAuth token for the scoped packages URL. This will allow you to download
; Add the token for the scoped packages URL. This will allow you to download
; `@foo/` packages from private projects.
//gitlab.com/api/v4/packages/npm/:_authToken=<your_oauth_token>
//gitlab.com/api/v4/packages/npm/:_authToken=<your_token>
; Add OAuth token for uploading to the registry. Replace <your_project_id>
; Add token for uploading to the registry. Replace <your_project_id>
; with the project you want your package to be uploaded to.
//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken=<your_oauth_token>
//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken=<your_token>
```
Replace `<your_project_id>` with your project ID which can be found on the home page
of your project and `<your_oauth_token>` with your OAuth token.
of your project and `<your_token>` with your OAuth or personal access token.
If you have a self-hosted GitLab installation, replace `gitlab.com` with your
domain name.
......
......@@ -90,8 +90,8 @@ module Gitlab
def find_personal_access_token
token =
current_request.params[PRIVATE_TOKEN_PARAM].presence ||
current_request.env[PRIVATE_TOKEN_HEADER].presence
current_request.env[PRIVATE_TOKEN_HEADER].presence ||
parsed_oauth_token
return unless token
# Expiration, revocation and scopes are verified in `validate_access_token!`
......@@ -99,9 +99,12 @@ module Gitlab
end
def find_oauth_access_token
token = Doorkeeper::OAuth::Token.from_request(current_request, *Doorkeeper.configuration.access_token_methods)
token = parsed_oauth_token
return unless token
# PATs with OAuth headers are not handled by OauthAccessToken
return if matches_personal_access_token_length?(token)
# Expiration, revocation and scopes are verified in `validate_access_token!`
oauth_token = OauthAccessToken.by_token(token)
raise UnauthorizedError unless oauth_token
......@@ -110,6 +113,14 @@ module Gitlab
oauth_token
end
def parsed_oauth_token
Doorkeeper::OAuth::Token.from_request(current_request, *Doorkeeper.configuration.access_token_methods)
end
def matches_personal_access_token_length?(token)
token.length == PersonalAccessToken::TOKEN_LENGTH
end
# Check if the request is GET/HEAD, or if CSRF token is valid.
def verified_request?
Gitlab::RequestForgeryProtection.verified?(current_request.env)
......
......@@ -138,6 +138,20 @@ describe Gitlab::Auth::UserAuthFinders do
expect { find_user_from_access_token }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
end
context 'with OAuth headers' do
it 'returns user' do
env['HTTP_AUTHORIZATION'] = "Bearer #{personal_access_token.token}"
expect(find_user_from_access_token).to eq user
end
it 'returns exception if invalid personal_access_token' do
env['HTTP_AUTHORIZATION'] = 'Bearer invalid_20byte_token'
expect { find_personal_access_token }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
end
end
describe '#find_user_from_web_access_token' do
......
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