Commit ead419f0 by Asad Iqbal Committed by Jonathan Piacenti

asadiqbal08/api-address-based-restriction:API Security: IP address based…

asadiqbal08/api-address-based-restriction:API Security: IP address based restriction added MCKIN-1108

uncomment the code
parent 57cd0f14
......@@ -8,13 +8,11 @@ from StringIO import StringIO
from django.contrib.auth.models import Group, User
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404
from rest_framework import status, generics
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from api_manager.permissions import ApiKeyHeaderPermission
from api_manager.models import CourseGroupRelationship, CourseContentGroupRelationship, GroupProfile
from api_manager.users.serializers import UserSerializer
from courseware import module_render
......@@ -24,6 +22,7 @@ from courseware.views import get_static_tab_contents
from student.models import CourseEnrollment, CourseEnrollmentAllowed
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location, InvalidLocationError
from api_manager.permissions import SecureAPIView
log = logging.getLogger(__name__)
......@@ -246,8 +245,8 @@ def _parse_updates_html(html):
return result
class CourseContentList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CourseContentList(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, content_id=None):
"""
......@@ -279,8 +278,8 @@ class CourseContentList(APIView):
return Response(response_data, status=status_code)
class CourseContentDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CourseContentDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, content_id):
"""
......@@ -316,8 +315,8 @@ class CourseContentDetail(APIView):
return Response(response_data, status=status_code)
class CoursesList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesList(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request):
"""
......@@ -336,8 +335,8 @@ class CoursesList(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class CoursesDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id):
"""
......@@ -375,8 +374,8 @@ class CoursesDetail(APIView):
return Response({}, status=status.HTTP_404_NOT_FOUND)
class CoursesGroupsList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesGroupsList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, course_id):
"""
......@@ -433,8 +432,9 @@ class CoursesGroupsList(APIView):
response_status = status.HTTP_200_OK
return Response(response_data, status=response_status)
class CoursesGroupsDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesGroupsDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, group_id):
"""
......@@ -480,8 +480,8 @@ class CoursesGroupsDetail(APIView):
return Response(response_data, status=status.HTTP_204_NO_CONTENT)
class CoursesOverview(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesOverview(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id):
"""
......@@ -507,8 +507,8 @@ class CoursesOverview(APIView):
return Response({}, status=status.HTTP_404_NOT_FOUND)
class CoursesUpdates(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesUpdates(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id):
"""
......@@ -532,8 +532,8 @@ class CoursesUpdates(APIView):
return Response(response_data)
class CoursesStaticTabsList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesStaticTabsList(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id):
"""
......@@ -564,8 +564,8 @@ class CoursesStaticTabsList(APIView):
return Response(response_data)
class CoursesStaticTabsDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesStaticTabsDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, tab_id):
"""
......@@ -594,8 +594,8 @@ class CoursesStaticTabsDetail(APIView):
return Response({}, status=status.HTTP_404_NOT_FOUND)
class CoursesUsersList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesUsersList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, course_id):
"""
......@@ -673,8 +673,8 @@ class CoursesUsersList(APIView):
return Response(response_data)
class CoursesUsersDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CoursesUsersDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, user_id):
"""
......@@ -732,8 +732,8 @@ class CoursesUsersDetail(APIView):
return Response(response_data, status=status.HTTP_204_NO_CONTENT)
class CourseContentGroupsList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CourseContentGroupsList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, course_id, content_id):
try:
......@@ -808,8 +808,8 @@ class CourseContentGroupsList(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class CourseContentGroupsDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class CourseContentGroupsDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, course_id, content_id, group_id):
"""
......@@ -841,7 +841,7 @@ class CourseContentGroupsDetail(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class CourseContentUsersList(generics.ListAPIView):
class CourseContentUsersList(SecureAPIView):
"""
### The CourseContentUsersList view allows clients to users enrolled and
users not enrolled for course within all groups of course
......@@ -855,15 +855,10 @@ class CourseContentUsersList(generics.ListAPIView):
* An example of specific group filtering is to get the set of users who are members of a particular workgroup related to the content
* An example of group type filtering is to get all users who are members of an organization group related to the content
"""
permission_classes = (ApiKeyHeaderPermission,)
serializer_class = UserSerializer
def get_queryset(self):
def get(self, request, course_id, content_id):
"""
GET /api/courses/{course_id}/content/{content_id}/users
"""
course_id = self.kwargs['course_id']
content_id = self.kwargs['content_id']
enrolled = self.request.QUERY_PARAMS.get('enrolled', 'True')
group_type = self.request.QUERY_PARAMS.get('type', None)
group_id = self.request.QUERY_PARAMS.get('group_id', None)
......@@ -883,4 +878,6 @@ class CourseContentUsersList(generics.ListAPIView):
queryset = enrolled_users
else:
queryset = list(itertools.ifilterfalse(lambda x: x in enrolled_users, users))
return queryset
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data) # pylint: disable=E1101
......@@ -8,13 +8,13 @@ from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.views import APIView
from api_manager.permissions import ApiKeyHeaderPermission
from api_manager.models import GroupRelationship, CourseGroupRelationship, GroupProfile
from xmodule.modulestore.django import modulestore
from api_manager.permissions import SecureAPIView
from xmodule.modulestore import Location, InvalidLocationError
RELATIONSHIP_TYPES = {'hierarchical': 'h', 'graph': 'g'}
......@@ -39,7 +39,7 @@ def _generate_base_uri(request, include_query_string=True):
return resource_uri
class GroupsList(APIView):
class GroupsList(SecureAPIView):
"""
### The GroupsList view allows clients to retrieve/append a list of Group entities
- URI: ```/api/groups/```
......@@ -74,7 +74,6 @@ class GroupsList(APIView):
** organization: display_name, contact_name, phone, email
* Ultimately, both 'type' and 'data' are determined by the client/caller. Open edX has no type or data specifications at the present time.
"""
permissions_classes = (ApiKeyHeaderPermission,)
def post(self, request):
"""
......@@ -140,7 +139,7 @@ class GroupsList(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class GroupsDetail(APIView):
class GroupsDetail(SecureAPIView):
"""
### The GroupsDetail view allows clients to interact with a specific Group entity
- URI: ```/api/groups/{group_id}```
......@@ -167,7 +166,6 @@ class GroupsDetail(APIView):
** Related Courses (/api/groups/{group_id}/courses)
** Related Groups(/api/groups/{group_id}/groups)
"""
permission_classes = (ApiKeyHeaderPermission,)
def post(self, request, group_id):
"""
......@@ -231,7 +229,7 @@ class GroupsDetail(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class GroupsUsersList(APIView):
class GroupsUsersList(SecureAPIView):
"""
### The GroupsUserList view allows clients to interact with the set of User entities related to the specified Group
- URI: ```/api/groups/{group_id}/users/```
......@@ -248,7 +246,6 @@ class GroupsUsersList(APIView):
* For example, as a newly-added member of a 'workgroup' group, a User could be presented with a list of their peers
* Once a User Group exists, you can additionally link to Courses and other Groups (see GroupsCoursesList, GroupsGroupsList)
"""
permission_classes = (ApiKeyHeaderPermission,)
def post(self, request, group_id):
"""
......@@ -304,7 +301,7 @@ class GroupsUsersList(APIView):
return Response(response_data, status=response_status)
class GroupsUsersDetail(APIView):
class GroupsUsersDetail(SecureAPIView):
"""
### The GroupsUsersDetail view allows clients to interact with a specific Group-User relationship
- URI: ```/api/groups/{group_id}/users/{user_id}```
......@@ -314,7 +311,6 @@ class GroupsUsersDetail(APIView):
* Use the GroupsUsersDetail to validate that a User is a member of a specific Group
* Cancelling a User's membership in a Group is as simple as calling DELETE on the URI
"""
permission_classes = (ApiKeyHeaderPermission,)
def get(self, request, group_id, user_id):
"""
......@@ -350,7 +346,7 @@ class GroupsUsersDetail(APIView):
return Response({}, status=status.HTTP_204_NO_CONTENT)
class GroupsGroupsList(APIView):
class GroupsGroupsList(SecureAPIView):
"""
### The GroupsGroupsList view allows clients to interact with the set of Groups related to the specified Group
- URI: ```/api/groups/{group_id}/groups/```
......@@ -381,7 +377,6 @@ class GroupsGroupsList(APIView):
** GET /groups/987/groups/246 -> 200 OK
* Once a Group Group exists, you can additionally link to Users and Courses (see GroupsUsersList, GroupsCoursesList)
"""
permission_classes = (ApiKeyHeaderPermission,)
def post(self, request, group_id):
"""
......@@ -454,7 +449,7 @@ class GroupsGroupsList(APIView):
return Response(response_data, status=response_status)
class GroupsGroupsDetail(APIView):
class GroupsGroupsDetail(SecureAPIView):
"""
### The GroupsGroupsDetail view allows clients to interact with a specific Group-Group relationship
- URI: ```/api/groups/{group_id}/groups/{related_group_id}```
......@@ -466,7 +461,6 @@ class GroupsGroupsDetail(APIView):
** Is the current course series linked to the specified workgroup?
* To remove an existing Group-Group relationship, simply call DELETE on the URI
"""
permission_classes = (ApiKeyHeaderPermission,)
def get(self, request, group_id, related_group_id):
"""
......@@ -520,7 +514,7 @@ class GroupsGroupsDetail(APIView):
return Response({}, status=response_status)
class GroupsCoursesList(APIView):
class GroupsCoursesList(SecureAPIView):
"""
### The GroupsCoursesList view allows clients to interact with the set of Courses related to the specified Group
- URI: ```/api/groups/{group_id}/courses/```
......@@ -536,7 +530,6 @@ class GroupsCoursesList(APIView):
* Create a Group of Courses to model cases such as an academic program or topical series
* Once a Course Group exists, you can additionally link to Users and other Groups (see GroupsUsersList, GroupsGroupsList)
"""
permission_classes = (ApiKeyHeaderPermission,)
def post(self, request, group_id):
"""
......@@ -595,7 +588,7 @@ class GroupsCoursesList(APIView):
return Response(response_data, status=response_status)
class GroupsCoursesDetail(APIView):
class GroupsCoursesDetail(SecureAPIView):
"""
### The GroupsCoursesDetail view allows clients to interact with a specific Group-Course relationship
- URI: ```/api/groups/{group_id}/courses/{course_id}```
......@@ -608,7 +601,6 @@ class GroupsCoursesDetail(APIView):
* Removing a Course from a Group is as simple as calling DELETE on the URI
* Remove a course from the specified academic program
"""
permission_classes = (ApiKeyHeaderPermission,)
def get(self, request, group_id, course_id):
"""
......
......@@ -3,7 +3,10 @@ import logging
from django.conf import settings
from api_manager.utils import get_client_ip_address, address_exists_in_network
from rest_framework import permissions
from rest_framework.views import APIView
log = logging.getLogger(__name__)
......@@ -50,3 +53,34 @@ class ApiKeyHeaderPermission(permissions.BasePermission):
# Allow the request to take place
return True
class IPAddressRestrictedPermission(permissions.BasePermission):
"""
Check for permissions by matching the request IP address
against the allowed ip address(s)
"""
def has_permission(self, request, view):
ip_address = get_client_ip_address(request)
allowed_ip_addresses = getattr(settings, 'ALLOWED_IP_ADDRESSES', None)
if allowed_ip_addresses:
for allowed_ip_address in allowed_ip_addresses:
if '/' in allowed_ip_address:
is_allowed = address_exists_in_network(ip_address, allowed_ip_address)
if is_allowed:
return is_allowed
else:
if ip_address == allowed_ip_address:
return True
log.warn("{} is not allowed to access Api".format(ip_address))
return False
else:
return True
class SecureAPIView(APIView):
"""
Inherited from APIView
"""
permission_classes = (ApiKeyHeaderPermission, IPAddressRestrictedPermission)
......@@ -10,14 +10,14 @@ from django.contrib.auth.models import AnonymousUser, User
from django.core.exceptions import ObjectDoesNotExist
from django.utils.importlib import import_module
from django.utils.translation import ugettext as _
from api_manager.permissions import SecureAPIView
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from util.bad_request_rate_limiter import BadRequestRateLimiter
from api_manager.permissions import ApiKeyHeaderPermission
from api_manager.users.serializers import UserSerializer
from student.models import (
LoginFailures, PasswordHistory
......@@ -40,8 +40,8 @@ def _generate_base_uri(request):
return resource_uri
class SessionsList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class SessionsList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request):
"""
......@@ -113,8 +113,8 @@ class SessionsList(APIView):
return Response(response_data, status=response_status)
class SessionsDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class SessionsDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, session_id):
"""
......
......@@ -3,7 +3,8 @@ from django.middleware.csrf import get_token
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from api_manager.permissions import SecureAPIView
from api_manager.permissions import ApiKeyHeaderPermission
......@@ -23,9 +24,8 @@ def _generate_base_uri(request):
return resource_uri
class SystemDetail(APIView):
class SystemDetail(SecureAPIView):
"""Manages system-level information about the Open edX API"""
permission_classes = (ApiKeyHeaderPermission,)
def get(self, request):
base_uri = _generate_base_uri(request)
......@@ -37,9 +37,8 @@ class SystemDetail(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class ApiDetail(APIView):
class ApiDetail(SecureAPIView):
"""Manages top-level information about the Open edX API"""
permission_classes = (ApiKeyHeaderPermission,)
def get(self, request):
base_uri = _generate_base_uri(request)
......
......@@ -13,130 +13,69 @@ from django.test.utils import override_settings
TEST_API_KEY = "123456ABCDEF"
@override_settings(DEBUG=True, EDX_API_KEY=None)
class PermissionsTestsDebug(TestCase):
@override_settings(ALLOWED_IP_ADDRESSES=['127.0.0.1', '10.0.2.2', '192.168.0.0/24'])
class PermissionsTests(TestCase):
""" Test suite for Permissions helper classes """
def setUp(self):
self.test_username = str(uuid.uuid4())
self.username = self.test_username + str(randint(11, 99))
self.username = self.username[3:-1] # username is a 32-character field
self.test_password = str(uuid.uuid4())
self.test_email = str(uuid.uuid4()) + '@test.org'
def do_post(self, uri, data):
"""Submit an HTTP POST request"""
headers = {
self.test_uri = '/api/users'
self.data = {'email': self.test_email, 'username': self.test_username, 'password': self.test_password}
self.headers = {
'Content-Type': 'application/json',
'X-Edx-Api-Key': str(TEST_API_KEY),
}
response = self.client.post(uri, headers=headers, data=data)
return response
@override_settings(DEBUG=True, EDX_API_KEY=None)
def test_has_permission_debug_enabled(self):
test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99))
local_username = local_username[3:-1] # username is a 32-character field
data = {'email': self.test_email, 'username': local_username, 'password': self.test_password}
response = self.do_post(test_uri, data)
response = self._do_post(self.test_uri, self.data, self.headers)
self.assertEqual(response.status_code, 201)
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
class PermissionsTestsApiKey(TestCase):
""" Test suite for Permissions helper classes """
def setUp(self):
self.test_username = str(uuid.uuid4())
self.test_password = str(uuid.uuid4())
self.test_email = str(uuid.uuid4()) + '@test.org'
def do_post(self, uri, data):
"""Submit an HTTP POST request"""
headers = {
'Content-Type': 'application/json',
'X-Edx-Api-Key': str(TEST_API_KEY),
}
response = self.client.post(uri, headers=headers, data=data)
return response
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
def test_has_permission_valid_api_key(self):
test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99))
local_username = local_username[3:-1] # username is a 32-character field
data = {'email': self.test_email, 'username': local_username, 'password': self.test_password}
response = self.do_post(test_uri, data)
response = self._do_post(self.test_uri, self.data, self.headers)
self.assertEqual(response.status_code, 201)
@override_settings(DEBUG=False, EDX_API_KEY=None)
class PermissionsTestDeniedMissingServerKey(TestCase):
""" Test suite for Permissions helper classes """
def setUp(self):
self.test_username = str(uuid.uuid4())
self.test_password = str(uuid.uuid4())
self.test_email = str(uuid.uuid4()) + '@test.org'
def do_post(self, uri, data):
"""Submit an HTTP POST request"""
headers = {
'Content-Type': 'application/json',
'X-Edx-Api-Key': str(TEST_API_KEY),
}
response = self.client.post(uri, headers=headers, data=data)
return response
@override_settings(DEBUG=False, EDX_API_KEY=None)
def test_has_permission_missing_server_key(self):
test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99))
local_username = local_username[3:-1] # username is a 32-character field
data = {'email': self.test_email, 'username': local_username, 'password': self.test_password}
response = self.do_post(test_uri, data)
response = self._do_post(self.test_uri, self.data, self.headers)
self.assertEqual(response.status_code, 403)
@override_settings(DEBUG=False, EDX_API_KEY="67890VWXYZ")
class PermissionsTestDeniedMissingClientKey(TestCase):
""" Test suite for Permissions helper classes """
def setUp(self):
self.test_username = str(uuid.uuid4())
self.test_password = str(uuid.uuid4())
self.test_email = str(uuid.uuid4()) + '@test.org'
def do_post(self, uri, data):
"""Submit an HTTP POST request"""
@override_settings(DEBUG=False, EDX_API_KEY="67890VWXYZ")
def test_has_permission_invalid_client_key(self):
headers = {
'Content-Type': 'application/json',
}
response = self.client.post(uri, headers=headers, data=data)
return response
response = self._do_post(self.test_uri, self.data, headers)
self.assertEqual(response.status_code, 403)
def test_has_permission_invalid_client_key(self):
test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99))
local_username = local_username[3:-1] # username is a 32-character field
data = {'email': self.test_email, 'username': local_username, 'password': self.test_password}
response = self.do_post(test_uri, data)
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
def test_has_permission_invalid_ip_address(self):
response = self._do_post(self.test_uri, self.data, self.headers, ip_address={'REMOTE_ADDR': '192.1.122.22'})
self.assertEqual(response.status_code, 403)
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
def test_has_permission_valid_ip_address(self):
response = self._do_post(self.test_uri, self.data, self.headers, ip_address={'REMOTE_ADDR': '127.0.0.1'})
self.assertEqual(response.status_code, 201)
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
def test_invalid_request_header_ip_address(self):
response = self._do_post(self.test_uri, self.data, self.headers, ip_address={'HTTP_X_FORWARDED_FOR': "192.0.0.2,102.0.0.22"})
self.assertEqual(response.status_code, 403)
@override_settings(DEBUG=False, EDX_API_KEY="67890VWXYZ")
class PermissionsTestDeniedInvalidClientKey(TestCase):
""" Test suite for Permissions helper classes """
def setUp(self):
self.test_username = str(uuid.uuid4())
self.test_password = str(uuid.uuid4())
self.test_email = str(uuid.uuid4()) + '@test.org'
@override_settings(DEBUG=False, EDX_API_KEY="123456ABCDEF")
def test_valid_subnet_ip_address(self):
response = self._do_post(self.test_uri, self.data, self.headers, ip_address={'REMOTE_ADDR': "192.168.0.1"})
self.assertEqual(response.status_code, 201)
def do_post(self, uri, data):
def _do_post(self, uri, data, headers, **kwargs):
"""Submit an HTTP POST request"""
headers = {
'Content-Type': 'application/json',
'X-Edx-Api-Key': str(TEST_API_KEY),
}
response = self.client.post(uri, headers=headers, data=data)
ip_address = kwargs.get('ip_address', {})
response = self.client.post(uri, headers=headers, data=data, **ip_address)
return response
def test_has_permission_invalid_client_key(self):
test_uri = '/api/users'
local_username = self.test_username + str(randint(11, 99))
local_username = local_username[3:-1] # username is a 32-character field
data = {'email': self.test_email, 'username': local_username, 'password': self.test_password}
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 403)
......@@ -10,11 +10,12 @@ from django.conf import settings
from django.utils.translation import get_language, ugettext_lazy as _
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db.models import Q
from api_manager.permissions import SecureAPIView
from api_manager.models import GroupProfile
from api_manager.permissions import ApiKeyHeaderPermission
from courseware import module_render
from courseware.model_data import FieldDataCache
from courseware.views import get_module_for_descriptor, save_child_position, get_current_child
......@@ -110,8 +111,8 @@ def _save_content_position(request, user, course_id, course_descriptor, position
return saved_content.id
class UsersList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request):
"""
......@@ -211,9 +212,8 @@ class UsersList(APIView):
return Response(response_data, status=status_code)
class UsersDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, user_id):
"""
GET retrieves an existing user from the system
......@@ -377,9 +377,8 @@ class UsersDetail(APIView):
return Response(response_data, status=status.HTTP_200_OK)
class UsersGroupsList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersGroupsList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, user_id):
"""
POST creates a new user-group relationship in the system
......@@ -439,9 +438,8 @@ class UsersGroupsList(APIView):
return Response(response_data, status=response_status)
class UsersGroupsDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersGroupsDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, user_id, group_id):
"""
GET retrieves an existing user-group relationship from the system
......@@ -472,9 +470,8 @@ class UsersGroupsDetail(APIView):
return Response({}, status=status.HTTP_204_NO_CONTENT)
class UsersCoursesList(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersCoursesList(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, user_id):
"""
POST creates a new course enrollment for a user
......@@ -529,9 +526,8 @@ class UsersCoursesList(APIView):
return Response(response_data, status=status_code)
class UsersCoursesDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersCoursesDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def post(self, request, user_id, course_id):
"""
POST creates an ACTIVE course enrollment for the specified user
......@@ -605,9 +601,8 @@ class UsersCoursesDetail(APIView):
return Response({}, status=status.HTTP_204_NO_CONTENT)
class UsersCoursesGradesDetail(APIView):
permission_classes = (ApiKeyHeaderPermission,)
class UsersCoursesGradesDetail(SecureAPIView):
""" Inherit with SecureAPIView """
def get(self, request, user_id, course_id):
"""
GET returns the current gradebook for the user in a course
......
""" API implementation for Secure api calls. """
import socket
import struct
def address_exists_in_network(ip_address, net_n_bits):
"""
return True if the ip address exists in the subnet address
otherwise return False
"""
ip_address = struct.unpack('<L', socket.inet_aton(ip_address))[0]
net, bits = net_n_bits.split('/')
net_address = struct.unpack('<L', socket.inet_aton(net))[0]
net_mask = ((1L << int(bits)) - 1)
return ip_address & net_mask == net_address & net_mask
def get_client_ip_address(request):
"""
get the client IP Address
"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip_address = x_forwarded_for.split(',')[-1].strip()
else:
ip_address = request.META.get('REMOTE_ADDR')
return ip_address
......@@ -573,6 +573,7 @@ if FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
##### ADVANCED_SECURITY_CONFIG #####
ADVANCED_SECURITY_CONFIG = ENV_TOKENS.get('ADVANCED_SECURITY_CONFIG', {})
ALLOWED_IP_ADDRESSES = ['127.0.0.1']
##### GOOGLE ANALYTICS IDS #####
GOOGLE_ANALYTICS_ACCOUNT = AUTH_TOKENS.get('GOOGLE_ANALYTICS_ACCOUNT')
......
......@@ -310,3 +310,6 @@ try:
from .private import * # pylint: disable=import-error
except ImportError:
pass
########################## ALLOWED API USER IP ########################
ALLOWED_IP_ADDRESSES = ['127.0.0.1']
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