bug 832. Fixing non-authorized configuration for testing
[osm/NBI.git] / osm_nbi / nbi.py
index 9188834..33147b7 100644 (file)
@@ -24,7 +24,7 @@ import logging.handlers
 import getopt
 import sys
 
 import getopt
 import sys
 
-from authconn import AuthException
+from authconn import AuthException, AuthconnException
 from auth import Authenticator
 from engine import Engine, EngineException
 from subscriptions import SubscriptionThread
 from auth import Authenticator
 from engine import Engine, EngineException
 from subscriptions import SubscriptionThread
@@ -598,7 +598,7 @@ class Server(object):
         try:
             if cherrypy.request.method == "GET":
                 token_info = self.authenticator.authorize()
         try:
             if cherrypy.request.method == "GET":
                 token_info = self.authenticator.authorize()
-                outdata = "Index page"
+                outdata = token_info   # Home page
             else:
                 raise cherrypy.HTTPError(HTTPStatus.METHOD_NOT_ALLOWED.value,
                                          "Method {} not allowed for tokens".format(cherrypy.request.method))
             else:
                 raise cherrypy.HTTPError(HTTPStatus.METHOD_NOT_ALLOWED.value,
                                          "Method {} not allowed for tokens".format(cherrypy.request.method))
@@ -629,6 +629,20 @@ class Server(object):
             }
             return self._format_out(problem_details, None)
 
             }
             return self._format_out(problem_details, None)
 
+    @staticmethod
+    def _format_login(token_info):
+        """
+        Changes cherrypy.request.login to include username/project_name;session so that cherrypy access log will
+        log this information
+        :param token_info: Dictionary with token content
+        :return: None
+        """
+        cherrypy.request.login = token_info.get("username", "-")
+        if token_info.get("project_name"):
+            cherrypy.request.login += "/" + token_info["project_name"]
+        if token_info.get("id"):
+            cherrypy.request.login += ";session=" + token_info["id"][0:12]
+
     @cherrypy.expose
     def token(self, method, token_id=None, kwargs=None):
         token_info = None
     @cherrypy.expose
     def token(self, method, token_id=None, kwargs=None):
         token_info = None
@@ -636,49 +650,48 @@ class Server(object):
         indata = self._format_in(kwargs)
         if not isinstance(indata, dict):
             raise NbiException("Expected application/yaml or application/json Content-Type", HTTPStatus.BAD_REQUEST)
         indata = self._format_in(kwargs)
         if not isinstance(indata, dict):
             raise NbiException("Expected application/yaml or application/json Content-Type", HTTPStatus.BAD_REQUEST)
-        try:
-            if method == "GET":
+
+        if method == "GET":
+            token_info = self.authenticator.authorize()
+            # for logging
+            self._format_login(token_info)
+            if token_id:
+                outdata = self.authenticator.get_token(token_info, token_id)
+            else:
+                outdata = self.authenticator.get_token_list(token_info)
+        elif method == "POST":
+            try:
                 token_info = self.authenticator.authorize()
                 token_info = self.authenticator.authorize()
-                if token_id:
-                    outdata = self.authenticator.get_token(token_info, token_id)
-                else:
-                    outdata = self.authenticator.get_token_list(token_info)
-            elif method == "POST":
-                try:
-                    token_info = self.authenticator.authorize()
-                except Exception:
-                    token_info = None
-                if kwargs:
-                    indata.update(kwargs)
-                outdata = self.authenticator.new_token(token_info, indata, cherrypy.request.remote)
-                token_info = outdata
-                cherrypy.session['Authorization'] = outdata["_id"]
-                self._set_location_header("admin", "v1", "tokens", outdata["_id"])
-                # cherrypy.response.cookie["Authorization"] = outdata["id"]
-                # cherrypy.response.cookie["Authorization"]['expires'] = 3600
-            elif method == "DELETE":
-                if not token_id and "id" in kwargs:
-                    token_id = kwargs["id"]
-                elif not token_id:
-                    token_info = self.authenticator.authorize()
-                    token_id = token_info["_id"]
-                outdata = self.authenticator.del_token(token_id)
+            except Exception:
                 token_info = None
                 token_info = None
