Skip to content

Commit

Permalink
Merge pull request #4 from edx/cpappas/ENT-1557
Browse files Browse the repository at this point in the history
ENT-1557 | Updating utils files with helper methods
  • Loading branch information
christopappas authored Mar 8, 2019
2 parents 33b289a + 59b9999 commit 0bcef2e
Show file tree
Hide file tree
Showing 16 changed files with 513 additions and 16 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ private.py
docs/_build
*.backup
*.log
*.pyc

# Making sure not to add init file for test module
tests/__init__.py

# Visual Studio Code
.vscode
7 changes: 6 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ Change Log
.. There should always be an "Unreleased" section for changes pending release.
[0.1.2] - 2019-03-07
[0.1.4] - 2019-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Adding a number of utils for roles in JWTs and the database

[0.1.3] - 2019-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Adding get_context to the UserRoleAssignment class.
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ requirements: ## install development environment requirements
pip-sync requirements/dev.txt requirements/private.*

test: clean ## run tests in the current virtualenv
touch tests/__init__.py
pytest
rm tests/__init__.py

diff_cover: test ## find diff lines that need test coverage
diff-cover coverage.xml
Expand Down
2 changes: 1 addition & 1 deletion edx_rbac/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

from __future__ import absolute_import, unicode_literals

__version__ = '0.1.3'
__version__ = '0.1.4'

default_app_config = 'edx_rbac.apps.EdxRbacConfig' # pylint: disable=invalid-name
135 changes: 135 additions & 0 deletions edx_rbac/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
"""
Utils for 'edx-rbac' module.
"""
from __future__ import absolute_import, unicode_literals

import crum
from django.apps import apps
from django.conf import settings
from django.test.client import RequestFactory
from edx_rest_framework_extensions.auth.jwt.cookies import jwt_cookie_name
from edx_rest_framework_extensions.auth.jwt.decoder import jwt_decode_handler
from six.moves.urllib.parse import urlparse # pylint: disable=import-error


# Taken from edx-platform
def get_request_or_stub():
"""
Return the current request or a stub request.
If called outside the context of a request, construct a fake
request that can be used to build an absolute URI.
This is useful in cases where we need to pass in a request object
but don't have an active request (for example, in tests, celery tasks, and XBlocks).
"""
request = crum.get_current_request()

if request is None:

# The settings SITE_NAME may contain a port number, so we need to
# parse the full URL.
full_url = "http://{site_name}".format(site_name=settings.SITE_NAME)
parsed_url = urlparse(full_url)

# Construct the fake request. This can be used to construct absolute
# URIs to other paths.
return RequestFactory(
SERVER_NAME=parsed_url.hostname,
SERVER_PORT=parsed_url.port or 80,
).get("/")

else:
return request


def get_decoded_jwt_from_request(request):
"""
Grab jwt from request if possible.
Returns a decoded jwt dict if it finds it.
Returns a None if it does not.
"""
jwt_cookie = request.COOKIES.get(jwt_cookie_name(), None)

if not jwt_cookie:
return None
return jwt_decode_handler(jwt_cookie)


def request_user_has_implicit_access_via_jwt(decoded_jwt, role_name):
"""
Check the request's user access by mapping user's roles found in jwt to local feature roles.
decoded_jwt is a dict
role_name is a string
Returns a boolean.
Mapping should be in settings and look like:
SYSTEM_TO_FEATURE_ROLE_MAPPING = {
'enterprise_admin': ['coupon-management', 'data_api_access'],
'enterprise_leaner': [],
'coupon-manager': ['coupon-management']
}
"""
jwt_roles_claim = decoded_jwt.get('roles', [])

feature_roles = []
for role_data in jwt_roles_claim:
role_in_jwt = role_data.split(':')[0] # split should be more robust because of our cousekeys having colons
mapped_roles = settings.SYSTEM_TO_FEATURE_ROLE_MAPPING.get(role_in_jwt, [])
feature_roles.extend(mapped_roles)

if role_name in feature_roles:
return True
return False


def user_has_access_via_database(user, role_name, role_assignment_class):
"""
Check if there is a role assignment for a given user and role.
The role object itself is found via the role_name
"""
try:
role_assignment_class.objects.get(user=user, role__name=role_name)
except role_assignment_class.DoesNotExist:
return False
return True


def create_role_auth_claim_for_user(user):
"""
Create role auth claim for a given user.
Takes a user, and for each RoleAssignment class specified in config as a
system wide jwt role associated with that user, creates a list of strings
denoting the role and context.
Returns a list.
This setting is a list of classes whose roles should be added to the
jwt. The setting should look something like this:
SYSTEM_WIDE_ROLE_CLASSES = [
SystemWideConcreteUserRoleAssignment
]
"""
role_auth_claim = []
for system_role_class in settings.SYSTEM_WIDE_ROLE_CLASSES:
app_name, model_name = system_role_class.split('.')
model_class = apps.get_model(app_name, model_name)

role_assignments = model_class.objects.filter(
user=user
).select_related('role')

for role_assignment in role_assignments:
role_string = role_assignment.role.name
context = role_assignment.get_context()
if context:
role_string += ':{}'.format(context)
role_auth_claim.append(role_string)
return role_auth_claim
4 changes: 3 additions & 1 deletion requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@

