Skip to content

Commit 4e6cfcc

Browse files
committed
ADD simplesamlphp extension support
SimpleSAMLphp extension requires a SimpleSAMLphp SP application to be run separately. It also expects the SimpleSAMLphp SP to be on the same server and will import from the SP. To duplicate this, I'm running the SP as a separate container but the codebase is in a shared volume that is mounted in both the wiki and the SP container. To make the shared volume work, the SP container initially has its codebase in /var/www/simplesamlphp-base which will be copied into the shared volume /var/www/simplesamlphp on startup. There is a local IDP counterpart that is only used for dev testing. In order to make setup easy, I've committed a set of certs of the SP in docker/simplesamlphp/sp/cert/ which is mounted into the SP. Warning: These certs are meant only for local dev and must not be used in any kind of prod environment. Check README for details on the SP's env vars and how to generate your own cert/key. Note that the SP is using an older version of SimpleSAMLphp that still supports php7.4. Newer versions require php8 or above and cannot be used with our current wiki build as its using php7.4. The SimpleSAMLphp extension adds its own logout button. The default logout button ends up being a non-functional duplicate. I think the extension is supposed to remove this duplicate logout button but I get the feeling the method they use only works for newer vector skin. I've manually deleted the duplicate logout button. Configuration of the SimpleSAMLphp extension is largely the same as it's also a PluggableAuth module. The main difference is that we configure the SAML attribute mapping there. Some of the attributes are used only by UBCAuth. Minor Mediawiki version upgrade 1.39.7 to 1.39.8. Remove deprecated LDAP hooks in CustomHooks.php. I think the remaining Caliper hook should only activate if the UBCAuth extension is enabled.
1 parent b5b9d2b commit 4e6cfcc

22 files changed

+3913
-104
lines changed

CustomHooks.php

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,8 @@
44
use IMSGlobal\Caliper\entities\agent\Person;
55
use CaliperExtension\caliper\CaliperSensor;
66

7-
# If LDAP environment variables are defined, enable additional customization
8-
if (getenv('LDAP_SERVER') || getenv('LDAP_BASE_DN') || getenv('LDAP_SEARCH_STRINGS') || getenv('LDAP_SEARCH_ATTRS')) {
9-
10-
// Remove the change password link from Preferences page.
11-
// ref: https://stackoverflow.com/questions/16893589/prevent-users-from-changing-their-passwords-in-mediawiki
12-
// note: many of the hooks mentioned in the stackoverflow post above have been deprecated
13-
$wgHooks['GetPreferences'][] = 'RemovePasswordChangeLink';
14-
function RemovePasswordChangeLink($user, &$preferences) {
15-
unset($preferences['password']);
16-
return true;
17-
}
18-
19-
///////////////////////////////////////////////////////////////////////////////
20-
21-
$wgHooks['AuthChangeFormFields'][] = 'ChangeAuthFormFields';
22-
function ChangeAuthFormFields($requests, $fieldInfo, &$formDescriptor, $action) {
23-
global $wgCookiePrefix;
24-
25-
// Remove "local" domain option from login page
26-
unset($formDescriptor['domain']['options']['local']);
27-
28-
// Remove username from cookies to avoid prefilling the field with wiki username.
29-
// Users should authenticate with usernames in LDAP.
30-
unset($_COOKIE[$wgCookiePrefix.'UserName']);
31-
32-
return true;
33-
}
34-
35-
# if Caliper is setup, use a custom actor with puid from LDAP
7+
if (filter_var( getenv( 'UBC_AUTH_ENABLED' ), FILTER_VALIDATE_BOOLEAN )) {
8+
# if Caliper is setup, use a custom actor with puid
369
if (getenv('CALIPER_HOST') && getenv('CALIPER_API_KEY')) {
3710
$wgHooks['SetCaliperActorObject'][] = 'SetCaliperActor';
3811

@@ -74,8 +47,4 @@ function SetCaliperActor(&$actor, &$user) {
7447
return true;
7548
}
7649
}
77-
} // end customization for LDAP authentication
78-
79-
#####################
80-
## End LDAP customization
81-
#####################
50+
}

Dockerfile

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM php:7.4-apache
22

33
ENV WIKI_VERSION_MAJOR_MINOR=1.39
4-
ENV WIKI_VERSION_BUGFIX=7
4+
ENV WIKI_VERSION_BUGFIX=8
55
ENV WIKI_VERSION=$WIKI_VERSION_MAJOR_MINOR.$WIKI_VERSION_BUGFIX
66
ENV WIKI_VERSION_STR=1_39
77

