#!/usr/bin/python import sys, urllib, urllib2, cookielib, ssl, argparse from lxml import etree # credentials and urls idp_login_url = "https://localhost/idp/profile/SAML2/Unsolicited/SSO" sp_entityid = "https://my.own.sp/shibboleth" sp_target_url = "https://my.own.sp/Shibboleth.sso/Session" user = "myuser" password = "mypassword" url_prefix = "https://localhost" parser = argparse.ArgumentParser(description="Script to check if shibboleth-login is working") group = parser.add_mutually_exclusive_group() group.add_argument("-s", "--short", help="short login attempt, which stops after entering credentials at idp-side", action="store_true") group.add_argument("-f", "--full", help="full login attempt, which stops after visiting session-page at sp-side", action="store_true") args = parser.parse_args() shortLoginMode = False fullLoginMode = False #check if short- or full-login-mode if args.short: shortLoginMode = True if args.full: fullLoginMode = True # create ssl context for missing or selfsigned certificates ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE # create cookiehandler for saving cookies and session-informations cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj), urllib2.HTTPSHandler(0, ctx)) # url to initiate login-attempt from idp-side try: url = idp_login_url+"?providerId="+sp_entityid+"&target="+sp_target_url response = opener.open(url) except: print "CRIT - Can't initiate login-process on idp-side" sys.exit(2) # get url from form to know where to post credentials try: html = etree.HTML(response.read()) form = html.find(".//form") action = form.get("action") except: print "CRIT - Can't read url from login-page where to post credentials" sys.exit(2) # check if really login-page proceed = False for inp in form.findall(".//input"): if inp.get("name") == "j_username": proceed = True break if not proceed: print "CRIT - No login-page found" sys.exit(2) # post credentials try: params = urllib.urlencode(dict(j_username=user, j_password=password, _eventId_proceed="Login")) url = "https://localhost"+action response = opener.open(url, params) except: print "CRIT - Can't post credentials to login-form" sys.exit(2) # read url from form to know where to post attributes try: html = etree.HTML(response.read()) form = html.find(".//form") action = form.get("action") except: print "CRIT - Can't read url from attribute-release-page where to post attributes" sys.exit(2) # check if login succeed, must be attribute-releas page proceed = False for div in form.findall(".//div"): if div.get("id") == "attributeRelease": proceed = True break if not proceed: print "CRIT - IdP Login failed, no attribute-release-page found" sys.exit(2) # if short-login-mode than exit, otherwise proceed if shortLoginMode: print "OK - short idp login successfull" sys.exit(0) # read attributes from form attributes = dict(_eventId_proceed="Accept") for elem in form.findall(".//input"): if elem.get("name") == "_shib_idp_consentIds": attributes[elem.get("id")] = elem.get("value") # post attributes try: params = urllib.urlencode(attributes) url = "https://localhost"+action response = opener.open(url, params) except: print "WARN - Can't post attributes to attribute-release-form" sys.exit(1) # read sp-url where to post saml-assertion try: html = etree.HTML(response.read()) form = html.find(".//form") action = form.get("action") except: print "WARN - Can't read url from saml-page where to post saml-assertion" sys.exit(1) # check if posting attributes succeed and read saml-assertion saml = "" relay = "" for elem in form.findall(".//input"): if elem.get("name") == "SAMLResponse": saml = elem.get("value") next if elem.get("name") == "RelayState": relay = elem.get("value") next # check if saml + relay found if not saml or not relay: print "WARN - No saml assertion found, maybe sending attributes failed" sys.exit(1) # if not full-login-mode than exit, otherwise proceed if not fullLoginMode: print "OK - idp login successfull" sys.exit(0) # post saml-assertion try: params = urllib.urlencode(dict(SAMLResponse=saml, RelayState=relay)) url = action response = opener.open(url, params) except: print "WARN - Can't post saml-assertion to saml-form" sys.exit(1) # read sp target side try: html = etree.HTML(response.read()) txt = etree.tostring(html) except: print "WARN - Can't read sp target side" sys.exit(1) # check if sp login succed if "A valid session was not found" in txt: print "WARN - SP login failed" sys.exit(1) if "Session Expiration" in txt: print "OK - SP login successfull" sys.exit(0) # exit unknown behaviour print "UNKNOWN - Unknown sp site, but idp login seams to be fine" sys.exit(3)