Authorize only list of selected VOs
[snf-occi] / snfOCCI / APIserver.py
index 0a8c857..d85e9e7 100755 (executable)
@@ -1,22 +1,25 @@
 #!/usr/bin/env python
 
+import re
+import string
 from snfOCCI.registry import snfRegistry
 from snfOCCI.compute import ComputeBackend
-from snfOCCI.config import SERVER_CONFIG
+from snfOCCI.config import SERVER_CONFIG, KAMAKI_CONFIG
 
 from kamaki.clients.compute import ComputeClient
 from kamaki.clients.cyclades import CycladesClient
 from kamaki.config  import Config
 
-from occi.core_model import Mixin
+from occi.core_model import Mixin, Resource
 from occi.backend import MixinBackend
 from occi.extensions.infrastructure import COMPUTE, START, STOP, SUSPEND, RESTART, RESOURCE_TEMPLATE, OS_TEMPLATE
 from occi.wsgi import Application
+from occi.exceptions import HTTPError
 
 from wsgiref.simple_server import make_server
 from wsgiref.validate import validator
 
-
+import voms
 
 
 class MyAPP(Application):
@@ -46,23 +49,106 @@ class MyAPP(Application):
             self.register_backend(FLAVOR, MixinBackend())
 
 
+    def refresh_compute_instances(self, snf):
+        '''Syncing registry with cyclades resources'''
+
+        servers = snf.list_servers()
+        snf_keys = []
+        for server in servers:
+            snf_keys.append(str(server['id']))
+
+        resources = self.registry.resources
+        occi_keys = resources.keys()
+        
+        #Compute instances in synnefo not available in registry
+        diff = [x for x in snf_keys if '/compute/'+x not in occi_keys]
+        for key in diff:
+
+            details = snf.get_server_details(int(key))
+            flavor = snf.get_flavor_details(details['flavorRef'])
+            image = snf.get_image_details(details['imageRef'])
+
+            for i in self.registry.backends:
+                if i.term == str(image['name']):
+                    rel_image = i
+                if i.term == str(flavor['name']):
+                    rel_flavor = i
+
+            resource = Resource(key, COMPUTE, [rel_flavor, rel_image])
+            resource.actions = [START]
+            resource.attributes['occi.core.id'] = key
+            resource.attributes['occi.compute.state'] = 'inactive'
+            resource.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
+            resource.attributes['occi.compute.cores'] = flavor['cpu']
+            resource.attributes['occi.compute.memory'] = flavor['ram']
+            resource.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':int(key)}
+
+            self.registry.add_resource(key, resource, None)
+
+        #Compute instances in registry not available in synnefo
+        diff = [x for x in occi_keys if x[9:] not in snf_keys]
+        for key in diff:
+            self.registry.delete_resource(key, None)
+
+
     def __call__(self, environ, response):
 
-        conf = Config()
-        conf.set('token',environ['HTTP_AUTH_TOKEN'])
-        compClient = ComputeClient(conf)
-        cyclClient = CycladesClient(conf)
+        compClient = ComputeClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
+        cyclClient = CycladesClient(KAMAKI_CONFIG['compute_url'], environ['HTTP_AUTH_TOKEN'])
 
         #Up-to-date flavors and images
-        self.refresh_images(compClient, cyclClient)
-        self.refresh_flavors(compClient, cyclClient)
+        self.refresh_images(compClient,cyclClient)
+        self.refresh_flavors(compClient,cyclClient)
+        self.refresh_compute_instances(compClient)
 
-        # token will be represented in self.extras
-        return self._call_occi(environ, response, security = None, token = environ['HTTP_AUTH_TOKEN'], snf = compClient, client = cyclClient)
+        ssl_dict = dict()
 
+        #Regular expression in HTTP headers
+        #environ[HTTP_SSL] contains PEM certificates in wrong format
+        
+        pem_re = r'^(-----BEGIN CERTIFICATE----- )(.*|\s]*)( -----END CERTIFICATE-----)'
 
-def main():
+        client_cert = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT"])
+        client_chain = re.search(pem_re, environ["HTTP_SSL_CLIENT_CERT_CHAIN_0"])
+
+        client_cert_list=[]
+        client_chain_list=[]
 
+        for i in range(1,4):
+            client_cert_list.append(string.strip(client_cert.group(i)))
+
+        for i in range(1,4):
+            client_chain_list.append(string.strip(client_chain.group(i)))
+
+
+        cert = client_cert_list[0]+"\n"+client_cert_list[1].replace(" "," \n")+"\n"+client_cert_list[2]
+        chain = client_chain_list[0]+"\n"+client_chain_list[1].replace(" "," \n")+"\n"+client_chain_list[2]
+
+        ssl_dict["SSL_CLIENT_S_DN"] = environ["HTTP_SSL_CLIENT_S_DN"]
+        ssl_dict["SSL_CLIENT_CERT"] = cert
+        ssl_dict["SSL_CLIENT_CERT_CHAIN_0"] = chain
+
+        (user_dn, user_vo, user_fqans) = voms.authenticate(ssl_dict)
+        print (user_dn, user_vo, user_fqans)
+
+
+        #Authenticate only VOs in list
+        VOs = ['see','fedcloud.egi.eu']
+        #Always authenticated, only for testing purposes 
+        
+        authenticated  = False
+
+        if user_vo in VOs:
+            authenticated = True
+
+        if authenticated:
+            # token will be represented in self.extras
+            return self._call_occi(environ, response, security = None, token = environ['HTTP_AUTH_TOKEN'], snf = compClient, client = cyclClient)
+        else:
+            raise HTTPError(404, "Unauthorized access")
+
+
+def main():
 
     APP = MyAPP(registry = snfRegistry())
     COMPUTE_BACKEND = ComputeBackend()