@@ -18,8 +18,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
1818
git \
1919
imagemagick \
2020
unzip \
21-
vim.tiny \
21+
vim \
2222
libonig-dev \
23+
# for simpleSAMLphp
24+
libzip-dev \
2325
# for TimedMediaHandler
2426
ffmpeg \
2527
&& rm -rf /var/lib/apt/lists/* \
@@ -28,16 +30,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
2830
&& ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so \
2931
&& docker-php-source extract
3032

31-
# pcntl for Scribunto
32-
RUN docker-php-ext-install -j$(nproc) mbstring xml intl mysqli ldap pcntl opcache calendar \
33-
&& docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
34-
&& docker-php-ext-install -j$(nproc) gd \
35-
&& docker-php-source delete \
36-
&& pecl install imagick-3.4.3 \
37-
&& pecl install redis \
38-
&& docker-php-ext-enable imagick mysqli redis \
39-
&& a2enmod rewrite \
40-
&& rm -rf /tmp/pear
33+
# install php extensions
34+
# pcntl for Scribunto, zip for SimpleSAMLphp
35+
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
36+
RUN install-php-extensions mbstring xml intl mysqli ldap pcntl opcache calendar zip imagick redis memcached
37+
38+
RUN a2enmod rewrite
4139

4240
WORKDIR /var/www/html
4341

@@ -61,13 +59,11 @@ COPY robots.txt /var/www/html/robots.txt
6159

6260
# composer won't load plugins if we don't explicitly allow executing as root
6361
ENV COMPOSER_ALLOW_SUPERUSER=1
64-
# FIXME temp hack to use lastest composer 1.x. composer 2.x version will break wikimedia/composer-merge-plugin
6562
RUN curl -L https://getcomposer.org/installer | php \
66-
#RUN curl -L https://getcomposer.org/composer-1.phar --output composer.phar \
6763
&& php composer.phar install --no-dev
6864

6965
RUN EXTS=`curl https://extdist.wmflabs.org/dist/extensions/ | awk 'BEGIN { FS = "\"" } ; {print $2}'` \
70-
&& for i in SmiteSpam VisualEditor Scribunto LiquidThreads Cite WikiEditor LDAPProvider PluggableAuth LDAPAuthentication2 ParserFunctions TemplateData InputBox Widgets Variables RightFunctions PageInCat CategoryTree LabeledSectionTransclusion UserPageEditProtection Quiz Collection DeleteBatch LinkTarget HitCounters Math 3D MultimediaViewer TimedMediaHandler; do \
66+
&& for i in SmiteSpam VisualEditor Scribunto LiquidThreads Cite WikiEditor LDAPProvider PluggableAuth LDAPAuthentication2 ParserFunctions TemplateData InputBox Widgets Variables RightFunctions PageInCat CategoryTree LabeledSectionTransclusion UserPageEditProtection Quiz Collection DeleteBatch LinkTarget HitCounters Math 3D MultimediaViewer TimedMediaHandler SimpleSAMLphp; do \
7167
FILENAME=`echo "$EXTS" | grep ^${i}-REL${WIKI_VERSION_STR}`; \
7268
echo "Installing https://extdist.wmflabs.org/dist/extensions/$FILENAME"; \
7369
curl -Ls https://extdist.wmflabs.org/dist/extensions/$FILENAME | tar xz -C /var/www/html/extensions; \

LocalSettings.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,13 @@ function loadenv($envName, $default = "") {
8585
ini_set( 'display_errors', 1 );
8686
$wgShowExceptionDetails = true;
8787
$wgCacheDirectory = false;
88+
$wgCachePages = false;
8889
$wgDebugLogFile = "/tmp/mw-debug-{$wgDBname}.log";
90+
$wgDebugLogGroups = [
91+
"SimpleSAMLphp" => "/tmp/mw-debug-SimpleSAMLphp.log",
92+
"PluggableAuth" => "/tmp/mw-debug-PluggableAuth.log",
93+
"UBCAuth" => "/tmp/mw-debug-UBCAuth.log",
94+
];
8995
}
9096

9197
## Shared memory settings
@@ -617,6 +623,55 @@ function loadenv($envName, $default = "") {
617623
}
618624
}
619625

626+
if (filter_var( getenv( 'SIMPLESAMLPHP_ENABLED' ), FILTER_VALIDATE_BOOLEAN )) {
627+
wfLoadExtension( 'PluggableAuth' );
628+
wfLoadExtension( 'SimpleSAMLphp' );
629+
$wgSimpleSAMLphp_InstallDir = '/var/www/simplesamlphp';
630+
$wgPluggableAuth_EnableLocalLogin = false;
631+
632+
$wgPluggableAuth_Config['CWL Log In'] = [
633+
'plugin' => 'SimpleSAMLphp',
634+
'data' => [
635+
'authSourceId' => 'wiki-sp',
636+
# standardized attributes with commonly used OIDs
637+
# uid attribute, which in Shib is the CWL login name
638+
'usernameAttribute' => 'urn:oid:0.9.2342.19200300.100.1.1',
639+
# displayName attribute, aka preferred name
640+
'realNameAttribute' => 'urn:oid:2.16.840.1.113730.3.1.241',
641+
# mail attribute, email address
642+
'emailAttribute' => 'urn:oid:0.9.2342.19200300.100.1.3',
643+
# eduPersonAffiliation, an array of (staff, student, faculty, etc)
644+
'eduPersonAffiliationAttribute' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.1',
645+
# non-standard attributes, uncertain OIDs
646+
# ubc's puid
647+
'puidAttribute' => 'ubcEduCwlPuid',
648+
]
649+
];
650+
651+
# disable local wiki account creation page
652+
$wgGroupPermissions['*']['createaccount'] = false;
653+
# allow auto creation
654+
$wgGroupPermissions['*']['autocreateaccount'] = true;
655+
656+
# disable password resets entirely
657+
# ref: https://www.mediawiki.org/wiki/Manual:$wgPasswordResetRoutes
658+
$wgPasswordResetRoutes = array(
659+
'username' => false,
660+
'email' => false,
661+
);
662+
663+
# enable local properties so users can edit their real name and email
664+
# ref: https://www.mediawiki.org/wiki/Extension:PluggableAuth
665+
$wgPluggableAuth_EnableLocalProperties = true;
666+
667+
if ( filter_var( getenv( 'UBC_AUTH_ENABLED' ), FILTER_VALIDATE_BOOLEAN ) ) {
668+
wfLoadExtension( 'UBCAuth' );
669+
$wgSimpleSAMLphp_MandatoryUserInfoProviders['username'] = [
670+
'class' => 'MediaWiki\Extension\UBCAuth\UsernameInfoProvider'
671+
];
672+
}
673+
}
674+
620675

621676
if (getenv('MEDIAWIKI_EXTENSIONS') && strpos(getenv('MEDIAWIKI_EXTENSIONS'), 'Scribunto') !== false) {
622677
# Scribunto

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,54 @@ docker-compose down
118118
docker-compose up -d
119119
```
120120

121-
## Adding new LDAP users
121+
### Setting up SAML2 auth using the SimpleSAMLphp Extension.
122+
123+
The dev docker compose configuration expects the wiki to be located at
124+
`wiki.docker` and the IDP to be located at `idp.docker`. This can be easily
125+
configured by editing the hosts file and mapping both `wiki.docker` and
126+
`idp.docker` to `127.0.0.1`.
127+
128+
#### Generate Key & Cert
129+
130+
**WARNING** the certs provided in `docker/simplesamlphp/sp/cert/` must NOT be
131+
used in any kind of prod environment. They are only there for easier setup of
132+
the docker compose dev environment.
133+
134+
To generate your own cert and key:
135+
136+
```bash
137+
openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -out wiki-sp.crt -keyout wiki-sp.pem
138+
```
139+
140+
The key and cert can replace the ones in `docker/simplesamlphp/sp/cert/` which
141+
will get mounted into the simplesamlphp container's
142+
/var/www/simplesamlphp/cert/ directory.
143+
144+
#### SP Required Environment Variables
145+
146+
Deployment of the SimpleSAMLphp SP is required if you want to use the
147+
SimpleSAMLphp extension. Note the IDP provided in docker compose is only for
148+
development purposes.
149+
150+
The SP pulls metadata from the target IDP's metadata URL.
151+
152+
Required SP environment variables:
153+
154+
* SIMPLESAMLPHP_SECRET_SALT - Cryptographically secured random string used for salting purposes.
155+
* SIMPLESAMLPHP_ADMIN_PASSWORD - Password for the default admin user.
156+
* SIMPLESAMLPHP_MEMCACHED_SERVER - SimpleSAMLphp's SP cannot use the cookie cache as the wiki side SimpleSAMLphp extension will conflict with it. So we need to use a separate cache. For this purpose, we can just use the same Memcached server that the wiki uses.
157+
* SIMPLESAMLPHP_TRUSTED_DOMAIN - Enter the wiki's domain here so that the SP knows it is safe.
158+
* SIMPLESAMLPHP_BASEURL - Base URL for the SP. The SP needs to share the same domain as the wiki (or you run into cookie domain issues), so the base URL should be a path under the wiki domain.
159+
* SIMPLESAMLPHP_SP_ENTITY_ID - The identifier that the SP uses to identify itself
160+
* SIMPLESAMLPHP_IDP_ENTITY_ID - The target IDP's identifier.
161+
* SIMPLESAMLPHP_IDP_METADATA_URL - URL where we can get the IDP's metadata.
162+
* SIMPLESAMLPHP_CRON_SECRET - Random alphanumeric string for cron security.
163+
164+
Optional SP environment variables:
165+
166+
* SIMPLESAMLPHP_DEV - This turns on dev mode which enables the admin interface at `<SIMPLESAMLPHP_BASEURL>/module.php/admin/`. It also allows SIMPLESAMLPHP_SECRET_SALT to default to 'secretsalt' if unset and SIMPLESAMLPHP_ADMIN_PASSWORD to default to 'admin' if unset.
167+
168+
### Adding new LDAP users
122169

123170
You can connect to the LDAP container using your preferred LDAP GUI using `localhost:1389` with login `cn=admin,dc=example,dc=org` and password `admin`.
124171

0 commit comments

Comments
 (0)