--- /dev/null
+import collections
+import commands
+import ctypes
+import os
+import tempfile
+
+import M2Crypto
+
+import snfOCCI.config
+import voms_helper
+
+SSL_CLIENT_S_DN_ENV = "SSL_CLIENT_S_DN"
+SSL_CLIENT_CERT_ENV = "SSL_CLIENT_CERT"
+SSL_CLIENT_CERT_CHAIN_0_ENV = "SSL_CLIENT_CERT_CHAIN_0"
+
+
+class VomsError(exception.Error):
+ """Voms credential management error"""
+
+ errors = {
+ 0: ('none', None),
+ 1: ('nosocket', 'Socket problem'),
+ 2: ('noident', 'Cannot identify itself (certificate problem)'),
+ 3: ('comm', 'Server problem'),
+ 4: ('param', 'Wrong parameters'),
+ 5: ('noext', 'VOMS extension missing'),
+ 6: ('noinit', 'Initialization error'),
+ 7: ('time', 'Error in time checking'),
+ 8: ('idcheck', 'User data in extension different from the real'),
+ 9: ('extrainfo', 'VO name and URI missing'),
+ 10: ('format', 'Wrong data format'),
+ 11: ('nodata', 'Empty extension'),
+ 12: ('parse', 'Parse error'),
+ 13: ('dir', 'Directory error'),
+ 14: ('sign', 'Signature error'),
+ 15: ('server', 'Unidentifiable VOMS server'),
+ 16: ('mem', 'Memory problems'),
+ 17: ('verify', 'Generic verification error'),
+ 18: ('type', 'Returned data of unknown type'),
+ 19: ('order', 'Ordering different than required'),
+ 20: ('servercode', 'Error from the server'),
+ 21: ('notavail', 'Method not available'),
+ }
+
+ http_codes = {
+ 5: (400, "Bad Request"),
+ 11: (400, "Bad Request"),
+ 14: (401, "Not Authorized"),
+ }
+
+
+def _get_cert_chain(ssl_info):
+ """Return certificate and chain from the ssl info in M2Crypto format"""
+
+ cert = ssl_info.get(SSL_CLIENT_CERT_ENV, "")
+ chain = ssl_info.get(SSL_CLIENT_CERT_CHAIN_0_ENV, "")
+ cert = M2Crypto.X509.load_cert_string(cert)
+ aux = M2Crypto.X509.load_cert_string(chain)
+ chain = M2Crypto.X509.X509_Stack()
+ chain.push(aux)
+ return cert, chain
+
+
+def _get_voms_info(self, ssl_info):
+ """Extract voms info from ssl_info and return dict with it."""
+
+ try:
+ cert, chain = self._get_cert_chain(ssl_info)
+ except M2Crypto.X509.X509Error:
+ print "Error getting certificate chain"
+
+ with voms_helper.VOMS(VOMS_CONFIG["vomsdir_path"],
+ VOMS_CONFIG["ca_path"], VOMS_CONFIG["vomsapi_lib"] as v:
+ if self._no_verify:
+ v.set_no_verify()
+ voms_data = v.retrieve(cert, chain)
+ if not voms_data:
+ raise VomsError(v.error.value)
+
+ d = {}
+ for attr in ('user', 'userca', 'server', 'serverca',
+ 'voname', 'uri', 'version', 'serial',
+ ('not_before', 'date1'), ('not_after', 'date2')):
+ if isinstance(attr, basestring):
+ d[attr] = getattr(voms_data, attr)
+ else:
+ d[attr[0]] = getattr(voms_data, attr[1])
+
+ d["fqans"] = []
+ for fqan in iter(voms_data.fqan):
+ if fqan is None:
+ break
+ d["fqans"].append(fqan)
+
+ return d
+
+
+def _split_fqan(fqan):
+ """
+ gets a fqan and returns a tuple containing
+ (vo/groups, role, capability)
+ """
+ l = fqan.split("/")
+ capability = l.pop().split("=")[-1]
+ role = l.pop().split("=")[-1]
+ vogroup = "/".join(l)
+ return (vogroup, role, capability)
+
+
+def _split_fqan(fqan):
+ """
+ gets a fqan and returns a tuple containing
+ (vo/groups, role, capability)
+ """
+ l = fqan.split("/")
+ capability = l.pop().split("=")[-1]
+ role = l.pop().split("=")[-1]
+ vogroup = "/".join(l)
+ return (vogroup, role, capability)
+
+
+def authenticate(self, ssl_data):
+ try:
+ voms_info = self._get_voms_info(ssl_data)
+ except VomsError as e:
+ raise e
+
+ user_dn = voms_info["user"]
+ user_vo = voms_info["voname"]
+ user_fqans = voms_info["fqans"]
+
+ return user_dn, user_vo, user_fqans
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import commands
+import ctypes
+import os
+
+import M2Crypto
+
+
+class _voms(ctypes.Structure):
+ _fields_ = [
+ ("siglen", ctypes.c_int32),
+ ("signature", ctypes.c_char_p),
+ ("user", ctypes.c_char_p),
+ ("userca", ctypes.c_char_p),
+ ("server", ctypes.c_char_p),
+ ("serverca", ctypes.c_char_p),
+ ("voname", ctypes.c_char_p),
+ ("uri", ctypes.c_char_p),
+ ("date1", ctypes.c_char_p),
+ ("date2", ctypes.c_char_p),
+ ("type", ctypes.c_int32),
+ ("std", ctypes.c_void_p),
+ ("custom", ctypes.c_char_p),
+ ("datalen", ctypes.c_int32),
+ ("version", ctypes.c_int32),
+ ("fqan", ctypes.POINTER(ctypes.c_char_p)),
+ ("serial", ctypes.c_char_p),
+ ("ac", ctypes.c_void_p),
+ ("holder", ctypes.c_void_p),
+ ]
+
+
+class _vomsdata(ctypes.Structure):
+ _fields_ = [
+ ("cdir", ctypes.c_char_p),
+ ("vdir", ctypes.c_char_p),
+ ("data", ctypes.POINTER(ctypes.POINTER(_voms))),
+ ("workvo", ctypes.c_char_p),
+ ("extra_data", ctypes.c_char_p),
+ ("volen", ctypes.c_int32),
+ ("extralen", ctypes.c_int32),
+ ("real", ctypes.c_void_p),
+ ]
+
+
+class VOMS(object):
+ """Context Manager for VOMS handling"""
+
+ def __init__(self, vomsdir_path, ca_path, vomsapi_lib):
+ self.VOMSApi = ctypes.CDLL(vomsapi_lib)
+ self.VOMSApi.VOMS_Init.restype = ctypes.POINTER(_vomsdata)
+
+ self.VOMSDIR = vomsdir_path
+ self.CADIR = ca_path
+
+ self.vd = None
+
+ def __enter__(self):
+ self.vd = self.VOMSApi.VOMS_Init(self.VOMSDIR, self.CADIR).contents
+ return self
+
+ def set_no_verify(self):
+ """Skip verification of AC.
+
+ This method skips the AC signature verification, this it should
+ only be used for debugging and tests.
+ """
+
+ error = ctypes.c_int32(0)
+ self.VOMSApi.VOMS_SetVerificationType(0x040,
+ ctypes.byref(self.vd),
+ ctypes.byref(error))
+
+ def retrieve(self, cert, chain):
+ """Retrieve VOMS credentials from a certificate and chain."""
+
+ self.error = ctypes.c_int32(0)
+
+ cert_ptr = ctypes.cast(long(cert._ptr()), ctypes.c_void_p)
+ chain_ptr = ctypes.cast(long(chain._ptr()), ctypes.c_void_p)
+
+ res = self.VOMSApi.VOMS_Retrieve(cert_ptr,
+ chain_ptr,
+ 0,
+ ctypes.byref(self.vd),
+ ctypes.byref(self.error))
+ if res == 0:
+ return None
+ else:
+ return self.vd.data.contents.contents
+
+ def __exit__(self, type, value, tb):
+ self.VOMSApi.VOMS_Destroy(ctypes.byref(self.vd))