-
Benachrichtigungen
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from arXiv/develop
Pre-release merge for v0.3.1
- Loading branch information
Showing
13 changed files
with
361 additions
and
370 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,20 @@ | ||
# Decision log | ||
|
||
1. To minimize complexity, we'll start with a managed Redis cluster in AWS | ||
ElastiCache. In the future, we may consider running our own HA key-value | ||
store, and potentially evaluate performance of other backends. | ||
2. In NG session store, will need to attach auth scope information. For now we | ||
can decide what "admin", "moderator", etc means and inject the relevant | ||
scopes. Later on, we will have an RBAC system. We therefore screen off the | ||
scope-determination concern from the session-creation concern. | ||
|
||
## 2019-02-28 Rename ``request.session`` to ``request.auth`` | ||
|
||
The auth middleware in ``arxiv.users`` package hands the authenticated session | ||
on ``flask.session``, which clobbers the built-in Flask session interface. This | ||
is a design flaw that's blocking other work. ARXIVNG-1920 | ||
|
||
Starting with v0.3.1, set ``AUTH_UPDATED_SESSION_REF=True`` in your | ||
application config to rename ``request.session`` to ``request.auth``. | ||
``request.auth`` will be the default name for the authenticated session | ||
starting in v0.4.1. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,6 +79,29 @@ def protected(): | |
with self.assertRaises(Forbidden): | ||
protected() | ||
|
||
@mock.patch(f'{decorators.__name__}.request') | ||
def test_scope_is_present(self, mock_request): | ||
"""Session has required scope.""" | ||
mock_request.session = domain.Session( | ||
session_id='fooid', | ||
start_time=datetime.now(tz=UTC), | ||
user=domain.User( | ||
user_id='235678', | ||
email='[email protected]', | ||
username='foouser' | ||
), | ||
authorizations=domain.Authorizations( | ||
scopes=[scopes.VIEW_SUBMISSION, scopes.CREATE_SUBMISSION] | ||
) | ||
) | ||
|
||
@decorators.scoped(scopes.CREATE_SUBMISSION) | ||
def protected(): | ||
"""A protected function.""" | ||
|
||
# with self.assertRaises(Forbidden): | ||
protected() | ||
|
||
@mock.patch(f'{decorators.__name__}.request') | ||
def test_user_and_client_are_missing(self, mock_request): | ||
"""Session does not user nor client information.""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,10 +57,49 @@ def test_legacy_is_valid(self, mock_request, mock_legacy): | |
mock_legacy.sessions.load.return_value = session | ||
|
||
inst = auth.Auth(mock_app) | ||
inst.load_session() | ||
# ARXIVNG-1920 using request.session is deprecated. | ||
with self.assertWarns(DeprecationWarning): | ||
inst.load_session() | ||
self.assertEqual(mock_request.session, session, | ||
"Session is attached to the request") | ||
|
||
@mock.patch(f'{auth.__name__}.legacy') | ||
@mock.patch(f'{auth.__name__}.request') | ||
def test_auth_session_rename(self, mock_request, mock_legacy): | ||
""" | ||
The auth session is accessed via ``request.auth``. | ||
Per ARXIVNG-1920 using ``request.session`` is deprecated. | ||
""" | ||
mock_request.environ = {'session': None} | ||
mock_request.cookies = {'foo_cookie': 'sessioncookie123'} | ||
mock_app = mock.MagicMock( | ||
config={'CLASSIC_COOKIE_NAME': 'foo_cookie', | ||
'AUTH_UPDATED_SESSION_REF': True} | ||
) | ||
mock_request.session = None | ||
mock_request.auth = None | ||
mock_legacy.is_configured.return_value = True | ||
session = domain.Session( | ||
session_id='fooid', | ||
start_time=datetime.now(tz=UTC), | ||
user=domain.User( | ||
user_id='235678', | ||
email='[email protected]', | ||
username='foouser' | ||
), | ||
authorizations=domain.Authorizations( | ||
scopes=[auth.scopes.VIEW_SUBMISSION] | ||
) | ||
) | ||
mock_legacy.sessions.load.return_value = session | ||
|
||
inst = auth.Auth(mock_app) | ||
inst.load_session() | ||
self.assertEqual(mock_request.auth, session, | ||
"Session is attached to the request") | ||
self.assertIsNone(mock_request.session, "request.session is not set") | ||
|
||
@mock.patch(f'{auth.__name__}.request') | ||
def test_middleware_exception(self, mock_request): | ||
"""Middleware has passed an exception.""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"""Tests for :mod:`.helpers`.""" | ||
|
||
from unittest import TestCase, mock | ||
import os | ||
from flask import Flask | ||
from arxiv import status | ||
from arxiv.base import Base | ||
from arxiv.base.middleware import wrap | ||
from .. import auth, helpers | ||
|
||
|
||
class TestGenerateToken(TestCase): | ||
"""Tests for :func:`.helpers.generate_token`.""" | ||
|
||
@mock.patch(f'{helpers.__name__}.get_application_config') | ||
def test_token_is_usable(self, mock_get_config): | ||
"""Verify that :func:`.helpers.generate_token` makes usable tokens.""" | ||
mock_get_config.return_value = {'JWT_SECRET': 'thesecret'} | ||
os.environ['JWT_SECRET'] = 'thesecret' | ||
scope = [auth.scopes.VIEW_SUBMISSION, auth.scopes.EDIT_SUBMISSION, | ||
auth.scopes.CREATE_SUBMISSION] | ||
token = helpers.generate_token("1234", "[email protected]", "theuser", | ||
scope=scope) | ||
|
||
app = Flask('test') | ||
app.config['JWT_SECRET'] = 'thesecret' | ||
Base(app) | ||
auth.Auth(app) # <- Install the Auth extension. | ||
wrap(app, [auth.middleware.AuthMiddleware]) # <- Install middleware. | ||
|
||
@app.route('/') | ||
@auth.decorators.scoped(auth.scopes.EDIT_SUBMISSION) | ||
def protected(): | ||
return "this is protected" | ||
|
||
client = app.test_client() | ||
with app.app_context(): | ||
response = client.get('/') | ||
self.assertEqual(response.status_code, | ||
status.HTTP_401_UNAUTHORIZED) | ||
|
||
response = client.get('/', headers={'Authorization': token}) | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters