Skip to content

Commit

Permalink
feat: add option to add all created users as staff
Browse files Browse the repository at this point in the history
Also fix bugs when reading upper and lower case emails
  • Loading branch information
chrismaille committed Jul 31, 2024
1 parent 7c8f362 commit 1a7b3ab
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/stale@v4
with:
days-before-stale: 60 # Mark as stale after 60 days
days-before-stale: 30 # Mark as stale after 60 days
days-before-close: 7 # Close 7 days after being marked as stale
stale-issue-message: 'This issue has been marked as stale due to lack of activity. It will be closed in 7 days if no further activity occurs.'
stale-pr-message: 'This pull request has been marked as stale due to lack of activity. It will be closed in 7 days if no further activity occurs.'
Expand Down
31 changes: 31 additions & 0 deletions .run/Serve Docs.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Serve Docs" type="PythonConfigurationType" factoryName="Python">
<module name="django-microsoft-sso" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Python 3.11.9 WSL (Ubuntu): (/home/chrismaille/.cache/pypoetry/virtualenvs/django-google-sso-Y1eudxms-py3.11/bin/python)" />
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<EXTENSION ID="software.aws.toolkits.jetbrains.core.execution.PythonAwsConnectionExtension">
<option name="credential" />
<option name="region" />
<option name="useCurrentConnection" value="false" />
</EXTENSION>
<option name="SCRIPT_NAME" value="mkdocs" />
<option name="PARAMETERS" value="serve" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="true" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>
15 changes: 10 additions & 5 deletions django_google_sso/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class UserHelper:

@property
def user_email(self):
return self.user_info["email"]
return self.user_info["email"].lower()

@property
def user_model(self) -> AbstractUser | Model:
Expand All @@ -113,8 +113,10 @@ def get_or_create_user(self, extra_users_args: dict | None = None):
user_defaults = extra_users_args or {}
if self.username_field.name not in user_defaults:
user_defaults[self.username_field.name] = self.user_email
if "email" not in user_defaults:
user_defaults["email"] = self.user_email
user, created = self.user_model.objects.get_or_create(
email=self.user_email, defaults=user_defaults
email__iexact=self.user_email, defaults=user_defaults
)
self.check_first_super_user(user)
self.check_for_update(created, user)
Expand Down Expand Up @@ -145,7 +147,7 @@ def check_for_update(self, created, user):
def check_first_super_user(self, user):
if conf.GOOGLE_SSO_AUTO_CREATE_FIRST_SUPERUSER:
superuser_exists = self.user_model.objects.filter(
is_superuser=True, email__contains=f"@{self.user_email.split('@')[-1]}"
is_superuser=True, email__icontains=f"@{self.user_email.split('@')[-1]}"
).exists()
if not superuser_exists:
message_text = _(
Expand All @@ -159,7 +161,10 @@ def check_first_super_user(self, user):
self.user_changed = True

def check_for_permissions(self, user):
if user.email in conf.GOOGLE_SSO_STAFF_LIST:
if (
user.email in conf.GOOGLE_SSO_STAFF_LIST
or "*" in conf.GOOGLE_SSO_STAFF_LIST
):
message_text = _(
f"User email: {self.user_email} in GOOGLE_SSO_STAFF_LIST. "
f"Added Staff Permission."
Expand All @@ -178,6 +183,6 @@ def check_for_permissions(self, user):
user.is_staff = True

def find_user(self):
query = self.user_model.objects.filter(email=self.user_email)
query = self.user_model.objects.filter(email__iexact=self.user_email)
if query.exists():
return query.get()
56 changes: 56 additions & 0 deletions django_google_sso/tests/test_user_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from copy import deepcopy

import pytest
from django.contrib.auth.models import User

from django_google_sso import conf
from django_google_sso.main import UserHelper
Expand Down Expand Up @@ -88,6 +89,32 @@ def test_update_existing_user_record(
assert user.email == google_response_update["email"]


def test_add_all_users_to_staff_list(
faker, google_response, callback_request, settings
):
# Arrange
settings.GOOGLE_SSO_STAFF_LIST = ["*"]
settings.GOOGLE_SSO_AUTO_CREATE_FIRST_SUPERUSER = False
importlib.reload(conf)

emails = [
faker.email(),
faker.email(),
faker.email(),
]

# Act
for email in emails:
response = deepcopy(google_response)
response["email"] = email
helper = UserHelper(response, callback_request)
helper.get_or_create_user()
helper.find_user()

# Assert
assert User.objects.filter(is_staff=True).count() == 3


def test_create_staff_from_list(google_response, callback_request, settings):
# Arrange
settings.GOOGLE_SSO_AUTO_CREATE_FIRST_SUPERUSER = False
Expand Down Expand Up @@ -140,3 +167,32 @@ def test_different_null_values(google_response, callback_request, monkeypatch):
# Assert
assert user_one.googlessouser.locale == "pt_BR"
assert user_two.googlessouser.locale == "pt_BR"


def test_duplicated_emails(google_response, callback_request):
# Arrange
User.objects.create(
email=google_response["email"].upper(),
username=google_response["email"].upper(),
first_name=google_response["given_name"],
last_name=google_response["family_name"],
)

lowercase_email_response = deepcopy(google_response)
lowercase_email_response["email"] = lowercase_email_response["email"].lower()
uppercase_email_response = deepcopy(google_response)
uppercase_email_response["email"] = uppercase_email_response["email"].upper()

# Act
user_one_helper = UserHelper(uppercase_email_response, callback_request)
user_one_helper.get_or_create_user()
user_one = user_one_helper.find_user()

user_two_helper = UserHelper(lowercase_email_response, callback_request)
user_two_helper.get_or_create_user()
user_two = user_two_helper.find_user()

# Assert
assert user_one.id == user_two.id
assert user_one.email == user_two.email
assert User.objects.count() == 1
7 changes: 7 additions & 0 deletions docs/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ GOOGLE_SSO_SUPERUSER_LIST = ["another-email@my-domain.com"]
GOOGLE_SSO_AUTO_CREATE_FIRST_SUPERUSER = True
```

For staff user creation _only_, you can add all users using "*" as the value:

```python
# Use "*" to add all users as staff
GOOGLE_SSO_STAFF_LIST = ["*"]
```

## Fine-tuning users before creation

If you need to do some processing _before_ user is created, you can set the
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ google-auth-oauthlib = "*"
auto-changelog = "*"
arrow = "*"
black = {version = "*", allow-prereleases = true}
Faker = "*"
pre-commit = "*"
pytest-coverage = "*"
pytest-django = "*"
Expand Down

0 comments on commit 1a7b3ab

Please sign in to comment.