def test_only_anon_allowed(self): CRUDManager.filter_set = {} CRUDManager.add_permissions(TestClass, 'R', 'anonymous', TestClass.objects.field_three_true) # Set expectations: self.expected_output['anonymous']['R']['__default'] = TestClass.objects.field_three_true(TestClass.objects.all(), self.user, None) url = reverse('api-test-list') self.verify_requests_against_expectations(TestClass, url, self.authentication_header, nested_key=None)
def test_add_permissions_succeeds_with_explicit_filter(self): CRUDManager.add_permissions(TestClass, 'CR', test_roles[0], TestClass.objects.field_one_true, 'filter_string') self.assertEqual( CRUDManager.filter_set[str(TestClass)]['filter'][test_roles[0]] ['filter_string'], TestClass.objects.field_one_true) self.assertEqual( CRUDManager.filter_set[str(TestClass)]['allowed_methods'][ test_roles[0]]['filter_string'], 'CR')
def test_init_filter_set_for_model(self): # TestClass shouldn't be represented in filter_set yet. self.assertTrue(str(TestClass) not in CRUDManager.filter_set.keys()) # Call init CRUDManager.init_filter_set_for_model(TestClass) # Look for model filter_set self.assertTrue(str(TestClass) in CRUDManager.filter_set.keys()) model_filter_set = CRUDManager.filter_set[str(TestClass)] self.verify_model_filter_set_structure(model_filter_set)
def test_only_anon_allowed(self): CRUDManager.filter_set = {} CRUDManager.add_permissions(TestClass, 'R', 'anonymous', TestClass.objects.field_three_true) # Set expectations: self.expected_output['anonymous']['R'][ '__default'] = TestClass.objects.field_three_true( TestClass.objects.all(), self.user, None) url = reverse('api-test-list') self.verify_requests_against_expectations(TestClass, url, self.authentication_header, nested_key=None)
def print_filters(request): """ Include all filters available for this user and role (role is set in session vars) """ redirect_field_name = "next" redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, '')) path = resolve(redirect_to) role = request.session['crud-role'] filters = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)['filter'][role] valid_filters = [filter_name for filter_name, filter_value in filters.items() if filter_value is not None] return_string = '' for filter_str in valid_filters: if filter_str == "__default": display_str = "(No Filter)" else: display_str = filter_str.title() return_string += '<input style="width: 20%" type="radio" name="filter" value="' + filter_str + '">' + display_str + '<br>' if return_string == '': return_string = '(No filters on this view. Click "Continue.")' else: return_string += "<br> " return mark_safe(return_string)
def print_filters(request): """ Include all filters available for this user and role (role is set in session vars) """ redirect_field_name = "next" redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, "")) path = resolve(redirect_to) role = request.session["crud-role"] filters = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)["filter"][role] valid_filters = [filter_name for filter_name, filter_value in filters.items() if filter_value is not None] return_string = "" for filter_str in valid_filters: if filter_str == "__default": display_str = "(No Filter)" else: display_str = filter_str.title() return_string += ( '<input style="width: 20%" type="radio" name="filter" value="' + filter_str + '">' + display_str + "<br>" ) if return_string == "": return_string = '(No filters on this view. Click "Continue.")' else: return_string += "<br> " return return_string
def test_get_filter_set_for_model_before_init(self): # TestClass shouldn't be represented in filter_set yet. self.assertTrue(str(TestClass) not in CRUDManager.filter_set.keys()) # Call get_filter_set_for_model, and verify that this initializes filter_set for this model model_filter_set = CRUDManager.get_filter_set_for_model(TestClass) self.verify_model_filter_set_structure(model_filter_set)
def _pre_setup(self): CRUDManager.set_authorization_function(default_auth_function) self.user = G(User) self.token, created = ExpiringToken.objects.get_or_create(user=self.user) self.expected_output = {} for role in CRUDManager.all_roles: self.expected_output[role] = {} for operation in ['C', 'R', 'U', 'D']: self.expected_output[role][operation] = {'__default': None} self.client = APIClient() # Disable REST_FRAMEWORK pagination, if it exists. try: rest_framework_settings = settings.REST_FRAMEWORK rest_framework_settings['PAGINATE_BY'] = None rest_framework_settings['DEFAULT_PERMISSION_CLASSES'] = ('rest_framework.permissions.AllowAny',) except (AttributeError, KeyError): pass
def _pre_setup(self): CRUDManager.set_authorization_function(default_auth_function) self.user = G(User) self.token, created = ExpiringToken.objects.get_or_create( user=self.user) self.expected_output = {} for role in CRUDManager.all_roles: self.expected_output[role] = {} for operation in ['C', 'R', 'U', 'D']: self.expected_output[role][operation] = {'__default': None} self.client = APIClient() # Disable REST_FRAMEWORK pagination, if it exists. try: rest_framework_settings = settings.REST_FRAMEWORK rest_framework_settings['PAGINATE_BY'] = None rest_framework_settings['DEFAULT_PERMISSION_CLASSES'] = ( 'rest_framework.permissions.AllowAny', ) except (AttributeError, KeyError): pass
def available_roles(user, request): """ Print the available roles for this user """ available_roles = [] for role in CRUDManager.all_roles: if role in ["anonymous", "authenticated"]: available_roles.append(role) elif role == "admin" and user.is_superuser: available_roles.append(role) elif CRUDManager.auth_function(role, user, request): available_roles.append(role) return available_roles
def available_roles(user, request): """ Print the available roles for this user """ available_roles = [] for role in CRUDManager.all_roles: if role in ['anonymous', 'authenticated']: available_roles.append(role) elif role == "admin" and user.is_superuser: available_roles.append(role) elif CRUDManager.auth_function(role, user, request): available_roles.append(role) return available_roles
def test_set_authorization_function(self): self.assertEqual(CRUDManager.auth_function, None) CRUDManager.set_authorization_function(always_fail_auth_function) self.assertEqual(CRUDManager.auth_function, always_fail_auth_function)
def setUp(self): # If you override this test class, remember to set the following: CRUDManager.set_authorization_function(default_auth_function)
def test_add_permissions_succeeds_with_default_filter(self): CRUDManager.add_permissions(TestClass, 'C', test_roles[0], TestClass.objects.field_one_true) CRUDManager.filter_set[str(TestClass)]['allowed_methods'][ test_roles[0]]['__default'] = TestClass.objects.field_one_true
def test_add_permissions_invalid_permission(self): with self.assertRaises(CRUDException): CRUDManager.add_permissions(TestClass, 'NOT_A_VALID_PERMISSION', test_roles[0], TestClass.objects.field_one_true)
def test_add_permissions_non_function(self): not_a_function = 3.14159 with self.assertRaises(CRUDException): CRUDManager.add_permissions(TestClass, 'R', test_roles[0], not_a_function)
def test_add_permissions_invalid_role(self): with self.assertRaises(CRUDException): CRUDManager.add_permissions(TestClass, 'C', 'NOT_A_VALID_ROLE', TestClass.objects.field_one_true)
def test_random_combinations_with_filters(self): CRUDManager.filter_set = {} CRUDManager.add_permissions(TestClass, 'RD', 'anonymous', TestClass.objects.field_three_true, 'three') CRUDManager.add_permissions(TestClass, 'R', 'authenticated', TestClass.objects.field_one_true, 'one') CRUDManager.add_permissions(TestClass, 'CRU', test_roles[0], CRUDManager.all_objects, 'all') CRUDManager.add_permissions(TestClass, 'UD', test_roles[1], TestClass.objects.field_two_true) CRUDManager.add_permissions(TestClass, 'CR', test_roles[2], TestClass.objects.field_four_true, 'four') CRUDManager.add_permissions(TestClass, 'CD', test_roles[3], TestClass.objects.field_five_true) CRUDManager.add_permissions(TestClass, 'CRUD', test_roles[4], TestClass.objects.no_objects, 'none') # Set expectations: self.expected_output['anonymous']['R']['three'] = TestClass.objects.field_three_true(TestClass.objects.all(), self.user, None) self.expected_output['anonymous']['D']['three'] = TestClass.objects.field_three_true(TestClass.objects.all(), self.user, None) self.expected_output['authenticated']['R']['one'] = TestClass.objects.field_one_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[0]]['C']['all'] = TestClass.objects.all() self.expected_output[test_roles[0]]['R']['all'] = TestClass.objects.all() self.expected_output[test_roles[0]]['U']['all'] = TestClass.objects.all() self.expected_output[test_roles[1]]['U']['__default'] = TestClass.objects.field_two_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[1]]['D']['__default'] = TestClass.objects.field_two_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[2]]['C']['four'] = TestClass.objects.field_four_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[2]]['R']['four'] = TestClass.objects.field_four_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[3]]['C']['__default'] = TestClass.objects.field_five_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[3]]['D']['__default'] = TestClass.objects.field_five_true(TestClass.objects.all(), self.user, None) self.expected_output[test_roles[4]]['C']['none'] = TestClass.objects.none() self.expected_output[test_roles[4]]['R']['none'] = TestClass.objects.none() self.expected_output[test_roles[4]]['U']['none'] = TestClass.objects.none() self.expected_output[test_roles[4]]['D']['none'] = TestClass.objects.none() url = reverse('api-test-list') self.verify_requests_against_expectations(TestClass, url, self.authentication_header, nested_key=None)
def print_available_options(request): """ Print the filter set for this model. """ path = resolve(request.path) allowed_methods = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)["allowed_methods"] htmlLines = [] all_roles_for_user = "" for role in CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)["filter"].keys(): # Decide if we can show this info to this user. if role == "anonymous": can_view_role = True elif role == "authenticated": can_view_role = request.user.is_authenticated() elif role == "admin": can_view_role = request.user.is_superuser else: can_view_role = CRUDManager.auth_function(role, request.user, request) if can_view_role: all_roles_for_user += str(allowed_methods[role].values()).replace("dict_values", "") if role not in ["authenticated", "anonymous"]: header_string = ' -H "CRUD-Role: ' + role + '"' else: header_string = "" if role != "anonymous" and TokenAuthentication in path.func.cls.authentication_classes: auth_string = ' -H "Authorization: Token ' + request.user.auth_token.key + '"' elif role != "anonymous" and BasicAuthentication in path.func.cls.authentication_classes: auth_string = ' -H "Authorization: Basic (base64 encoding of "username:password")"' else: auth_string = "" # Make sure this role can perform at least one operation on this view: if not all(value is None for value in allowed_methods[role].values()): filters = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)["filter"][role] htmlLines.append("<br><b><u> Role " + role + "</b></u>") for filter_str in filters.keys(): filter_func = filters[filter_str] methods = allowed_methods[role][filter_str] if methods is None: methods = "(none)" if filter_str == "__default": filters_string = "" filter_str = "no filter: " else: filters_string = ' -H "CRUD-Filters: ' + filter_str + '"' filter_str = "filter '{filter_str}': ".format(filter_str=filter_str) htmlLines.append("Operations " + methods + " with " + filter_str) if filter_func is not None and methods != "C": doc_string = filter_func.__doc__ if doc_string is None: doc_string = "(No doc string available for this function)" doc_string = doc_string.replace("\n", "") # Remove all duplicate whitespace doc_string = " ".join(doc_string.split()) htmlLines.append(" Uses objects from function '<i>" + doc_string + "</i>'") try: full_url = request.META["werkzeug.request"].base_url htmlLines.append( " Example using CURL and GET: <i>'curl -X GET " + full_url + header_string + filters_string + auth_string + "</i>'" ) except KeyError: htmlLines.append(" (Could not create example CURL commands)") # This sucks, but if any of the users have 'C' as an allowed method (gross), # grab the code from our create function (ummm), and use regular expressions # (what?!) to find the required_params and optional_params dictionaries (WHY?!). # # Note: this doesn't work when there's a method decorator like rate_limit. # # TODO: Extract the required_params and optional_params design pattern up one # level, so that (among other things) we can do away with this. if "C" in all_roles_for_user: source_string = inspect.getsource(path.func.cls.create) required_expression = re.compile("required_params[\s]*=[\s]*(([\[\{]){1}[^\]]*[\]\}]{1})") required_iterator = required_expression.finditer(source_string) htmlLines.append("<br><b><u>Required 'Create' POST Parameters:</u></b>") required_string = "(none)" for match in required_iterator: required_string = match.groups()[0] required_string = " ".join(required_string.split()) htmlLines.append(required_string) optional_expression = re.compile("optional_params[\s]*=[\s]*(([\[\{]){1}[^\]]*[\]\}]{1})") optional_iterator = optional_expression.finditer(source_string) htmlLines.append("<br><b><u>Optional 'Create' POST Parameters:</u></b>") optional_string = "(none)" for match in optional_iterator: optional_string = match.groups()[0] optional_string = " ".join(optional_string.split()) htmlLines.append(optional_string) htmlText = "\n".join(htmlLines) return htmlText
def test_add_permissions_succeeds_with_default_filter(self): CRUDManager.add_permissions(TestClass, 'C', test_roles[0], TestClass.objects.field_one_true) CRUDManager.filter_set[str(TestClass)]['allowed_methods'][test_roles[0]]['__default'] = TestClass.objects.field_one_true
def test_add_permissions_succeeds_with_explicit_filter(self): CRUDManager.add_permissions(TestClass, 'CR', test_roles[0], TestClass.objects.field_one_true, 'filter_string') self.assertEqual(CRUDManager.filter_set[str(TestClass)]['filter'][test_roles[0]]['filter_string'], TestClass.objects.field_one_true) self.assertEqual(CRUDManager.filter_set[str(TestClass)]['allowed_methods'][test_roles[0]]['filter_string'], 'CR')
def print_available_options(request): """ Print the filter set for this model. """ path = resolve(request.path) allowed_methods = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)['allowed_methods'] htmlLines = [] all_roles_for_user = '' for role in CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)['filter'].keys(): # Decide if we can show this info to this user. if role == 'anonymous': can_view_role = True elif role == 'authenticated': can_view_role = request.user.is_authenticated() elif role == "admin": can_view_role = request.user.is_superuser else: can_view_role = CRUDManager.auth_function(role, request.user, request) if can_view_role: all_roles_for_user += str(allowed_methods[role].values()).replace("dict_values", "") if role not in ['authenticated', 'anonymous']: header_string = ' -H "CRUD-Role: ' + role + '"' else: header_string = '' if role != 'anonymous' and TokenAuthentication in path.func.cls.authentication_classes: auth_string = ' -H "Authorization: Token ' + request.user.auth_token.key + '"' elif role != 'anonymous' and BasicAuthentication in path.func.cls.authentication_classes: auth_string = ' -H "Authorization: Basic (base64 encoding of "username:password")"' else: auth_string = '' # Make sure this role can perform at least one operation on this view: if not all(value is None for value in allowed_methods[role].values()): filters = CRUDManager.get_filter_set_for_model(path.func.cls.crud_model)['filter'][role] htmlLines.append("<br><b><u> Role " + role + "</b></u>") for filter_str in filters.keys(): filter_func = filters[filter_str] methods = allowed_methods[role][filter_str] if methods is None: methods = "(none)" if filter_str == '__default': filters_string = '' filter_str = "no filter: " else: filters_string = ' -H "CRUD-Filters: ' + filter_str + '"' filter_str = "filter '{filter_str}': ".format(filter_str=filter_str) htmlLines.append("Operations " + methods + " with " + filter_str) if filter_func is not None and methods != 'C': doc_string = filter_func.__doc__ if doc_string is None: doc_string = "(No doc string available for this function)" doc_string = doc_string.replace("\n", "") # Remove all duplicate whitespace doc_string = ' '.join(doc_string.split()) htmlLines.append(" Uses objects from function '<i>" + doc_string + "</i>'") try: full_url = request.META['werkzeug.request'].base_url htmlLines.append(" Example using CURL and GET: <i>\'curl -X GET " + full_url + header_string + filters_string + auth_string + '</i>\'') except KeyError: htmlLines.append(" (Could not create example CURL commands)") # This sucks, but if any of the users have 'C' as an allowed method (gross), # grab the code from our create function (ummm), and use regular expressions # (what?!) to find the required_params and optional_params dictionaries (WHY?!). # # Note: this doesn't work when there's a method decorator like rate_limit. # # TODO: Extract the required_params and optional_params design pattern up one # level, so that (among other things) we can do away with this. if 'C' in all_roles_for_user: source_string = inspect.getsource(path.func.cls.create) required_expression = re.compile('required_params[\s]*=[\s]*(([\[\{]){1}[^\]]*[\]\}]{1})') required_iterator = required_expression.finditer(source_string) htmlLines.append("<br><b><u>Required 'Create' POST Parameters:</u></b>") required_string = "(none)" for match in required_iterator: required_string = match.groups()[0] required_string = ' '.join(required_string.split()) htmlLines.append(required_string) optional_expression = re.compile('optional_params[\s]*=[\s]*(([\[\{]){1}[^\]]*[\]\}]{1})') optional_iterator = optional_expression.finditer(source_string) htmlLines.append("<br><b><u>Optional 'Create' POST Parameters:</u></b>") optional_string = "(none)" for match in optional_iterator: optional_string = match.groups()[0] optional_string = ' '.join(optional_string.split()) htmlLines.append(optional_string) htmlText = '\n'.join(htmlLines) return mark_safe(htmlText)
def test_random_combinations_with_filters(self): CRUDManager.filter_set = {} CRUDManager.add_permissions(TestClass, 'RD', 'anonymous', TestClass.objects.field_three_true, 'three') CRUDManager.add_permissions(TestClass, 'R', 'authenticated', TestClass.objects.field_one_true, 'one') CRUDManager.add_permissions(TestClass, 'CRU', test_roles[0], CRUDManager.all_objects, 'all') CRUDManager.add_permissions(TestClass, 'UD', test_roles[1], TestClass.objects.field_two_true) CRUDManager.add_permissions(TestClass, 'CR', test_roles[2], TestClass.objects.field_four_true, 'four') CRUDManager.add_permissions(TestClass, 'CD', test_roles[3], TestClass.objects.field_five_true) CRUDManager.add_permissions(TestClass, 'CRUD', test_roles[4], TestClass.objects.no_objects, 'none') # Set expectations: self.expected_output['anonymous']['R'][ 'three'] = TestClass.objects.field_three_true( TestClass.objects.all(), self.user, None) self.expected_output['anonymous']['D'][ 'three'] = TestClass.objects.field_three_true( TestClass.objects.all(), self.user, None) self.expected_output['authenticated']['R'][ 'one'] = TestClass.objects.field_one_true(TestClass.objects.all(), self.user, None) self.expected_output[ test_roles[0]]['C']['all'] = TestClass.objects.all() self.expected_output[ test_roles[0]]['R']['all'] = TestClass.objects.all() self.expected_output[ test_roles[0]]['U']['all'] = TestClass.objects.all() self.expected_output[test_roles[1]]['U'][ '__default'] = TestClass.objects.field_two_true( TestClass.objects.all(), self.user, None) self.expected_output[test_roles[1]]['D'][ '__default'] = TestClass.objects.field_two_true( TestClass.objects.all(), self.user, None) self.expected_output[ test_roles[2]]['C']['four'] = TestClass.objects.field_four_true( TestClass.objects.all(), self.user, None) self.expected_output[ test_roles[2]]['R']['four'] = TestClass.objects.field_four_true( TestClass.objects.all(), self.user, None) self.expected_output[test_roles[3]]['C'][ '__default'] = TestClass.objects.field_five_true( TestClass.objects.all(), self.user, None) self.expected_output[test_roles[3]]['D'][ '__default'] = TestClass.objects.field_five_true( TestClass.objects.all(), self.user, None) self.expected_output[ test_roles[4]]['C']['none'] = TestClass.objects.none() self.expected_output[ test_roles[4]]['R']['none'] = TestClass.objects.none() self.expected_output[ test_roles[4]]['U']['none'] = TestClass.objects.none() self.expected_output[ test_roles[4]]['D']['none'] = TestClass.objects.none() url = reverse('api-test-list') self.verify_requests_against_expectations(TestClass, url, self.authentication_header, nested_key=None)