diff options
author | Jonathan Bauer | 2016-04-13 18:08:59 +0200 |
---|---|---|
committer | Jonathan Bauer | 2016-04-13 18:08:59 +0200 |
commit | f540599721c8c47b39b0855c9ec85b61f7727a54 (patch) | |
tree | 0d558f81eb93fc2fd12ceaba9846edaaabf94fe3 /remote/modules/pam-bwidm | |
parent | [rfs-stage31] Support multiple SLX_LOCAL_CONFIGs (space separated) (diff) | |
download | tm-scripts-f540599721c8c47b39b0855c9ec85b61f7727a54.tar.gz tm-scripts-f540599721c8c47b39b0855c9ec85b61f7727a54.tar.xz tm-scripts-f540599721c8c47b39b0855c9ec85b61f7727a54.zip |
[pam-bwidm] initial commit
Diffstat (limited to 'remote/modules/pam-bwidm')
-rw-r--r-- | remote/modules/pam-bwidm/data/etc/pam.d/common-account | 27 | ||||
-rw-r--r-- | remote/modules/pam-bwidm/data/etc/pam.d/common-auth | 29 | ||||
-rw-r--r-- | remote/modules/pam-bwidm/data/opt/openslx/bwidm_soap.xml | 22 | ||||
-rwxr-xr-x | remote/modules/pam-bwidm/data/opt/openslx/scripts/pam_bwidm | 137 | ||||
-rw-r--r-- | remote/modules/pam-bwidm/module.build | 11 | ||||
-rw-r--r-- | remote/modules/pam-bwidm/module.conf | 2 |
6 files changed, 228 insertions, 0 deletions
diff --git a/remote/modules/pam-bwidm/data/etc/pam.d/common-account b/remote/modules/pam-bwidm/data/etc/pam.d/common-account new file mode 100644 index 00000000..86f61a1a --- /dev/null +++ b/remote/modules/pam-bwidm/data/etc/pam.d/common-account @@ -0,0 +1,27 @@ +# +# /etc/pam.d/common-account - authorization settings common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of the authorization modules that define +# the central access policy for use on the system. The default is to +# only deny service to users whose accounts are expired in /etc/shadow. +# +# As of pam 1.0.1-6, this file is managed by pam-auth-update by default. +# To take advantage of this, it is recommended that you configure any +# local modules either before or after the default block, and use +# pam-auth-update to manage selection of other modules. See +# pam-auth-update(8) for details. +# + +# here are the per-package modules (the "Primary" block) +account [success=3 new_authtok_reqd=done default=ignore] pam_exec.so quiet debug log=/var/log/openslx/bwidm.log /opt/openslx/scripts/pam_bwidm +account [success=2 new_authtok_reqd=done default=ignore] pam_unix.so use_first_pass +account [success=1 new_authtok_reqd=done default=ignore] pam_sss.so use_first_pass +# here's the fallback if no module succeeds +account requisite pam_deny.so +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +account required pam_permit.so +# and here are more per-package modules (the "Additional" block) +# end of pam-auth-update config diff --git a/remote/modules/pam-bwidm/data/etc/pam.d/common-auth b/remote/modules/pam-bwidm/data/etc/pam.d/common-auth new file mode 100644 index 00000000..f0f4d473 --- /dev/null +++ b/remote/modules/pam-bwidm/data/etc/pam.d/common-auth @@ -0,0 +1,29 @@ +# +# /etc/pam.d/common-auth - authentication settings common to all services +# +# This file is included from other service-specific PAM config files, +# and should contain a list of the authentication modules that define +# the central authentication scheme for use on the system +# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the +# traditional Unix authentication mechanisms. +# +# As of pam 1.0.1-6, this file is managed by pam-auth-update by default. +# To take advantage of this, it is recommended that you configure any +# local modules either before or after the default block, and use +# pam-auth-update to manage selection of other modules. See +# pam-auth-update(8) for details. + +# here are the per-package modules (the "Primary" block) +auth [success=4 default=ignore] pam_exec.so quiet debug log=/var/log/openslx/bwidm.log expose_authtok /opt/openslx/scripts/pam_bwidm +auth [success=ok default=ignore] pam_krb5.so minimum_uid=1000 try_first_pass +auth [success=2 default=ignore] pam_unix.so try_first_pass +auth [success=1 default=ignore] pam_sss.so use_first_pass +# here's the fallback if no module succeeds +auth requisite pam_deny.so +auth optional pam_script.so expose=1 +# prime the stack with a positive return value if there isn't one already; +# this avoids us returning an error just because nothing sets a success code +# since the modules above will each just jump around +auth required pam_permit.so +# and here are more per-package modules (the "Additional" block) +# end of pam-auth-update config diff --git a/remote/modules/pam-bwidm/data/opt/openslx/bwidm_soap.xml b/remote/modules/pam-bwidm/data/opt/openslx/bwidm_soap.xml new file mode 100644 index 00000000..ef2c9490 --- /dev/null +++ b/remote/modules/pam-bwidm/data/opt/openslx/bwidm_soap.xml @@ -0,0 +1,22 @@ +<SOAP-ENV:Envelope + xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" + xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" + xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" + xmlns:ecp="urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"> + <SOAP-ENV:Header> + </SOAP-ENV:Header> + <SOAP-ENV:Body> + <samlp:AuthnRequest + ID="__RANDOM_STRING__2" + ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" + AssertionConsumerServiceURL="__AssertionConsumerUrl__" + IssueInstant="__2016-04-11T1:24:00Z__" + Version="2.0" + > + <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> + __REMOTE_ENTITY_ID__ + </saml:Issuer> + <samlp:NameIDPolicy AllowCreate="1"/> + </samlp:AuthnRequest> + </SOAP-ENV:Body> +</SOAP-ENV:Envelope> diff --git a/remote/modules/pam-bwidm/data/opt/openslx/scripts/pam_bwidm b/remote/modules/pam-bwidm/data/opt/openslx/scripts/pam_bwidm new file mode 100755 index 00000000..ff343d19 --- /dev/null +++ b/remote/modules/pam-bwidm/data/opt/openslx/scripts/pam_bwidm @@ -0,0 +1,137 @@ +#!/bin/ash +# +# This script is to be called by PAM (specifically pam_exec). +# +# some sanity checks +set -x +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/openslx/sbin:/opt/openslx/bin" +if ! busybox which curl; then + echo "'curl' missing. This script won't work without it." + exit 1 +fi + +# sanity check on PAM_USER: contains '@'? +if [ -z "$PAM_USER" ] || [ "x${PAM_USER}" == "x${PAM_USER%@*}" ]; then + # no @ contained, invalid username, abort + echo "Invalid username '$PAM_USER'. Aborting." + exit 1 +fi + +# valid username, we can already split it here +readonly USER_USERNAME="${PAM_USER%@*}" +readonly USER_ORGANISATION="${PAM_USER#*@}" +[ -z "$USER_ORGANISATION" ] && echo "Could not parse organisation from given username: ${PAM_USER}. Aborting." && exit 1 + +# The given username is valid. Now we get the list of IdPs from the bwlp masterserver +# and try to find the user's organisation + +# URL to query masterserver for IDPs +readonly IDP_QUERY_URL="https://bwlp-masterserver.ruf.uni-freiburg.de/webif/pam.php" +readonly IDP_QUERY_CACHE="/run/openslx/bwlp-idp" +mkdir -p /run/openslx + +# check if we have a (non-zero bytes) cached copy of the list +if [ ! -s "${IDP_QUERY_CACHE}" ]; then + if ! curl -k -o "/run/openslx/bwlp-idp" --connect-timeout 5 --max-time 15 "$IDP_QUERY_URL"; then + echo "Could not download the list of identity providers from '$IDP_QUERY_URL'. Aborting." + exit 1 + fi +fi +# here we have the cache for sure, search for the given organisation's ECP URL +USER_ECP_URL="" +USER_ECP_URL="$(awk -v idp="${USER_ORGANISATION}" -F '=' '{if($1==idp) print $2}' < "$IDP_QUERY_CACHE")" +[ -z "$USER_ECP_URL" ] && echo "Could not determine ECP URL for '${USER_ORGANISATION}'" && exit 1 + +# recap: here we have validated +# - username +# - organisation +# - ECP URL for that organisation + +# now create the bwidm group: find the first free GID from 1000 "downwards" to 100 +BWIDM_GROUP="$(getent group bwidm)" +if [ -z "$BWIDM_GROUP" ]; then + BWIDM_GID=1000 + while [ $BWIDM_GID -gt 100 ]; do + getent group $BWIDM_GID || break + let BWIDM_GID-- + done + if [ $BWIDM_GID -eq 100 ]; then + # use demo's gid as a fallback + readonly BWIDM_GID="$(id -g "demo")" + [ -z "$BWIDM_GID" ] && echo "Could not determine the GID of 'demo'. Cannot use it as fallback. Aborting." && exit 1 + fi + + # now create the group + if ! echo "bwidm:x:$BWIDM_GID:" >> /etc/group; then + echo "Could not create 'bwidm' group with gid '$BWIDM_GID'. Aborting." + exit 1 + fi +else + readonly BWIDM_GID="$(echo $BWIDM_GROUP | cut -d: -f3)" +fi +if [ -z "$BWIDM_GID" ]; then + echo "Could not determine BWIDM-GID. Aborting." + exit 1 +fi +readonly USER_GID="$BWIDM_GID" + +# path to the SOAP enveloppe we are gonna need soon +readonly SOAP_ENVELOPPE="/opt/openslx/bwidm_soap.xml" +[ ! -f "${SOAP_ENVELOPPE}" ] && echo "Failed to find the SOAP enveloppe at '${SOAP_ENVELOPPE}'. Aborting." && exit 1 + +# now the pam-type specific part starts +if [ "x$PAM_TYPE" == "xauth" ]; then + # pam exposes the password through stdin, lets get that + read USER_PASSWORD + [ -z "$USER_PASSWORD" ] && echo "No password given." && exit 1 + + # now we are ready to actually send the credentials to the IdP + # to be sure everything is working as expected + # we will first send a wrong password (by repeating the given password) and expect a 401 + ret=$(curl --connect-timeout 5 --max-time 15 -o /dev/null -w "%{http_code}" -k -d @"${SOAP_ENVELOPPE}" -H "Content-Type: application/vnd.paos+xml" --basic -u "${USER_USERNAME}:${USER_PASSWORD}${USER_PASSWORD}" "$USER_ECP_URL") + + if [ "x$ret" != "x401" ]; then + # this means something else is bad, just exit + echo "False authentication attempt did not return 401 but: $ret" + exit 1 + fi + # the fake auth call behaved as expected, do the actualy login + ret=$(curl --connect-timeout 5 --max-time 15 -o /dev/null -w "%{http_code}" -k -d @"${SOAP_ENVELOPPE}" -H "Content-Type: application/vnd.paos+xml" --basic -u "${USER_USERNAME}:${USER_PASSWORD}" "$USER_ECP_URL") + + if [ "x$ret" == "x200" ]; then + # auth succeeded, lets create a local user representing the bwIDM user + echo "Login for '$USER_USERNAME' on '$USER_ORGANISATION' succeeded." + # create a random 6digit UID + LOOPS=0 + while [ $LOOPS -lt 5 ]; do + USER_UID="$(( 100000 + $RANDOM ))" + # check existance of this UID, if its free, use it + getent passwd "$USER_UID" || break + let LOOPS++ + done + if [ $LOOPS -eq 5 ]; then + # could not find an empty random 6-digit UID, so we will use demo's UID... + USER_UID="$(id -u demo)" + [ -z "$USER_UID" ] && echo "Could not use UID of 'demo' as a fallback, aborting..." && exit 1 + fi + + # we have a uid, gid, lets just create the local user now + if ! grep -q "$USER_USERNAME@$USER_ORGANISATION" /etc/passwd; then + echo "$USER_USERNAME@$USER_ORGANISATION:x:${USER_UID}:${USER_GID}:$USER_USERNAME@$USER_ORGANISATION:/home/${USER_USERNAME}@${USER_ORGANISATION}:/bin/bash" >> /etc/passwd + fi + exit 0 + fi + exit 1 +fi + +if [ "x$PAM_TYPE" == "xaccount" ]; then + # the sanity checks we did before reacting to PAM_TYPE is enough to validate + # the given username as a valid bwIDM username + # ('@' contained and IdP found in the idp list fetched from the masterserver) + # so just "accept" + exit 0 +fi + +# script should never get to the following line +echo "$0 called for unsupported PAM_TYPE '$PAM_TYPE'. Aborting." +exit 1 diff --git a/remote/modules/pam-bwidm/module.build b/remote/modules/pam-bwidm/module.build new file mode 100644 index 00000000..62d96224 --- /dev/null +++ b/remote/modules/pam-bwidm/module.build @@ -0,0 +1,11 @@ +fetch_source() { + : +} + +build() { + pinfo "Static module, nothing to build." +} + +post_copy() { + : +} diff --git a/remote/modules/pam-bwidm/module.conf b/remote/modules/pam-bwidm/module.conf new file mode 100644 index 00000000..4ae05d5a --- /dev/null +++ b/remote/modules/pam-bwidm/module.conf @@ -0,0 +1,2 @@ +REQUIRED_BINARIES=" +" |