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

SAML to prod #530

Merged
merged 22 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
00266b9
feature: initial saml login support
tymees Jun 13, 2023
cb1ade1
fix: use the right login URL in the footer menu
tymees Jun 13, 2023
ae17bd4
refactor: removed unneeded JS
tymees Jun 13, 2023
dc18eff
chore: po file cleanup
tymees Jun 13, 2023
99013f3
feature: fine-grained login display options
tymees Jun 15, 2023
80fd956
chore: update to DSC 3.1 alpha 2
tymees Jun 15, 2023
9f2246e
fix: use DSC's LogoutInitView instead
tymees Jun 15, 2023
a19a5b1
chore: update to DSC 3.1 alpha 3
tymees Jul 3, 2023
64fdb96
refactor: use provided settings to add django apps and middleware
tymees Jul 3, 2023
898ff93
Merge develop into acceptation (#496)
tymees Jul 11, 2023
870e718
Hotfix and requirements bump for acceptation (#489)
miggol Jul 11, 2023
dc4aeab
Merge branch 'acceptation' into feature/saml
tymees Jul 24, 2023
323fe93
deps: update dependencies
tymees Jul 24, 2023
7ad6247
fix: missing package namespace
tymees Jul 24, 2023
e389bba
feature: default SHOW_LOGIN_DESCRIPTORS to DEBUG
tymees Jul 24, 2023
0a8c375
fix: use normal tag instead of self-closing
tymees Jul 24, 2023
7b94e90
fix: use the right cover
tymees Jul 24, 2023
0ed8cfe
docs: added a ton of SAML documentation
tymees Jul 24, 2023
5aa233f
Added a note about localhost and 127.0.0.1 in saml_settings.example.py
miggol Jul 28, 2023
7eb5662
fix: duplicated Model removed
tymees Aug 18, 2023
b481c8e
Merge pull request #497 from DH-IT-Portal-Development/feature/saml
tymees Aug 24, 2023
8e478db
Merge branch 'master' into acceptation
tymees Aug 28, 2023
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ __pycache__/

### Project-specific ###
media/
certs/
fetc/ldap_settings.py
fetc/saml_settings.py
*.sqlite3

### Coverage ###
Expand Down
1 change: 1 addition & 0 deletions docs/installation/steps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The following packages needs to be installed:
+ libsasl2-dev
+ libssl-dev
+ gettext
+ libpoppler-cpp-dev

2. Prepare Filesystem & Files
=============================
Expand Down
90 changes: 90 additions & 0 deletions fetc/saml_settings.example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Copy this file to saml_settings.py if you want to use local SAML

This will 1) enable SAML in settings.py and 2) configure the SAML library to
use your local Development IdP.

For more information on the DevIdP, please consult its Github page:
https://github.com/CentreForDigitalHumanities/Development-IdP

You'll also need some certs, this code assumes they are located in a 'certs'
dir at the project-root. These certs can either be borrowed from the Dev-IdP
project or generated by hand. For the latter, see the CDH Docs.

These certs are used for signing the SAML data from this app to the IdP.

