-
-
Notifications
You must be signed in to change notification settings - Fork 165
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This has two components, a regular Webwork Authen module and a Mojolicious plugin for SAML2. The plugin implements a SAML2 SP using the Net::SAML2 library. Net::SAML2 claims to be compatible with many SAML2 implementations, including Shibboleth. The intent for this plugin is to replace the old Shibboleth auth that depended on the shibd service which requires Apache's mod_shib. The WeBWorK::Authen::Saml2 authen module's main purpose is to call the Saml2 plugin helper sendLoginRequest() that properly sends the user to the IdP to authenticate. There is a bypass option that allows skipping the Saml2 authen in favour of the authen module after it. So you can, for example, put Basic_TheLastOption after it allow access to the internal username/password auth. It seems to be standard for Mojolicous plugins to be located in lib/Mojolicious/Plugin, so I've put the Saml2 plugin there. Additional detail and configuration instructions can be found in lib/Mojolicious/Plugin/Saml2/README.md The Saml2 plugin will only be loaded if the corresponding conf file exists. Copy conf/authen_saml2.dist.yml to conf/authen_saml2.yml to enable it. 3 settings in the conf are crucial, the idp.metadata_url must be set to the IdP's xml metadata endpoint and a unique sp.cert & sp.signing_key pair should be generated. The example cert and signing_key must not be used for prod under any circumstances. I initially put the config in conf/mojolicious.webwork.yml under a saml2 section but seeing as how other authen modules have their own conf files, I figure it was better to follow that convention. And as there seems to be more work around the yaml config, I've made the saml2 authen conf also a yaml file. The NotYAMLConfig plugin for reading yaml conf files gave me some trouble though, as I didn't want to step on the main conf and had to read the code to figure out how to use just the load conf file functionality. The Saml2 plugin will generate its own xml metadata that can be used by the IdP for configuration. This is available at the /saml2/metadata URL under the default config. Note that endpoints are configurable as I wanted to be able to change them to match shibd endpoints. The Saml2 plugin has its own set of controllers and a router for them. The AcsPostController is the most important one as it handles the SAMLResponse that sends the user back to Webwork from the IdP. The errors aren't the most friendly unfortunately, should probably add a proper 401 error template so users don't see the more scary stacktrace one. Note that unlike shibd, attribute maps are not supported. So you probably have to replace user friendly attribute names like "studentNumber" with URN style names like "urn:mace:dir:attribute-def:studentNumber". You can check your IdP's attribute map xml for the official URN names. Some discussion about alternatives that I tried before settling on the Mojolicious plugin approach: The Saml2 as a plugin idea started after trying out Mojolicious::Plugin::SAML. Mojolicious::Plugin::SAML didn't work out in the end due to two downsides. The major one being a lack of RelayState support. RelayState is the defacto standard way for SPs to store where the user wants to go after returning from a successful auth from the IdP. This is a necessary feature for Webwork as auth to each course is handled separately and we need to know exactly what course the user wants to get into. The minor issue is that it doesn't parse the SAMLResponse attributes for you and I really didn't want to have to muck with xml parsing. Apache mod_proxy using mod_shib and shibd was another possibility. This requires passing shib params through HTTP headers via the use of the ShibUseHeaders setting. Shibboleth documentation says the ShibUseHeaders option should be avoided as they're not confident in the protections against spoofed HTTP header attacks. Running Webwork under mod_perl again so we don't need to use mod_proxy. This resulted in hard to debug issues with a few sections of async code. While I was able to 'unasync' those sections to get the thing running, it feels unmaintainable in the long run, especially if Webwork increases usage of async features.
- Loading branch information
1 parent
629f1c9
commit 753b969
Showing
20 changed files
with
2,517 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
--- | ||
################################################################################ | ||
# Configuration for the Saml2 plugin | ||
# | ||
# To enable the Saml2 plugin, copy authen_saml2.dist.yml to authen_saml2.yml | ||
# | ||
# The Saml2 plugin uses the Net::SAML2 library, the library claims to be | ||
# compatible with a wide range of SAML2 implementations, including Shibboleth. | ||
################################################################################ | ||
|
||
# add this query to the end of a course url to skip the saml2 authen module | ||
# and go to the next one, comment out to disable this feature | ||
bypass_query: bypassSaml2 | ||
idp: # this is the central SAML2 server | ||
# url where we can get the SAML2 metadata xml for the IdP | ||
metadata_url: http://idp.docker:8180/simplesaml/module.php/saml/idp/metadata | ||
sp: # this is the Webwork side | ||
# also known as iss (issuer) | ||
entity_id: http://localhost:8080/saml2 | ||
# endoints created by the plugin, relative to the webwork root url | ||
route: | ||
base: '/saml2' # prefix path for all URLs handled by the plugin | ||
metadata: '/metadata' # actual path would be /saml2/metadata | ||
# 'Assertion Consumer Service', basically handles the SAML response, plugin | ||
# only supports a POST response (HTTP POST Binding) | ||
acs: | ||
post: '/acs/post' | ||
# Ideally, there would be a way to have separate app info and org info but | ||
# Net::SAML2's metadata generation doesn't seem to have that separation. So | ||
# I've filled out the org info with app info instead. | ||
org: | ||
contact: '[email protected]' | ||
name: 'webwork' | ||
url: 'https://localhost:8080/' | ||
display_name: 'WeBWorK' | ||
# list of attributes that can be used as the username, each of them will be | ||
# tried in turn to see if there's a matching user in the classlist. If no | ||
# attributes are given, then we'll default to the NameID. Please use the | ||
# attribute's OID | ||
attributes: | ||
- 'urn:oid:0.9.2342.19200300.100.1.1' | ||
############################################################################## | ||
# SECURITY WARNING | ||
# For production, you MUST generate your own unique 'cert' and 'signing_key'. | ||
# The examples below are publicly exposed and thus provides NO SECURITY. | ||
############################################################################## | ||
# Cert and key pairs can be generated using an openssl command such as: | ||
# openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out webwork.crt -keyout webwork.pem | ||
# Where webwork.crt contains the cert and webwork.pem contains the signing_key | ||
cert: | | ||
-----BEGIN CERTIFICATE----- | ||
MIIE7zCCA1egAwIBAgIUIteyNYLSAiB0FcNl0GLJNYRppk8wDQYJKoZIhvcNAQEL | ||
BQAwgYYxCzAJBgNVBAYTAkFBMQswCQYDVQQIDAJBQTEQMA4GA1UEBwwHRXhhbXBs | ||
ZTEQMA4GA1UECgwHRXhhbXBsZTEQMA4GA1UECwwHRXhhbXBsZTEQMA4GA1UEAwwH | ||
RXhhbXBsZTEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmVkdTAeFw0y | ||
NDA1MDMwMTA2MzNaFw0zNDA1MDMwMTA2MzNaMIGGMQswCQYDVQQGEwJBQTELMAkG | ||
A1UECAwCQUExEDAOBgNVBAcMB0V4YW1wbGUxEDAOBgNVBAoMB0V4YW1wbGUxEDAO | ||
BgNVBAsMB0V4YW1wbGUxEDAOBgNVBAMMB0V4YW1wbGUxIjAgBgkqhkiG9w0BCQEW | ||
E2V4YW1wbGVAZXhhbXBsZS5lZHUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGK | ||
AoIBgQC45DCHUejzAeq+eVwEX5zSQWC+kqydEmoxpydT4YiSXnNeoNAkilKfHGOY | ||
Uc4djwx148N14A+S0GCys2j3Ey2wuL7DSep5y1Z9Uxj6Ayg23XGIFFFJJLMy1Qfe | ||
pjCcr1djPH9PpwglG1nTsiWqvHGGc3WWn1u6RfyrCf+jxbhygNRTA+LVPpqNvko6 | ||
MWKsbVLKrYMV2kPcQ0PQByNHJnjBy3KH2k99lS20h32sgHbgbVpJWdAWjeyJrOh9 | ||
aDt4/AfK90BvhkjF4BuQ+Jw5oIwMhbx7YmzIfiJmBLLaGjVRppuoAQtLX9uLst9l | ||
aLZzaeutg+G3RUYcvDMlnP7cU8Sq4BD7uK0ChKxxCMFcihAhQ8wqCKncaaE9WqPs | ||
CM16SB/6xptOxoLcg/5q3PJyUi2g4VDKXuQc6AURKIJxSM9nlrcv/R7fCFgk3Nj/ | ||
piWykDk6/BDWFpEHaj+NnFE9ZIxKr9CjTxdmqiDTyqSv50rNCjleyL/iASBTSCCF | ||
OPVOYQECAwEAAaNTMFEwHQYDVR0OBBYEFGs8F3VIGSEk+DE2MBqqNKX6UuZTMB8G | ||
A1UdIwQYMBaAFGs8F3VIGSEk+DE2MBqqNKX6UuZTMA8GA1UdEwEB/wQFMAMBAf8w | ||
DQYJKoZIhvcNAQELBQADggGBAIpDktpfGH7ZqgdWvxbJrjekb1IyCGrWsHOYSjwM | ||
+MxnhAA6oY63wC04a2i31zIMNOkY9F0tAdd4uDchxA9IWHqpb7t7zBlZdDabPPC3 | ||
WoDYnKhtZBULVVo7AvWO0UJGfZNJE393aKer3ePvfoG0OpCyrw4eFI/GCd4UjJBF | ||
DnD7hvUxE7RRwOhbuYrtDRuB3Z7CeeP8o81eDVexyuBpM/9UQjYPqBBAfoeYKQzu | ||
ZIhpGRWXw0ntH+EEOWagRXA5pRru61hteParZe4LBjPqisqN4Ek6ZR7MD9gB5xnt | ||
Pn1BKRY08quFOZyaogzwfkYk5SCF8F8jBA8ZNAYwJWe1gtO3iw5vpUaQc2iCabvI | ||
Y+Pc6qsSNwbkl7+sFrVHzI9QZVyz1cARUXxvrgGNLBkYtprkG91k6mCjX90cQspb | ||
ZwHixcQyCNv+4H738e99h/Wf0YzjxFjDKrbGoosYBzWAsYYtzrtsBvw3SJMTXIh7 | ||
OvFMA+rbIL8XWs8oNmZDDh8g0A== | ||
-----END CERTIFICATE----- | ||
signing_key: | | ||
-----BEGIN PRIVATE KEY----- | ||
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 | ||
dzDq+xUD8nHpKM33A2EaUFY= | ||
-----END PRIVATE KEY----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# actual image we'll run in the end | ||
FROM php:8.3-apache | ||
WORKDIR /var/www | ||
|
||
# Install composer & php extension installer | ||
COPY --from=composer/composer:2-bin /composer /usr/bin/composer | ||
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ | ||
|
||
RUN apt-get update && \ | ||
apt-get -y install git curl vim && \ | ||
install-php-extensions ldap zip | ||
|
||
# dirs used by simplesamlphp needs to be accessible by apache user | ||
RUN mkdir simplesamlphp/ /var/cache/simplesamlphp | ||
RUN chown www-data. simplesamlphp/ /var/cache/simplesamlphp | ||
# Composer doesn't like to be root, so we'll run the rest as the apache user | ||
USER www-data | ||
|
||
# Install simplesamlphp | ||
ARG SIMPLESAMLPHP_TAG=v2.2.1 | ||
RUN git clone --branch $SIMPLESAMLPHP_TAG https://github.com/simplesamlphp/simplesamlphp.git | ||
WORKDIR /var/www/simplesamlphp | ||
|
||
# Generate certs | ||
RUN cd cert/ && \ | ||
openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out server.crt -keyout server.pem -subj "/C=CA/SP=BC/L=Vancouver/O=UBC/CN=idp.docker" | ||
|
||
# Use composer to install dependencies | ||
RUN composer install && \ | ||
composer require simplesamlphp/simplesamlphp-module-metarefresh | ||
|
||
# Copy config files | ||
COPY ./config/ config/ | ||
COPY ./metadata/ metadata/ | ||
|
||
COPY ./apache.conf /etc/apache2/sites-available/000-default.conf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<VirtualHost *:80> | ||
# The ServerName directive sets the request scheme, hostname and port that | ||
# the server uses to identify itself. This is used when creating | ||
# redirection URLs. In the context of virtual hosts, the ServerName | ||
# specifies what hostname must appear in the request's Host: header to | ||
# match this virtual host. For the default virtual host (this file) this | ||
# value is not decisive as it is used as a last resort host regardless. | ||
# However, you must set it for any further virtual host explicitly. | ||
#ServerName www.example.com | ||
|
||
ServerAdmin webmaster@localhost | ||
DocumentRoot /var/www/simplesamlphp | ||
|
||
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn, | ||
# error, crit, alert, emerg. | ||
# It is also possible to configure the loglevel for particular | ||
# modules, e.g. | ||
#LogLevel info ssl:warn | ||
|
||
ErrorLog ${APACHE_LOG_DIR}/error.log | ||
CustomLog ${APACHE_LOG_DIR}/access.log combined | ||
|
||
# For most configuration files from conf-available/, which are | ||
# enabled or disabled at a global level, it is possible to | ||
# include a line for only one particular virtual host. For example the | ||
# following line enables the CGI configuration for this host only | ||
# after it has been globally disabled with "a2disconf". | ||
#Include conf-available/serve-cgi-bin.conf | ||
|
||
SetEnv SIMPLESAMLPHP_CONFIG_DIR /var/www/simplesamlphp/config | ||
|
||
Alias /simplesaml /var/www/simplesamlphp/public | ||
|
||
<Directory /var/www/simplesamlphp/public> | ||
Require all granted | ||
</Directory> | ||
|
||
</VirtualHost> |
Oops, something went wrong.