docs: def authenticate(url, username, password):
      ''' Queries an asset behind CMU's WebISO wall.
      It uses Shibboleth authentication (see: http://dev.e-taxonomy.eu/trac/wiki/ShibbolethProtocol)
      Note that you can use this to authenticate stuff beyond just grades! (any CMU service)
      Sample usage:
          s = authenticate('https://enr-apps.as.cmu.edu/audit/audit', 'wcrichto', '<wcrichto password>')
          print s.get('https://enr-apps.as.cmu.edu/audit/audit').content
      '''
  
      # We're using a Requests (http://www.python-requests.org/en/latest/) session
      s = requests.Session()
  
      # 1. Initiate sequence by querying the protected asset
      data = s.get(url).content
  
      # 2. Login to CMU's Shibboleth sign-in page
      class LoginParser(HTMLParser):
          url = ''
          def handle_starttag(self, tag, alist):
              attrs = dict(alist)
  
              # Figure out where we need to submit to
              if tag == 'form':
                  self.url = attrs['action']
  
      loginparser = LoginParser()
      loginparser.feed(data.decode())
      targeturl = 'https://login.cmu.edu' + loginparser.url
  
      s.headers = {'Host': 'login.cmu.edu', 'Referer': targeturl}
      form = s.post(targeturl,
                    data={'j_username': username, 'j_password': password,
                          'j_continue': '1', '_eventId_proceed': 'Login'}).content
  
      # 3. Parse resultant HTML and send corresponding POST request
      # Here, if you were in a browser, you'd get fed an HTML form
      # that you don't actualy see--it submits instantly with some JS
      # magic, but we don't have that luxury, so we manually parse the form.
      class ShibbolethParser(HTMLParser):
          url = ''
          to_post = {}
          def handle_starttag(self, tag, alist):
              attrs = dict(alist)
  
              # Figure out where we need to submit to
              if tag == 'form':
                  self.url = attrs['action']
  
              # Save input values
              elif tag == 'input' and attrs['type'] != 'submit':
                  self.to_post[attrs['name']] = attrs['value']
  
      parser = ShibbolethParser()
      parser.feed(form.decode())
  
      # Update headers for where we're coming from
      s.headers = {'Host':  urlparse(url).netloc,
                   'Origin': 'https://login.cmu.edu',
                   'Referer': targeturl,
                   'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.14 Safari/537.36'}
  
      # 4. Finish authentication by sending POST request
      s.post(parser.url, data=parser.to_post).content
  
      return s