-                cherrypy.session['Authorization'] = "logout"
-                # cherrypy.response.cookie["Authorization"] = token_id
-                # cherrypy.response.cookie["Authorization"]['expires'] = 0
-            else:
-                raise NbiException("Method {} not allowed for token".format(method), HTTPStatus.METHOD_NOT_ALLOWED)
-            return self._format_out(outdata, token_info)
-        except (NbiException, EngineException, DbException, AuthException) as e:
-            cherrypy.log("tokens Exception {}".format(e))
-            cherrypy.response.status = e.http_code.value
-            problem_details = {
-                "code": e.http_code.name,
-                "status": e.http_code.value,
-                "detail": str(e),
-            }
-            return self._format_out(problem_details, token_info)
+            if kwargs:
+                indata.update(kwargs)
+            # This is needed to log the user when authentication fails
+            cherrypy.request.login = "{}".format(indata.get("username", "-"))
+            outdata = token_info = self.authenticator.new_token(token_info, indata, cherrypy.request.remote)
+            cherrypy.session['Authorization'] = outdata["_id"]
+            self._set_location_header("admin", "v1", "tokens", outdata["_id"])
+            # for logging
+            self._format_login(token_info)
+
+            # cherrypy.response.cookie["Authorization"] = outdata["id"]
+            # cherrypy.response.cookie["Authorization"]['expires'] = 3600
+        elif method == "DELETE":
+            if not token_id and "id" in kwargs:
+                token_id = kwargs["id"]
+            elif not token_id:
+                token_info = self.authenticator.authorize()
+                # for logging
+                self._format_login(token_info)
+                token_id = token_info["_id"]
+            outdata = self.authenticator.del_token(token_id)
+            token_info = None
+            cherrypy.session['Authorization'] = "logout"
+            # cherrypy.response.cookie["Authorization"] = token_id
+            # cherrypy.response.cookie["Authorization"]['expires'] = 0
+        else:
+            raise NbiException("Method {} not allowed for token".format(method), HTTPStatus.METHOD_NOT_ALLOWED)
+        return self._format_out(outdata, token_info)
 
     @cherrypy.expose
     def test(self, *args, **kwargs):
 
     @cherrypy.expose
     def test(self, *args, **kwargs):
@@ -929,8 +942,6 @@ class Server(object):
             if main_topic == "admin" and topic == "tokens":
                 return self.token(method, _id, kwargs)
 
             if main_topic == "admin" and topic == "tokens":
                 return self.token(method, _id, kwargs)
 
-            # self.engine.load_dbase(cherrypy.request.app.config)
-
             token_info = self.authenticator.authorize(role_permission, query_string_operations)
             engine_session = self._manage_admin_query(token_info, kwargs, method, _id)
             indata = self._format_in(kwargs)
             token_info = self.authenticator.authorize(role_permission, query_string_operations)
             engine_session = self._manage_admin_query(token_info, kwargs, method, _id)
             indata = self._format_in(kwargs)
@@ -982,11 +993,12 @@ class Server(object):
                         _id = args[0]
                     outdata = self.engine.get_item(engine_session, engine_topic, _id)
             elif method == "POST":
                         _id = args[0]
                     outdata = self.engine.get_item(engine_session, engine_topic, _id)
             elif method == "POST":
+                cherrypy.response.status = HTTPStatus.CREATED.value
                 if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"):
                     _id = cherrypy.request.headers.get("Transaction-Id")
                     if not _id:
                 if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"):
                     _id = cherrypy.request.headers.get("Transaction-Id")
                     if not _id:
-                        _id = self.engine.new_item(rollback, engine_session, engine_topic, {}, None,
-                                                   cherrypy.request.headers)
+                        _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, {}, None,
+                                                      cherrypy.request.headers)
                     completed = self.engine.upload_content(engine_session, engine_topic, _id, indata, kwargs,
                                                            cherrypy.request.headers)
                     if completed:
                     completed = self.engine.upload_content(engine_session, engine_topic, _id, indata, kwargs,
                                                            cherrypy.request.headers)
                     if completed:
