From bce4081920132be04a91ea60e7d0a2e1d030e88d Mon Sep 17 00:00:00 2001 From: "Varma, Vikas" Date: Mon, 10 Sep 2018 23:02:05 -0400 Subject: Python implementation of the aaf cadi client Change-Id: I0cae202775361f221a7d8774254febfaf0a4bbac Python implementation of the aaf cadi client Change-Id: Icd31276a908eaf72ab30fc04e1d2a4715817a5b6 Signed-off-by: Varma, Vikas Issue-ID: OPTFRA-339 --- config/osdf_config.yaml | 8 ++- osdf/adapters/aaf/__init__.py | 0 osdf/adapters/aaf/aaf_authentication.py | 99 +++++++++++++++++++++++++++++++++ osdf/webapp/appcontroller.py | 12 ++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 osdf/adapters/aaf/__init__.py create mode 100644 osdf/adapters/aaf/aaf_authentication.py diff --git a/config/osdf_config.yaml b/config/osdf_config.yaml index 34855df..022104d 100755 --- a/config/osdf_config.yaml +++ b/config/osdf_config.yaml @@ -43,4 +43,10 @@ osdfPlacementVFCPassword: vfc_testpwd # Credentials for the OOF CM scheduling service - Generic osdfCMSchedulerUsername: test1 -osdfCMSchedulerPassword: testpwd1 \ No newline at end of file +osdfCMSchedulerPassword: testpwd1 + +is_aaf_enabled: False +aaf_cache_expiry_hrs: 3 +aaf_url: https://aaftest.simpledemo.onap.org:8095 +aaf_user_roles: + - /api/oof/v1/placement:org.onap.osdf.access|*|read ALL diff --git a/osdf/adapters/aaf/__init__.py b/osdf/adapters/aaf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/osdf/adapters/aaf/aaf_authentication.py b/osdf/adapters/aaf/aaf_authentication.py new file mode 100644 index 0000000..26a3992 --- /dev/null +++ b/osdf/adapters/aaf/aaf_authentication.py @@ -0,0 +1,99 @@ +# ------------------------------------------------------------------------- +# Copyright (c) 2015-2017 AT&T Intellectual Property +# +# 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 base64 +import re +from datetime import datetime, timedelta +from flask import request + +from osdf.config.base import osdf_config +from osdf.logging.osdf_logging import error_log, debug_log +from osdf.utils.interfaces import RestClient + +AUTHZ_PERMS_USER = '{}/authz/perms/user/{}' + +EXPIRE_TIME = 'expire_time' + +perm_cache = {} +deploy_config = osdf_config.deployment + + +def clear_cache(): + perm_cache.clear() + + +def authenticate(uid, passwd): + try: + perms = get_aaf_permissions(uid, passwd) + return has_valid_role(perms) + except Exception as exp: + error_log.error("Error Authenticating the user {} : {}: ".format(uid, exp)) + pass + return False + + +""" +Check whether the user has valid permissions +return True if the user has valid permissions +else return false +""" + + +def has_valid_role(perms): + aaf_user_roles = deploy_config['aaf_user_roles'] + + for roles in aaf_user_roles: + path_perm = roles.split(':') + uri = path_perm[0] + role = path_perm[1].split('|')[0] + if re.search(uri, request.path) and perms: + roles = perms.get('roles') + if roles: + perm_list = roles.get('perm') + for p in perm_list: + if role == p['type']: + return True + return False + +""" +Make the remote aaf api call if user is not in the cache. + +Return the perms +""" +def get_aaf_permissions(uid, passwd): + key = base64.b64encode(bytes("{}_{}".format(uid, passwd), "ascii")) + time_delta = timedelta(hours=deploy_config.get('aaf_cache_expiry_hrs', 3)) + + perms = perm_cache.get(key) + + if perms and datetime.now() < perms.get(EXPIRE_TIME): + debug_log.debug("Returning cached value") + return perms + debug_log.debug("Invoking AAF authentication API") + perms = {EXPIRE_TIME: datetime.now() + time_delta, 'roles': remote_api(passwd, uid)} + perm_cache[key] = perms + return perms + + +def remote_api(passwd, uid): + headers = {"Accept": "application/Users+xml;q=1.0;charset=utf-8;version=2.0,text/xml;q=1.0;version=2.0", + "Accept": "application/Users+json;q=1.0;charset=utf-8;version=2.0,application/json;q=1.0;version=2.0,*/*;q=1.0"} + url = AUTHZ_PERMS_USER.format(deploy_config['aaf_url'], uid) + rc = RestClient(userid=uid, passwd=passwd, headers=headers, url=url, log_func=debug_log.debug, + req_id='aaf_user_id', service='aaf_authentication_service') + return rc.request(method='GET', asjson=True) diff --git a/osdf/webapp/appcontroller.py b/osdf/webapp/appcontroller.py index 49f84ff..a56a53d 100644 --- a/osdf/webapp/appcontroller.py +++ b/osdf/webapp/appcontroller.py @@ -22,6 +22,7 @@ from flask import Response import json import osdf from osdf.config.base import http_basic_auth_credentials +from osdf.adapters.aaf import aaf_authentication as aaf_auth auth_basic = HTTPBasicAuth() @@ -45,3 +46,14 @@ def auth_error(): response.headers.add('content-length', len(unauthorized_message)) response.status_code = 401 return response + + +@auth_basic.verify_password +def verify_pw(username, password): + is_aaf_enabled = osdf.deployment.get('is_aaf_enabled', False) + if is_aaf_enabled: + return aaf_auth.authenticate(username, password) + else: + pw = get_pw(username) + return pw == password + return False \ No newline at end of file -- cgit 1.2.3-korg