...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
#! /bin/sh #set -x ################################################################################ DESCRIPTION=" This shell script will check whether a user account identified by a SAML2 NameID exists at a given Identity Provider. For that it will do an attribute query using a provided NameID. If the Identity Provider then returns at least one of the personal attributes that can be configured below, the script assumes that the account still exists. In order to execute the script, it must be copied to a host where a Shibboleth Service Provider (SP) 2.x is installed because it requires the resolvertest binary that comes bundled with the SP. Using the -v options the script will produce verbose output. If you see this description you either have used the -h option standing for help or you have used an illegal option. If you are wondering why you have to enter your password, this is because the scrip has to execute the resolvertest binary as root in order to allow it access to the (hopefully) read protected private key that is used by the Service Provider. The script can be executed with a NameID or a file as an argument. If the value that is provided to the script does not consist of the tripel 'SP!IdP!NameID', the entityID of the default application of this SP is used as well as a default IdP accountChecking.sh -h Print these instructions -w Print instructions for setuid wrapper script -v Enable verbose mode -s Enable silent mode and just output status code -i NameID value to check -f File containing NameIDs to check accountChecking.sh -h accountChecking.sh -w accountChecking.sh [-v] [-s] -i <NameID> accountChecking.sh [-v] [-s] -f <file> The script will do an attribute query using a provided NameID and the resolvertest binary that comes with every Shibboleth Service Provider. If the Identity Provider then returns at least one of the personal attributes that can be configured inbelow, thisthe script. assumes When calledthat with the -iaccount optionstill theexists. script returnsIn theorder followingto statusexecute codes:the script, it must be 0copied to a host where If accounta probablyShibboleth doesn'tService existProvider anymore 1 If account still exists 255 If an error occured If the script is called with a file as argument (-f), it assumes that each line of the file consists either of(SP) 2.x is installed because it requires the resolvertest binary that comes bundled with the SP. The script has to be called as user that is able to read the private key that is used by the Service Provider. Otherwise, resolvertest will output errors saying it cannot read the private key. The script can be executed with a NameID or a file theas tripel 'SP!IdP!NameID'an argument. ItIf thenthe willvalue checkthat eachis NameIDprovided andto createthe ascript commadoes separatednot copyconsist of the giventripel file with 'SP!IdP!NameID', the suffix '.result.csv'. This new file contains an additonal column where the numbers stand for the above-mentioned status codes. Version: 20090715 Authors: lukas.haemmerle@switch.ch " ################################################################################ ### CONFIG SECTION START ### # Path to Service Provider's resolvertest binary RESOLVERTEST=`which resolvertest` # NameID format to use FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent # Default IdP to use if IdP is not provided as argument IDP=https://default.idp.example.org/idp/shibboleth # Personal attributes to check as proof of account's existence # The following values should correspond to the IDs or aliases of attribute # definitions in Shibboleth's attribute-map.xml file ATTRIBUTES=( eppn uniqueID Shib-SwissEP-UniqueID mail Shib-InetOrgPerson-mail givenName Shib-InetOrgPerson-givenName surname Shib-Person-surname Shib-SwissEP-DateOfBirth dateOfBirth employeeNumber Shib-InetOrgPerson-employeeNumber) ### CONFIG SECTION END ### ################################################################################ #------------------------------------------------------------------------------- # Checks whether attributes are returned for NameID parseNameID(){ TLINE=$1 # Parse complete NameID NAMEIDP1=`echo "$TLINE" | cut -d! -f1` NAMEIDP2=`echo "$TLINE" | cut -d! -f2` NAMEIDP3=`echo "$TLINE" | cut -d! -f3` # Check if we got the full NameID if [ "$NAMEIDP1" != "$NAMEIDP3" ] ; then ID=$NAMEIDP3 IDP=$NAMEIDP1 else ID=$NAMEIDP1 fi if [ $VERBOSE -eq 1 -a $ID ] ; then echo -n "Checking NameID: $ID" echo " against Identity Provider: $IDP" fi (CheckNameID "$ID" "$IDP") return $?entityID of the default application of this SP is used as well as a default IdP that can be configured in this script. When called with the -i option the script returns the following status codes: 0 If account probably doesn't exist anymore 1 If account still exists 255 If an error occured If the script is called with a file as argument (-f), it assumes that each line of the file consists either of a NameID or the tripel 'SP!IdP!NameID'. It then will check each NameID and create a comma separated copy of the given file with the suffix '.result.csv'. This new file contains an additonal column where the numbers stand for the above-mentioned status codes. Status: Beta Version: 20091102 Authors: lukas.haemmerle@switch.ch " ################################################################################ ### CONFIG SECTION START ### # Path to Service Provider's resolvertest binary RESOLVERTEST=/usr/bin/resolvertest # NameID format to use FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent # Default IdP to use if IdP is not provided as argument IDP=https://aai-logon.vho-switchaai.ch/idp/shibboleth # Personal attributes to check as proof of account's existence # The following values should correspond to the IDs or aliases of attribute # definitions in Shibboleth's attribute-map.xml file ATTRIBUTES=( eppn uniqueID Shib-SwissEP-UniqueID mail Shib-InetOrgPerson-mail givenName Shib-InetOrgPerson-givenName surname Shib-Person-surname Shib-SwissEP-DateOfBirth dateOfBirth employeeNumber Shib-InetOrgPerson-employeeNumber) ### CONFIG SECTION END ### ################################################################################ SCRIPTPATH="`pwd`/$(basename $0)" WRAPPERDESCRIPTION=" Account Checking SETUID Wrapper Script: ############################################################################### USE THIS AT YOUR OWN RISK AND BE AWARE THAT FOLLOWING THESE INSTRUCTIONS COULD RESULT IN POTENTIAL SECURITY HOLES! ############################################################################### It might be that you have to run the script as root user in order to allow access to the Service Provider's private key. If this is the case, you could use the following procedure: 1. Create a file called runAccountCheckingScript.c with this content: -----------------------8<----------------------------- #include <unistd.h> #include <errno.h> main(int argc, char** argv) { if( setgid(getegid()) ) perror( \"setgid\" ); if( setuid(geteuid()) ) perror( \"setuid\" ); execv(\"$SCRIPTPATH\", argv); return errno; } -----------------------8<----------------------------- 2. Compile the C file with: $ gcc runAccountCheckingScript.c -o runAccountCheckingScript 3. Change owner of binary to root user: $ chown root:root runAccountCheckingScript 4. Set the setuid bit with: $ chmod 4755 runAccountCheckingScript Now any user can exeucte runAccountCheckingScript as root user who can read the Service Provider's private key. " # Reset IFS for security IFS=$' \t\n' # Prevent all sorts of alias trickery unset -f unalias \unalias -a unset -f command # Reset path variables for security path=/bin:/usr/bin #------------------------------------------------------------------------------- # Checks whether attributes are returned for NameID parseNameID(){ #Filter any suspicous characters TLINE=`/bin/echo "$1" | sed 's/[$;]//g'` # Parse complete NameID NAMEIDP1=`/bin/echo "$TLINE" | cut -d! -f1` NAMEIDP2=`/bin/echo "$TLINE" | cut -d! -f2` NAMEIDP3=`/bin/echo "$TLINE" | cut -d! -f3` # Check if we got the full NameID if [ "$NAMEIDP1" != "$NAMEIDP3" ] ; then ID=$NAMEIDP3 IDP=$NAMEIDP1 else ID=$NAMEIDP1 fi if [ $VERBOSE -eq 1 -a $ID ] ; then /bin/echo "Checking NameID: $ID against Identity Provider: $IDP" fi (CheckNameID "$ID" "$IDP") RETURNCODE=$? if [ $SILENT -eq 1 ] ; then /bin/echo $RETURNCODE fi return $RETURNCODE } #------------------------------------------------------------------------------- # Checks whether attributes are returned for NameID CheckNameID(){ TID=$1 TIDP=$2 RESULT="`\ sudo $RESOLVERTEST \ -saml2 \ -f $FORMAT \ -n $TID \ -i $TIDP \ `" ERRORS="`echo`/bin/echo \"$RESULT\" | /bin/grep ERROR`" if [ "$ERRORS" != "" -a "$NAMEID" != "" -a $SILENT -eq 0 ] ; then /bin/echo "Erorr occured:" /bin/echo "$ERRORS" return 255 elif [ "$ERRORS" != "" ] ; then return 255 fi for name in ${ATTRIBUTES[@]} do FOUND="`echo`/bin/echo \"$RESULT\" | /bin/grep \"ID[^ID: $name:|^$name: ]\"`" if [ "$FOUND" != "" ] ; then if [ $VERBOSE -eq 1 ] ; then /bin/echo -n "Found personal attribute with $FOUND " echo " $name -> User account with NameID $TID still exists"; fi return 1 fi done if [ $VERBOSE -eq 1 ] ; then /bin/echo -n "No personal attributes found for user account with NameID $TID" echo " -> User account probably doesn't exist anymore" fi return 0 } #------------------------------------------------------------------------------- # Init some variables VERBOSE=0; SILENT=0; # Parse arguments while getopts hvfhvswf:i: c do case $c in $c in v) VERBOSE=1;; vs) VERBOSESILENT=1;; f) FILE=$OPTARG;; i) NAMEID=$OPTARG;; w) /bin/echo "$WRAPPERDESCRIPTION" exit 0;; h) /bin/echo "$0 [-h] [-v] -i persistentID" /bin/echo "$0 [-h] [-v] -f file" /bin/echo "$0 -h echo "$DESCRIPTION" exit 2550;; [?]) /bin/echo "$0 [-h] [-v] -i persistentID" /bin/echo "$0 [-h] [-v] -f file" /bin/echo "$0 -h echo "$DESCRIPTION" exit 255;; esac done if [ "$FILE" == "" -a "$NAMEID" == "" ] ; then /bin/echo "You must provide at least the options -i or -f" exit 2551 fi if [ "$FILE" != "" -a "$NAMEID" != "" ] ; then /bin/echo "You can only use -i or -f as options!" exit 2551 fi # Parse file if [ "$FILE" != "" ] ; then if [ ! -f $FILE ] ; then /bin/echo "File $FILE doesn't exist!" exit 2551 fi if [ $VERBOSE -eq 1 -a $FILE ] ; then /bin/echo "Parsing file: $FILE" fi RESULTFILE="$FILE.result.csv" /bin/echo "#NAMEID,#RESULT" > $RESULTFILE while read LINE ;do (parseNameID "$LINE") /bin/echo "$LINE,$?" >> $RESULTFILE done < $FILE exit 0; elif [ "$NAMEID" != "" ] ; then # Parse single NameID (parseNameID "$NAMEID") exit $? else /bin/echo "Something unexpected happened :-(" exit 255 fi #------------------------------------------------------------------------------- |
...