Commit 5a561f81 by Clinton Blackburn

Added OAuth2 Permissions Scope Handler

This scope offers a simple claim, administrator, that is true iff the user is a superuser.
parent 142c38ed
...@@ -34,6 +34,21 @@ class OpenIDHandler(object): ...@@ -34,6 +34,21 @@ class OpenIDHandler(object):
return value return value
class PermissionsHandler(object):
""" Permissions scope handler """
def scope_permissions(self, _data):
return ['administrator']
def claim_administrator(self, data):
"""
Return boolean indicating user's administrator status.
For our purposes an administrator is any user with is_staff set to True.
"""
return data['user'].is_staff
class ProfileHandler(object): class ProfileHandler(object):
""" Basic OpenID Connect `profile` scope handler with `locale` claim. """ """ Basic OpenID Connect `profile` scope handler with `locale` claim. """
...@@ -193,8 +208,9 @@ class CourseAccessHandler(object): ...@@ -193,8 +208,9 @@ class CourseAccessHandler(object):
return course_ids return course_ids
class IDTokenHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler): class IDTokenHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler, PermissionsHandler):
""" Configure the ID Token handler for the LMS. """ """ Configure the ID Token handler for the LMS. """
def claim_instructor_courses(self, data): def claim_instructor_courses(self, data):
# Don't return list of courses unless they are requested as essential. # Don't return list of courses unless they are requested as essential.
if data.get('essential'): if data.get('essential'):
...@@ -210,16 +226,13 @@ class IDTokenHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler): ...@@ -210,16 +226,13 @@ class IDTokenHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler):
return None return None
class UserInfoHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler): class UserInfoHandler(OpenIDHandler, ProfileHandler, CourseAccessHandler, PermissionsHandler):
""" Configure the UserInfo handler for the LMS. """ """ Configure the UserInfo handler for the LMS. """
pass pass
def _get_all_courses(): def _get_all_courses():
""" """ Utility function to list all available courses. """
Utitilty function to list all available courses.
"""
ms_courses = modulestore().get_courses() ms_courses = modulestore().get_courses()
courses = [c for c in ms_courses if isinstance(c, CourseDescriptor)] courses = [c for c in ms_courses if isinstance(c, CourseDescriptor)]
......
...@@ -98,7 +98,7 @@ class IDTokenTest(BaseTestMixin, IDTokenTestCase): ...@@ -98,7 +98,7 @@ class IDTokenTest(BaseTestMixin, IDTokenTestCase):
scopes, claims = self.get_id_token_values('openid course_instructor') scopes, claims = self.get_id_token_values('openid course_instructor')
self.assertIn('course_instructor', scopes) self.assertIn('course_instructor', scopes)
self.assertNotIn('instructor_courses', claims) # should not return courses in id_token self.assertNotIn('instructor_courses', claims) # should not return courses in id_token
def test_course_staff_courses_with_claims(self): def test_course_staff_courses_with_claims(self):
CourseStaffRole(self.course_key).add_users(self.user) CourseStaffRole(self.course_key).add_users(self.user)
...@@ -121,6 +121,16 @@ class IDTokenTest(BaseTestMixin, IDTokenTestCase): ...@@ -121,6 +121,16 @@ class IDTokenTest(BaseTestMixin, IDTokenTestCase):
self.assertIn(course_id, claims['staff_courses']) self.assertIn(course_id, claims['staff_courses'])
self.assertNotIn(nonexistent_course_id, claims['staff_courses']) self.assertNotIn(nonexistent_course_id, claims['staff_courses'])
def test_permissions_scope(self):
scopes, claims = self.get_id_token_values('openid profile permissions')
self.assertIn('permissions', scopes)
self.assertFalse(claims['administrator'])
self.user.is_staff = True
self.user.save()
_scopes, claims = self.get_id_token_values('openid profile permissions')
self.assertTrue(claims['administrator'])
class UserInfoTest(BaseTestMixin, UserInfoTestCase): class UserInfoTest(BaseTestMixin, UserInfoTestCase):
def token_for_scope(self, scope): def token_for_scope(self, scope):
...@@ -185,3 +195,13 @@ class UserInfoTest(BaseTestMixin, UserInfoTestCase): ...@@ -185,3 +195,13 @@ class UserInfoTest(BaseTestMixin, UserInfoTestCase):
courses = claims['instructor_courses'] courses = claims['instructor_courses']
self.assertIn(self.course_id, courses) self.assertIn(self.course_id, courses)
self.assertEqual(len(courses), 1) self.assertEqual(len(courses), 1)
def test_permissions_scope(self):
claims = self.get_with_scope('permissions')
self.assertIn('administrator', claims)
self.assertFalse(claims['administrator'])
self.user.is_staff = True
self.user.save()
claims = self.get_with_scope('permissions')
self.assertTrue(claims['administrator'])
...@@ -33,5 +33,5 @@ git+https://github.com/edx/edx-ora2.git@release-2014-10-27T19.33#egg=edx-ora2 ...@@ -33,5 +33,5 @@ git+https://github.com/edx/edx-ora2.git@release-2014-10-27T19.33#egg=edx-ora2
git+https://github.com/edx/opaque-keys.git@0.1.2#egg=opaque-keys git+https://github.com/edx/opaque-keys.git@0.1.2#egg=opaque-keys
git+https://github.com/edx/ease.git@97de68448e5495385ba043d3091f570a699d5b5f#egg=ease git+https://github.com/edx/ease.git@97de68448e5495385ba043d3091f570a699d5b5f#egg=ease
git+https://github.com/edx/i18n-tools.git@56f048af9b6868613c14aeae760548834c495011#egg=i18n-tools git+https://github.com/edx/i18n-tools.git@56f048af9b6868613c14aeae760548834c495011#egg=i18n-tools
git+https://github.com/edx/edx-oauth2-provider.git@0.3.1#egg=oauth2-provider git+https://github.com/edx/edx-oauth2-provider.git@0.4.0#egg=oauth2-provider
git+https://github.com/edx/edx-val.git@a3c54afe30375f7a5755ba6f6412a91de23c3b86#egg=edx-val git+https://github.com/edx/edx-val.git@a3c54afe30375f7a5755ba6f6412a91de23c3b86#egg=edx-val
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment