Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
e40e3fdc
Commit
e40e3fdc
authored
Aug 25, 2016
by
Patricio Cano
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added LFS support to SSH
- Required on the GitLab Rails side is mostly authentication and API related.
parent
f8bd9625
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
169 additions
and
21 deletions
+169
-21
app/controllers/projects/git_http_client_controller.rb
app/controllers/projects/git_http_client_controller.rb
+30
-12
app/helpers/lfs_helper.rb
app/helpers/lfs_helper.rb
+1
-1
app/models/deploy_key.rb
app/models/deploy_key.rb
+5
-0
app/models/user.rb
app/models/user.rb
+2
-1
db/migrate/20160825173042_add_lfs_token_to_users.rb
db/migrate/20160825173042_add_lfs_token_to_users.rb
+16
-0
db/migrate/20160825182924_add_lfs_token_to_keys.rb
db/migrate/20160825182924_add_lfs_token_to_keys.rb
+16
-0
lib/api/entities.rb
lib/api/entities.rb
+1
-1
lib/api/internal.rb
lib/api/internal.rb
+12
-1
lib/gitlab/auth.rb
lib/gitlab/auth.rb
+12
-1
spec/lib/gitlab/auth_spec.rb
spec/lib/gitlab/auth_spec.rb
+16
-0
spec/models/concerns/token_authenticatable_spec.rb
spec/models/concerns/token_authenticatable_spec.rb
+20
-0
spec/requests/api/internal_spec.rb
spec/requests/api/internal_spec.rb
+22
-4
spec/requests/lfs_http_spec.rb
spec/requests/lfs_http_spec.rb
+16
-0
No files found.
app/controllers/projects/git_http_client_controller.rb
View file @
e40e3fdc
...
@@ -4,6 +4,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
...
@@ -4,6 +4,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
include
ActionController
::
HttpAuthentication
::
Basic
include
ActionController
::
HttpAuthentication
::
Basic
include
KerberosSpnegoHelper
include
KerberosSpnegoHelper
class
MissingPersonalTokenError
<
StandardError
;
end
attr_reader
:user
attr_reader
:user
# Git clients will not know what authenticity token to send along
# Git clients will not know what authenticity token to send along
...
@@ -21,18 +23,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
...
@@ -21,18 +23,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
if
allow_basic_auth?
&&
basic_auth_provided?
if
allow_basic_auth?
&&
basic_auth_provided?
login
,
password
=
user_name_and_password
(
request
)
login
,
password
=
user_name_and_password
(
request
)
auth_result
=
Gitlab
::
Auth
.
find_for_git_client
(
login
,
password
,
project:
project
,
ip:
request
.
ip
)
handle_authentication
(
login
,
password
)
if
auth_result
.
type
==
:ci
&&
download_request?
@ci
=
true
elsif
auth_result
.
type
==
:oauth
&&
!
download_request?
# Not allowed
elsif
auth_result
.
type
==
:missing_personal_token
render_missing_personal_token
return
# Render above denied access, nothing left to do
else
@user
=
auth_result
.
user
end
if
ci?
||
user
if
ci?
||
user
return
# Allow access
return
# Allow access
...
@@ -48,6 +40,10 @@ class Projects::GitHttpClientController < Projects::ApplicationController
...
@@ -48,6 +40,10 @@ class Projects::GitHttpClientController < Projects::ApplicationController
send_challenges
send_challenges
render
plain:
"HTTP Basic: Access denied
\n
"
,
status:
401
render
plain:
"HTTP Basic: Access denied
\n
"
,
status:
401
rescue
MissingPersonalTokenError
render_missing_personal_token
return
end
end
def
basic_auth_provided?
def
basic_auth_provided?
...
@@ -118,6 +114,28 @@ class Projects::GitHttpClientController < Projects::ApplicationController
...
@@ -118,6 +114,28 @@ class Projects::GitHttpClientController < Projects::ApplicationController
@ci
.
present?
@ci
.
present?
end
end
def
handle_authentication
(
login
,
password
)
auth_result
=
Gitlab
::
Auth
.
find_for_git_client
(
login
,
password
,
project:
project
,
ip:
request
.
ip
)
if
auth_result
.
type
==
:ci
&&
download_request?
@ci
=
true
elsif
auth_result
.
type
==
:oauth
&&
!
download_request?
# Not allowed
elsif
auth_result
.
type
==
:missing_personal_token
raise
MissingPersonalTokenError
elsif
auth_result
.
type
==
:lfs_deploy_token
&&
download_request?
@lfs_deploy_key
=
true
@user
=
auth_result
.
user
else
@user
=
auth_result
.
user
end
end
def
lfs_deploy_key?
key
=
user
@lfs_deploy_key
.
present?
&&
(
key
&&
key
.
projects
.
include?
(
project
))
end
def
verify_workhorse_api!
def
verify_workhorse_api!
Gitlab
::
Workhorse
.
verify_api_request!
(
request
.
headers
)
Gitlab
::
Workhorse
.
verify_api_request!
(
request
.
headers
)
end
end
...
...
app/helpers/lfs_helper.rb
View file @
e40e3fdc
...
@@ -25,7 +25,7 @@ module LfsHelper
...
@@ -25,7 +25,7 @@ module LfsHelper
def
lfs_download_access?
def
lfs_download_access?
return
false
unless
project
.
lfs_enabled?
return
false
unless
project
.
lfs_enabled?
project
.
public?
||
ci?
||
(
user
&&
user
.
can?
(
:download_code
,
project
))
project
.
public?
||
ci?
||
lfs_deploy_key?
||
(
user
&&
user
.
can?
(
:download_code
,
project
))
end
end
def
lfs_upload_access?
def
lfs_upload_access?
...
...
app/models/deploy_key.rb
View file @
e40e3fdc
class
DeployKey
<
Key
class
DeployKey
<
Key
include
TokenAuthenticatable
add_authentication_token_field
:lfs_token
has_many
:deploy_keys_projects
,
dependent: :destroy
has_many
:deploy_keys_projects
,
dependent: :destroy
has_many
:projects
,
through: :deploy_keys_projects
has_many
:projects
,
through: :deploy_keys_projects
before_save
:ensure_lfs_token
scope
:in_projects
,
->
(
projects
)
{
joins
(
:deploy_keys_projects
).
where
(
'deploy_keys_projects.project_id in (?)'
,
projects
)
}
scope
:in_projects
,
->
(
projects
)
{
joins
(
:deploy_keys_projects
).
where
(
'deploy_keys_projects.project_id in (?)'
,
projects
)
}
scope
:are_public
,
->
{
where
(
public:
true
)
}
scope
:are_public
,
->
{
where
(
public:
true
)
}
...
...
app/models/user.rb
View file @
e40e3fdc
...
@@ -13,6 +13,7 @@ class User < ActiveRecord::Base
...
@@ -13,6 +13,7 @@ class User < ActiveRecord::Base
DEFAULT_NOTIFICATION_LEVEL
=
:participating
DEFAULT_NOTIFICATION_LEVEL
=
:participating
add_authentication_token_field
:authentication_token
add_authentication_token_field
:authentication_token
add_authentication_token_field
:lfs_token
default_value_for
:admin
,
false
default_value_for
:admin
,
false
default_value_for
(
:external
)
{
current_application_settings
.
user_default_external
}
default_value_for
(
:external
)
{
current_application_settings
.
user_default_external
}
...
@@ -117,7 +118,7 @@ class User < ActiveRecord::Base
...
@@ -117,7 +118,7 @@ class User < ActiveRecord::Base
before_validation
:set_public_email
,
if:
->
(
user
)
{
user
.
public_email_changed?
}
before_validation
:set_public_email
,
if:
->
(
user
)
{
user
.
public_email_changed?
}
after_update
:update_emails_with_primary_email
,
if:
->
(
user
)
{
user
.
email_changed?
}
after_update
:update_emails_with_primary_email
,
if:
->
(
user
)
{
user
.
email_changed?
}
before_save
:ensure_authentication_token
before_save
:ensure_authentication_token
,
:ensure_lfs_token
before_save
:ensure_external_user_rights
before_save
:ensure_external_user_rights
after_save
:ensure_namespace_correct
after_save
:ensure_namespace_correct
after_initialize
:set_projects_limit
after_initialize
:set_projects_limit
...
...
db/migrate/20160825173042_add_lfs_token_to_users.rb
0 → 100644
View file @
e40e3fdc
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class
AddLfsTokenToUsers
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME
=
false
disable_ddl_transaction!
def
change
add_column
:users
,
:lfs_token
,
:string
add_concurrent_index
:users
,
:lfs_token
end
end
db/migrate/20160825182924_add_lfs_token_to_keys.rb
0 → 100644
View file @
e40e3fdc
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class
AddLfsTokenToKeys
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME
=
false
disable_ddl_transaction!
def
change
add_column
:keys
,
:lfs_token
,
:string
add_concurrent_index
:keys
,
:lfs_token
end
end
lib/api/entities.rb
View file @
e40e3fdc
module
API
module
API
module
Entities
module
Entities
class
UserSafe
<
Grape
::
Entity
class
UserSafe
<
Grape
::
Entity
expose
:name
,
:username
expose
:name
,
:username
,
:lfs_token
end
end
class
UserBasic
<
UserSafe
class
UserBasic
<
UserSafe
...
...
lib/api/internal.rb
View file @
e40e3fdc
...
@@ -69,6 +69,10 @@ module API
...
@@ -69,6 +69,10 @@ module API
else
else
project
.
repository
.
path_to_repo
project
.
repository
.
path_to_repo
end
end
# Return HTTP full path, so that gitlab-shell has this information
# ready for git-lfs-authenticate
response
[
:repository_http_path
]
=
project
.
http_url_to_repo
end
end
response
response
...
@@ -83,7 +87,14 @@ module API
...
@@ -83,7 +87,14 @@ module API
#
#
get
"/discover"
do
get
"/discover"
do
key
=
Key
.
find
(
params
[
:key_id
])
key
=
Key
.
find
(
params
[
:key_id
])
present
key
.
user
,
with:
Entities
::
UserSafe
user
=
key
.
user
if
user
user
.
ensure_lfs_token!
present
user
,
with:
Entities
::
UserSafe
else
key
.
ensure_lfs_token!
{
username:
'lfs-deploy-key'
,
lfs_token:
key
.
lfs_token
}
end
end
end
get
"/check"
do
get
"/check"
do
...
...
lib/gitlab/auth.rb
View file @
e40e3fdc
...
@@ -79,12 +79,13 @@ module Gitlab
...
@@ -79,12 +79,13 @@ module Gitlab
result
=
result
=
user_with_password_for_git
(
login
,
password
)
||
user_with_password_for_git
(
login
,
password
)
||
oauth_access_token_check
(
login
,
password
)
||
oauth_access_token_check
(
login
,
password
)
||
lfs_token_check
(
login
,
password
)
||
personal_access_token_check
(
login
,
password
)
personal_access_token_check
(
login
,
password
)
if
result
if
result
result
.
type
=
nil
unless
result
.
user
result
.
type
=
nil
unless
result
.
user
if
result
.
user
&&
result
.
user
.
two_factor_enabled?
&&
result
.
type
==
:gitlab_or_ldap
if
result
.
user
&&
result
.
type
==
:gitlab_or_ldap
&&
result
.
user
.
two_factor_enabled?
result
.
type
=
:missing_personal_token
result
.
type
=
:missing_personal_token
end
end
end
end
...
@@ -114,6 +115,16 @@ module Gitlab
...
@@ -114,6 +115,16 @@ module Gitlab
Result
.
new
(
user
,
:personal_token
)
if
user
==
validation
Result
.
new
(
user
,
:personal_token
)
if
user
==
validation
end
end
end
end
def
lfs_token_check
(
login
,
password
)
if
login
==
'lfs-deploy-key'
key
=
DeployKey
.
find_by_lfs_token
(
password
)
Result
.
new
(
key
,
:lfs_deploy_token
)
if
key
else
user
=
User
.
find_by_lfs_token
(
password
)
Result
.
new
(
user
,
:lfs_token
)
if
user
&&
user
.
username
==
login
end
end
end
end
end
end
end
end
spec/lib/gitlab/auth_spec.rb
View file @
e40e3fdc
...
@@ -23,6 +23,22 @@ describe Gitlab::Auth, lib: true do
...
@@ -23,6 +23,22 @@ describe Gitlab::Auth, lib: true do
expect
(
gl_auth
.
find_for_git_client
(
user
.
username
,
'password'
,
project:
nil
,
ip:
ip
)).
to
eq
(
Gitlab
::
Auth
::
Result
.
new
(
user
,
:gitlab_or_ldap
))
expect
(
gl_auth
.
find_for_git_client
(
user
.
username
,
'password'
,
project:
nil
,
ip:
ip
)).
to
eq
(
Gitlab
::
Auth
::
Result
.
new
(
user
,
:gitlab_or_ldap
))
end
end
it
'recognizes user lfs tokens'
do
user
=
create
(
:user
)
ip
=
'ip'
expect
(
gl_auth
).
to
receive
(
:rate_limit!
).
with
(
ip
,
success:
true
,
login:
user
.
username
)
expect
(
gl_auth
.
find_for_git_client
(
user
.
username
,
user
.
lfs_token
,
project:
nil
,
ip:
ip
)).
to
eq
(
Gitlab
::
Auth
::
Result
.
new
(
user
,
:lfs_token
))
end
it
'recognizes deploy key lfs tokens'
do
key
=
create
(
:deploy_key
)
ip
=
'ip'
expect
(
gl_auth
).
to
receive
(
:rate_limit!
).
with
(
ip
,
success:
true
,
login:
'lfs-deploy-key'
)
expect
(
gl_auth
.
find_for_git_client
(
'lfs-deploy-key'
,
key
.
lfs_token
,
project:
nil
,
ip:
ip
)).
to
eq
(
Gitlab
::
Auth
::
Result
.
new
(
key
,
:lfs_deploy_token
))
end
it
'recognizes OAuth tokens'
do
it
'recognizes OAuth tokens'
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
)
...
...
spec/models/concerns/token_authenticatable_spec.rb
View file @
e40e3fdc
...
@@ -18,6 +18,26 @@ describe User, 'TokenAuthenticatable' do
...
@@ -18,6 +18,26 @@ describe User, 'TokenAuthenticatable' do
subject
{
create
(
:user
).
send
(
token_field
)
}
subject
{
create
(
:user
).
send
(
token_field
)
}
it
{
is_expected
.
to
be_a
String
}
it
{
is_expected
.
to
be_a
String
}
end
end
describe
'lfs token'
do
let
(
:token_field
)
{
:lfs_token
}
it_behaves_like
'TokenAuthenticatable'
describe
'ensure it'
do
subject
{
create
(
:user
).
send
(
token_field
)
}
it
{
is_expected
.
to
be_a
String
}
end
end
end
describe
DeployKey
,
'TokenAuthenticatable'
do
let
(
:token_field
)
{
:lfs_token
}
it_behaves_like
'TokenAuthenticatable'
describe
'ensures authentication token'
do
subject
{
create
(
:deploy_key
).
send
(
token_field
)
}
it
{
is_expected
.
to
be_a
String
}
end
end
end
describe
ApplicationSetting
,
'TokenAuthenticatable'
do
describe
ApplicationSetting
,
'TokenAuthenticatable'
do
...
...
spec/requests/api/internal_spec.rb
View file @
e40e3fdc
...
@@ -101,12 +101,28 @@ describe API::API, api: true do
...
@@ -101,12 +101,28 @@ describe API::API, api: true do
end
end
describe
"GET /internal/discover"
do
describe
"GET /internal/discover"
do
it
do
context
'user key'
do
get
(
api
(
"/internal/discover"
),
key_id:
key
.
id
,
secret_token:
secret_token
)
it
'returns the correct information about the key'
do
get
(
api
(
"/internal/discover"
),
key_id:
key
.
id
,
secret_token:
secret_token
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'name'
]).
to
eq
(
user
.
name
)
expect
(
json_response
[
'lfs_token'
]).
to
eq
(
user
.
lfs_token
)
end
end
expect
(
json_response
[
'name'
]).
to
eq
(
user
.
name
)
context
'deploy key'
do
let
(
:key
)
{
create
(
:deploy_key
)
}
it
'returns the correct information about the key'
do
get
(
api
(
"/internal/discover"
),
key_id:
key
.
id
,
secret_token:
secret_token
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
'username'
]).
to
eq
(
'lfs-deploy-key'
)
expect
(
json_response
[
'lfs_token'
]).
to
eq
(
key
.
lfs_token
)
end
end
end
end
end
...
@@ -143,6 +159,7 @@ describe API::API, api: true do
...
@@ -143,6 +159,7 @@ describe API::API, api: true do
expect
(
response
).
to
have_http_status
(
200
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
"status"
]).
to
be_truthy
expect
(
json_response
[
"status"
]).
to
be_truthy
expect
(
json_response
[
"repository_path"
]).
to
eq
(
project
.
repository
.
path_to_repo
)
expect
(
json_response
[
"repository_path"
]).
to
eq
(
project
.
repository
.
path_to_repo
)
expect
(
json_response
[
"repository_http_path"
]).
to
eq
(
project
.
http_url_to_repo
)
end
end
end
end
...
@@ -153,6 +170,7 @@ describe API::API, api: true do
...
@@ -153,6 +170,7 @@ describe API::API, api: true do
expect
(
response
).
to
have_http_status
(
200
)
expect
(
response
).
to
have_http_status
(
200
)
expect
(
json_response
[
"status"
]).
to
be_truthy
expect
(
json_response
[
"status"
]).
to
be_truthy
expect
(
json_response
[
"repository_path"
]).
to
eq
(
project
.
repository
.
path_to_repo
)
expect
(
json_response
[
"repository_path"
]).
to
eq
(
project
.
repository
.
path_to_repo
)
expect
(
json_response
[
"repository_http_path"
]).
to
eq
(
project
.
http_url_to_repo
)
end
end
end
end
end
end
...
...
spec/requests/lfs_http_spec.rb
View file @
e40e3fdc
...
@@ -244,6 +244,18 @@ describe 'Git LFS API and storage' do
...
@@ -244,6 +244,18 @@ describe 'Git LFS API and storage' do
end
end
end
end
context
'when deploy key is authorized'
do
let
(
:key
)
{
create
(
:deploy_key
)
}
let
(
:authorization
)
{
authorize_deploy_key
}
let
(
:update_permissions
)
do
project
.
deploy_keys
<<
key
project
.
lfs_objects
<<
lfs_object
end
it_behaves_like
'responds with a file'
end
context
'when CI is authorized'
do
context
'when CI is authorized'
do
let
(
:authorization
)
{
authorize_ci_project
}
let
(
:authorization
)
{
authorize_ci_project
}
...
@@ -904,6 +916,10 @@ describe 'Git LFS API and storage' do
...
@@ -904,6 +916,10 @@ describe 'Git LFS API and storage' do
ActionController
::
HttpAuthentication
::
Basic
.
encode_credentials
(
user
.
username
,
user
.
password
)
ActionController
::
HttpAuthentication
::
Basic
.
encode_credentials
(
user
.
username
,
user
.
password
)
end
end
def
authorize_deploy_key
ActionController
::
HttpAuthentication
::
Basic
.
encode_credentials
(
'lfs-deploy-key'
,
key
.
lfs_token
)
end
def
fork_project
(
project
,
user
,
object
=
nil
)
def
fork_project
(
project
,
user
,
object
=
nil
)
allow
(
RepositoryForkWorker
).
to
receive
(
:perform_async
).
and_return
(
true
)
allow
(
RepositoryForkWorker
).
to
receive
(
:perform_async
).
and_return
(
true
)
Projects
::
ForkService
.
new
(
project
,
user
,
{}).
execute
Projects
::
ForkService
.
new
(
project
,
user
,
{}).
execute
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment