summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Sandoval <frank.sandoval@oamtechnologies.com>2018-10-24 02:15:50 -0600
committerDileep Ranganathan <dileep.ranganathan@intel.com>2018-10-31 02:55:23 -0700
commit17690987fe470a962164ec168dc805db8a511130 (patch)
tree6db42b71cdc09e609ce3f6e3bb79a7d2363aaf24
parented7c491c37db044b07ab97781a2d8cab63bcfe99 (diff)
Enforce AAF permissions
Issue-ID: OPTFRA-331 Change-Id: I046ddef243f73ae90ca0a28184ee0decf73069ee Signed-off-by: Frank Sandoval <frank.sandoval@oamtechnologies.com> Signed-off-by: Dileep Ranganathan <dileep.ranganathan@intel.com>
-rwxr-xr-xconductor.conf21
-rw-r--r--conductor/conductor/api/adapters/aaf/aaf_authentication.py118
-rw-r--r--conductor/conductor/api/controllers/v1/plans.py6
-rw-r--r--conductor/conductor/common/sms.py3
-rw-r--r--conductor/conductor/opts.py2
-rwxr-xr-xpreload_secrets.yaml5
6 files changed, 107 insertions, 48 deletions
diff --git a/conductor.conf b/conductor.conf
index 027335d..0c0ae2b 100755
--- a/conductor.conf
+++ b/conductor.conf
@@ -131,20 +131,30 @@
#fatal_deprecations = false
-[aaf_authentication]
+[aaf_api]
#
# From conductor
#
# is_aaf_enabled. (boolean value)
-#is_aaf_enabled = true
+#is_aaf_enabled = false
# aaf_cache_expiry_hrs. (integer value)
-#aaf_cache_expiry_hrs = 3
+aaf_cache_expiry_hrs = 3
# aaf_url. (string value)
-aaf_url = http://aaf-service:8100/authz/perms/user/
+#aaf_url = https://aaf-service:8100/authz/perms/user/
+
+# aaf_cert_file. (string value)
+#aaf_cert_file = <None>
+
+# aaf_cert_key_file. (string value)
+#aaf_cert_key_file = <None>
+
+# aaf_ca_bundle_file. (string value)
+#aaf_ca_bundle_file =
+aaf_ca_bundle_file = AAF_RootCA.cer
# aaf_retries. (integer value)
#aaf_retries = 3
@@ -153,7 +163,7 @@ aaf_url = http://aaf-service:8100/authz/perms/user/
#aaf_timeout = 100
# aaf_user_roles. (list value)
-#aaf_user_roles = {"type": "org.onap.oof","instance": "plans","action": "GET"},{"type": "org.onap.oof","instance": "plans","action": "POST"}
+#aaf_permissions = {"type": "org.onap.oof.access","instance": "*","action": "*"}
[aaf_sms]
@@ -594,3 +604,4 @@ concurrent = true
# Extensions list to use (list value)
#extensions = multicloud
+
diff --git a/conductor/conductor/api/adapters/aaf/aaf_authentication.py b/conductor/conductor/api/adapters/aaf/aaf_authentication.py
index e6b79d2..f669ba4 100644
--- a/conductor/conductor/api/adapters/aaf/aaf_authentication.py
+++ b/conductor/conductor/api/adapters/aaf/aaf_authentication.py
@@ -20,9 +20,11 @@
import base64
from datetime import datetime, timedelta
import json
+import os
from conductor.common import rest
from conductor.i18n import _LE, _LI
+from conductor import __file__ as conductor_root
from oslo_log import log
LOG = log.getLogger(__name__)
@@ -30,32 +32,46 @@ LOG = log.getLogger(__name__)
from oslo_config import cfg
CONF = cfg.CONF
-# TBD - read values from conductor.conf
AAF_OPTS = [
cfg.BoolOpt('is_aaf_enabled',
- default=True,
+ default=False,
help='is_aaf_enabled.'),
cfg.IntOpt('aaf_cache_expiry_hrs',
- default='3',
+ default='24',
help='aaf_cache_expiry_hrs.'),
cfg.StrOpt('aaf_url',
- default='http://aaf-service:8100/authz/perms/user/',
+ default='https://aaf-service:8100/authz/perms/user/',
help='aaf_url.'),
+ cfg.StrOpt('username',
+ default=None,
+ help='username.'),
+ cfg.StrOpt('password',
+ default=None,
+ help='pasword.'),
+ cfg.StrOpt('aaf_cert_file',
+ default=None,
+ help='aaf_cert_file.'),
+ cfg.StrOpt('aaf_cert_key_file',
+ default=None,
+ help='aaf_cert_key_file.'),
+ cfg.StrOpt('aaf_ca_bundle_file',
+ default="",
+ help='aaf_ca_bundle_file.'),
cfg.IntOpt('aaf_retries',
default='3',
help='aaf_retries.'),
cfg.IntOpt('aaf_timeout',
default='100',
help='aaf_timeout.'),
- cfg.ListOpt('aaf_user_roles',
- default=['{"type": "org.onap.oof","instance": "plans","action": "GET"}',
- '{"type": "org.onap.oof","instance": "plans","action": "POST"}'],
+ cfg.StrOpt('aaf_conductor_user',
+ default=None,
+ help='aaf_conductor_user.'),
+ cfg.ListOpt('aaf_permissions',
+ default=['{"type": "org.onap.oof.access","instance": "*","action": "*"}'],
help='aaf_user_roles.')
]
-CONF.register_opts(AAF_OPTS, group='aaf_authentication')
-
-AUTHZ_PERMS_USER = '{}/authz/perms/user/{}'
+CONF.register_opts(AAF_OPTS, group='aaf_api')
EXPIRE_TIME = 'expire_time'
@@ -64,11 +80,22 @@ perm_cache = {}
def clear_cache():
perm_cache.clear()
-
def authenticate(uid, passwd):
+ # FS - trace
+ LOG.info("Authenticating username:password {} : {}: ".format(uid, passwd))
+
+ aafUser = None
+ username = CONF.conductor_api.username
+ password = CONF.conductor_api.password
+ if username == uid and password == passwd:
+ aafUser = CONF.aaf_api.aaf_conductor_user
+ else:
+ LOG.debug("Error Authenticating the user {} : {}: ".format(uid, passwd))
+ return False
+
try:
- perms = get_aaf_permissions(uid, passwd)
- return has_valid_role(perms)
+ perms = get_aaf_permissions(aafUser)
+ return has_valid_permissions(perms)
except Exception as exp:
LOG.error("Error Authenticating the user {} : {}: ".format(uid, exp))
pass
@@ -80,22 +107,27 @@ return True if the user has valid permissions
else return false
"""
-def has_valid_role(perms):
- aaf_user_roles = CONF.aaf_authentication.aaf_user_roles
-
- permObj = json.loads(perms)
- permList = permObj["perm"]
- for user_role in aaf_user_roles:
- role = json.loads(user_role)
- userType = role["type"]
- userInstance = role["instance"]
- userAction = role["action"]
- for perm in permList:
- permType = perm["type"]
- permInstance = perm["instance"]
- permAction = perm["action"]
+def has_valid_permissions(userPerms):
+ permissions = CONF.aaf_api.aaf_permissions
+
+ LOG.info("Validate permisions: acquired permissions {} ".format(userPerms))
+ LOG.info("Validate permisions: allowed permissions {} ".format(permissions))
+
+ userPermObj = json.loads(userPerms)
+ userPermList = userPermObj["perm"]
+ for perm in permissions:
+ permObj = json.loads(perm)
+ permType = permObj["type"]
+ permInstance = permObj["instance"]
+ permAction = permObj["action"]
+ for userPerm in userPermList:
+ userType = userPerm["type"]
+ userInstance = userPerm["instance"]
+ userAction = userPerm["action"]
if userType == permType and userInstance == permInstance and \
(userAction == permAction or userAction == "*"):
+ # FS - trace
+ LOG.info("User has valid permissions ")
return True
return False
@@ -104,35 +136,43 @@ 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("{}_{}".format(uid, passwd), "ascii")
- time_delta = timedelta(hours = CONF.aaf_authentication.aaf_cache_expiry_hrs)
+def get_aaf_permissions(aafUser):
+ key = base64.b64encode("{}".format(aafUser), "ascii")
+ time_delta = timedelta(hours = CONF.aaf_api.aaf_cache_expiry_hrs)
-# TBD - test cache logic
perms = perm_cache.get(key)
if perms and datetime.now() < perms.get(EXPIRE_TIME):
LOG.debug("Returning cached value")
return perms['roles']
LOG.debug("Invoking AAF authentication API")
- response = remote_api(passwd, uid)
+ response = remote_api(aafUser)
perms = {EXPIRE_TIME: datetime.now() + time_delta, 'roles': response}
perm_cache[key] = perms
return response
-def remote_api(passwd, uid):
- server_url = CONF.aaf_authentication.aaf_url.rstrip('/')
+
+"""
+The remote api is the AAF service
+
+"""
+def remote_api(aafUser):
+ server_url = CONF.aaf_api.aaf_url+aafUser
+
kwargs = {
"server_url": server_url,
- "retries": CONF.aaf_authentication.aaf_retries,
- "username": uid,
- "password": passwd,
+ "retries": CONF.aaf_api.aaf_retries,
+ "username": CONF.aaf_api.username,
+ "password": CONF.aaf_api.password,
"log_debug": LOG.debug,
- "read_timeout": CONF.aaf_authentication.aaf_timeout,
+ "read_timeout": CONF.aaf_api.aaf_timeout,
+ "cert_file": CONF.aaf_api.aaf_cert_file,
+ "cert_key_file": CONF.aaf_api.aaf_cert_key_file,
+ "ca_bundle_file": CONF.aaf_api.aaf_ca_bundle_file,
}
restReq = rest.REST(**kwargs)
- headers = {"Accept": "application/json"}
+ headers = {"Accept": "application/Perms+json;q=1.0;charset=utf-8;version=2.1,application/json;q=1.0;version=2.1,*/*;q=1.0"}
rkwargs = {
"method": 'GET',
"path": '',
diff --git a/conductor/conductor/api/controllers/v1/plans.py b/conductor/conductor/api/controllers/v1/plans.py
index b32caef..411686b 100644
--- a/conductor/conductor/api/controllers/v1/plans.py
+++ b/conductor/conductor/api/controllers/v1/plans.py
@@ -85,7 +85,7 @@ class PlansBaseController(object):
def plans_get(self, plan_id=None):
- auth_flag = CONF.conductor_api.basic_auth_secure or CONF.aaf_authentication.is_aaf_enabled
+ auth_flag = CONF.conductor_api.basic_auth_secure or CONF.aaf_api.is_aaf_enabled
# TBD - is healthcheck properly supported?
if plan_id == 'healthcheck' or \
@@ -291,7 +291,7 @@ class PlansController(PlansBaseController):
if args and args['name']:
LOG.info('Plan name: {}'.format(args['name']))
- auth_flag = CONF.conductor_api.basic_auth_secure or CONF.aaf_authentication.is_aaf_enabled
+ auth_flag = CONF.conductor_api.basic_auth_secure or CONF.aaf_api.is_aaf_enabled
# Create the plan only when the basic authentication is disabled or pass the authenticaiton check
if not auth_flag or \
@@ -360,7 +360,7 @@ def verify_user(authstr):
retVal = False
- if CONF.aaf_authentication.is_aaf_enabled:
+ if CONF.aaf_api.is_aaf_enabled:
retVal = aaf_auth.authenticate(user_dict['username'], user_dict['password'])
else:
if username == user_dict['username'] and password == user_dict['password']:
diff --git a/conductor/conductor/common/sms.py b/conductor/conductor/common/sms.py
index c5eee3a..6e21392 100644
--- a/conductor/conductor/common/sms.py
+++ b/conductor/conductor/common/sms.py
@@ -111,6 +111,9 @@ def load_secrets():
config.set_override('aafns', secret_dict['music_api']['aafns'], 'music_api')
config.set_override('username', secret_dict['sdnc']['username'], 'sdnc')
config.set_override('password', secret_dict['sdnc']['password'], 'sdnc')
+ config.set_override('username', secret_dict['aaf_api']['username'], 'aaf_api')
+ config.set_override('password', secret_dict['aaf_api']['password'], 'aaf_api')
+ config.set_override('aaf_conductor_user', secret_dict['aaf_api']['aaf_conductor_user'], 'aaf_api')
def delete_secrets():
diff --git a/conductor/conductor/opts.py b/conductor/conductor/opts.py
index 106de2d..d711a4e 100644
--- a/conductor/conductor/opts.py
+++ b/conductor/conductor/opts.py
@@ -75,7 +75,7 @@ def list_opts():
('solver', conductor.solver.service.SOLVER_OPTS),
('reservation', conductor.reservation.service.reservation_OPTS),
('aaf_sms', conductor.common.sms.AAF_SMS_OPTS),
- ('aaf_authentication',
+ ('aaf_api',
conductor.api.adapters.aaf.aaf_authentication.AAF_OPTS),
('prometheus', conductor.common.prometheus_metrics.METRICS_OPTS),
]
diff --git a/preload_secrets.yaml b/preload_secrets.yaml
index 98e5197..3ec1b92 100755
--- a/preload_secrets.yaml
+++ b/preload_secrets.yaml
@@ -20,3 +20,8 @@ secrets:
aafuser: conductor
aafpass: c0nduct0r
aafns: conductor
+- name: aaf_api
+ values:
+ username: aaf_admin@people.osaaf.org
+ password: demo123456!
+ aaf_conductor_user: oof@oof.onap.org