Skip to content

Commit

Permalink
- cleanup unused lines of code
Browse files Browse the repository at this point in the history
- updates backend so it considers minimal authentication parameters
- updates unittests to consider more authentication flows

Ref: #71
  • Loading branch information
oliveratfoodcoopx committed Nov 17, 2022
1 parent 4066b1c commit b6f7d29
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 20 deletions.
29 changes: 20 additions & 9 deletions tapir/accounts/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
from django.contrib.auth.backends import BaseBackend
from django.conf import settings
from keycloak import KeycloakOpenID, KeycloakAuthenticationError
from tapir.accounts.models import KeycloakUser


User = get_user_model()
class KeycloakAuthorizationCredentialsBackend(BaseBackend):

def get_user(self, user_id):
UserModel = get_user_model()


try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
user = User.objects.get(pk=user_id)
except User.DoesNotExist:
return None

# needs to validate token before returning user
Expand All @@ -26,11 +27,21 @@ def authenticate(self, request, username=None, password=None):
client_secret_key=config["CLIENT_SECRET_KEY"],
)
try:
token = kk.token("demo", "demo")
token = kk.token(username, password)
except KeycloakAuthenticationError:
return None

remote_user = kk.introspect(token["access_token"])
# User a another model, that uses remore_user fill/update this instead of AUTH_USER_MODEL
UserModel = get_user_model()
return UserModel.objects.last()
user, _ = User.objects.get_or_create(
username=remote_user['sub'],
defaults={
'first_name': remote_user.get('given_name', ''),
'last_name': remote_user.get('family_name', '')
}
)
keycloakuser, _ = KeycloakUser.objects.get_or_create(
user=user,
sub=remote_user["sub"],
defaults={},
)
return keycloakuser.user

29 changes: 29 additions & 0 deletions tapir/accounts/migrations/0003_auto_20221117_1841.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 3.2.16 on 2022-11-17 17:41

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import ldapdb.models.fields


class Migration(migrations.Migration):

dependencies = [
('accounts', '0002_initial'),
]

operations = [
migrations.CreateModel(
name='KeycloakUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sub', models.CharField(max_length=255, unique=True)),
('realm', models.CharField(max_length=255)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='keycloak_user', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddConstraint(
model_name='keycloakuser',
constraint=models.UniqueConstraint(fields=('sub', 'realm'), name='unique_sub_realm'),
),
]
16 changes: 16 additions & 0 deletions tapir/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.conf import settings
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth import get_user_model
from django.core.mail import EmailMultiAlternatives
from django.db import connections, router, models
from django.template import loader
Expand Down Expand Up @@ -383,3 +384,18 @@ def middleware(request):
return response

return middleware


class KeycloakUser(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name='keycloak_user')

sub = models.CharField(max_length=255, unique=True)
realm = models.CharField(max_length=255)


class Meta:
constraints = [
models.UniqueConstraint(fields=['sub', 'realm'], name='unique_sub_realm')
]


23 changes: 12 additions & 11 deletions tapir/accounts/tests/test_keycloak.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from django.contrib.auth import authenticate, login
from tapir.utils.tests_utils import TapirFactoryTestBase
from tapir.accounts.tests.factories.factories import TapirUserFactory
from django.test import RequestFactory

class KeyCloakAuthentication(TapirFactoryTestBase):

def setUp(self):
# Every test needs access to the request factory.
self.factory = RequestFactory()
class KeycloakAuthentication(TapirFactoryTestBase):

def test_backend_authenticates_user_against_keycloak_server(self):
request = RequestFactory().get('/')
auth_user = authenticate(request, username='demo@demo.com', password='demo')
self.assertIsNotNone(auth_user)

def test_backend_sets_active_status(self):
self.fail('check for the is_active key value and update')

def test_bla(self):
from django.contrib.auth import authenticate, login
request = self.factory.get('/')
user = TapirUserFactory()
auth_user = authenticate(request, username='asd', password='asd')
login(request, auth_user)
def test_backend_differentiates_between_diferent_realms(self):
self.fail("user from another realm cannot login")

0 comments on commit b6f7d29

Please sign in to comment.