-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Backend Security Audit fixes #352
Changes from 1 commit
b585295
3204c7e
ca03c46
cc77cd0
73b18a1
810ea86
6b17024
69aabe8
c7d7b0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,4 @@ class Meta: | |
abstract = True | ||
|
||
def __str__(self): | ||
return "ah yes" | ||
return "__str__ not defined for this model" | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ class CustomUserAdmin(UserAdmin): | |
) | ||
}, | ||
), | ||
("Admin Options", {"classes": ("collapse",), "fields": ("is_staff", "groups")}), | ||
("Admin Options", {"classes": ("collapse",), "fields": ("is_active", "is_staff", "is_superuser", "groups")}), | ||
) | ||
add_fieldsets = ( | ||
( | ||
|
@@ -35,7 +35,7 @@ class CustomUserAdmin(UserAdmin): | |
}, | ||
), | ||
) | ||
list_display = ("email", "first_name", "last_name", "is_active", "is_staff", "is_superuser", "permissions") | ||
list_display = ("email", "permissions", "is_active", "is_staff", "is_superuser", "first_name", "last_name",) | ||
list_display_links = ( | ||
"is_active", | ||
"email", | ||
|
@@ -57,7 +57,7 @@ class CustomUserAdmin(UserAdmin): | |
ordering = [] | ||
|
||
def permissions(self, obj): | ||
return ", ".join([g.name for g in obj.groups.all()]) | ||
return [g.name for g in obj.groups.all()] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @oudeismetis - I trust that you checked that this works? This is changing the return type from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct. I pulled this from a project where I made the change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great! This is good to go then. |
||
|
||
class Media(AutocompleteAdminMedia): | ||
pass | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ class Meta: | |
"last_name", | ||
"full_name", | ||
) | ||
read_only_fields = ["email"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default behavior shouldn't allow changing of a users email just by having a valid token. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @paribaker I know you had thoughts about this one |
||
|
||
|
||
class UserLoginSerializer(serializers.ModelSerializer): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,9 +18,9 @@ | |
from rest_framework.exceptions import ValidationError | ||
from rest_framework.response import Response | ||
|
||
from {{ cookiecutter.project_slug }}.core.forms import PreviewTemplateForm | ||
from {{ cookiecutter.project_slug }}.utils.emails import send_html_email | ||
|
||
from .forms import PreviewTemplateForm | ||
from .models import User | ||
from .permissions import CreateOnlyPermissions | ||
from .serializers import UserLoginSerializer, UserRegistrationSerializer, UserSerializer | ||
|
@@ -50,13 +50,7 @@ def post(self, request, *args, **kwargs): | |
return Response(response_data) | ||
|
||
|
||
class UserViewSet( | ||
viewsets.GenericViewSet, | ||
mixins.RetrieveModelMixin, | ||
mixins.ListModelMixin, | ||
mixins.UpdateModelMixin, | ||
mixins.DestroyModelMixin, | ||
): | ||
class UserViewSet(viewsets.GenericViewSet, mixins.RetrieveModelMixin): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We implement some of these with overrides below. |
||
queryset = User.objects.all() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to remove this but it raises an error: I couldn't find any deep discussion on how to better use the queryset here. You can't auto-filter here by the logged in user or anything like that. All examples just have it as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, in that case I think you could replace it with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like it, but that doesn't work. A couple of tests are failing now because the chain of filters starts by finding nothing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setting it to just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think that's a good place to land |
||
serializer_class = UserSerializer | ||
|
||
|
@@ -66,29 +60,29 @@ class UserViewSet( | |
|
||
@transaction.atomic | ||
def create(self, request, *args, **kwargs): | ||
""" | ||
Endpoint to create/register a new user. | ||
""" | ||
serializer = UserRegistrationSerializer(data=request.data) | ||
serializer.is_valid(raise_exception=True) | ||
serializer.save() # This calls .create() on serializer | ||
user = serializer.instance | ||
|
||
user = serializer.save() | ||
# Log-in user and re-serialize response | ||
response_data = UserLoginSerializer.login(user, request) | ||
return Response(response_data, status=status.HTTP_201_CREATED) | ||
|
||
def update(self, request, *args, **kwargs): | ||
""" | ||
Endpoint to create/register a new user. | ||
""" | ||
serializer = UserSerializer(data=request.data, instance=self.get_object(), partial=True) | ||
|
||
serializer.is_valid(raise_exception=True) | ||
serializer.save() | ||
user = serializer.data | ||
return Response(serializer.data, status=status.HTTP_200_OK) | ||
|
||
return Response(user, status=status.HTTP_200_OK) | ||
def destroy(self, request, *args, **kwargs): | ||
""" | ||
When deleting a user's account, just disable their account first | ||
The user may have a regret and try to get their account back | ||
A background job should then properly delete the data after X days | ||
""" | ||
user = self.get_object() | ||
user.is_active = False | ||
user.save() | ||
return Response(status=status.HTTP_204_NO_CONTENT) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment above should be clear. |
||
|
||
|
||
@api_view(["post"]) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,9 @@ | |
if CURRENT_DOMAIN not in ALLOWED_HOSTS: | ||
ALLOWED_HOSTS.append(CURRENT_DOMAIN) | ||
|
||
# Used by the corsheaders app/middleware (django-cors-headers) to allow multiple domains to access the backend | ||
CORS_ALLOWED_ORIGINS = [f"https://{host}" for host in ALLOWED_HOSTS] | ||
|
||
# Application definition | ||
|
||
INSTALLED_APPS = [ | ||
|
@@ -306,7 +309,6 @@ | |
if not IN_DEV: | ||
SECURE_SSL_REDIRECT = True | ||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") | ||
MIDDLEWARE += ["django.middleware.security.SecurityMiddleware"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. duplicate from another spot in this file. |
||
|
||
# | ||
# Custom logging configuration | ||
|
@@ -390,11 +392,6 @@ def filter(self, record): | |
# Popular testing framework that allows logging to stdout while running unit tests | ||
TEST_RUNNER = "django_nose.NoseTestSuiteRunner" | ||
|
||
CORS_ALLOWED_ORIGINS = ["https://{{ cookiecutter.project_slug|replace('_', '-') }}-staging.herokuapp.com", "https://{{ cookiecutter.project_slug|replace('_', '-') }}.herokuapp.com"] | ||
{% if cookiecutter.client_app.lower() != 'none' -%} | ||
CORS_ALLOWED_ORIGINS.append("http://localhost:8080") | ||
{% endif -%} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See further up. |
||
SWAGGER_SETTINGS = { | ||
"LOGIN_URL": "/login", | ||
"USE_SESSION_AUTH": False, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
from django.contrib import admin | ||
from django.urls import include, path | ||
|
||
admin.site.site_header = "{{ cookiecutter.project_name }} Admin" | ||
admin.site.site_title = "{{ cookiecutter.project_name }}" | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a nice little addition so that managing multiple projects makes it more obvious which admin you are in. Also, non-dev project stakeholders don't know (or need to care) what the "Django Admin" is. It's just the admin for the app. |
||
urlpatterns = [ | ||
path(r"staff/", admin.site.urls), | ||
path(r"", include("{{ cookiecutter.project_slug }}.common.favicon_urls")), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gentle nudge for devs to set this for their new models
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you