Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

for details on how to use it:

Code Block
none
none
titleSave in a file AccountChecker.sh and chmod +x AccountChecker.shnone
#!/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.

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 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. 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 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 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="`\
$RESOLVERTEST \
-saml2 \
-f $FORMAT \
-n $TID \
-i $TIDP \
`"
	
	ERRORS="`/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="`/bin/echo \"$RESULT\" | /bin/grep \"[^ID: $name:|^$name: ]\"`"
		if [ "$FOUND" != "" ] ; then
			if [ $VERBOSE -eq 1 ] ; then
				/bin/echo "Found personal attribute $name -> User account with NameID $TID still exists";
			fi
		return 1
	fi
	done
	
	if [ $VERBOSE -eq 1 ] ; then
		/bin/echo  "No personal attributes found for user account with NameID $TID -> User account probably doesn't exist anymore"
	fi
	return 0
}

#-------------------------------------------------------------------------------

# Init some variables
VERBOSE=0;
SILENT=0;

# Parse arguments
while getopts hvswf:i: c
do
	case $c in
		v) VERBOSE=1;;
		s) SILENT=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 "$DESCRIPTION"
		exit 0;;
		[?]) 
		/bin/echo "$0 [-h] [-v] -i persistentID"
		/bin/echo "$0 [-h] [-v] -f file"
		/bin/echo "$DESCRIPTION"
		exit 255;;
	esac
done

if [ "$FILE" == "" -a "$NAMEID" == "" ] ; then
	/bin/echo "You must provide at least the options -i or -f"
	exit 1
fi

if [ "$FILE" != "" -a "$NAMEID" != "" ] ; then
	/bin/echo "You can only use -i or -f as options!"
	exit 1
fi

# Parse file
if [ "$FILE" != "" ] ; then
	if [ ! -f $FILE  ] ; then
		/bin/echo "File $FILE doesn't exist!"
		exit 1
	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

#-------------------------------------------------------------------------------

...