Commit 14b6dbc9 authored by Stavros Sachtouris's avatar Stavros Sachtouris

Remove authentication capabilities

parent b2db666d
......@@ -13,14 +13,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import uuid
from snfOCCI.registry import snfRegistry
from snfOCCI.compute import ComputeBackend, SNFBackend
from snfOCCI import config
from snfOCCI.config import VOMS_CONFIG, KEYSTONE_URL
from snfOCCI import snf_voms
from snfOCCI.network import (
NetworkBackend, IpNetworkBackend, IpNetworkInterfaceBackend,
NetworkInterfaceBackend)
......@@ -337,99 +335,6 @@ class MyAPP(wsgi.Application):
snf_project=snf_project)
def application(env, start_response):
"""/v2.0/tokens"""
print "In /v2.0/tokens"
t = snf_voms.VomsAuthN()
user_dn, user_vo, user_fqans, snf_token, snf_project = t.process_request(
env)
print (user_dn, user_vo, user_fqans)
env['HTTP_AUTH_TOKEN'] = snf_token
env['SNF_PROJECT'] = snf_project
# Get user authentication details
print "@ refresh_user authentication details"
pool = False
astakosClient = astakos.AstakosClient(
config.KAMAKI['astakos_url'], env['HTTP_AUTH_TOKEN'], use_pool=pool)
user_details = astakosClient.authenticate()
response = {
'access': {
'token': {
'issued_at': '',
'expires': user_details['access']['token']['expires'],
'id': env['HTTP_AUTH_TOKEN']
},
'serviceCatalog': [],
'user': {
'username': user_dn,
'roles_links': user_details['access']['user']['roles_links'],
'id': user_details['access']['user']['id'],
'roles': [],
'name': user_dn
},
'metadata': {
'is_admin': 0,
'roles': user_details['access']['user']['roles']
}
}
}
status = '200 OK'
headers = [('Content-Type', 'application/json')]
start_response(status, headers)
body = json.dumps(response)
print body
return [body]
def app_factory(global_config, **local_config):
"""This function wraps our simple WSGI app so it
can be used with paste.deploy"""
return application
def tenant_application(env, start_response):
"""/v2.0/tennants"""
print "In /v2.0/tennants"
req = Request(env)
if 'HTTP_X_AUTH_TOKEN' in req.environ:
env['HTTP_AUTH_TOKEN'] = req.environ['HTTP_X_AUTH_TOKEN']
else:
raise HTTPError(404, "Unauthorized access")
# Get user authentication details
print "@ refresh_user authentication details"
pool = False
astakosClient = astakos.AstakosClient(
config.KAMAKI['astakos_url'], env['HTTP_AUTH_TOKEN'], use_pool=pool)
user_details = astakosClient.authenticate()
response = {
'tenants_links': [],
'tenants': [
{
'description': 'Instances of EGI Federated Clouds TF',
'enabled': True,
'id': user_details['access']['user']['id'],
'name': 'ops'
},
]
}
status = '200 OK'
headers = [('Content-Type', 'application/json'), ]
start_response(status, headers)
body = json.dumps(response)
print body
return [body]
def tenant_app_factory(global_config, **local_config):
"""This function wraps our simple WSGI app so it
can be used with paste.deploy"""
return tenant_application
def occify_terms(term):
""":return: Occified term, compliant with GFD 185"""
return term.strip().lower().replace(' ', '_').replace('.', '-').replace(
......
# Copyright (C) 2012-2014 GRNET S.A.
# Copyright (C) 2012-2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -19,14 +19,6 @@
[composite:main]
use = egg:Paste#urlmap
/:snf_occiapp
/v2.0/tokens:authapp
/v2.0/tenants:tenantapp
[app:snf_occiapp]
use = egg:snf-occi#snf_occi_app
[app:authapp]
paste.app_factory = snfOCCI.APIserver:app_factory
[app:tenantapp]
paste.app_factory = snfOCCI.APIserver:tenant_app_factory
\ No newline at end of file
# Copyright (C) 2012-2014 GRNET S.A.
# Copyright (C) 2012-2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -17,11 +17,3 @@
[composite:main]
use = egg:Paste#urlmap
/v2.0/tokens:authapp
/v2.0/tenants:tenantapp
[app:authapp]
paste.app_factory = snfOCCI.APIserver:app_factory
[app:tenantapp]
paste.app_factory = snfOCCI.APIserver:tenant_app_factory
\ No newline at end of file
# Copyright (C) 2013-2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
Created on Jul 31, 2013
@author: nassia
'''
import json
import M2Crypto
import ast
from logging import getLogger, DEBUG
import voms_helper
from kamaki.clients import ClientError
from astavomaki.client import AstavomsClient
# import saferun
LOG = getLogger(__name__)
# Environment variable used to pass the request context
CONTEXT_ENV = 'snf.context'
SSL_CLIENT_S_DN_ENV = "SSL_CLIENT_S_DN"
SSL_CLIENT_CERT_ENV = "SSL_CLIENT_CERT"
SSL_CLIENT_CERT_CHAIN_ENV_PREFIX = "SSL_CLIENT_CERT_CHAIN_"
"""Global variables that contain VOMS related paths
"""
VOMS_POLICY = "/etc/snf/voms.json"
VOMSDIR_PATH = "/etc/grid-security/vomsdir/"
CA_PATH = "/etc/grid-security/certificates/"
VOMSAPI_LIB = "/usr/lib/libvomsapi.so.1"
# VOMSAPI_LIB = "voms.x86_64 0:2.0.10-3.el6"
AUTOCREATE_USERS = False
PARAMS_ENV = 'snf_voms.params'
ASTAVOMS_URL = 'https://okeanos-astavoms.hellasgrid.gr'
ASTAVOMS_TOKEN = 'Nothing for now'
class VomsError():
"""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 __init__(self, code):
short, message = self.errors.get(code, ('oops',
'Unknown error %d' % code))
message = "(%s, %s)" % (code, message)
# super(VomsError, self).__init__(message=message)
code, title = self.http_codes.get(code, (500, "Unexpected Error"))
self.code = code
self.title = title
class VomsAuthN():
"""Filter that checks for the SSL data in the reqest.
Sets 'ssl' in the context as a dictionary containing this data.
"""
def __init__(self, *args, **kwargs):
self.astavoms = AstavomsClient(ASTAVOMS_URL, ASTAVOMS_TOKEN)
# VOMS stuff
try:
with open(VOMS_POLICY) as f:
self.voms_json = json.load(f)
except ValueError:
raise ClientError(
'Bad Formatted VOMS json',
details='The VOMS json data was not corectly formatted in file %s' % VOMS_POLICY)
except Exception as e:
raise ClientError(
'No loading of VOMS json file',
details='The VOMS json file located in %s was not loaded (%s:, e)' % (
VOMS_POLICY, type(e), e))
self._no_verify = False
#super(VomsAuthN, self).__init__(*args, **kwargs)
@staticmethod
def _get_cert_chain(ssl_info):
"""Return certificate and chain from the ssl info in M2Crypto format"""
cert = M2Crypto.X509.load_cert_string(ssl_info.get("cert"))
chain = M2Crypto.X509.X509_Stack()
for c in ssl_info.get("chain", []):
aux = M2Crypto.X509.load_cert_string(c)
chain.push(aux)
return cert, chain
def _get_voms_info(self, ssl_info):
"""Extract voms info from ssl_info and return dict with it."""
# Use astavoms instead of doing it by yourself
# astaresults = test_and_log_astavoms(ssl_info)
from kamaki.clients.utils import https
https.patch_ignore_ssl()
return self.astavoms.authenticate(**ssl_info)
# STOP HERE
# Keep this until verification is supported in astavoms
try:
cert, chain = self._get_cert_chain(ssl_info)
except M2Crypto.X509.X509Error:
raise ClientError(
'SSL data not verified',
details=CONTEXT_ENV)
with voms_helper.VOMS(VOMSDIR_PATH,
CA_PATH, VOMSAPI_LIB) as v:
if self._no_verify:
v.set_no_verify()
voms_data = v.retrieve(cert, chain)
if not voms_data:
# TODO(aloga): move this to a keystone exception
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)
# compare_results(d, astaresults)
return d
@staticmethod
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 _process_environ(self, environ):
LOG.warning("Getting the environment parameters...")
# the environment variable CONTENT_LENGTH may be empty or missing
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
raise ClientError(
'Not auth method provided',
details='The request body is empty, while it should contain the authentication method')
request_body = environ['wsgi.input'].read(request_body_size)
# print request_body
request_body = request_body.replace("true","\"true\"")
request_body = request_body.replace('"','\'' )
try:
params_parsed = ast.literal_eval(request_body)
except Exception as e:
LOG.warning('Skipping error: {t}: {e}'.format(t=type(e), e=e))
print 'Skipping error: {t}: {e}'.format(t=type(e), e=e)
params_parsed = {}
params = {}
for k, v in params_parsed.iteritems():
if k in ('self', 'context'):
continue
if k.startswith('_'):
continue
params[k] = v
environ[PARAMS_ENV] = params
# print environ[PARAMS_ENV]
def is_applicable(self, environ):
"""Check if the request is applicable for this handler or not"""
print "Checking if the request is applicable for this handler"
self._process_environ(environ)
params = environ.get(PARAMS_ENV, {})
auth = params.get("auth", {})
if "voms" in auth:
if "true" in auth["voms"]:
return True
else:
raise ClientError(
'Error in json',
details='Error in JSON, voms must be set to true')
return False
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, voms_info['snf:token'],
voms_info['snf:project'])
def process_request(self, environ):
print "Inside process_request!!!!"
if not self.is_applicable(environ):
raise ClientError('This environ is not applicable')
# return self.application
ssl_dict = {
"dn": environ.get(SSL_CLIENT_S_DN_ENV, None),
"cert": environ.get(SSL_CLIENT_CERT_ENV, None),
"chain": [],
}
for k, v in environ.iteritems():
if k.startswith(SSL_CLIENT_CERT_CHAIN_ENV_PREFIX):
ssl_dict["chain"].append(v)
voms_info = self._get_voms_info(ssl_dict)
params = environ[PARAMS_ENV]
tenant_from_req = params["auth"].get("tenantName", None)
user_dn = voms_info["user"]
user_vo = voms_info["voname"]
user_fqans = voms_info["fqans"]
environ['REMOTE_USER'] = user_dn
return (
user_dn, user_vo, user_fqans, voms_info['snf:token'],
voms_info['snf:project'])
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Spanish National Research Council
#
# 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 ctypes
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))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment