Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-shell
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
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gitlab-shell
Commits
2100c3d2
Commit
2100c3d2
authored
Feb 12, 2015
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into git-annex
Conflicts: lib/gitlab_shell.rb
parents
849d8fdc
f61186ba
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
171 additions
and
75 deletions
+171
-75
bin/check
bin/check
+10
-5
lib/gitlab_access.rb
lib/gitlab_access.rb
+13
-8
lib/gitlab_net.rb
lib/gitlab_net.rb
+47
-40
lib/gitlab_post_receive.rb
lib/gitlab_post_receive.rb
+7
-3
lib/gitlab_shell.rb
lib/gitlab_shell.rb
+12
-14
spec/gitlab_access_spec.rb
spec/gitlab_access_spec.rb
+45
-4
spec/gitlab_net_spec.rb
spec/gitlab_net_spec.rb
+21
-1
spec/gitlab_shell_spec.rb
spec/gitlab_shell_spec.rb
+16
-0
No files found.
bin/check
View file @
2100c3d2
...
@@ -8,13 +8,18 @@ require_relative '../lib/gitlab_net'
...
@@ -8,13 +8,18 @@ require_relative '../lib/gitlab_net'
#
#
print
"Check GitLab API access: "
print
"Check GitLab API access: "
resp
=
GitlabNet
.
new
.
check
begin
if
resp
.
code
==
"200"
resp
=
GitlabNet
.
new
.
check
print
'OK'
if
resp
.
code
==
"200"
else
print
'OK'
abort
"FAILED. code:
#{
resp
.
code
}
"
else
abort
"FAILED. code:
#{
resp
.
code
}
"
end
rescue
GitlabNet
::
ApiUnreachableError
abort
"FAILED: Failed to connect to internal API"
end
end
puts
"
\n
Check directories and files: "
puts
"
\n
Check directories and files: "
config
=
GitlabConfig
.
new
config
=
GitlabConfig
.
new
...
...
lib/gitlab_access.rb
View file @
2100c3d2
...
@@ -18,15 +18,20 @@ class GitlabAccess
...
@@ -18,15 +18,20 @@ class GitlabAccess
end
end
def
exec
def
exec
status
=
api
.
check_access
(
'git-receive-pack'
,
@repo_name
,
@actor
,
@changes
)
begin
if
status
.
allowed?
status
=
api
.
check_access
(
'git-receive-pack'
,
@repo_name
,
@actor
,
@changes
)
true
else
return
true
if
status
.
allowed?
# reset GL_ID env since we stop git push here
ENV
[
'GL_ID'
]
=
nil
message
=
status
.
message
puts
"GitLab:
#{
status
.
message
}
"
rescue
GitlabNet
::
ApiUnreachableError
false
message
=
"Failed to authorize your Git request: internal API unreachable"
end
end
# reset GL_ID env since we stop git push here
ENV
[
'GL_ID'
]
=
nil
puts
"GitLab:
#{
message
}
"
false
end
end
protected
protected
...
...
lib/gitlab_net.rb
View file @
2100c3d2
...
@@ -7,6 +7,8 @@ require_relative 'gitlab_logger'
...
@@ -7,6 +7,8 @@ require_relative 'gitlab_logger'
require_relative
'gitlab_access'
require_relative
'gitlab_access'
class
GitlabNet
class
GitlabNet
class
ApiUnreachableError
<
StandardError
;
end
def
check_access
(
cmd
,
repo
,
actor
,
changes
)
def
check_access
(
cmd
,
repo
,
actor
,
changes
)
project_name
=
repo
.
gsub
(
"'"
,
""
)
project_name
=
repo
.
gsub
(
"'"
,
""
)
project_name
=
project_name
.
gsub
(
/\.git\Z/
,
""
)
project_name
=
project_name
.
gsub
(
/\.git\Z/
,
""
)
...
@@ -64,63 +66,66 @@ class GitlabNet
...
@@ -64,63 +66,66 @@ class GitlabNet
"
#{
config
.
gitlab_url
}
/api/v3/internal"
"
#{
config
.
gitlab_url
}
/api/v3/internal"
end
end
def
http_client_for
(
ur
l
)
def
http_client_for
(
ur
i
)
Net
::
HTTP
.
new
(
url
.
host
,
url
.
port
).
tap
do
|
http
|
http
=
Net
::
HTTP
.
new
(
uri
.
host
,
uri
.
port
)
if
URI
::
HTTPS
===
url
http
.
use_ssl
=
true
if
uri
.
is_a?
(
URI
::
HTTPS
)
http
.
cert_store
=
cert_stor
e
http
.
use_ssl
=
tru
e
http
.
verify_mode
=
OpenSSL
::
SSL
::
VERIFY_NONE
if
config
.
http_settings
[
'self_signed_cert'
]
http
.
cert_store
=
cert_store
end
http
.
verify_mode
=
OpenSSL
::
SSL
::
VERIFY_NONE
if
config
.
http_settings
[
'self_signed_cert'
]
end
end
http
end
end
def
http_request_for
(
url
,
method
=
:get
)
def
http_request_for
(
method
,
uri
,
params
=
{})
request_klass
=
method
==
:get
?
Net
::
HTTP
::
Get
:
Net
::
HTTP
::
Post
request
=
request_klass
.
new
(
uri
.
request_uri
)
user
=
config
.
http_settings
[
'user'
]
user
=
config
.
http_settings
[
'user'
]
password
=
config
.
http_settings
[
'password'
]
password
=
config
.
http_settings
[
'password'
]
request
.
basic_auth
(
user
,
password
)
if
user
&&
password
request
.
set_form_data
(
params
.
merge
(
secret_token:
secret_token
))
request
end
def
request
(
method
,
url
,
params
=
{})
$logger
.
debug
"Performing
#{
method
.
to_s
.
upcase
}
#{
url
}
"
uri
=
URI
.
parse
(
url
)
http
=
http_client_for
(
uri
)
request
=
http_request_for
(
method
,
uri
,
params
)
if
method
==
:get
begin
Net
::
HTTP
::
Get
.
new
(
url
.
request_uri
).
tap
{
|
r
|
r
.
basic_auth
(
user
,
password
)
if
user
&&
password
}
response
=
http
.
start
{
http
.
request
(
request
)
}
rescue
=>
e
$logger
.
warn
"Failed to connect to internal API <
#{
method
.
to_s
.
upcase
}
#{
url
}
>:
#{
e
.
inspect
}
"
raise
ApiUnreachableError
end
if
response
.
code
==
"200"
$logger
.
debug
"Received response
#{
response
.
code
}
=> <
#{
response
.
body
}
>."
else
else
Net
::
HTTP
::
Post
.
new
(
url
.
request_uri
).
tap
{
|
r
|
r
.
basic_auth
(
user
,
password
)
if
user
&&
password
}
$logger
.
error
"API call <
#{
method
.
to_s
.
upcase
}
#{
url
}
> failed:
#{
response
.
code
}
=> <
#{
response
.
body
}
>."
end
end
response
end
end
def
get
(
url
)
def
get
(
url
)
$logger
.
debug
"Performing GET
#{
url
}
"
request
(
:get
,
url
)
url
=
URI
.
parse
(
url
)
http
=
http_client_for
url
request
=
http_request_for
url
request
.
set_form_data
(
secret_token:
secret_token
)
http
.
start
{
|
http
|
http
.
request
(
request
)
}.
tap
do
|
resp
|
if
resp
.
code
==
"200"
$logger
.
debug
{
"Received response
#{
resp
.
code
}
=> <
#{
resp
.
body
}
>."
}
else
$logger
.
error
{
"API call <GET
#{
url
}
> failed:
#{
resp
.
code
}
=> <
#{
resp
.
body
}
>."
}
end
end
end
end
def
post
(
url
,
params
)
def
post
(
url
,
params
)
$logger
.
debug
"Performing POST
#{
url
}
"
request
(
:post
,
url
,
params
)
url
=
URI
.
parse
(
url
)
http
=
http_client_for
(
url
)
request
=
http_request_for
(
url
,
:post
)
request
.
set_form_data
(
params
.
merge
(
secret_token:
secret_token
))
http
.
start
{
|
http
|
http
.
request
(
request
)
}.
tap
do
|
resp
|
if
resp
.
code
==
"200"
$logger
.
debug
{
"Received response
#{
resp
.
code
}
=> <
#{
resp
.
body
}
>."
}
else
$logger
.
error
{
"API call <POST
#{
url
}
> failed:
#{
resp
.
code
}
=> <
#{
resp
.
body
}
>."
}
end
end
end
end
def
cert_store
def
cert_store
@cert_store
||=
OpenSSL
::
X509
::
Store
.
new
.
tap
do
|
store
|
@cert_store
||=
begin
store
=
OpenSSL
::
X509
::
Store
.
new
store
.
set_default_paths
store
.
set_default_paths
if
ca_file
=
config
.
http_settings
[
'ca_file'
]
if
ca_file
=
config
.
http_settings
[
'ca_file'
]
...
@@ -130,6 +135,8 @@ class GitlabNet
...
@@ -130,6 +135,8 @@ class GitlabNet
if
ca_path
=
config
.
http_settings
[
'ca_path'
]
if
ca_path
=
config
.
http_settings
[
'ca_path'
]
store
.
add_path
(
ca_path
)
store
.
add_path
(
ca_path
)
end
end
store
end
end
end
end
...
...
lib/gitlab_post_receive.rb
View file @
2100c3d2
...
@@ -18,9 +18,13 @@ class GitlabPostReceive
...
@@ -18,9 +18,13 @@ class GitlabPostReceive
update_redis
update_redis
if
broadcast_message
=
GitlabNet
.
new
.
broadcast_message
begin
puts
broadcast_message
=
GitlabNet
.
new
.
broadcast_message
print_broadcast_message
(
broadcast_message
[
"message"
])
if
broadcast_message
puts
print_broadcast_message
(
broadcast_message
[
"message"
])
end
rescue
GitlabNet
::
ApiUnreachableError
end
end
end
end
...
...
lib/gitlab_shell.rb
View file @
2100c3d2
...
@@ -21,15 +21,14 @@ class GitlabShell
...
@@ -21,15 +21,14 @@ class GitlabShell
if
git_cmds
.
include?
(
@git_cmd
)
if
git_cmds
.
include?
(
@git_cmd
)
ENV
[
'GL_ID'
]
=
@key_id
ENV
[
'GL_ID'
]
=
@key_id
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
access
=
api
.
check_access
(
@git_cmd
,
@repo_name
,
@key_id
,
'_any'
)
# TODO: Fix validation for git-annex-shell !!!!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if
access
.
allowed?
if
validate_access
process_cmd
process_cmd
else
else
message
=
"gitlab-shell: Access denied for git command <
#{
@origin_cmd
}
> by
#{
log_username
}
."
message
=
"gitlab-shell: Access denied for git command <
#{
@origin_cmd
}
> by
#{
log_username
}
."
$logger
.
warn
message
$logger
.
warn
message
$stderr
.
puts
"Access denied."
puts
access
.
message
end
end
else
else
raise
DisallowedCommandError
raise
DisallowedCommandError
...
@@ -37,10 +36,12 @@ class GitlabShell
...
@@ -37,10 +36,12 @@ class GitlabShell
else
else
puts
"Welcome to GitLab,
#{
username
}
!"
puts
"Welcome to GitLab,
#{
username
}
!"
end
end
rescue
GitlabNet
::
ApiUnreachableError
=>
ex
puts
"Failed to authorize your Git request: internal API unreachable"
rescue
DisallowedCommandError
=>
ex
rescue
DisallowedCommandError
=>
ex
message
=
"gitlab-shell: Attempt to execute disallowed command <
#{
@origin_cmd
}
> by
#{
log_username
}
."
message
=
"gitlab-shell: Attempt to execute disallowed command <
#{
@origin_cmd
}
> by
#{
log_username
}
."
$logger
.
warn
message
$logger
.
warn
message
puts
'
Not
allowed command'
puts
'
Dis
allowed command'
end
end
protected
protected
...
@@ -90,10 +91,6 @@ class GitlabShell
...
@@ -90,10 +91,6 @@ class GitlabShell
end
end
end
end
def
validate_access
api
.
check_access
(
@git_cmd
,
@repo_name
,
@key_id
,
'_any'
).
allowed?
end
# This method is not covered by Rspec because it ends the current Ruby process.
# This method is not covered by Rspec because it ends the current Ruby process.
def
exec_cmd
(
*
args
)
def
exec_cmd
(
*
args
)
Kernel
::
exec
({
'PATH'
=>
ENV
[
'PATH'
],
'LD_LIBRARY_PATH'
=>
ENV
[
'LD_LIBRARY_PATH'
],
'GL_ID'
=>
ENV
[
'GL_ID'
]},
*
args
,
unsetenv_others:
true
)
Kernel
::
exec
({
'PATH'
=>
ENV
[
'PATH'
],
'LD_LIBRARY_PATH'
=>
ENV
[
'LD_LIBRARY_PATH'
],
'GL_ID'
=>
ENV
[
'GL_ID'
]},
*
args
,
unsetenv_others:
true
)
...
@@ -104,11 +101,12 @@ class GitlabShell
...
@@ -104,11 +101,12 @@ class GitlabShell
end
end
def
user
def
user
# Can't use "@user ||=" because that will keep hitting the API when @user is really nil!
return
@user
if
defined?
(
@user
)
if
instance_variable_defined?
(
'@user'
)
@user
begin
else
@user
=
api
.
discover
(
@key_id
)
@user
=
api
.
discover
(
@key_id
)
rescue
GitlabNet
::
ApiUnreachableError
@user
=
nil
end
end
end
end
...
...
spec/gitlab_access_spec.rb
View file @
2100c3d2
...
@@ -5,15 +5,56 @@ describe GitlabAccess do
...
@@ -5,15 +5,56 @@ describe GitlabAccess do
let
(
:repository_path
)
{
"/home/git/repositories"
}
let
(
:repository_path
)
{
"/home/git/repositories"
}
let
(
:repo_name
)
{
'dzaporozhets/gitlab-ci'
}
let
(
:repo_name
)
{
'dzaporozhets/gitlab-ci'
}
let
(
:repo_path
)
{
File
.
join
(
repository_path
,
repo_name
)
+
".git"
}
let
(
:repo_path
)
{
File
.
join
(
repository_path
,
repo_name
)
+
".git"
}
let
(
:gitlab_access
)
{
GitlabAccess
.
new
(
repo_path
,
'key-123'
,
'wow'
)
}
let
(
:api
)
do
double
(
GitlabNet
).
tap
do
|
api
|
api
.
stub
(
check_access:
GitAccessStatus
.
new
(
true
))
end
end
subject
do
GitlabAccess
.
new
(
repo_path
,
'key-123'
,
'wow'
).
tap
do
|
access
|
access
.
stub
(
exec_cmd: :exec_called
)
access
.
stub
(
api:
api
)
end
end
before
do
before
do
GitlabConfig
.
any_instance
.
stub
(
repos_path:
repository_path
)
GitlabConfig
.
any_instance
.
stub
(
repos_path:
repository_path
)
end
end
describe
:initialize
do
describe
:initialize
do
it
{
gitlab_access
.
repo_name
.
should
==
repo_name
}
it
{
subject
.
repo_name
.
should
==
repo_name
}
it
{
gitlab_access
.
repo_path
.
should
==
repo_path
}
it
{
subject
.
repo_path
.
should
==
repo_path
}
it
{
gitlab_access
.
changes
.
should
==
[
'wow'
]
}
it
{
subject
.
changes
.
should
==
[
'wow'
]
}
end
describe
"#exec"
do
context
"access is granted"
do
it
"returns true"
do
expect
(
subject
.
exec
).
to
be_true
end
end
context
"access is denied"
do
before
do
api
.
stub
(
check_access:
GitAccessStatus
.
new
(
false
))
end
it
"returns false"
do
expect
(
subject
.
exec
).
to
be_false
end
end
context
"API connection fails"
do
before
do
api
.
stub
(
:check_access
).
and_raise
(
GitlabNet
::
ApiUnreachableError
)
end
it
"returns false"
do
expect
(
subject
.
exec
).
to
be_false
end
end
end
end
end
end
spec/gitlab_net_spec.rb
View file @
2100c3d2
...
@@ -26,6 +26,11 @@ describe GitlabNet, vcr: true do
...
@@ -26,6 +26,11 @@ describe GitlabNet, vcr: true do
gitlab_net
.
check
gitlab_net
.
check
end
end
end
end
it
"raises an exception if the connection fails"
do
Net
::
HTTP
.
any_instance
.
stub
(
:request
).
and_raise
(
StandardError
)
expect
{
gitlab_net
.
check
}.
to
raise_error
(
GitlabNet
::
ApiUnreachableError
)
end
end
end
describe
:discover
do
describe
:discover
do
...
@@ -42,6 +47,13 @@ describe GitlabNet, vcr: true do
...
@@ -42,6 +47,13 @@ describe GitlabNet, vcr: true do
gitlab_net
.
discover
(
'key-126'
)
gitlab_net
.
discover
(
'key-126'
)
end
end
end
end
it
"raises an exception if the connection fails"
do
VCR
.
use_cassette
(
"discover-ok"
)
do
Net
::
HTTP
.
any_instance
.
stub
(
:request
).
and_raise
(
StandardError
)
expect
{
gitlab_net
.
discover
(
'key-126'
)
}.
to
raise_error
(
GitlabNet
::
ApiUnreachableError
)
end
end
end
end
describe
:broadcast_message
do
describe
:broadcast_message
do
...
@@ -110,6 +122,13 @@ describe GitlabNet, vcr: true do
...
@@ -110,6 +122,13 @@ describe GitlabNet, vcr: true do
end
end
end
end
end
end
it
"raises an exception if the connection fails"
do
Net
::
HTTP
.
any_instance
.
stub
(
:request
).
and_raise
(
StandardError
)
expect
{
gitlab_net
.
check_access
(
'git-upload-pack'
,
'gitlab/gitlabhq.git'
,
'user-1'
,
changes
)
}.
to
raise_error
(
GitlabNet
::
ApiUnreachableError
)
end
end
end
describe
:host
do
describe
:host
do
...
@@ -139,12 +158,13 @@ describe GitlabNet, vcr: true do
...
@@ -139,12 +158,13 @@ describe GitlabNet, vcr: true do
let
(
:user
)
{
'user'
}
let
(
:user
)
{
'user'
}
let
(
:password
)
{
'password'
}
let
(
:password
)
{
'password'
}
let
(
:url
)
{
URI
'http://localhost/'
}
let
(
:url
)
{
URI
'http://localhost/'
}
subject
{
gitlab_net
.
send
:http_request_for
,
url
}
subject
{
gitlab_net
.
send
:http_request_for
,
:get
,
url
}
before
do
before
do
gitlab_net
.
send
(
:config
).
http_settings
.
stub
(
:[]
).
with
(
'user'
)
{
user
}
gitlab_net
.
send
(
:config
).
http_settings
.
stub
(
:[]
).
with
(
'user'
)
{
user
}
gitlab_net
.
send
(
:config
).
http_settings
.
stub
(
:[]
).
with
(
'password'
)
{
password
}
gitlab_net
.
send
(
:config
).
http_settings
.
stub
(
:[]
).
with
(
'password'
)
{
password
}
get
.
should_receive
(
:basic_auth
).
with
(
user
,
password
).
once
get
.
should_receive
(
:basic_auth
).
with
(
user
,
password
).
once
get
.
should_receive
(
:set_form_data
).
with
(
hash_including
(
secret_token:
'a123'
)).
once
end
end
it
{
should_not
be_nil
}
it
{
should_not
be_nil
}
...
...
spec/gitlab_shell_spec.rb
View file @
2100c3d2
...
@@ -135,6 +135,22 @@ describe GitlabShell do
...
@@ -135,6 +135,22 @@ describe GitlabShell do
api
.
should_receive
(
:discover
).
with
(
key_id
)
api
.
should_receive
(
:discover
).
with
(
key_id
)
end
end
end
end
context
"failed connection"
do
before
{
ssh_cmd
'git-upload-pack gitlab-ci.git'
api
.
stub
(
:check_access
).
and_raise
(
GitlabNet
::
ApiUnreachableError
)
}
after
{
subject
.
exec
}
it
"should not process the command"
do
subject
.
should_not_receive
(
:process_cmd
)
end
it
"should not execute the command"
do
subject
.
should_not_receive
(
:exec_cmd
)
end
end
end
end
describe
:validate_access
do
describe
:validate_access
do
...
...
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