Skip to content
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

oidc keycloak adaptions #7

Merged
merged 1 commit into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dojo/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ def globalize_vars(request):
"AZUREAD_TENANT_OAUTH2_GET_GROUPS": settings.AZUREAD_TENANT_OAUTH2_GET_GROUPS,
"AZUREAD_TENANT_OAUTH2_GROUPS_FILTER": settings.AZUREAD_TENANT_OAUTH2_GROUPS_FILTER,
"AZUREAD_TENANT_OAUTH2_CLEANUP_GROUPS": settings.AZUREAD_TENANT_OAUTH2_CLEANUP_GROUPS,
"KEYCLOAK_TENANT_OAUTH2_GET_GROUPS": settings.AZUREAD_TENANT_OAUTH2_GET_GROUPS,
"KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER": settings.AZUREAD_TENANT_OAUTH2_GROUPS_FILTER,
"KEYCLOAK_TENANT_OAUTH2_CLEANUP_GROUPS": settings.AZUREAD_TENANT_OAUTH2_CLEANUP_GROUPS,
"KEYCLOAK_ENABLED": settings.KEYCLOAK_OAUTH2_ENABLED,
"SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT": settings.SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT,
"GITHUB_ENTERPRISE_ENABLED": settings.GITHUB_ENTERPRISE_OAUTH2_ENABLED,
Expand Down
18 changes: 18 additions & 0 deletions dojo/db_migrations/0209_alter_dojo_group_social_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.1.13 on 2024-04-11 12:16

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0208_merge_acunetix'),
]

operations = [
migrations.AlterField(
model_name='dojo_group',
name='social_provider',
field=models.CharField(blank=True, choices=[('AzureAD', 'AzureAD'), ('Remote', 'Remote'), ('Keycloak', 'Keycloak')], help_text='Group imported from a social provider.', max_length=10, null=True, verbose_name='Social Authentication Provider'),
),
]
5 changes: 2 additions & 3 deletions dojo/group/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from django.contrib.auth.models import Group
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from dojo.models import Dojo_Group, Dojo_Group_Member, Role
from django.conf import settings
from dojo.models import Dojo_Group, Dojo_Group_Member, Role, Dojo_User


def get_auth_group_name(group, attempt=0):
Expand Down Expand Up @@ -41,7 +40,7 @@ def group_post_save_handler(sender, **kwargs):
group.save()

user = get_current_user()
if user and not settings.AZUREAD_TENANT_OAUTH2_GET_GROUPS:
if user and isinstance(user, Dojo_User):
# Add the current user as the owner of the group
member = Dojo_Group_Member()
member.user = user
Expand Down
2 changes: 2 additions & 0 deletions dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,11 @@ class UserContactInfo(models.Model):
class Dojo_Group(models.Model):
AZURE = 'AzureAD'
REMOTE = 'Remote'
KEYCLOAK = 'Keycloak'
SOCIAL_CHOICES = (
(AZURE, _('AzureAD')),
(REMOTE, _('Remote')),
(KEYCLOAK, _('Keycloak')),
)
name = models.CharField(max_length=255, unique=True)
description = models.CharField(max_length=4000, null=True, blank=True)
Expand Down
20 changes: 20 additions & 0 deletions dojo/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.conf import settings
from dojo.models import Product, Product_Member, Product_Type, Role, Dojo_Group, Dojo_Group_Member
from social_core.backends.azuread_tenant import AzureADTenantOAuth2
from social_core.backends.open_id_connect import OpenIdConnectAuth
from social_core.backends.google import GoogleOAuth2
from dojo.authorization.roles_permissions import Permissions, Roles
from dojo.product.queries import get_authorized_products
Expand Down Expand Up @@ -65,6 +66,25 @@ def modify_permissions(backend, uid, user=None, social=None, *args, **kwargs):
pass


def update_keycloak_groups(backend, uid, user=None, social=None, *args, **kwargs):
if settings.KEYCLOAK_OAUTH2_ENABLED and settings.KEYCLOAK_TENANT_OAUTH2_GET_GROUPS and isinstance(backend, OpenIdConnectAuth):
group_names = []
if 'groups' not in kwargs['response'] or kwargs['response']['groups'] == "":
logger.warning("No groups in response. Stopping to update groups of user based on azureAD")
return
group_ids = kwargs['response']['groups']
for group_from_response in group_ids:
if settings.KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER == "" or re.search(settings.KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER, group_from_response):
group_names.append(group_from_response)
else:
logger.debug("Skipping group " + group_from_response + " due to KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER " + settings.KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER)

if len(group_names) > 0:
assign_user_to_groups(user, group_names, 'Keycloak')
if settings.KEYCLOAK_TENANT_OAUTH2_CLEANUP_GROUPS:
cleanup_old_groups_for_user(user, group_names)


