summaryrefslogtreecommitdiffstats
path: root/remote/modules/pam-bwidm
diff options
context:
space:
mode:
authorJonathan Bauer2016-04-13 18:08:59 +0200
committerJonathan Bauer2016-04-13 18:08:59 +0200
commitf540599721c8c47b39b0855c9ec85b61f7727a54 (patch)
tree0d558f81eb93fc2fd12ceaba9846edaaabf94fe3 /remote/modules/pam-bwidm
parent[rfs-stage31] Support multiple SLX_LOCAL_CONFIGs (space separated) (diff)
downloadtm-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-account27
-rw-r--r--remote/modules/pam-bwidm/data/etc/pam.d/common-auth29
-rw-r--r--remote/modules/pam-bwidm/data/opt/openslx/bwidm_soap.xml22
-rwxr-xr-xremote/modules/pam-bwidm/data/opt/openslx/scripts/pam_bwidm137
-rw-r--r--remote/modules/pam-bwidm/module.build11
-rw-r--r--remote/modules/pam-bwidm/module.conf2
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="
+"