commit
d9015a1863
5 changed files with 125 additions and 103 deletions
|
@ -10,7 +10,7 @@ COPY requirements.txt requirements-tests.txt ./
|
|||
# Due to the following bug, pip results must be piped to a file before grepping:
|
||||
# https://github.com/pypa/pip/pull/3304
|
||||
RUN cat requirements.txt | grep -v "^-e" | awk -F'==' '{print $1}' | xargs venv/bin/pip --disable-pip-version-check show > pipinfo.txt && \
|
||||
test -z $(cat pipinfo.txt | grep GPL | grep -v LGPL) && \
|
||||
test -z "$(cat pipinfo.txt | grep GPL | grep -v LGPL)" && \
|
||||
rm pipinfo.txt
|
||||
|
||||
RUN virtualenv --distribute venv \
|
||||
|
@ -57,4 +57,4 @@ RUN PYTHONPATH=$QUAYPATH venv/bin/alembic heads | grep -E '^[0-9a-f]+ \(head\)$'
|
|||
|
||||
RUN ./scripts/detect-config.sh
|
||||
|
||||
CMD ./quay-entrypoint.sh
|
||||
CMD ./quay-entrypoint.sh
|
||||
|
|
|
@ -110,30 +110,31 @@ def test_token_with_access(access, initialized_db):
|
|||
|
||||
|
||||
@pytest.mark.parametrize('token', [
|
||||
(_token(
|
||||
pytest.param(_token(
|
||||
_token_data(access=[{
|
||||
'toipe': 'repository',
|
||||
'namesies': 'somens/somerepo',
|
||||
'akshuns': ['pull', 'push', '*']}]))),
|
||||
(_token(_token_data(audience='someotherapp'))),
|
||||
(_token(_delete_field(_token_data(), 'aud'))),
|
||||
(_token(_token_data(nbf=int(time.time()) + 600))),
|
||||
(_token(_delete_field(_token_data(), 'nbf'))),
|
||||
(_token(_token_data(iat=int(time.time()) + 600))),
|
||||
(_token(_delete_field(_token_data(), 'iat'))),
|
||||
(_token(_token_data(exp=int(time.time()) + MAX_SIGNED_S * 2))),
|
||||
(_token(_token_data(exp=int(time.time()) - 60))),
|
||||
(_token(_delete_field(_token_data(), 'exp'))),
|
||||
(_token(_delete_field(_token_data(), 'sub'))),
|
||||
(_token(_token_data(iss='badissuer'))),
|
||||
(_token(_delete_field(_token_data(), 'iss'))),
|
||||
(_token(_token_data(), skip_header=True)),
|
||||
(_token(_token_data(), key_id='someunknownkey')),
|
||||
(_token(_token_data(), key_id='kid7')),
|
||||
(_token(_token_data(), alg='none', private_key=None)),
|
||||
('some random token'),
|
||||
('Bearer: sometokenhere'),
|
||||
('\nBearer: dGVzdA'),])
|
||||
'akshuns': ['pull', 'push', '*']}])), id='bad access'),
|
||||
pytest.param(_token(_token_data(audience='someotherapp')), id='bad aud'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'aud')), id='no aud'),
|
||||
pytest.param(_token(_token_data(nbf=int(time.time()) + 600)), id='future nbf'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'nbf')), id='no nbf'),
|
||||
pytest.param(_token(_token_data(iat=int(time.time()) + 600)), id='future iat'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'iat')), id='no iat'),
|
||||
pytest.param(_token(_token_data(exp=int(time.time()) + MAX_SIGNED_S * 2)), id='exp too long'),
|
||||
pytest.param(_token(_token_data(exp=int(time.time()) - 60)), id='expired'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'exp')), id='no exp'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'sub')), id='no sub'),
|
||||
pytest.param(_token(_token_data(iss='badissuer')), id='bad iss'),
|
||||
pytest.param(_token(_delete_field(_token_data(), 'iss')), id='no iss'),
|
||||
pytest.param(_token(_token_data(), skip_header=True), id='no header'),
|
||||
pytest.param(_token(_token_data(), key_id='someunknownkey'), id='bad key'),
|
||||
pytest.param(_token(_token_data(), key_id='kid7'), id='bad key :: kid7'),
|
||||
pytest.param(_token(_token_data(), alg='none', private_key=None), id='none alg'),
|
||||
pytest.param('some random token', id='random token'),
|
||||
pytest.param('Bearer: sometokenhere', id='extra bearer'),
|
||||
pytest.param('\nBearer: dGVzdA', id='leading newline'),
|
||||
])
|
||||
def test_invalid_jwt(token, initialized_db):
|
||||
with pytest.raises(InvalidJWTException):
|
||||
_parse_token(token)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
-e git+https://github.com/coreos/pyapi-gitlab.git@timeout#egg=pyapi-gitlab
|
||||
-e git+https://github.com/coreos/resumablehashlib.git#egg=resumablehashlib
|
||||
-e git+https://github.com/jepcastelein/marketo-rest-python.git#egg=marketorestpython
|
||||
-e git+https://github.com/app-registry/appr-server.git#egg=cnr-server
|
||||
-e git+https://github.com/app-registry/appr-server.git@c2ef3b88afe926a92ef5f2e11e7d4a259e286a17#egg=cnr_server # naming has changed
|
||||
APScheduler==3.0.5
|
||||
Flask-Login
|
||||
Flask-Mail
|
||||
|
@ -77,5 +77,4 @@ tzlocal
|
|||
xhtml2pdf
|
||||
recaptcha2
|
||||
mockredispy
|
||||
cnr
|
||||
yapf
|
||||
|
|
164
requirements.txt
164
requirements.txt
|
@ -1,139 +1,147 @@
|
|||
aiowsgi==0.6
|
||||
alembic==0.9.1
|
||||
alembic==0.9.8
|
||||
-e git+https://github.com/coreos/mockldap.git@59a46efbe8c7cd8146a87a7c4f2b09746b953e11#egg=mockldap
|
||||
-e git+https://github.com/coreos/py-bitbucket.git@07a80f63388d004f05f58441983bdf195f9b666e#egg=py_bitbucket
|
||||
-e git+https://github.com/coreos/py-bitbucket.git@55a1ada645f2fb6369147996ec71edd7828d91c8#egg=py_bitbucket
|
||||
-e git+https://github.com/coreos/pyapi-gitlab.git@136c3970d591136a4f766a846c5d22aad52e124f#egg=pyapi_gitlab
|
||||
-e git+https://github.com/coreos/resumablehashlib.git@b1b631249589b07adf40e0ee545b323a501340b4#egg=resumablehashlib
|
||||
-e git+https://github.com/DevTable/aniso8601-fake.git@bd7762c7dea0498706d3f57db60cd8a8af44ba90#egg=aniso8601
|
||||
-e git+https://github.com/DevTable/anunidecode.git@d59236a822e578ba3a0e5e5abbd3855873fa7a88#egg=anunidecode
|
||||
-e git+https://github.com/app-registry/appr-server.git@c2ef3b88afe926a92ef5f2e11e7d4a259e286a17#egg=cnr_server
|
||||
-e git+https://github.com/DevTable/container-cloud-config.git@bce675537904175f6975024a4c89269027ea6792#egg=container_cloud_config
|
||||
-e git+https://github.com/DevTable/container-cloud-config.git@8e8ae177c3d5cd6608f64250fcd8770022d61562#egg=container_cloud_config
|
||||
-e git+https://github.com/DevTable/python-etcd.git@f1168cb02a2a8c83bec1108c6fcd8615ef463b14#egg=python_etcd
|
||||
-e git+https://github.com/jarus/flask-testing.git@18baff32969a0634a414ce61d2dd4a77433817a8#egg=Flask_Testing
|
||||
-e git+https://github.com/jepcastelein/marketo-rest-python.git@e26af0c5acd3d4ad899383442703a053120aa7ab#egg=marketorestpython
|
||||
-e git+https://github.com/jarus/flask-testing.git@17f19d7fee0e1e176703fc7cb04917a77913ba1a#egg=Flask_Testing
|
||||
-e git+https://github.com/jepcastelein/marketo-rest-python.git@6134d1129f2435b313c4301503a4b74974d79a42#egg=marketorestpython
|
||||
-e git+https://github.com/NateFerrero/oauth2lib.git@d161b010f8a596826050a09e5e94d59443cc12d9#egg=oauth2lib
|
||||
appdirs==1.4.3
|
||||
APScheduler==3.0.5
|
||||
asn1crypto==0.22.0
|
||||
asn1crypto==0.24.0
|
||||
autobahn==0.9.3.post3
|
||||
azure-common==1.1.8
|
||||
azure-nspkg==2.0.0
|
||||
azure-storage-blob==1.1.0
|
||||
Babel==2.4.0
|
||||
beautifulsoup4==4.5.3
|
||||
azure-storage-common==1.1.0
|
||||
azure-storage-nspkg==3.0.0
|
||||
Babel==2.5.3
|
||||
beautifulsoup4==4.6.0
|
||||
bencode==1.0
|
||||
bintrees==2.0.6
|
||||
bintrees==2.0.7
|
||||
bitmath==1.3.1.2
|
||||
blinker==1.4
|
||||
boto==2.46.1
|
||||
boto3==1.4.7
|
||||
boto==2.48.0
|
||||
boto3==1.5.36
|
||||
botocore==1.8.50
|
||||
cachetools==1.1.6
|
||||
certifi==2017.11.5
|
||||
cffi==1.10.0
|
||||
certifi==2018.1.18
|
||||
cffi==1.11.4
|
||||
chardet==3.0.4
|
||||
click==6.7
|
||||
contextlib2==0.5.4
|
||||
cryptography==1.8.1
|
||||
debtcollector==1.13.0
|
||||
decorator==4.0.11
|
||||
contextlib2==0.5.5
|
||||
cryptography==2.1.4
|
||||
debtcollector==1.19.0
|
||||
decorator==4.2.1
|
||||
enum34==1.1.6
|
||||
Flask-Login==0.4.0
|
||||
Flask-Cors==3.0.3
|
||||
Flask-Login==0.4.1
|
||||
Flask-Mail==0.9.1
|
||||
Flask-Principal==0.4.0
|
||||
Flask-RESTful==0.3.5
|
||||
Flask==0.12.1
|
||||
Flask-RESTful==0.3.6
|
||||
Flask==0.12.2
|
||||
funcparserlib==0.3.6
|
||||
funcsigs==1.0.2
|
||||
functools32==3.2.3.post2
|
||||
furl==1.0.0
|
||||
furl==1.0.1
|
||||
future==0.16.0
|
||||
futures==3.0.5
|
||||
geoip2==2.5.0
|
||||
gevent==1.2.1
|
||||
futures==3.2.0
|
||||
geoip2==2.7.0
|
||||
gevent==1.2.2
|
||||
gipc==0.6.0
|
||||
greenlet==0.4.12
|
||||
greenlet==0.4.13
|
||||
gunicorn==18.0
|
||||
hiredis==0.2.0
|
||||
html5lib==0.9999999
|
||||
httmock==1.2.6
|
||||
httplib2==0.10.3
|
||||
httpretty==0.8.10
|
||||
idna==2.5
|
||||
ipaddress==1.0.18
|
||||
iso8601==0.1.11
|
||||
idna==2.6
|
||||
ipaddress==1.0.19
|
||||
iso8601==0.1.12
|
||||
itsdangerous==0.24
|
||||
Jinja2==2.9.6
|
||||
Jinja2==2.10
|
||||
jmespath==0.9.3
|
||||
jsonpath-rw==1.4.0
|
||||
jsonschema==2.6.0
|
||||
keystoneauth1==2.19.0
|
||||
Mako==1.0.6
|
||||
keystoneauth1==3.4.0
|
||||
Mako==1.0.7
|
||||
marisa-trie==0.7.4
|
||||
MarkupSafe==1.0
|
||||
maxminddb==1.3.0
|
||||
mixpanel==4.3.2
|
||||
mock==2.0.0
|
||||
mockredispy==2.9.3
|
||||
monotonic==1.3
|
||||
monotonic==1.4
|
||||
moto==0.4.25
|
||||
msgpack-python==0.4.8
|
||||
msgpack==0.5.6
|
||||
namedlist==1.7
|
||||
ndg-httpsclient==0.4.2
|
||||
ndg-httpsclient==0.4.4
|
||||
netaddr==0.7.19
|
||||
netifaces==0.10.5
|
||||
oauthlib==2.0.2
|
||||
olefile==0.44
|
||||
netifaces==0.10.6
|
||||
oauthlib==2.0.6
|
||||
orderedmultidict==0.7.11
|
||||
oslo.config==3.24.0
|
||||
oslo.i18n==3.15.0
|
||||
oslo.serialization==2.18.0
|
||||
oslo.utils==3.25.0
|
||||
packaging==16.8
|
||||
pathvalidate==0.15.0
|
||||
pbr==2.0.0
|
||||
oslo.config==5.2.0
|
||||
oslo.i18n==3.19.0
|
||||
oslo.serialization==2.24.0
|
||||
oslo.utils==3.35.0
|
||||
pathvalidate==0.16.3
|
||||
pbr==3.1.1
|
||||
peewee==2.8.1
|
||||
Pillow==4.1.0
|
||||
ply==3.10
|
||||
positional==1.1.1
|
||||
psutil==5.2.1
|
||||
psycopg2==2.7.1
|
||||
pyasn1==0.3.7
|
||||
Pillow==5.0.0
|
||||
ply==3.11
|
||||
psutil==5.4.3
|
||||
psycopg2==2.7.4
|
||||
pyasn1==0.4.2
|
||||
py-bcrypt==0.4
|
||||
pycparser==2.17
|
||||
pycryptodome==3.4.5
|
||||
pycryptodomex==3.4.5
|
||||
PyGithub==1.34
|
||||
pycparser==2.18
|
||||
pycryptodome==3.4.11
|
||||
pycryptodomex==3.4.12
|
||||
PyGithub==1.36
|
||||
pygpgme==0.3
|
||||
pyjwkest==1.3.2
|
||||
PyJWT==1.4.2
|
||||
pyjwkest==1.4.0
|
||||
PyJWT==1.5.3
|
||||
PyMySQL==0.6.7
|
||||
pyOpenSSL==16.2.0
|
||||
pyOpenSSL==17.5.0
|
||||
pyparsing==2.2.0
|
||||
PyPDF2==1.26.0
|
||||
python-dateutil==2.6.0
|
||||
python-dateutil==2.6.1
|
||||
python-editor==1.0.3
|
||||
python-keystoneclient==3.10.0
|
||||
python-ldap==2.4.32
|
||||
python-magic==0.4.13
|
||||
python-swiftclient==3.3.0
|
||||
pytz==2017.2
|
||||
python-keystoneclient==3.15.0
|
||||
python-ldap==2.5.2
|
||||
python-magic==0.4.15
|
||||
python-swiftclient==3.5.0
|
||||
pytz==2018.3
|
||||
PyYAML==3.12
|
||||
raven==6.0.0
|
||||
raven==6.5.0
|
||||
recaptcha2==0.1
|
||||
redis==2.10.5
|
||||
redis==2.10.6
|
||||
redlock==1.2.0
|
||||
reportlab==2.7
|
||||
requests-oauthlib==0.8.0
|
||||
requests[security]==2.18.4
|
||||
rfc3986==0.4.1
|
||||
rfc3986==1.1.0
|
||||
s3transfer==0.1.13
|
||||
semantic-version==2.6.0
|
||||
six==1.10.0
|
||||
simplejson==3.13.2
|
||||
six==1.11.0
|
||||
SQLAlchemy==1.1.5
|
||||
stevedore==1.21.0
|
||||
stevedore==1.28.0
|
||||
stringscore==0.1.0
|
||||
stripe==1.51.0
|
||||
stripe==1.79.0
|
||||
toposort==1.5
|
||||
trollius==2.1
|
||||
tzlocal==1.3
|
||||
urllib3==1.20
|
||||
waitress==1.0.2
|
||||
WebOb==1.7.2
|
||||
Werkzeug==0.12.1
|
||||
wrapt==1.10.10
|
||||
xhtml2pdf==0.0.6
|
||||
xmltodict==0.10.2
|
||||
tzlocal==1.5.1
|
||||
urllib3==1.22
|
||||
waitress==1.1.0
|
||||
WebOb==1.7.4
|
||||
Werkzeug==0.14.1
|
||||
wrapt==1.10.11
|
||||
xhtml2pdf==0.2.1
|
||||
xmltodict==0.11.0
|
||||
yapf==0.20.2
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import re
|
||||
|
||||
from calendar import timegm
|
||||
from datetime import datetime, timedelta
|
||||
from jwt import PyJWT
|
||||
from jwt.exceptions import (
|
||||
|
@ -42,6 +43,9 @@ class StrictJWT(PyJWT):
|
|||
# Do all of the other checks
|
||||
super(StrictJWT, self)._validate_claims(payload, options, audience, issuer, leeway, **kwargs)
|
||||
|
||||
now = timegm(datetime.utcnow().utctimetuple())
|
||||
self._reject_future_iat(payload, now, leeway)
|
||||
|
||||
if 'exp' in payload and options.get('exp_max_s') is not None:
|
||||
# Validate that the expiration was not more than exp_max_s seconds after the issue time
|
||||
# or in the absense of an issue time, more than exp_max_s in the future from now
|
||||
|
@ -58,6 +62,16 @@ class StrictJWT(PyJWT):
|
|||
raise InvalidTokenError('Token was signed for more than %s seconds from %s', max_signed_s,
|
||||
start_time)
|
||||
|
||||
def _reject_future_iat(self, payload, now, leeway):
|
||||
try:
|
||||
iat = int(payload['iat'])
|
||||
except ValueError:
|
||||
raise DecodeError('Issued At claim (iat) must be an integer.')
|
||||
|
||||
if iat > (now + leeway):
|
||||
raise InvalidIssuedAtError('Issued At claim (iat) cannot be in'
|
||||
' the future.')
|
||||
|
||||
|
||||
def exp_max_s_option(max_exp_s):
|
||||
return {
|
||||
|
|
Reference in a new issue