Skip to content

Commit

Permalink
Implement OIDC OP logout
Browse files Browse the repository at this point in the history
  • Loading branch information
sbreker committed Aug 6, 2024
1 parent fe82c25 commit 3e74220
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
3 changes: 3 additions & 0 deletions hack/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ services:
- "archivematica-storage-service"

archivematica-dashboard:
stdin_open: true
tty: true
build:
context: "../"
dockerfile: "hack/Dockerfile"
Expand Down Expand Up @@ -211,6 +213,7 @@ services:
OIDC_OP_TOKEN_ENDPOINT: "http://keycloak:8080/realms/artefactual/protocol/openid-connect/token"
OIDC_OP_USER_ENDPOINT: "http://keycloak:8080/realms/artefactual/protocol/openid-connect/userinfo"
OIDC_OP_JWKS_ENDPOINT: "http://keycloak:8080/realms/artefactual/protocol/openid-connect/certs"
LOGOUT_REDIRECT_URL: "http://127.0.0.1:62080/administration/accounts/login/"
OIDC_RP_SIGN_ALGO: "RS256"
volumes:
- "../:/src"
Expand Down
9 changes: 8 additions & 1 deletion src/dashboard/src/components/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from components.accounts import views
from django.conf import settings
from django.urls import path
from django.urls import reverse

app_name = "accounts"
urlpatterns = [
Expand All @@ -39,6 +40,7 @@

elif "mozilla_django_oidc" in settings.INSTALLED_APPS:
from components.accounts.views import CustomOIDCLoginView
from components.accounts.views import CustomOIDCLogoutView

urlpatterns += [
path(
Expand All @@ -48,7 +50,12 @@
),
name="login",
),
path("logout/", django.contrib.auth.views.logout_then_login, name="logout"),
#path("logout/", django.contrib.auth.views.logout_then_login, name="logout"),
path(
"logout/",
CustomOIDCLogoutView.as_view(),
name="logout",
),
]

else:
Expand Down
75 changes: 75 additions & 0 deletions src/dashboard/src/components/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
from django.utils.translation import gettext as _
from main.models import UserProfile
from mozilla_django_oidc.views import OIDCAuthenticationRequestView
from mozilla_django_oidc.views import OIDCLogoutView
from tastypie.models import ApiKey
from urllib.parse import urlencode


@user_passes_test(lambda u: u.is_superuser, login_url="/forbidden/")
Expand Down Expand Up @@ -243,3 +245,76 @@ def get(self, request):
self.request = request

return super().get(request)


class CustomOIDCLogoutView(OIDCLogoutView):
"""
Provide OpenID Logout capability
"""

def get_settings(self, attr, *args):
if attr in ["OIDC_RP_CLIENT_ID", "OIDC_RP_CLIENT_SECRET"]:
# Retrieve the request object stored in the instance.
request = getattr(self, "request", None)

if request:
provider_name = request.session.get("providername")

if (
provider_name
and provider_name in settings.OIDC_SECONDARY_PROVIDER_NAMES
):
provider_settings = settings.OIDC_PROVIDERS.get(provider_name, {})
value = provider_settings.get(attr)

if value is None:
raise ImproperlyConfigured(
f"Setting {attr} for provider {provider_name} not found"
)
return value

# If request is None or provider_name session var is not set or attr is
# not in the list, call the superclass's get_settings method.
return OIDCLogoutView.get_settings(attr, *args)

def post(self, request):
self.request = request

return super().post(request)

def get(self, request):
self.request = request

return super().post(request)

def get_oidc_logout_url(self, request):
"""
Constructs the OIDC logout URL for Keycloak.
"""
# Retrieve the ID token from the session
id_token = request.session.get('oidc_id_token')

if not id_token:
raise ValueError("ID token not found in session.")

# Retrieve the current provider name from the session
provider_name = request.session.get("providername", settings.OIDC_PRIMARY_PROVIDER_NAME)
provider_settings = settings.OIDC_PROVIDERS.get(provider_name, {})

# Get the end session endpoint from the provider settings
end_session_endpoint = provider_settings.get("OIDC_OP_LOGOUT_ENDPOINT")

if not end_session_endpoint:
raise ValueError("OIDC logout endpoint not configured for provider.")

# Define the post logout redirect URL
post_logout_redirect_uri = request.build_absolute_uri(settings.LOGOUT_REDIRECT_URL)

# Construct the logout URL with required parameters
params = {
'id_token_hint': id_token,
'post_logout_redirect_uri': post_logout_redirect_uri,
}
logout_url = f"{end_session_endpoint}?{urlencode(params)}"

return logout_url

0 comments on commit 3e74220

Please sign in to comment.