diff --git a/README.md b/README.md index c02d4f3045e308f454f3fc528ddae725509f15ab..650c39d422ab88af7b67ea328b0fcf48d0c9d41e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,19 @@ -#### Minimal Intro: +#### ssoauth: +- Manages users and permissions +- Authenticates users using SAML2 (Shibboleth) +- Authorizes users based on groups: + - Groups are normally received via SAML2 + - Groups can also be fetched locally: this is enabled automatically if the `hsh` app is available, skipping multiple software layers for additional security +- Suppresses direct permission assignment (`django.contrib.auth` `User`<->`Permission`), use groups instead + + +#### Minimal SSO Intro: - [SSO](https://lmddgtfy.net/?q=SSO): Single Sign On - SLO: Single Log Out - SP: Service Provider (your web app) -- IdP: Identity Provider (server with some dreadful software like Shibboleth) -- Metadata/Meta: an XML that describes SP or IdP (or some other entity) -- SAML/SAML2: It's just another XML-based enterprise-grade standard that will make you cry blood and shit bricks +- IDP: Identity Provider (e.g. Shibboleth) +- Metadata: an XML that describes SP or IDP (or some other relying party) +- SAML/SAML2: yet another XML-based enterprise-grade standard that will make you cry blood #### Necessary Stuff @@ -21,7 +30,7 @@ #### Development Setup - Should work with zero additional configuration. -- You can use `localhost:8000/dev/` _(might change depending on your configuration)_ to access the dev view with all its helper features. +- You can use `localhost:8000/dev/` _(might change depending on your url configuration)_ to access the dev view with all its helper features. #### Advanced development setup If you are not sure whether you need it: you don't need it. @@ -49,19 +58,19 @@ There are some apps like `django.contrib.admin` or `wagtail` that will simply ig ```python3 re_path(r"^(?:\w+/)?login/?$", ssoauth_views.LogInView.as_view(already_authenticated_403=True)), ``` - - Adjust the path if required - - Optional argument `already_authenticated_403=True` is used to avoid redirect loops (e.g. caused by `django.contrib.admin`). You can also use `already_authenticated_redirect="url-name"`. + - Adjust the path if needed + - Optional argument `already_authenticated_403=True` is used to avoid redirect loops (e.g. those caused by `django.contrib.admin`). You can also use `already_authenticated_redirect="url-name"`. #### Regarding Logging Out -After logging out locally, user will be redirected to one of the following (with this priority): +After logging out locally, user will be redirected to one of the following (in this order): - `?next=` GET value (Note: instead of `next` use use `django.contrib.auth.REDIRECT_FIELD_NAME`) - `LOGOUT_REDIRECT_URL` (vanilla django setting), recommended values are: - `LOGOUT_REDIRECT_URL = None` for the default behavior - `LOGOUT_REDIRECT_URL = urls.reverse_lazy("sso-logout-idp")` if you want to instantly initiate IDP log out, possibly triggering SLO - `LOGOUT_REDIRECT_URL = urls.reverse_lazy("sso-logged-out-locally")` - - Default: redirect to the view that asks users what to do next. Don't forget to override template `ssoauth/logged_out_locally.html` + - Default: redirect to the view that asks users what to do next. You might want to override template `ssoauth/logged_out_locally.html` #### Advanced Logging Out and SLO @@ -69,18 +78,18 @@ If unsure, ignore this section. **SLO**: SLO/SLS is disabled by default. If you want to try your luck with SLO you should add to your project settings `SP_SLS_ENABLED = True` -Currently only IdP-initiated SLO is supported by this app. The only supported binding type is HTTP-Redirect due to the limitations of the underlying library used. +Currently only IDP-initiated SLO is supported by this app. The only supported binding type is HTTP-Redirect due to the limitations of the underlying library used. For SLO with HTTP-Redirect to work, the SLS page must be included as `<iframe>`. Your server and/or browser might restrict such behavior. Start with setting `SP_SLS_X_FRAME_OPTIONS` (check `ssoauth.app_settings.defaults`). -If you have `nginx` serving pages to users, you might need to configure `x-frame-options` for the SLS view (Only the SLS view, nowhere else!). Additionally you might need to configure CSP on the web server on the IdP side. Anyways it will most likely be a lot of [fun](https://duckduckgo.com/?q=dwarf+fortress+fun) for you. +If you have `nginx` serving pages to users, you might need to configure `x-frame-options` for the SLS view (Only the SLS view, nowhere else!). Additionally you might need to configure CSP on the web server on the IDP side. Anyways it will most likely be a lot of [fun](https://duckduckgo.com/?q=dwarf+fortress+fun) for you. #### Groups and Permissions With `ssoauth` the only way to assign permissions is with groups: - - when user logs in, `ssoauth` receives group names from the IDP - - if your project has `django.contrib.admin` `Groups` with exactly the same names, as received from the IDP, these groups are assigned to the user. - - all other groups and permissions are automatically removed from the user (so it's not possible to "patch" what IDP says with some extra rules in the project) + - when user logs in, `ssoauth` receives group names from the IDP, or fetches them from the `hsh` app if it's present + - if your project has local groups (`django.contrib.auth` `Group`) with exactly the same names, these groups are assigned to the user + - all other groups and permissions are removed from the user for security reasons (better don't workaround this behaviour in your project) You can predefine some groups in project settings (see `ssoauth` default config for details). These predefined groups will be created automatically (when migrating). For example, a superuser group: @@ -95,12 +104,12 @@ PREDEFINED_GROUPS = { This example might be incomplete. See `ssoauth.app_settings.defaults` for additional info ```python -""" settings/prod.py """ +""" settings.py """ from django import urls SP_HOST = "foobar.it.hs-hannover.de" # FQDN of your SP IDP_META_URL = "https://idp.hs-hannover.de/idp/shibboleth" # production -IDP_LOGOUT_URL = "https://idp.it.hs-hannover.de/idp/profile/Logout" # web page for IdP logout (might initiate SLO) +IDP_LOGOUT_URL = "https://idp.it.hs-hannover.de/idp/profile/Logout" # web page for IDP logout (might initiate SLO) LOGIN_URL = urls.reverse_lazy("sso-login") # django setting ``` @@ -119,16 +128,16 @@ openssl req -newkey rsa:16384 -x509 -days 3650 -nodes -out sp.pem -keyout sp.key - if you prefer your keys somewhere else, set `SP_KEY` and `SP_CERT` settings -#### Add an SP to an IdP +#### Add your SP to an IDP -- Ask for assistance. Seriously. -- Please try on the test IdP before you brick the production! -- Grab your meta - - Run your project. - - Find meta of your SP (relative path `/saml2/meta`) +- Ask for assistance if not sure +- The project should be running with production settings +- Take the metadata of your project: + - Run your project + - The metadata of your SP is generated and shown on a web page, default path is `/saml2/meta` - Use Ctrl+U ("view source") to get the actual XML, otherwise your browser could mess it up -- IdP: - - `SSH` to the IdP and locate the Shibboleth directory, most likely `/opt/shibboleth-idp/` +- Shibboleth IDP: + - `SSH` to the IDP and locate the Shibboleth directory, e.g. `/opt/shibboleth-idp/` - put your meta into a new file in `./metadata/` and give it a nice verbose name - edit `./conf/metadata-providers.xml` - create a new `<MetadataProvider .../>` element, your best guess is to copy an existing line that belongs to some existing Django project @@ -136,5 +145,4 @@ openssl req -newkey rsa:16384 -x509 -days 3650 -nodes -out sp.pem -keyout sp.key - `metadataFile` should point on your new metadata - edit `./conf/attribute-filter.xml` - `systemctl restart tomcat8` - - make sure that IDP works - - if IDP does not work, rollback your changes and restart the IDP again + - make sure the IDP still works, it can be super picky regarding its config files diff --git a/setup.py b/setup.py index d46e7c474f4d3b03f0dc209ede5d7aadb9cfb176..152d0690ebddd373fb3fcd7eb2ee7b9882b15167 100644 --- a/setup.py +++ b/setup.py @@ -36,5 +36,5 @@ setup( ], ) -# binary dependencies: -# sudo apt install libxml2-dev libxslt1-dev xmlsec1 libxmlsec1-dev pkg-config +# debian dependencies: +# sudo apt install libxml2-dev libxslt1-dev xmlsec1 libxmlsec1-dev pkg-config python3-dev diff --git a/ssoauth/app_settings/defaults.py b/ssoauth/app_settings/defaults.py index 4b9aad1fb588219079360f0d3b2f4de910859533..733a7d9f2f9710eb6064912a70bd909267fcd6aa 100644 --- a/ssoauth/app_settings/defaults.py +++ b/ssoauth/app_settings/defaults.py @@ -3,9 +3,12 @@ from django.conf import settings as django_settings """ -If you want to change something: +Changing settings in Django: + - put the setting it into your project settings - optionally prefix the setting with "SSOAUTH_" - - put it into your project settings +Changing settings outside of Django: + - import ssoauth.app_settings + - ssoauth.app_settings.SETTING_NAME = "your new value" """ diff --git a/ssoauth/extras/hsh_compat.py b/ssoauth/extras/hsh_compat.py index 87872e37fc4423b695ac7efd5cd34350ce3935b1..9daf1fc9a2fa18265adf3e8d01caa3e71060914d 100644 --- a/ssoauth/extras/hsh_compat.py +++ b/ssoauth/extras/hsh_compat.py @@ -1,5 +1,5 @@ """ -Compatibility features with the `hsh` app. +Compatibility features with the `hsh` app """ from .. import logger