def update_azure_groups(backend, uid, user=None, social=None, *args, **kwargs):
if settings.AZUREAD_TENANT_OAUTH2_ENABLED and settings.AZUREAD_TENANT_OAUTH2_GET_GROUPS and isinstance(backend, AzureADTenantOAuth2):
# In some wild cases, there could be two social auth users
Expand Down
25 changes: 19 additions & 6 deletions dojo/settings/settings.dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
DD_SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_GET_GROUPS=(bool, False),
DD_SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_GROUPS_FILTER=(str, ''),
DD_SOCIAL_AUTH_AZUREAD_TENANT_OAUTH2_CLEANUP_GROUPS=(bool, True),
DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_GET_GROUPS=(bool, False),
DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_CLEANUP_GROUPS=(bool, True),
DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_GROUPS_FILTER=(str, ''),
DD_SOCIAL_AUTH_GITLAB_OAUTH2_ENABLED=(bool, False),
DD_SOCIAL_AUTH_GITLAB_PROJECT_AUTO_IMPORT=(bool, False),
DD_SOCIAL_AUTH_GITLAB_PROJECT_IMPORT_TAGS=(bool, False),
Expand All @@ -134,6 +137,7 @@
DD_SOCIAL_AUTH_GITLAB_API_URL=(str, 'https://gitlab.com'),
DD_SOCIAL_AUTH_GITLAB_SCOPE=(list, ['read_user', 'openid']),
DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_ENABLED=(bool, False),
DD_SOCIAL_AUTH_OIDC_OIDC_ENDPOINT=(str, ''),
DD_SOCIAL_AUTH_KEYCLOAK_KEY=(str, ''),
DD_SOCIAL_AUTH_KEYCLOAK_SECRET=(str, ''),
DD_SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY=(str, ''),
Expand Down Expand Up @@ -533,7 +537,8 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param
'dojo.okta.OktaOAuth2',
'social_core.backends.azuread_tenant.AzureADTenantOAuth2',
'social_core.backends.gitlab.GitLabOAuth2',
'social_core.backends.keycloak.KeycloakOAuth2',
# 'social_core.backends.keycloak.KeycloakOAuth2',
'social_core.backends.open_id_connect.OpenIdConnectAuth',
'social_core.backends.github_enterprise.GithubEnterpriseOAuth2',
'dojo.remote_user.RemoteUserBackend',
'django.contrib.auth.backends.RemoteUserBackend',
Expand Down Expand Up @@ -569,6 +574,7 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'dojo.pipeline.update_azure_groups',
'dojo.pipeline.update_keycloak_groups',
'dojo.pipeline.update_product_access',
)

Expand Down Expand Up @@ -630,13 +636,20 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param
SOCIAL_AUTH_TRAILING_SLASH = env('DD_SOCIAL_AUTH_TRAILING_SLASH')

KEYCLOAK_OAUTH2_ENABLED = env('DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_ENABLED')
SOCIAL_AUTH_KEYCLOAK_KEY = env('DD_SOCIAL_AUTH_KEYCLOAK_KEY')
SOCIAL_AUTH_KEYCLOAK_SECRET = env('DD_SOCIAL_AUTH_KEYCLOAK_SECRET')
SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = env('DD_SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY')
SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = env('DD_SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL')
SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = env('DD_SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL')
SOCIAL_AUTH_OIDC_OIDC_ENDPOINT = env('DD_SOCIAL_AUTH_OIDC_OIDC_ENDPOINT')
SOCIAL_AUTH_OIDC_KEY = env('DD_SOCIAL_AUTH_KEYCLOAK_KEY')
SOCIAL_AUTH_OIDC_SECRET = env('DD_SOCIAL_AUTH_KEYCLOAK_SECRET')
SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT = env('DD_SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT')

KEYCLOAK_TENANT_OAUTH2_GET_GROUPS = env('DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_GET_GROUPS')
KEYCLOAK_TENANT_OAUTH2_CLEANUP_GROUPS = env('DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_CLEANUP_GROUPS')
KEYCLOAK_TENANT_OAUTH2_GROUPS_FILTER = env('DD_SOCIAL_AUTH_KEYCLOAK_OAUTH2_GROUPS_FILTER')

# SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = env('DD_SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY')
# SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = env('DD_SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL')
# SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = env('DD_SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL')


GITHUB_ENTERPRISE_OAUTH2_ENABLED = env('DD_SOCIAL_AUTH_GITHUB_ENTERPRISE_OAUTH2_ENABLED')
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL = env('DD_SOCIAL_AUTH_GITHUB_ENTERPRISE_URL')
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL = env('DD_SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL')
Expand Down
2 changes: 1 addition & 1 deletion dojo/templates/dojo/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ <h3>{% trans "Login" %}</h3>
{% if KEYCLOAK_ENABLED is True %}
<div class="col-sm-offset-1 col-sm-2">
<button class="btn btn-success" type="button">
<a href="{% url 'social:begin' 'keycloak' %}?next={{ request.GET.next }}" style="color: rgb(255,255,255)">{{ SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT }}</a>
<a href="{% url 'social:begin' 'oidc' %}?next={{ request.GET.next }}" style="color: rgb(255,255,255)">{{ SOCIAL_AUTH_KEYCLOAK_LOGIN_BUTTON_TEXT }}</a>
</button>
</div>
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion dojo/user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def login_view(request):
elif settings.GITLAB_OAUTH2_ENABLED:
social_auth = 'gitlab'
elif settings.KEYCLOAK_OAUTH2_ENABLED:
social_auth = 'keycloak'
social_auth = 'oidc'
elif settings.AUTH0_OAUTH2_ENABLED:
social_auth = 'auth0'
elif settings.GITHUB_ENTERPRISE_OAUTH2_ENABLED:
Expand Down
Loading