1 # Copyright 2012 Spanish National Research Council
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
19 from logging import getLogger
21 from kamaki.clients import ClientError
23 LOG = getLogger(__name__)
25 # Environment variable used to pass the request context
26 CONTEXT_ENV = 'snf.context'
29 SSL_CLIENT_S_DN_ENV = "SSL_CLIENT_S_DN"
30 SSL_CLIENT_CERT_ENV = "SSL_CLIENT_CERT"
31 SSL_CLIENT_CERT_CHAIN_ENV_PREFIX = "SSL_CLIENT_CERT_CHAIN_"
33 """Global variables that contain VOMS related paths
35 VOMS_POLICY = "/etc/snf/voms.json"
36 VOMSDIR_PATH = "/etc/grid-security/vomsdir/"
37 CA_PATH = "/etc/grid-security/certificates/"
38 VOMSAPI_LIB = "/usr/lib/libvomsapi.so.1"
39 PARAMS_ENV = 'snf_voms.params'
42 """Filter that checks for the SSL data in the reqest.
44 Sets 'ssl' in the context as a dictionary containing this data.
47 def __init__(self, *args, **kwargs):
52 self.voms_json = json.loads(
53 open(VOMS_POLICY).read())
56 'Bad Formatted VOMS json',
57 details='The VOMS json data was not corectly formatted in file %s' % VOMS_POLICY)
60 'No loading of VOMS json file',
61 details='The VOMS json file located in %s was not loaded' % VOMS_POLICY)
63 self._no_verify = False
65 #super(VomsAuthN, self).__init__(*args, **kwargs)
68 def _get_cert_chain(ssl_info):
69 """Return certificate and chain from the ssl info in M2Crypto format"""
71 cert = M2Crypto.X509.load_cert_string(ssl_info.get("cert", ""))
72 chain = M2Crypto.X509.X509_Stack()
73 for c in ssl_info.get("chain", []):
74 aux = M2Crypto.X509.load_cert_string(c)
78 def _get_voms_info(self, ssl_info):
79 """Extract voms info from ssl_info and return dict with it."""
82 cert, chain = self._get_cert_chain(ssl_info)
83 except M2Crypto.X509.X509Error:
85 'SSL data not verified',
88 with voms_helper.VOMS(VOMSDIR_PATH,
89 CA_PATH, VOMSAPI_LIB) as v:
93 voms_data = v.retrieve(cert, chain)
96 raise VomsError(v.error.value)
99 for attr in ('user', 'userca', 'server', 'serverca',
100 'voname', 'uri', 'version', 'serial',
101 ('not_before', 'date1'), ('not_after', 'date2')):
102 if isinstance(attr, basestring):
103 d[attr] = getattr(voms_data, attr)
105 d[attr[0]] = getattr(voms_data, attr[1])
108 for fqan in iter(voms_data.fqan):
111 d["fqans"].append(fqan)
116 def _split_fqan(fqan):
118 gets a fqan and returns a tuple containing
119 (vo/groups, role, capability)
122 capability = l.pop().split("=")[-1]
123 role = l.pop().split("=")[-1]
124 vogroup = "/".join(l)
125 return (vogroup, role, capability)
127 def _process_environ(self, environ):
129 LOG.warning("Getting the environment parameters...")
130 # the environment variable CONTENT_LENGTH may be empty or missing
132 request_body_size = int(environ.get('CONTENT_LENGTH', 0))
134 request_body_size = 0
136 'Not auth method provided',
137 details='The request body is empty, while it should contain the authentication method')
139 request_body = environ['wsgi.input'].read(request_body_size)
143 request_body = request_body.replace("true","\"true\"")
144 request_body = request_body.replace('"','\'' )
146 params_parsed = ast.literal_eval(request_body)
150 for k, v in params_parsed.iteritems():
151 if k in ('self', 'context'):
153 if k.startswith('_'):
158 environ[PARAMS_ENV] = params
159 print environ[PARAMS_ENV]
161 def is_applicable(self, environ):
162 """Check if the request is applicable for this handler or not"""
163 print "Checking if the request is applicable for this handler or not..."
164 self._process_environ(environ)
165 params = environ.get(PARAMS_ENV, {})
166 auth = params.get("auth", {})
168 if "true" in auth["voms"]:
173 details='Error in JSON, voms must be set to true')
178 def authenticate(self,ssl_data):
181 voms_info = self._get_voms_info(ssl_data)
182 except VomsError as e:
184 user_dn = voms_info["user"]
185 user_vo = voms_info["voname"]
186 user_fqans = voms_info["fqans"]
188 return user_dn, user_vo, user_fqans
191 def process_request(self, environ):
193 print "Inside process_Request at last!!!!"
194 if not self.is_applicable(environ):
195 return self.application
198 "dn": environ.get(SSL_CLIENT_S_DN_ENV, None),
199 "cert": environ.get(SSL_CLIENT_CERT_ENV, None),
202 for k, v in environ.iteritems():
203 if k.startswith(SSL_CLIENT_CERT_CHAIN_ENV_PREFIX):
204 ssl_dict["chain"].append(v)
206 voms_info = self._get_voms_info(ssl_dict)
208 params = environ[PARAMS_ENV]
210 tenant_from_req = params["auth"].get("tenantName", None)
212 print voms_info, tenant_from_req
213 user_dn = voms_info["user"]
214 user_vo = voms_info["voname"]
215 user_fqans = voms_info["fqans"]
216 environ['REMOTE_USER'] = user_dn
218 return user_dn, user_vo, user_fqans