Django>=1.8,<2.0 # Web application framework
django-model-utils # Provides TimeStampedModel abstract base class
six
six
django-crum
edx-drf-extensions
24 changes: 24 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,31 @@
#
# make upgrade
#
certifi==2018.11.29 # via requests
chardet==3.0.4 # via requests
django-crum==0.7.3
django-model-utils==3.1.2
django-waffle==0.15.1 # via edx-django-utils, edx-drf-extensions
django==1.11.20
djangorestframework-jwt==1.11.0 # via edx-drf-extensions
djangorestframework==3.9.2 # via edx-drf-extensions, rest-condition
edx-django-utils==1.0.3 # via edx-drf-extensions
edx-drf-extensions==2.0.1
edx-opaque-keys==0.4.4 # via edx-drf-extensions
future==0.17.1 # via pyjwkest
idna==2.8 # via requests
newrelic==4.14.0.115 # via edx-django-utils
pbr==5.1.3 # via stevedore
psutil==1.2.1 # via edx-django-utils, edx-drf-extensions
pycryptodomex==3.7.3 # via pyjwkest
pyjwkest==1.3.2 # via edx-drf-extensions
pyjwt==1.7.1 # via djangorestframework-jwt
pymongo==3.7.2 # via edx-opaque-keys
python-dateutil==2.8.0 # via edx-drf-extensions
pytz==2018.9 # via django
requests==2.21.0 # via edx-drf-extensions, pyjwkest
rest-condition==1.0.3 # via edx-drf-extensions
semantic-version==2.6.0 # via edx-drf-extensions
six==1.12.0
stevedore==1.30.1 # via edx-opaque-keys
urllib3==1.24.1 # via requests
18 changes: 18 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@ contextlib2==0.5.5 # via importlib-metadata
coverage==4.5.2
diff-cover==1.0.6
distlib==0.2.8
django-crum==0.7.3
django-model-utils==3.1.2
django-waffle==0.15.1
django==1.11.20
djangorestframework-jwt==1.11.0
djangorestframework==3.9.2
edx-django-utils==1.0.3
edx-drf-extensions==2.0.1
edx-i18n-tools==0.4.8
edx-lint==1.1.1
edx-opaque-keys==0.4.4
enum34==1.1.6
filelock==3.0.10
funcsigs==1.0.2
future==0.17.1
futures==3.1.1
idna==2.8
importlib-metadata==0.8 # via path.py
Expand All @@ -38,31 +46,41 @@ jinja2==2.10
lazy-object-proxy==1.3.1
markupsafe==1.1.1
mccabe==0.6.1
mock==2.0.0
more-itertools==5.0.0
newrelic==4.14.0.115
packaging==19.0
path.py==11.5.0 # via edx-i18n-tools
pathlib2==2.3.3
pbr==5.1.3
pip-tools==3.4.0
pluggy==0.9.0
polib==1.1.0 # via edx-i18n-tools
psutil==1.2.1
py==1.8.0
pycodestyle==2.5.0
pycryptodomex==3.7.3
pydocstyle==3.0.0
pygments==2.3.1 # via diff-cover
pyjwkest==1.3.2
pyjwt==1.7.1
pylint-celery==0.3
pylint-django==0.7.2
pylint-plugin-utils==0.5
pylint==1.7.6
pymongo==3.7.2
pyparsing==2.3.1
pytest-cov==2.6.1
pytest-django==3.4.8
pytest==4.3.0
python-dateutil==2.8.0
python-slugify==3.0.0
pytz==2018.9
pyyaml==3.13
requests==2.21.0
rest-condition==1.0.3
scandir==1.9.0
semantic-version==2.6.0
singledispatch==3.4.0.3
six==1.12.0
snowballstemmer==1.2.1
Expand Down
28 changes: 23 additions & 5 deletions requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,63 @@ atomicwrites==1.3.0
attrs==19.1.0
babel==2.6.0 # via sphinx
bleach==3.1.0 # via readme-renderer
certifi==2018.11.29 # via requests
chardet==3.0.4 # via doc8, requests
certifi==2018.11.29
chardet==3.0.4
click==7.0
code-annotations==0.3
coverage==4.5.2
django-crum==0.7.3
django-model-utils==3.1.2
django-waffle==0.15.1
django==1.11.20
djangorestframework-jwt==1.11.0
djangorestframework==3.9.2
doc8==0.8.0
docutils==0.14 # via doc8, readme-renderer, restructuredtext-lint, sphinx
edx-django-utils==1.0.3
edx-drf-extensions==2.0.1
edx-opaque-keys==0.4.4
edx-sphinx-theme==1.4.0
funcsigs==1.0.2
idna==2.8 # via requests
future==0.17.1
idna==2.8
imagesize==1.1.0 # via sphinx
jinja2==2.10
markupsafe==1.1.1
mock==2.0.0
more-itertools==5.0.0
newrelic==4.14.0.115
packaging==19.0 # via sphinx
pathlib2==2.3.3
pbr==5.1.3
pluggy==0.9.0
psutil==1.2.1
py==1.8.0
pycryptodomex==3.7.3
pygments==2.3.1 # via readme-renderer, sphinx
pyjwkest==1.3.2
pyjwt==1.7.1
pymongo==3.7.2
pyparsing==2.3.1 # via packaging
pytest-cov==2.6.1
pytest-django==3.4.8
pytest==4.3.0
python-dateutil==2.8.0
python-slugify==3.0.0
pytz==2018.9
pyyaml==3.13
readme-renderer==24.0
requests==2.21.0 # via sphinx
requests==2.21.0
rest-condition==1.0.3
restructuredtext-lint==1.2.2 # via doc8
scandir==1.9.0
semantic-version==2.6.0
six==1.12.0
snowballstemmer==1.2.1 # via sphinx
sphinx==1.8.4
sphinxcontrib-websupport==1.1.0 # via sphinx
stevedore==1.30.1
text-unidecode==1.2
typing==3.6.6 # via sphinx
urllib3==1.24.1 # via requests
urllib3==1.24.1
webencodings==0.5.1 # via bleach
Loading

0 comments on commit 0bcef2e

Please sign in to comment.