@@ -996,43 +1008,45 @@ class Server(object):
                     outdata = {"id": _id}
                 elif topic == "ns_instances_content":
                     # creates NSR
                     outdata = {"id": _id}
                 elif topic == "ns_instances_content":
                     # creates NSR
-                    _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
+                    _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
                     # creates nslcmop
                     indata["lcmOperationType"] = "instantiate"
                     indata["nsInstanceId"] = _id
                     # creates nslcmop
                     indata["lcmOperationType"] = "instantiate"
                     indata["nsInstanceId"] = _id
-                    nslcmop_id = self.engine.new_item(rollback, engine_session, "nslcmops", indata, None)
+                    nslcmop_id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", indata, None)
                     self._set_location_header(main_topic, version, topic, _id)
                     outdata = {"id": _id, "nslcmop_id": nslcmop_id}
                 elif topic == "ns_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["nsInstanceId"] = _id
                     self._set_location_header(main_topic, version, topic, _id)
                     outdata = {"id": _id, "nslcmop_id": nslcmop_id}
                 elif topic == "ns_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["nsInstanceId"] = _id
-                    _id = self.engine.new_item(rollback, engine_session, "nslcmops", indata, kwargs)
+                    _id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", indata, kwargs)
                     self._set_location_header(main_topic, version, "ns_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 elif topic == "netslice_instances_content":
                     # creates NetSlice_Instance_record (NSIR)
                     self._set_location_header(main_topic, version, "ns_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 elif topic == "netslice_instances_content":
                     # creates NetSlice_Instance_record (NSIR)
-                    _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
+                    _id, _ = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs)
                     self._set_location_header(main_topic, version, topic, _id)
                     indata["lcmOperationType"] = "instantiate"
                     indata["netsliceInstanceId"] = _id
                     self._set_location_header(main_topic, version, topic, _id)
                     indata["lcmOperationType"] = "instantiate"
                     indata["netsliceInstanceId"] = _id
-                    nsilcmop_id = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
+                    nsilcmop_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
                     outdata = {"id": _id, "nsilcmop_id": nsilcmop_id}
 
                 elif topic == "netslice_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["netsliceInstanceId"] = _id
                     outdata = {"id": _id, "nsilcmop_id": nsilcmop_id}
 
                 elif topic == "netslice_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["netsliceInstanceId"] = _id
-                    _id = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
+                    _id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
                     self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 else:
                     self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 else:
-                    _id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
-                                               cherrypy.request.headers)
+                    _id, op_id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
+                                                      cherrypy.request.headers)
                     self._set_location_header(main_topic, version, topic, _id)
                     outdata = {"id": _id}
                     self._set_location_header(main_topic, version, topic, _id)
                     outdata = {"id": _id}
+                    if op_id:
+                        outdata["op_id"] = op_id
+                        cherrypy.response.status = HTTPStatus.ACCEPTED.value
                     # TODO form NsdInfo when topic in ("ns_descriptors", "vnf_packages")
                     # TODO form NsdInfo when topic in ("ns_descriptors", "vnf_packages")
-                cherrypy.response.status = HTTPStatus.CREATED.value
 
             elif method == "DELETE":
                 if not _id:
 
             elif method == "DELETE":
                 if not _id:
@@ -1046,7 +1060,7 @@ class Server(object):
                             "nsInstanceId": _id,
                             "autoremove": True
                         }
                             "nsInstanceId": _id,
                             "autoremove": True
                         }
-                        opp_id = self.engine.new_item(rollback, engine_session, "nslcmops", nslcmop_desc, None)
+                        opp_id, _ = self.engine.new_item(rollback, engine_session, "nslcmops", nslcmop_desc, None)
                         if opp_id:
                             delete_in_process = True
                             outdata = {"_id": opp_id}
                         if opp_id:
                             delete_in_process = True
                             outdata = {"_id": opp_id}
@@ -1057,7 +1071,7 @@ class Server(object):
                             "netsliceInstanceId": _id,
                             "autoremove": True
                         }
                             "netsliceInstanceId": _id,
                             "autoremove": True
                         }