For detailed documentation on SAML and the CDH Federated Auth library, please
consult the CDH Federated Authentication docs:
https://centrefordigitalhumanities.github.io/Federated-Authentication-Docs/
"""
import os

# Import all default SAML settings from the library, we override some later
# Tip: the imported file also contains a lot of docs, which might be nice to
# read also
from cdh.federated_auth.saml.settings import *

# Used to get the full path of <project_root>
_BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# This dict is used to map attributes send by the IdP to the attributes used
# in this app's user model. They key is the name of the attribute as sent by
# the IdP, the value is a tuple with the name of the field on the user model
# See also:
# https://djangosaml2.readthedocs.io/contents/setup.html#users-attributes-and-account-linking
SAML_ATTRIBUTE_MAPPING = {
'uuShortID': ('username',),
'mail': ('email',),
'givenName': ('first_name',),
'uuPrefixedSn': ('last_name',),
# TODO: create an attribute on the user model to store this value
# 'uuLegacyDepartment': (),
}

# Controls which mechanism is used to exchange SAML data with the IdP
# Either POST or REDIRECT. POST is generally preferred, as REDIRECT can run
# into problems as it encodes the SAML data into the URL.
SAML_DEFAULT_BINDING = saml2.BINDING_HTTP_POST

# Use the helper function to generate the SAML_CONFIG.
# This is the main setting used to set up SAML
SAML_CONFIG = create_saml_config(
# This should be the URL of the ethics app (with protocol). Currently
# localhost, port 8000. Please change if you run the app on a different
# hostname/port
# Note that localhost and 127.0.0.1 are not interchangeable here
base_url='http://localhost:8000/',
# The name of the app, does not _really_ matter
name='FEtC-H Portal',
# The full location of the private key of the cert, currently
# <project_root>/certs/private.key
key_file=os.path.join(_BASE_DIR, 'certs/private.key'),
# The full location of the certificate, currently
# <project_root>/certs/private.key
cert_file=os.path.join(_BASE_DIR, 'certs/public.cert'),
# The location of the IdP's metadata
# The current value is valid for the Development IdP, if run at port 7000
# If you run it in a different place/port, please update
# If you use a different IdP, find its metadata URL and copy/paste it here
idp_metadata='http://localhost:7000/saml/idp/metadata/',
# If set to True, the app will allow login attempts not requested by the app
# This _can_ happen if a user logs in directly from the IdP. Currently set
# to true, as the DevIdP can sometimes do funky stuff with the session ID
allow_unsolicited=True,
# A list of attributes the IdP needs to provide for the app to authenticate
# Uses the naming of the IdP, not the internal names in Django
required_attributes=['uuShortID', 'mail', 'givenName', 'uuPrefixedSn'],
# A list of nice-to-have attributes from the IdP
# Uses the naming of the IdP, not the internal names in Django
optional_attributes=['uuLegacyDepartment', ],
# Contact info for this app; will be added to the app's metadata and is
# generally used by the IdP admins to contact all app-admins if they change
# something.
contact_given_name='Humanities IT Portal Development',
contact_email='[email protected]',
)

# Add the SAML auth backend to the list of enabled backends.
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'djangosaml2.backends.Saml2Backend',
)
32 changes: 28 additions & 4 deletions fetc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""
import os

from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
Expand All @@ -28,7 +29,7 @@

# Application definition

INSTALLED_APPS = (
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
Expand Down Expand Up @@ -56,9 +57,9 @@

'django.contrib.admin',
'django_user_agents',
)
]

MIDDLEWARE = (
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
Expand All @@ -70,7 +71,7 @@
'django.middleware.security.SecurityMiddleware',
'django_user_agents.middleware.UserAgentMiddleware',
'impersonate.middleware.ImpersonateMiddleware',
)
]

TEMPLATES = [
{
Expand All @@ -92,6 +93,16 @@

LOGIN_REDIRECT_URL = '/'

# Determines what login options are displayed on the landing page. NOTE: this
# does not determine which login screen is actually used as default when using
# a LoginRequiredMixin or similar.
# Django login is also used by LDAP auth
# SHOW_SAML_LOGIN is set to true if saml_settings.py is present and loaded
SHOW_DJANGO_LOGIN = True
SHOW_SAML_LOGIN = False
# Debug option, adds a label to the buttons. Otherwise, the buttons are
# identical
SHOW_LOGIN_DESCRIPTORS = DEBUG

# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
Expand Down Expand Up @@ -171,3 +182,16 @@
from .ldap_settings import *
except ImportError:
print('Proceeding without LDAP settings')

try:
from .saml_settings import *

# Only add stuff to settings if we actually have SAML settings
INSTALLED_APPS += SAML_APPS
MIDDLEWARE += SAML_MIDDLEWARE

LOGIN_URL = reverse_lazy('saml-login')
SHOW_SAML_LOGIN = True

except ImportError:
print('Proceeding without SAML settings')
25 changes: 24 additions & 1 deletion fetc/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@


urlpatterns = [
# Always keep the default login view available, just to be sure
# We set the correct login view (this or SAML) in settings
path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),

# Access user uploads
path('media/<str:filename>',
Expand Down Expand Up @@ -52,6 +53,28 @@
path('__debug__/', include(debug_toolbar.urls)),
)

# If SAML is enabled, add the required URL patterns for SAML
if 'cdh.federated_auth' in settings.INSTALLED_APPS:
from djangosaml2.views import LoginView
from cdh.federated_auth.saml.views import LogoutInitView

urlpatterns.extend([
path('saml/login/', LoginView.as_view(), name='saml-login'),
# We can only have one logout view. Luckily, the SAML logout view can
# handle local accounts as well.
path('saml/logout/', LogoutInitView.as_view(), name='logout'),
path('saml/', include('djangosaml2.urls')),
])
else:
# If not, append the default logout-view
urlpatterns.append(
path(
'accounts/logout/',
auth_views.LogoutView.as_view(),
name='logout'
),
)

admin.site.site_header = 'FETC-GW'
admin.site.site_title = 'FETC-GW administratie'
admin.site.index_title = 'FETC-GW administratie'
Binary file modified locale/en/LC_MESSAGES/django.mo
Binary file not shown.
Loading
Loading