Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Tanner Prestegard
gracedb-client
Commits
5ca1b0fc
Verified
Commit
5ca1b0fc
authored
Nov 15, 2019
by
Tanner Prestegard
Browse files
Add ability to specify basic auth creds via environment variable
Useful for testing and running against a local GraceDB instance.
parent
17912053
Pipeline
#88916
passed with stages
in 8 minutes and 37 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
docs/source/changelog.rst
View file @
5ca1b0fc
...
...
@@ -2,7 +2,7 @@ Changelog
=========
2.4.0 (August 21, 2019)
---------------------
---------------------
--
- Change minimum required version of ``six`` to 1.9.0
- Add client method for updating GRB event parameters
...
...
ligo/gracedb/rest.py
View file @
5ca1b0fc
...
...
@@ -210,14 +210,19 @@ class GsiRest(object):
# If the user didn't provide credentials in the constructor,
# we try to look up the credentials
if
not
force_noauth
and
not
credentials_provided
:
# Look for X509 certificate and key
cred
=
self
.
_find_x509_credentials
()
if
cred
:
self
.
credentials
[
'cert_file'
],
self
.
credentials
[
'key_file'
]
=
\
cred
self
.
auth_type
=
'x509'
else
:
# Look for basic auth credentials in .netrc file
# Look for credentials in environment variables
creds
,
auth_type
=
self
.
_get_creds_from_envvars
()
# Look for X509 certificate and key in default location
if
creds
is
None
:
creds
=
self
.
_find_x509_credentials
()
if
creds
is
not
None
:
auth_type
=
'x509'
# If no X509 credentials found, look for basic auth
# credentials in .netrc file
if
creds
is
None
:
try
:
basic_auth_tuple
=
safe_netrc
().
authenticators
(
host
)
except
IOError
:
...
...
@@ -226,9 +231,17 @@ class GsiRest(object):
else
:
# If credentials were found for host, set them up!
if
basic_auth_tuple
is
not
None
:
self
.
credentials
[
'username'
]
=
basic_auth_tuple
[
0
]
self
.
credentials
[
'password'
]
=
basic_auth_tuple
[
2
]
self
.
auth_type
=
'basic'
creds
=
(
basic_auth_tuple
[
0
],
basic_auth_tuple
[
2
])
auth_type
=
'basic'
# Process final credentials
if
creds
is
not
None
:
if
auth_type
==
'x509'
:
creds_dict
=
{
'cert_file'
:
creds
[
0
],
'key_file'
:
creds
[
1
]}
elif
auth_type
==
'basic'
:
creds_dict
=
{
'username'
:
creds
[
0
],
'password'
:
creds
[
1
]}
self
.
auth_type
=
auth_type
self
.
credentials
.
update
(
creds_dict
)
if
(
fail_if_noauth
and
not
self
.
credentials
):
raise
RuntimeError
(
'No authentication credentials found.'
)
...
...
@@ -386,21 +399,47 @@ class GsiRest(object):
return
credentials_provided
def
_find_x509_credentials
(
self
):
"""
Tries to find a user's X509 certificate and key. Checks environment
variables first, then expected location for default proxy.
def
_get_creds_from_envvars
(
self
):
"""
proxyFile
=
os
.
environ
.
get
(
'X509_USER_PROXY'
)
certFile
=
os
.
environ
.
get
(
'X509_USER_CERT'
)
keyFile
=
os
.
environ
.
get
(
'X509_USER_KEY'
)
Tries to look up user credentials from environment variables in the
following order:
if
certFile
and
keyFile
:
return
certFile
,
keyFile
if
proxyFile
:
return
proxyFile
,
proxyFile
#. X.509 certificate and key (`X509_USER_CERT`, `X509_USER_KEY`)
#. X.509 proxy (`X509_USER_PROXY`)
#. Basic auth user and password (`GRACEDB_USER`, `GRACEDB_PASSWORD`)
"""
creds
=
None
auth_type
=
None
# Check for X509 certificate and key first
cert_file
=
os
.
environ
.
get
(
'X509_USER_CERT'
,
None
)
key_file
=
os
.
environ
.
get
(
'X509_USER_KEY'
,
None
)
if
cert_file
and
key_file
:
creds
=
(
cert_file
,
key_file
)
auth_type
=
'x509'
# Next, check for X509 proxy
if
creds
is
None
:
proxy_file
=
os
.
environ
.
get
(
'X509_USER_PROXY'
,
None
)
if
proxy_file
:
creds
=
(
proxy_file
,
proxy_file
)
auth_type
=
'x509'
# Finally, look for basic auth credentials
if
creds
is
None
:
username
=
os
.
environ
.
get
(
'GRACEDB_USER'
,
None
)
password
=
os
.
environ
.
get
(
'GRACEDB_PASSWORD'
,
None
)
if
username
and
password
:
creds
=
(
username
,
password
)
auth_type
=
'basic'
return
creds
,
auth_type
def
_find_x509_credentials
(
self
):
"""
Tries to find a user's X509 certificate and key in some
default locations.
"""
# Try default proxy
proxyFile
=
os
.
path
.
join
(
'/tmp'
,
"x509up_u%d"
%
os
.
getuid
())
if
os
.
path
.
exists
(
proxyFile
):
...
...
@@ -415,6 +454,8 @@ class GsiRest(object):
if
os
.
path
.
exists
(
certFile
)
and
os
.
path
.
exists
(
keyFile
):
return
certFile
,
keyFile
return
None
def
show_credentials
(
self
,
print_output
=
True
):
"""Prints authentication type and credentials information."""
output
=
{
'auth_type'
:
self
.
auth_type
}
...
...
@@ -670,6 +711,8 @@ class GraceDb(GsiRest):
are set, load the corresponding certificate and key.
#. If the ``X509_USER_PROXY`` environment variable is set, load the
\
corresponding proxy file.
#. If the ``GRACEDB_USER`` and ``GRACEDB_PASSWORD`` environment variables
\
are set, use those credentials for basic authentication.
#. Look for a X.509 proxy from ligo-proxy-init in the default location
\
(``/tmp/x509up_u${UID}``).
#. Look for a certificate and key file in ``$HOME/.globus/usercert.pem``
\
...
...
ligo/gracedb/test/test_client.py
View file @
5ca1b0fc
...
...
@@ -104,6 +104,7 @@ def test_x509_credentials_lookup():
load_cert_func
=
'ligo.gracedb.rest.GraceDb._load_certificate'
find_x509_func
=
'ligo.gracedb.rest.GraceDb._find_x509_credentials'
with
mock
.
patch
(
'ligo.gracedb.rest.GraceDb.set_up_connector'
),
\
mock
.
patch
.
dict
(
'ligo.gracedb.rest.os.environ'
,
clear
=
True
),
\
mock
.
patch
(
load_cert_func
),
\
mock
.
patch
(
find_x509_func
)
as
mock_find_x509
:
# noqa: E127
mock_find_x509
.
return_value
=
(
cert_file
,
key_file
)
...
...
@@ -116,53 +117,102 @@ def test_x509_credentials_lookup():
assert
g
.
credentials
.
get
(
'key_file'
)
==
key_file
def
test_x509_lookup_cert_key_from_envvars
():
"""Test lookup of X509 cert and key from environment variables"""
# Setup
cert_file
=
'/tmp/cert_file'
key_file
=
'/tmp/key_file'
# Initialize client
fake_creds_dict
=
{
@
pytest
.
mark
.
parametrize
(
"cert_file,key_file,proxy_file,username,password"
,
[
(
'/tmp/cert_file'
,
'/tmp/key_file'
,
None
,
None
,
None
),
(
None
,
None
,
'/tmp/proxy_file'
,
None
,
None
),
(
None
,
None
,
None
,
'user'
,
'pass'
),
(
'/tmp/cert_file'
,
'/tmp/key_file'
,
'/tmp/proxy_file'
,
None
,
None
),
(
'/tmp/cert_file'
,
'/tmp/key_file'
,
None
,
'username'
,
'password'
),
(
None
,
None
,
'/tmp/proxy_file'
,
'username'
,
'password'
),
(
'/tmp/cert_file'
,
'/tmp/key_file'
,
'/tmp/proxy_file'
,
'username'
,
'password'
),
]
)
def
test_lookup_creds_from_envvars
(
cert_file
,
key_file
,
proxy_file
,
username
,
password
):
# Set up environment
creds
=
{
'X509_USER_CERT'
:
cert_file
,
'X509_USER_KEY'
:
key_file
,
'X509_USER_PROXY'
:
proxy_file
,
'GRACEDB_USER'
:
username
,
'GRACEDB_PASSWORD'
:
password
,
}
# mock can't handle Nones in os.environ, so we remove them
creds
=
{
k
:
v
for
k
,
v
in
creds
.
items
()
if
v
is
not
None
}
load_cert_func
=
'ligo.gracedb.rest.GraceDb._load_certificate'
os_environ_func
=
'ligo.gracedb.rest.os.environ'
with
mock
.
patch
(
'ligo.gracedb.rest.GraceDb.set_up_connector'
),
\
mock
.
patch
(
load_cert_func
),
\
mock
.
patch
.
dict
(
os_environ_func
,
fake_creds_dict
):
# noqa: E127
mock
.
patch
.
dict
(
os_environ_func
,
creds
,
clear
=
True
):
# noqa: E127
g
=
GraceDb
()
# Check credentials - should prioritze x509 credentials
# Check credentials - should priorit
i
ze x509 credentials
assert
len
(
g
.
credentials
)
==
2
assert
g
.
auth_type
==
'x509'
assert
g
.
credentials
.
get
(
'cert_file'
)
==
cert_file
assert
g
.
credentials
.
get
(
'key_file'
)
==
key_file
if
(
cert_file
and
key_file
)
or
proxy_file
:
assert
g
.
auth_type
==
'x509'
if
cert_file
and
key_file
:
assert
g
.
credentials
.
get
(
'cert_file'
)
==
cert_file
assert
g
.
credentials
.
get
(
'key_file'
)
==
key_file
else
:
assert
g
.
credentials
.
get
(
'cert_file'
)
==
proxy_file
assert
g
.
credentials
.
get
(
'key_file'
)
==
proxy_file
else
:
assert
g
.
auth_type
==
'basic'
assert
g
.
credentials
.
get
(
'username'
)
==
username
assert
g
.
credentials
.
get
(
'password'
)
==
password
def
test_x509_lookup_proxy_from_envvars
():
"""Test lookup of X509 combined provxy file from environment variables"""
# Setup
proxy_file
=
'/tmp/proxy_file'
@
pytest
.
mark
.
parametrize
(
"creds_dict"
,
[
{
'cred'
:
(
'c1'
,
'k1'
)},
{
'username'
:
'u1'
,
'password'
:
'p1'
},
{
'cred'
:
(
'c1'
,
'k1'
),
'username'
:
'u1'
,
'password'
:
'p1'
},
{},
]
)
def
test_creds_and_envvars
(
creds_dict
):
"""
Test different combinations of directly-provided credentials and
credentials provided in envvars
"""
# Set up environment - only need to test with cert and key since
# we have another test which checks how the different environment
# variables interact
env_creds
=
{
'X509_USER_CERT'
:
'c2'
,
'X509_USER_KEY'
:
'k2'
,
}
# Initialize client
os_environ_func
=
'ligo.gracedb.rest.os.environ'
load_cert_func
=
'ligo.gracedb.rest.GraceDb._load_certificate'
mock
_environ_
dict
=
{
'X509_USER_PROXY'
:
proxy_file
}
os
_environ_
func
=
'ligo.gracedb.rest.os.environ'
with
mock
.
patch
(
'ligo.gracedb.rest.GraceDb.set_up_connector'
),
\
mock
.
patch
(
load_cert_func
),
\
mock
.
patch
.
dict
(
os_environ_func
,
mock_environ_dict
):
# noqa: E127
g
=
GraceDb
()
mock
.
patch
.
dict
(
os_environ_func
,
env_creds
,
clear
=
True
):
# noqa: E127
g
=
GraceDb
(
**
creds_dict
)
# Check credentials - should prioritze
x509
credentials
# Check credentials - should priorit
i
ze
directly-provided
credentials
assert
len
(
g
.
credentials
)
==
2
assert
g
.
auth_type
==
'x509'
assert
g
.
credentials
.
get
(
'cert_file'
)
==
proxy_file
assert
g
.
credentials
.
get
(
'key_file'
)
==
proxy_file
if
creds_dict
:
if
'cred'
in
creds_dict
:
assert
g
.
auth_type
==
'x509'
assert
g
.
credentials
.
get
(
'cert_file'
)
==
creds_dict
[
'cred'
][
0
]
assert
g
.
credentials
.
get
(
'key_file'
)
==
creds_dict
[
'cred'
][
1
]
else
:
assert
g
.
auth_type
==
'basic'
assert
g
.
credentials
.
get
(
'username'
)
==
creds_dict
[
'username'
]
assert
g
.
credentials
.
get
(
'password'
)
==
creds_dict
[
'password'
]
else
:
assert
g
.
auth_type
==
'x509'
assert
g
.
credentials
.
get
(
'cert_file'
)
==
env_creds
[
'X509_USER_CERT'
]
assert
g
.
credentials
.
get
(
'key_file'
)
==
env_creds
[
'X509_USER_KEY'
]
def
test_basic_credentials_lookup
():
def
test_basic_credentials_lookup
_from_netrc
():
"""Test client instantiation - look up basic auth creds from .netrc file"""
# Set up credentials and mock_netrc return
fake_creds
=
{
...
...
@@ -175,6 +225,7 @@ def test_basic_credentials_lookup():
safe_netrc
=
'ligo.gracedb.rest.safe_netrc'
with
mock
.
patch
(
conn_func
),
\
mock
.
patch
(
find_x509_func
)
as
mock_find_x509
,
\
mock
.
patch
.
dict
(
'ligo.gracedb.rest.os.environ'
,
clear
=
True
),
\
mock
.
patch
(
safe_netrc
)
as
mock_netrc
:
# noqa: E127
# Force lookup to not find any X509 credentials
...
...
@@ -201,6 +252,7 @@ def test_no_credentials(fail_if_noauth):
safe_netrc
=
'ligo.gracedb.rest.safe_netrc'
with
mock
.
patch
(
conn_func
),
\
mock
.
patch
(
find_x509_func
)
as
mock_find_x509
,
\
mock
.
patch
.
dict
(
'ligo.gracedb.rest.os.environ'
,
clear
=
True
),
\
mock
.
patch
(
safe_netrc
)
as
mock_netrc
:
# noqa: E127
# Force lookup to not find any X509 credentials
...
...
@@ -259,6 +311,7 @@ def test_fail_if_noauth(creds_found):
with
mock
.
patch
(
conn_func
),
\
mock
.
patch
(
load_cert_func
),
\
mock
.
patch
(
find_x509_func
)
as
mock_find_x509
,
\
mock
.
patch
.
dict
(
'ligo.gracedb.rest.os.environ'
,
clear
=
True
),
\
mock
.
patch
(
safe_netrc
)
as
mock_netrc
:
# noqa: E127
if
not
creds_found
:
...
...
tox.ini
View file @
5ca1b0fc
...
...
@@ -4,7 +4,13 @@ skip_missing_interpreters = True
[testenv]
passenv
=
integration_test:
TEST_SERVICE
integration_test:
TEST_SERVICE
X509_USER_CERT
X509_USER_KEY
X509_USER_PROXY
GRACEDB_USER
GRACEDB_PASSWORD
commands
=
unit_test:
python
setup.py
test
integration_test:
python
setup.py
test
--addopts
"-m
integration"
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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