-                        opp_id = self.engine.new_item(rollback, engine_session, "nsilcmops", nsilcmop_desc, None)
+                        opp_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", nsilcmop_desc, None)
                         if opp_id:
                             delete_in_process = True
                             outdata = {"_id": opp_id}
                         if opp_id:
                             delete_in_process = True
                             outdata = {"_id": opp_id}
@@ -1069,7 +1083,7 @@ class Server(object):
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
 
             elif method in ("PUT", "PATCH"):
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
 
             elif method in ("PUT", "PATCH"):
-                outdata = None
+                op_id = None
                 if not indata and not kwargs and not engine_session.get("set_project"):
                     raise NbiException("Nothing to update. Provide payload and/or query string",
                                        HTTPStatus.BAD_REQUEST)
                 if not indata and not kwargs and not engine_session.get("set_project"):
                     raise NbiException("Nothing to update. Provide payload and/or query string",
                                        HTTPStatus.BAD_REQUEST)
@@ -1079,8 +1093,14 @@ class Server(object):
                     if not completed:
                         cherrypy.response.headers["Transaction-Id"] = id
                 else:
                     if not completed:
                         cherrypy.response.headers["Transaction-Id"] = id
                 else:
-                    self.engine.edit_item(engine_session, engine_topic, _id, indata, kwargs)
-                cherrypy.response.status = HTTPStatus.NO_CONTENT.value
+                    op_id = self.engine.edit_item(engine_session, engine_topic, _id, indata, kwargs)
+
+                if op_id:
+                    cherrypy.response.status = HTTPStatus.ACCEPTED.value
+                    outdata = {"op_id": op_id}
+                else:
+                    cherrypy.response.status = HTTPStatus.NO_CONTENT.value
+                    outdata = None
             else:
                 raise NbiException("Method {} not allowed".format(method), HTTPStatus.METHOD_NOT_ALLOWED)
 
             else:
                 raise NbiException("Method {} not allowed".format(method), HTTPStatus.METHOD_NOT_ALLOWED)
 
@@ -1090,7 +1110,7 @@ class Server(object):
             return self._format_out(outdata, token_info, _format)
         except Exception as e:
             if isinstance(e, (NbiException, EngineException, DbException, FsException, MsgException, AuthException,
             return self._format_out(outdata, token_info, _format)
         except Exception as e:
             if isinstance(e, (NbiException, EngineException, DbException, FsException, MsgException, AuthException,
-                              ValidationError)):
+                              ValidationError, AuthconnException)):
                 http_code_value = cherrypy.response.status = e.http_code.value
                 http_code_name = e.http_code.name
                 cherrypy.log("Exception {}".format(e))
                 http_code_value = cherrypy.response.status = e.http_code.value
                 http_code_name = e.http_code.name
                 cherrypy.log("Exception {}".format(e))
@@ -1124,6 +1144,13 @@ class Server(object):
             }
             return self._format_out(problem_details, token_info)
             # raise cherrypy.HTTPError(e.http_code.value, str(e))
             }
             return self._format_out(problem_details, token_info)
             # raise cherrypy.HTTPError(e.http_code.value, str(e))
+        finally:
+            if token_info:
+                self._format_login(token_info)
+                if method in ("PUT", "PATCH", "POST") and isinstance(outdata, dict):
+                    for logging_id in ("id", "op_id", "nsilcmop_id", "nslcmop_id"):
+                        if outdata.get(logging_id):
+                            cherrypy.request.login += ";{}={}".format(logging_id, outdata[logging_id][:36])
 
 
 def _start_service():
 
 
 def _start_service():
@@ -1228,7 +1255,10 @@ def _start_service():
     try:
         with open("{}/version".format(engine_config["/static"]['tools.staticdir.dir'])) as version_file:
             version_data = version_file.read()
     try:
         with open("{}/version".format(engine_config["/static"]['tools.staticdir.dir'])) as version_file:
             version_data = version_file.read()
-            cherrypy.log.error("Starting OSM NBI Version: {}".format(version_data.replace("\n", " ")))
+            version = version_data.replace("\n", " ")
+            backend = engine_config["authentication"]["backend"]
+            cherrypy.log.error("Starting OSM NBI Version {} with {} authentication backend"
+                               .format(version, backend))
     except Exception:
         pass
 
     except Exception:
         pass