CMS 3D CMS Logo

ws_sso_content_reader.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 ###Description: The tool reads cern web services behind SSO using user certificates
3 from __future__ import print_function
4 import os, urllib, urllib2, httplib, cookielib, sys, HTMLParser, re
5 from optparse import OptionParser
6 
7 def getFile(path):
8  npath = os.path.expanduser(path)
9  while os.path.islink(npath):
10  path = os.readlink(npath)
11  if path[0] != "/": path = os.path.join(os.path.dirname(npath),path)
12  npath = path
13  return npath
14 
15 class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
16  def __init__(self, key, cert):
17  urllib2.HTTPSHandler.__init__(self)
18  self.key = getFile(key)
19  self.cert = getFile(cert)
20 
21  def https_open(self, req):
22  return self.do_open(self.getConnection, req)
23 
24  def getConnection(self, host, timeout=300):
25  return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert)
26 
27 def _getResponse(opener, url, post_data=None, debug=False):
28  response = opener.open(url, post_data)
29  if debug:
30  sys.stderr.write("Code: %s\n" % response.code)
31  sys.stderr.write("Headers: %s\n" % response.headers)
32  sys.stderr.write("Msg: %s\n" % response.msg)
33  sys.stderr.write("Url: %s\n" % response.url)
34  return response
35 
36 def getResponseContent(opener, url, post_data=None, debug=False):
37  return _getResponse(opener, url, post_data, debug).read()
38 
39 def getResponseURL(opener, url, post_data=None, debug=False):
40  return urllib2.unquote(_getResponse(opener, url, post_data, debug).url)
41 
42 def getParentURL(url):
43  items = url.split("/")
44  return '%s//%s/%s/' % (items[0],items[2],items[3])
45 
46 def getSSOCookie(opener, target_url, cookie, debug=False):
47  opener.addheaders = [('User-agent', 'curl-sso-certificate/0.0.2')] #in sync with cern-get-sso-cookie tool
48  url = getResponseURL(opener, getParentURL(target_url), debug=debug)
49  content = getResponseContent(opener, url, debug=debug)
50  ret = re.search('<form .+? action="(.+?)">', content)
51  if ret == None:
52  raise Exception("error: The page doesn't have the form with adfs url, check 'User-agent' header")
53  url = urllib2.unquote(ret.group(1))
54  h = HTMLParser.HTMLParser()
55  post_data_local = ''
56  for match in re.finditer('input type="hidden" name="([^"]*)" value="([^"]*)"', content):
57  post_data_local += "&%s=%s" % (match.group(1), urllib.quote(h.unescape(match.group(2))))
58  is_link_found = True
59 
60  if not is_link_found:
61  raise Exception("error: The page doesn't have the form with security attributes, check 'User-agent' header")
62  post_data_local = post_data_local[1:] #remove first &
63  getResponseContent(opener, url, post_data_local, debug)
64 
65 def getContent(target_url, cert_path, key_path, post_data=None, debug=False, adfslogin=None):
66  opener = urllib2.build_opener(urllib2.HTTPSHandler())
67  if adfslogin:
68  opener.addheaders = [('Adfs-Login', adfslogin)] #local version of tc test
69 
70  #try to access the url first
71  try:
72  content = getResponseContent(opener, target_url, post_data, debug)
73  if not 'Sign in with your CERN account' in content:
74  return content
75  except Exception:
76  if debug:
77  sys.stderr.write("The request has an error, will try to create a new cookie\n")
78 
79  cookie = cookielib.CookieJar()
80  opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie), HTTPSClientAuthHandler(key_path, cert_path)) #will use private key and ceritifcate
81  if debug:
82  sys.stderr.write("The return page is sso login page, will request cookie.")
83  hasCookie = False
84  # if the access gave an exception, try to get a cookie
85  try:
86  getSSOCookie(opener, target_url, cookie, debug)
87  hasCookie = True
88  result = getResponseContent(opener, target_url, post_data, debug)
89  except Exception as e:
90  result = ""
91  print(sys.stderr.write("ERROR:"+str(e)))
92  if hasCookie:
93  burl = getParentURL(target_url)
94  try:
95  _getResponse(opener, burl+"signOut").read()
96  _getResponse(opener, "https://login.cern.ch/adfs/ls/?wa=wsignout1.0").read()
97  except:
98  sys.stderr.write("Error, could not logout correctly from server")
99  return result
100 
101 def checkRequiredArguments(opts, parser):
102  missing_options = []
103  for option in parser.option_list:
104  if re.match(r'^\[REQUIRED\]', option.help) and eval('opts. %s' % option.dest) == None:
105  missing_options.extend(option._long_opts)
106  if len(missing_options) > 0:
107  parser.error('Missing REQUIRED parameters: %s' % str(missing_options))
108 
109 if __name__ == "__main__":
110  parser = OptionParser(usage="%prog [-d(ebug)] -o(ut) COOKIE_FILENAME -c(cert) CERN-PEM -k(ey) CERT-KEY -u(rl) URL")
111  parser.add_option("-d", "--debug", dest="debug", help="Enable pycurl debugging. Prints to data and headers to stderr.", action="store_true", default=False)
112  parser.add_option("-p", "--postdata", dest="postdata", help="Data to be sent as post request", action="store", default=None)
113  parser.add_option("-c", "--cert", dest="cert_path", help="[REQUIRED] Absolute path to cert file.", action="store")
114  parser.add_option("-k", "--key", dest="key_path", help="[REQUIRED] Absolute path to key file.", action="store")
115  parser.add_option("-u", "--url", dest="url", help="[REQUIRED] Url to a service behind the SSO", action="store")
116  (opts, args) = parser.parse_args()
117  checkRequiredArguments(opts, parser)
118  content = getContent(opts.url, opts.cert_path, opts.key_path, opts.postdata, opts.debug)
119  print(content)
def getResponseContent(opener, url, post_data=None, debug=False)
def getSSOCookie(opener, target_url, cookie, debug=False)
def checkRequiredArguments(opts, parser)
def getContent(target_url, cert_path, key_path, post_data=None, debug=False, adfslogin=None)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def getResponseURL(opener, url, post_data=None, debug=False)
def _getResponse(opener, url, post_data=None, debug=False)
#define str(s)