Commit 36b3210b authored by Timothy Andrew's avatar Timothy Andrew

Validate access token scopes in `Gitlab::Auth`

- This module is used for git-over-http, as well as JWT.

- The only valid scope here is `api`, currently.
parent 7fa06ed5
...@@ -92,7 +92,7 @@ module Gitlab ...@@ -92,7 +92,7 @@ module Gitlab
def oauth_access_token_check(login, password) def oauth_access_token_check(login, password)
if login == "oauth2" && password.present? if login == "oauth2" && password.present?
token = Doorkeeper::AccessToken.by_token(password) token = Doorkeeper::AccessToken.by_token(password)
if token && token.accessible? if token && token.accessible? && token_has_scope?(token)
user = User.find_by(id: token.resource_owner_id) user = User.find_by(id: token.resource_owner_id)
Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities) Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities)
end end
...@@ -101,12 +101,20 @@ module Gitlab ...@@ -101,12 +101,20 @@ module Gitlab
def personal_access_token_check(login, password) def personal_access_token_check(login, password)
if login && password if login && password
user = User.find_by_personal_access_token(password) token = PersonalAccessToken.active.find_by_token(password)
validation = User.by_login(login) validation = User.by_login(login)
Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities) if user.present? && user == validation
if token && token.user == validation && token_has_scope?(token)
Gitlab::Auth::Result.new(validation, nil, :personal_token, full_authentication_abilities)
end
end end
end end
def token_has_scope?(token)
AccessTokenValidationService.sufficient_scope?(token, ['api'])
end
def lfs_token_check(login, password) def lfs_token_check(login, password)
deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/) deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/)
......
...@@ -79,16 +79,48 @@ describe Gitlab::Auth, lib: true do ...@@ -79,16 +79,48 @@ describe Gitlab::Auth, lib: true do
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_authentication_abilities))
end end
it 'recognizes OAuth tokens' do context "while using OAuth tokens as passwords" do
it 'succeeds for OAuth tokens with the `api` scope' do
user = create(:user) user = create(:user)
application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user)
token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id) token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api")
ip = 'ip' ip = 'ip'
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'oauth2') expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'oauth2')
expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities)) expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities))
end end
it 'fails for OAuth tokens with other scopes' do
user = create(:user)
application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user)
token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "read_user")
ip = 'ip'
expect(gl_auth).to receive(:rate_limit!).with(ip, success: false, login: 'oauth2')
expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, nil))
end
end
context "while using personal access tokens as passwords" do
it 'succeeds for personal access tokens with the `api` scope' do
user = create(:user)
personal_access_token = create(:personal_access_token, user: user, scopes: ['api'])
ip = 'ip'
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: user.email)
expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities))
end
it 'fails for personal access tokens with other scopes' do
user = create(:user)
personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
ip = 'ip'
expect(gl_auth).to receive(:rate_limit!).with(ip, success: false, login: user.email)
expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, nil))
end
end
it 'returns double nil for invalid credentials' do it 'returns double nil for invalid credentials' do
login = 'foo' login = 'foo'
ip = 'ip' ip = 'ip'
......
...@@ -230,7 +230,7 @@ describe 'Git HTTP requests', lib: true do ...@@ -230,7 +230,7 @@ describe 'Git HTTP requests', lib: true do
context "when an oauth token is provided" do context "when an oauth token is provided" do
before do before do
application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user)
@token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id) @token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api")
end end
it "downloads get status 200" do it "downloads get status 200" 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