From 0ab0d80e5e2467c40c22afa1a6de0041b472c658 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matev=C5=BE=20Er=C5=BEen?= <matevz.erzen@xlab.si>
Date: Tue, 22 Mar 2022 15:04:16 +0000
Subject: [PATCH] Oauth2 implementation

---
 .env                                          |   5 +-
 MANIFEST                                      |   2 +-
 README.md                                     |   3 +
 forward_evidence/clouditor_authentication.py  |  48 ++++
 forward_evidence/forward_evidence.py          |   6 +-
 grpc_gen/assessment_pb2.py                    | 258 +++++++++++++-----
 grpc_gen/assessment_pb2_grpc.py               |  74 +++--
 grpc_gen/evidence_pb2.py                      |   5 +-
 grpc_gen/metric_pb2.py                        |  82 +++++-
 proto/assessment.proto                        |  64 +++--
 proto/evidence.proto                          |   6 +-
 proto/metric.proto                            |  20 +-
 .../wazuh_evidence_collector.py               |  13 +-
 13 files changed, 421 insertions(+), 165 deletions(-)
 create mode 100644 forward_evidence/clouditor_authentication.py

diff --git a/.env b/.env
index b9b03d8..908aec1 100644
--- a/.env
+++ b/.env
@@ -15,4 +15,7 @@ redis_port=6379
 redis_queue=low
 
 clouditor_host=192.168.33.14
-clouditor_port=9090
\ No newline at end of file
+clouditor_port=9090
+clouditor_oauth2_port=8080
+clouditor_client_id=clouditor
+clouditor_client_secret=clouditor
\ No newline at end of file
diff --git a/MANIFEST b/MANIFEST
index 9f9cd1c..ca1dc8e 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,2 +1,2 @@
-VERSION=v0.0.9
+VERSION=v0.0.10
 SERVICE=evidence-collector
diff --git a/README.md b/README.md
index 7277081..01e8f72 100644
--- a/README.md
+++ b/README.md
@@ -100,6 +100,9 @@ All of the following environment variables have to be set (or passed to containe
 | `redis_queue` | Redis queue name. |
 | `clouditor_host` | Clouditor host's IP address. |
 | `clouditor_port` | Clouditor port. Default value `9090`. |
+| `clouditor_oauth2_port` | Clouditor port used for authentication services. Default value `8080`. |
+| `clouditor_client_id` | Clouditor OAuth2 default id. Default value `clouditor`. |
+| `clouditor_client_secret` | Clouditor OAuth2 default secret. Default value `clouditor`. |
 
 ### Generate gRPC code from `.proto` files
 
diff --git a/forward_evidence/clouditor_authentication.py b/forward_evidence/clouditor_authentication.py
new file mode 100644
index 0000000..77bb580
--- /dev/null
+++ b/forward_evidence/clouditor_authentication.py
@@ -0,0 +1,48 @@
+import os
+import json
+import requests
+import urllib3
+from datetime import datetime, timedelta
+
+CLOUDITOR_HOST = os.environ.get("clouditor_host")
+CLOUDITOR_OAUTH2_PORT = int(os.environ.get("clouditor_oauth2_port"))
+CLIENT_ID = os.environ.get("clouditor_client_id")
+CLIENT_SECRET = os.environ.get("clouditor_client_secret")
+
+class ClouditorAuthentication(object):
+    
+    def __init__(self, logger):
+        self.logger = logger
+
+        self.__access_token = None
+        self.__token_expiration_time = None
+
+        self.__token_url = 'http://{}:{}/v1/auth/token'.format(CLOUDITOR_HOST, CLOUDITOR_OAUTH2_PORT)
+
+        self.__data = {'grant_type': 'client_credentials'}
+
+        self.request_token()
+
+    def request_token(self):
+        try:
+            access_token_response = requests.post(self.__token_url, data=self.__data, verify=False, allow_redirects=False, auth=(CLIENT_ID, CLIENT_SECRET))
+        except (TimeoutError, urllib3.exceptions.NewConnectionError, 
+                urllib3.exceptions.MaxRetryError, requests.exceptions.ConnectionError) as err:
+            self.logger.error(err)
+            self.logger.error("Clouditor OAuth2 token endpoint not available")
+        else:
+            token = json.loads(access_token_response.text)
+
+            self.__access_token = token['access_token']
+            self.__token_expiration_time = datetime.utcnow() + timedelta(seconds=token['expires_in'])
+
+            self.logger.info("New OAuth2 token successfully acquired")
+            self.logger.debug("OAuth2 token expiring at: " + str(self.__token_expiration_time - 10))
+
+    def get_token(self):
+        # In practice this condition isn't even needed as every scheduled job creates new ClouditorAuthentication object and acquires new token.
+        if (datetime.utcnow() > self.__token_expiration_time):
+            self.logger.debug("OAuth2 token expired.")
+            self.request_token()
+
+        return self.__access_token
diff --git a/forward_evidence/forward_evidence.py b/forward_evidence/forward_evidence.py
index fcb0369..99ca462 100644
--- a/forward_evidence/forward_evidence.py
+++ b/forward_evidence/forward_evidence.py
@@ -12,9 +12,11 @@ class ForwardEvidence(object):
         self.stub = AssessmentStub(self.channel)
         self.logger = logger
 
-    def send_evidence(self, assessevidencerequest):
+    def send_evidence(self, assessevidencerequest, token):
         try:
-            response = self.stub.AssessEvidence(assessevidencerequest)
+            metadata = [('authorization', 'Bearer ' + token)]
+
+            response = self.stub.AssessEvidence(assessevidencerequest, metadata=metadata)
             self.logger.info('gRPC evidence forwarded: ' + str(response))
         except grpc.RpcError as err:
             self.logger.error(err)
diff --git a/grpc_gen/assessment_pb2.py b/grpc_gen/assessment_pb2.py
index 82565b5..7f0efe0 100644
--- a/grpc_gen/assessment_pb2.py
+++ b/grpc_gen/assessment_pb2.py
@@ -22,27 +22,87 @@ DESCRIPTOR = _descriptor.FileDescriptor(
   name='assessment.proto',
   package='clouditor',
   syntax='proto3',
-  serialized_options=b'Z\016api/assessment',
+  serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x10\x61ssessment.proto\x12\tclouditor\x1a\x1cgoogle/api/annotations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x0e\x65vidence.proto\x1a\x0cmetric.proto\".\n\x18TriggerAssessmentRequest\x12\x12\n\nsomeOption\x18\x01 \x01(\t\"\x1e\n\x1cListAssessmentResultsRequest\"C\n\x1dListAssessmentResultsResponse\x12\"\n\x07results\x18\x01 \x03(\x0b\x32\x11.clouditor.Result\">\n\x15\x41ssessEvidenceRequest\x12%\n\x08\x65vidence\x18\x01 \x01(\x0b\x32\x13.clouditor.Evidence\"(\n\x16\x41ssessEvidenceResponse\x12\x0e\n\x06status\x18\x01 \x01(\x08\"\xe9\x01\n\x06Result\x12\n\n\x02id\x18\x01 \x01(\t\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\tmetric_id\x18\x03 \x01(\t\x12\x33\n\x0bmetric_data\x18\x04 \x01(\x0b\x32\x1e.clouditor.MetricConfiguration\x12\x11\n\tcompliant\x18\x05 \x01(\x08\x12\x13\n\x0b\x65vidence_id\x18\x06 \x01(\t\x12\x13\n\x0bresource_id\x18\x07 \x01(\t\x12\x1f\n\x17non_compliance_comments\x18\x08 \x01(\t2\xae\x03\n\nAssessment\x12R\n\x11TriggerAssessment\x12#.clouditor.TriggerAssessmentRequest\x1a\x16.google.protobuf.Empty\"\x00\x12\x8d\x01\n\x15ListAssessmentResults\x12\'.clouditor.ListAssessmentResultsRequest\x1a(.clouditor.ListAssessmentResultsResponse\"!\x82\xd3\xe4\x93\x02\x1b\"\x16/v1/assessment/resultsb\x01*\x12z\n\x0e\x41ssessEvidence\x12 .clouditor.AssessEvidenceRequest\x1a!.clouditor.AssessEvidenceResponse\"#\x82\xd3\xe4\x93\x02\x1d\"\x18/v1/assessment/evidencesb\x01*\x12@\n\x0f\x41ssessEvidences\x12\x13.clouditor.Evidence\x1a\x16.google.protobuf.Empty(\x01\x42\x10Z\x0e\x61pi/assessmentb\x06proto3'
+  serialized_pb=b'\n\x10\x61ssessment.proto\x12\tclouditor\x1a\x1cgoogle/api/annotations.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x0e\x65vidence.proto\x1a\x0cmetric.proto\"\x1e\n\x1cListAssessmentResultsRequest\"M\n\x1dListAssessmentResultsResponse\x12,\n\x07results\x18\x01 \x03(\x0b\x32\x1b.clouditor.AssessmentResult\"\x1c\n\x1a\x43onfigureAssessmentRequest\"\x1d\n\x1b\x43onfigureAssessmentResponse\"/\n\x18TriggerAssessmentRequest\x12\x13\n\x0bsome_option\x18\x01 \x01(\t\">\n\x15\x41ssessEvidenceRequest\x12%\n\x08\x65vidence\x18\x01 \x01(\x0b\x32\x13.clouditor.Evidence\"\xde\x01\n\x16\x41ssessEvidenceResponse\x12\x42\n\x06status\x18\x01 \x01(\x0e\x32\x32.clouditor.AssessEvidenceResponse.AssessmentStatus\x12\x16\n\x0estatus_message\x18\x02 \x01(\t\"h\n\x10\x41ssessmentStatus\x12!\n\x1d\x41SSESSMENT_STATUS_UNSPECIFIED\x10\x00\x12\x17\n\x13WAITING_FOR_RELATED\x10\x01\x12\x0c\n\x08\x41SSESSED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"\xfc\x01\n\x10\x41ssessmentResult\x12\n\n\x02id\x18\x01 \x01(\t\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x11\n\tmetric_id\x18\x03 \x01(\t\x12<\n\x14metric_configuration\x18\x04 \x01(\x0b\x32\x1e.clouditor.MetricConfiguration\x12\x11\n\tcompliant\x18\x05 \x01(\x08\x12\x13\n\x0b\x65vidence_id\x18\x06 \x01(\t\x12\x13\n\x0bresource_id\x18\x07 \x01(\t\x12\x1f\n\x17non_compliance_comments\x18\x08 \x01(\t2\xd7\x03\n\nAssessment\x12R\n\x11TriggerAssessment\x12#.clouditor.TriggerAssessmentRequest\x1a\x16.google.protobuf.Empty\"\x00\x12\x89\x01\n\x0e\x41ssessEvidence\x12 .clouditor.AssessEvidenceRequest\x1a!.clouditor.AssessEvidenceResponse\"2\x82\xd3\xe4\x93\x02,\"\x18/v1/assessment/evidences:\x08\x65videnceb\x06status\x12\\\n\x0f\x41ssessEvidences\x12 .clouditor.AssessEvidenceRequest\x1a!.clouditor.AssessEvidenceResponse\"\x00(\x01\x30\x01\x12\x8a\x01\n\x15ListAssessmentResults\x12\'.clouditor.ListAssessmentResultsRequest\x1a(.clouditor.ListAssessmentResultsResponse\"\x1e\x82\xd3\xe4\x93\x02\x18\x12\x16/v1/assessment/resultsb\x06proto3'
   ,
   dependencies=[google_dot_api_dot_annotations__pb2.DESCRIPTOR,google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,evidence__pb2.DESCRIPTOR,metric__pb2.DESCRIPTOR,])
 
 
 
+_ASSESSEVIDENCERESPONSE_ASSESSMENTSTATUS = _descriptor.EnumDescriptor(
+  name='AssessmentStatus',
+  full_name='clouditor.AssessEvidenceResponse.AssessmentStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='ASSESSMENT_STATUS_UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='WAITING_FOR_RELATED', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='ASSESSED', index=2, number=2,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='FAILED', index=3, number=3,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=557,
+  serialized_end=661,
+)
+_sym_db.RegisterEnumDescriptor(_ASSESSEVIDENCERESPONSE_ASSESSMENTSTATUS)
+
 
-_TRIGGERASSESSMENTREQUEST = _descriptor.Descriptor(
-  name='TriggerAssessmentRequest',
-  full_name='clouditor.TriggerAssessmentRequest',
+_LISTASSESSMENTRESULTSREQUEST = _descriptor.Descriptor(
+  name='ListAssessmentResultsRequest',
+  full_name='clouditor.ListAssessmentResultsRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=153,
+  serialized_end=183,
+)
+
+
+_LISTASSESSMENTRESULTSRESPONSE = _descriptor.Descriptor(
+  name='ListAssessmentResultsResponse',
+  full_name='clouditor.ListAssessmentResultsResponse',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='someOption', full_name='clouditor.TriggerAssessmentRequest.someOption', index=0,
-      number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=b"".decode('utf-8'),
+      name='results', full_name='clouditor.ListAssessmentResultsResponse.results', index=0,
+      number=1, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
@@ -58,14 +118,14 @@ _TRIGGERASSESSMENTREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=153,
-  serialized_end=199,
+  serialized_start=185,
+  serialized_end=262,
 )
 
 
-_LISTASSESSMENTRESULTSREQUEST = _descriptor.Descriptor(
-  name='ListAssessmentResultsRequest',
-  full_name='clouditor.ListAssessmentResultsRequest',
+_CONFIGUREASSESSMENTREQUEST = _descriptor.Descriptor(
+  name='ConfigureAssessmentRequest',
+  full_name='clouditor.ConfigureAssessmentRequest',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
@@ -83,23 +143,48 @@ _LISTASSESSMENTRESULTSREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=201,
-  serialized_end=231,
+  serialized_start=264,
+  serialized_end=292,
 )
 
 
-_LISTASSESSMENTRESULTSRESPONSE = _descriptor.Descriptor(
-  name='ListAssessmentResultsResponse',
-  full_name='clouditor.ListAssessmentResultsResponse',
+_CONFIGUREASSESSMENTRESPONSE = _descriptor.Descriptor(
+  name='ConfigureAssessmentResponse',
+  full_name='clouditor.ConfigureAssessmentResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=294,
+  serialized_end=323,
+)
+
+
+_TRIGGERASSESSMENTREQUEST = _descriptor.Descriptor(
+  name='TriggerAssessmentRequest',
+  full_name='clouditor.TriggerAssessmentRequest',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='results', full_name='clouditor.ListAssessmentResultsResponse.results', index=0,
-      number=1, type=11, cpp_type=10, label=3,
-      has_default_value=False, default_value=[],
+      name='some_option', full_name='clouditor.TriggerAssessmentRequest.some_option', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
@@ -115,8 +200,8 @@ _LISTASSESSMENTRESULTSRESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=233,
-  serialized_end=300,
+  serialized_start=325,
+  serialized_end=372,
 )
 
 
@@ -147,8 +232,8 @@ _ASSESSEVIDENCEREQUEST = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=302,
-  serialized_end=364,
+  serialized_start=374,
+  serialized_end=436,
 )
 
 
@@ -162,8 +247,15 @@ _ASSESSEVIDENCERESPONSE = _descriptor.Descriptor(
   fields=[
     _descriptor.FieldDescriptor(
       name='status', full_name='clouditor.AssessEvidenceResponse.status', index=0,
-      number=1, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='status_message', full_name='clouditor.AssessEvidenceResponse.status_message', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
@@ -172,6 +264,7 @@ _ASSESSEVIDENCERESPONSE = _descriptor.Descriptor(
   ],
   nested_types=[],
   enum_types=[
+    _ASSESSEVIDENCERESPONSE_ASSESSMENTSTATUS,
   ],
   serialized_options=None,
   is_extendable=False,
@@ -179,70 +272,70 @@ _ASSESSEVIDENCERESPONSE = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=366,
-  serialized_end=406,
+  serialized_start=439,
+  serialized_end=661,
 )
 
 
-_RESULT = _descriptor.Descriptor(
-  name='Result',
-  full_name='clouditor.Result',
+_ASSESSMENTRESULT = _descriptor.Descriptor(
+  name='AssessmentResult',
+  full_name='clouditor.AssessmentResult',
   filename=None,
   file=DESCRIPTOR,
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
     _descriptor.FieldDescriptor(
-      name='id', full_name='clouditor.Result.id', index=0,
+      name='id', full_name='clouditor.AssessmentResult.id', index=0,
       number=1, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='timestamp', full_name='clouditor.Result.timestamp', index=1,
+      name='timestamp', full_name='clouditor.AssessmentResult.timestamp', index=1,
       number=2, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='metric_id', full_name='clouditor.Result.metric_id', index=2,
+      name='metric_id', full_name='clouditor.AssessmentResult.metric_id', index=2,
       number=3, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='metric_data', full_name='clouditor.Result.metric_data', index=3,
+      name='metric_configuration', full_name='clouditor.AssessmentResult.metric_configuration', index=3,
       number=4, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='compliant', full_name='clouditor.Result.compliant', index=4,
+      name='compliant', full_name='clouditor.AssessmentResult.compliant', index=4,
       number=5, type=8, cpp_type=7, label=1,
       has_default_value=False, default_value=False,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='evidence_id', full_name='clouditor.Result.evidence_id', index=5,
+      name='evidence_id', full_name='clouditor.AssessmentResult.evidence_id', index=5,
       number=6, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='resource_id', full_name='clouditor.Result.resource_id', index=6,
+      name='resource_id', full_name='clouditor.AssessmentResult.resource_id', index=6,
       number=7, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
     _descriptor.FieldDescriptor(
-      name='non_compliance_comments', full_name='clouditor.Result.non_compliance_comments', index=7,
+      name='non_compliance_comments', full_name='clouditor.AssessmentResult.non_compliance_comments', index=7,
       number=8, type=9, cpp_type=9, label=1,
       has_default_value=False, default_value=b"".decode('utf-8'),
       message_type=None, enum_type=None, containing_type=None,
@@ -260,29 +353,26 @@ _RESULT = _descriptor.Descriptor(
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=409,
-  serialized_end=642,
+  serialized_start=664,
+  serialized_end=916,
 )
 
-_LISTASSESSMENTRESULTSRESPONSE.fields_by_name['results'].message_type = _RESULT
+_LISTASSESSMENTRESULTSRESPONSE.fields_by_name['results'].message_type = _ASSESSMENTRESULT
 _ASSESSEVIDENCEREQUEST.fields_by_name['evidence'].message_type = evidence__pb2._EVIDENCE
-_RESULT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
-_RESULT.fields_by_name['metric_data'].message_type = metric__pb2._METRICCONFIGURATION
-DESCRIPTOR.message_types_by_name['TriggerAssessmentRequest'] = _TRIGGERASSESSMENTREQUEST
+_ASSESSEVIDENCERESPONSE.fields_by_name['status'].enum_type = _ASSESSEVIDENCERESPONSE_ASSESSMENTSTATUS
+_ASSESSEVIDENCERESPONSE_ASSESSMENTSTATUS.containing_type = _ASSESSEVIDENCERESPONSE
+_ASSESSMENTRESULT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
+_ASSESSMENTRESULT.fields_by_name['metric_configuration'].message_type = metric__pb2._METRICCONFIGURATION
 DESCRIPTOR.message_types_by_name['ListAssessmentResultsRequest'] = _LISTASSESSMENTRESULTSREQUEST
 DESCRIPTOR.message_types_by_name['ListAssessmentResultsResponse'] = _LISTASSESSMENTRESULTSRESPONSE
+DESCRIPTOR.message_types_by_name['ConfigureAssessmentRequest'] = _CONFIGUREASSESSMENTREQUEST
+DESCRIPTOR.message_types_by_name['ConfigureAssessmentResponse'] = _CONFIGUREASSESSMENTRESPONSE
+DESCRIPTOR.message_types_by_name['TriggerAssessmentRequest'] = _TRIGGERASSESSMENTREQUEST
 DESCRIPTOR.message_types_by_name['AssessEvidenceRequest'] = _ASSESSEVIDENCEREQUEST
 DESCRIPTOR.message_types_by_name['AssessEvidenceResponse'] = _ASSESSEVIDENCERESPONSE
-DESCRIPTOR.message_types_by_name['Result'] = _RESULT
+DESCRIPTOR.message_types_by_name['AssessmentResult'] = _ASSESSMENTRESULT
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
-TriggerAssessmentRequest = _reflection.GeneratedProtocolMessageType('TriggerAssessmentRequest', (_message.Message,), {
-  'DESCRIPTOR' : _TRIGGERASSESSMENTREQUEST,
-  '__module__' : 'assessment_pb2'
-  # @@protoc_insertion_point(class_scope:clouditor.TriggerAssessmentRequest)
-  })
-_sym_db.RegisterMessage(TriggerAssessmentRequest)
-
 ListAssessmentResultsRequest = _reflection.GeneratedProtocolMessageType('ListAssessmentResultsRequest', (_message.Message,), {
   'DESCRIPTOR' : _LISTASSESSMENTRESULTSREQUEST,
   '__module__' : 'assessment_pb2'
@@ -297,6 +387,27 @@ ListAssessmentResultsResponse = _reflection.GeneratedProtocolMessageType('ListAs
   })
 _sym_db.RegisterMessage(ListAssessmentResultsResponse)
 
+ConfigureAssessmentRequest = _reflection.GeneratedProtocolMessageType('ConfigureAssessmentRequest', (_message.Message,), {
+  'DESCRIPTOR' : _CONFIGUREASSESSMENTREQUEST,
+  '__module__' : 'assessment_pb2'
+  # @@protoc_insertion_point(class_scope:clouditor.ConfigureAssessmentRequest)
+  })
+_sym_db.RegisterMessage(ConfigureAssessmentRequest)
+
+ConfigureAssessmentResponse = _reflection.GeneratedProtocolMessageType('ConfigureAssessmentResponse', (_message.Message,), {
+  'DESCRIPTOR' : _CONFIGUREASSESSMENTRESPONSE,
+  '__module__' : 'assessment_pb2'
+  # @@protoc_insertion_point(class_scope:clouditor.ConfigureAssessmentResponse)
+  })
+_sym_db.RegisterMessage(ConfigureAssessmentResponse)
+
+TriggerAssessmentRequest = _reflection.GeneratedProtocolMessageType('TriggerAssessmentRequest', (_message.Message,), {
+  'DESCRIPTOR' : _TRIGGERASSESSMENTREQUEST,
+  '__module__' : 'assessment_pb2'
+  # @@protoc_insertion_point(class_scope:clouditor.TriggerAssessmentRequest)
+  })
+_sym_db.RegisterMessage(TriggerAssessmentRequest)
+
 AssessEvidenceRequest = _reflection.GeneratedProtocolMessageType('AssessEvidenceRequest', (_message.Message,), {
   'DESCRIPTOR' : _ASSESSEVIDENCEREQUEST,
   '__module__' : 'assessment_pb2'
@@ -311,15 +422,14 @@ AssessEvidenceResponse = _reflection.GeneratedProtocolMessageType('AssessEvidenc
   })
 _sym_db.RegisterMessage(AssessEvidenceResponse)
 
-Result = _reflection.GeneratedProtocolMessageType('Result', (_message.Message,), {
-  'DESCRIPTOR' : _RESULT,
+AssessmentResult = _reflection.GeneratedProtocolMessageType('AssessmentResult', (_message.Message,), {
+  'DESCRIPTOR' : _ASSESSMENTRESULT,
   '__module__' : 'assessment_pb2'
-  # @@protoc_insertion_point(class_scope:clouditor.Result)
+  # @@protoc_insertion_point(class_scope:clouditor.AssessmentResult)
   })
-_sym_db.RegisterMessage(Result)
+_sym_db.RegisterMessage(AssessmentResult)
 
 
-DESCRIPTOR._options = None
 
 _ASSESSMENT = _descriptor.ServiceDescriptor(
   name='Assessment',
@@ -328,8 +438,8 @@ _ASSESSMENT = _descriptor.ServiceDescriptor(
   index=0,
   serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_start=645,
-  serialized_end=1075,
+  serialized_start=919,
+  serialized_end=1390,
   methods=[
   _descriptor.MethodDescriptor(
     name='TriggerAssessment',
@@ -342,33 +452,33 @@ _ASSESSMENT = _descriptor.ServiceDescriptor(
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
-    name='ListAssessmentResults',
-    full_name='clouditor.Assessment.ListAssessmentResults',
+    name='AssessEvidence',
+    full_name='clouditor.Assessment.AssessEvidence',
     index=1,
     containing_service=None,
-    input_type=_LISTASSESSMENTRESULTSREQUEST,
-    output_type=_LISTASSESSMENTRESULTSRESPONSE,
-    serialized_options=b'\202\323\344\223\002\033\"\026/v1/assessment/resultsb\001*',
+    input_type=_ASSESSEVIDENCEREQUEST,
+    output_type=_ASSESSEVIDENCERESPONSE,
+    serialized_options=b'\202\323\344\223\002,\"\030/v1/assessment/evidences:\010evidenceb\006status',
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
-    name='AssessEvidence',
-    full_name='clouditor.Assessment.AssessEvidence',
+    name='AssessEvidences',
+    full_name='clouditor.Assessment.AssessEvidences',
     index=2,
     containing_service=None,
     input_type=_ASSESSEVIDENCEREQUEST,
     output_type=_ASSESSEVIDENCERESPONSE,
-    serialized_options=b'\202\323\344\223\002\035\"\030/v1/assessment/evidencesb\001*',
+    serialized_options=None,
     create_key=_descriptor._internal_create_key,
   ),
   _descriptor.MethodDescriptor(
-    name='AssessEvidences',
-    full_name='clouditor.Assessment.AssessEvidences',
+    name='ListAssessmentResults',
+    full_name='clouditor.Assessment.ListAssessmentResults',
     index=3,
     containing_service=None,
-    input_type=evidence__pb2._EVIDENCE,
-    output_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
-    serialized_options=None,
+    input_type=_LISTASSESSMENTRESULTSREQUEST,
+    output_type=_LISTASSESSMENTRESULTSRESPONSE,
+    serialized_options=b'\202\323\344\223\002\030\022\026/v1/assessment/results',
     create_key=_descriptor._internal_create_key,
   ),
 ])
diff --git a/grpc_gen/assessment_pb2_grpc.py b/grpc_gen/assessment_pb2_grpc.py
index 11ab55b..fbf893c 100644
--- a/grpc_gen/assessment_pb2_grpc.py
+++ b/grpc_gen/assessment_pb2_grpc.py
@@ -3,7 +3,6 @@
 import grpc
 
 import grpc_gen.assessment_pb2 as assessment__pb2
-import grpc_gen.evidence_pb2 as evidence__pb2
 from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
 
 
@@ -23,20 +22,20 @@ class AssessmentStub(object):
                 request_serializer=assessment__pb2.TriggerAssessmentRequest.SerializeToString,
                 response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
                 )
-        self.ListAssessmentResults = channel.unary_unary(
-                '/clouditor.Assessment/ListAssessmentResults',
-                request_serializer=assessment__pb2.ListAssessmentResultsRequest.SerializeToString,
-                response_deserializer=assessment__pb2.ListAssessmentResultsResponse.FromString,
-                )
         self.AssessEvidence = channel.unary_unary(
                 '/clouditor.Assessment/AssessEvidence',
                 request_serializer=assessment__pb2.AssessEvidenceRequest.SerializeToString,
                 response_deserializer=assessment__pb2.AssessEvidenceResponse.FromString,
                 )
-        self.AssessEvidences = channel.stream_unary(
+        self.AssessEvidences = channel.stream_stream(
                 '/clouditor.Assessment/AssessEvidences',
-                request_serializer=evidence__pb2.Evidence.SerializeToString,
-                response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                request_serializer=assessment__pb2.AssessEvidenceRequest.SerializeToString,
+                response_deserializer=assessment__pb2.AssessEvidenceResponse.FromString,
+                )
+        self.ListAssessmentResults = channel.unary_unary(
+                '/clouditor.Assessment/ListAssessmentResults',
+                request_serializer=assessment__pb2.ListAssessmentResultsRequest.SerializeToString,
+                response_deserializer=assessment__pb2.ListAssessmentResultsResponse.FromString,
                 )
 
 
@@ -46,33 +45,30 @@ class AssessmentServicer(object):
     """
 
     def TriggerAssessment(self, request, context):
-        """Triggers the assessment. Part of the private API,
-        not exposed as REST.
+        """Triggers the assessment. Part of the private API. Not exposed as REST.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
-    def ListAssessmentResults(self, request, context):
-        """TODO(all): Part of public API because external entities (mainly
-        discoveries) can use it? List the latest set of assessment results. Part of
-        the public API, also exposed as REST
+    def AssessEvidence(self, request, context):
+        """Assesses the evidence sent by the discovery. Part of the public API, also
+        exposed as REST.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
-    def AssessEvidence(self, request, context):
-        """Assesses the evidence sent by discovery. Part of the public API,
-        also exposed as REST
+    def AssessEvidences(self, request_iterator, context):
+        """Assesses stream of evidences sent by the discovery and returns a response
+        stream. Part of the public API. Not exposed as REST.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
-    def AssessEvidences(self, request_iterator, context):
-        """Assesses stream of evidences coming from the discovery. Part of the public
-        API, not exposed as REST
+    def ListAssessmentResults(self, request, context):
+        """List all assessment results. Part of the public API, also exposed as REST.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
@@ -86,20 +82,20 @@ def add_AssessmentServicer_to_server(servicer, server):
                     request_deserializer=assessment__pb2.TriggerAssessmentRequest.FromString,
                     response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
             ),
-            'ListAssessmentResults': grpc.unary_unary_rpc_method_handler(
-                    servicer.ListAssessmentResults,
-                    request_deserializer=assessment__pb2.ListAssessmentResultsRequest.FromString,
-                    response_serializer=assessment__pb2.ListAssessmentResultsResponse.SerializeToString,
-            ),
             'AssessEvidence': grpc.unary_unary_rpc_method_handler(
                     servicer.AssessEvidence,
                     request_deserializer=assessment__pb2.AssessEvidenceRequest.FromString,
                     response_serializer=assessment__pb2.AssessEvidenceResponse.SerializeToString,
             ),
-            'AssessEvidences': grpc.stream_unary_rpc_method_handler(
+            'AssessEvidences': grpc.stream_stream_rpc_method_handler(
                     servicer.AssessEvidences,
-                    request_deserializer=evidence__pb2.Evidence.FromString,
-                    response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                    request_deserializer=assessment__pb2.AssessEvidenceRequest.FromString,
+                    response_serializer=assessment__pb2.AssessEvidenceResponse.SerializeToString,
+            ),
+            'ListAssessmentResults': grpc.unary_unary_rpc_method_handler(
+                    servicer.ListAssessmentResults,
+                    request_deserializer=assessment__pb2.ListAssessmentResultsRequest.FromString,
+                    response_serializer=assessment__pb2.ListAssessmentResultsResponse.SerializeToString,
             ),
     }
     generic_handler = grpc.method_handlers_generic_handler(
@@ -131,7 +127,7 @@ class Assessment(object):
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
     @staticmethod
-    def ListAssessmentResults(request,
+    def AssessEvidence(request,
             target,
             options=(),
             channel_credentials=None,
@@ -141,14 +137,14 @@ class Assessment(object):
             wait_for_ready=None,
             timeout=None,
             metadata=None):
-        return grpc.experimental.unary_unary(request, target, '/clouditor.Assessment/ListAssessmentResults',
-            assessment__pb2.ListAssessmentResultsRequest.SerializeToString,
-            assessment__pb2.ListAssessmentResultsResponse.FromString,
+        return grpc.experimental.unary_unary(request, target, '/clouditor.Assessment/AssessEvidence',
+            assessment__pb2.AssessEvidenceRequest.SerializeToString,
+            assessment__pb2.AssessEvidenceResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
     @staticmethod
-    def AssessEvidence(request,
+    def AssessEvidences(request_iterator,
             target,
             options=(),
             channel_credentials=None,
@@ -158,14 +154,14 @@ class Assessment(object):
             wait_for_ready=None,
             timeout=None,
             metadata=None):
-        return grpc.experimental.unary_unary(request, target, '/clouditor.Assessment/AssessEvidence',
+        return grpc.experimental.stream_stream(request_iterator, target, '/clouditor.Assessment/AssessEvidences',
             assessment__pb2.AssessEvidenceRequest.SerializeToString,
             assessment__pb2.AssessEvidenceResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
     @staticmethod
-    def AssessEvidences(request_iterator,
+    def ListAssessmentResults(request,
             target,
             options=(),
             channel_credentials=None,
@@ -175,8 +171,8 @@ class Assessment(object):
             wait_for_ready=None,
             timeout=None,
             metadata=None):
-        return grpc.experimental.stream_unary(request_iterator, target, '/clouditor.Assessment/AssessEvidences',
-            evidence__pb2.Evidence.SerializeToString,
-            google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+        return grpc.experimental.unary_unary(request, target, '/clouditor.Assessment/ListAssessmentResults',
+            assessment__pb2.ListAssessmentResultsRequest.SerializeToString,
+            assessment__pb2.ListAssessmentResultsResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/grpc_gen/evidence_pb2.py b/grpc_gen/evidence_pb2.py
index ff09aaf..0f152a5 100644
--- a/grpc_gen/evidence_pb2.py
+++ b/grpc_gen/evidence_pb2.py
@@ -19,9 +19,9 @@ DESCRIPTOR = _descriptor.FileDescriptor(
   name='evidence.proto',
   package='clouditor',
   syntax='proto3',
-  serialized_options=b'Z\014api/evidence',
+  serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x0e\x65vidence.proto\x12\tclouditor\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xa1\x01\n\x08\x45vidence\x12\n\n\x02id\x18\x01 \x01(\t\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x12\n\nservice_id\x18\x03 \x01(\t\x12\x0f\n\x07tool_id\x18\x04 \x01(\t\x12\x0b\n\x03raw\x18\x05 \x01(\t\x12(\n\x08resource\x18\x06 \x01(\x0b\x32\x16.google.protobuf.ValueB\x0eZ\x0c\x61pi/evidenceb\x06proto3'
+  serialized_pb=b'\n\x0e\x65vidence.proto\x12\tclouditor\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xa1\x01\n\x08\x45vidence\x12\n\n\x02id\x18\x01 \x01(\t\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x12\n\nservice_id\x18\x03 \x01(\t\x12\x0f\n\x07tool_id\x18\x04 \x01(\t\x12\x0b\n\x03raw\x18\x05 \x01(\t\x12(\n\x08resource\x18\x06 \x01(\x0b\x32\x16.google.protobuf.Valueb\x06proto3'
   ,
   dependencies=[google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,])
 
@@ -107,5 +107,4 @@ Evidence = _reflection.GeneratedProtocolMessageType('Evidence', (_message.Messag
 _sym_db.RegisterMessage(Evidence)
 
 
-DESCRIPTOR._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/grpc_gen/metric_pb2.py b/grpc_gen/metric_pb2.py
index 433292d..cd0fdb1 100644
--- a/grpc_gen/metric_pb2.py
+++ b/grpc_gen/metric_pb2.py
@@ -18,9 +18,9 @@ DESCRIPTOR = _descriptor.FileDescriptor(
   name='metric.proto',
   package='clouditor',
   syntax='proto3',
-  serialized_options=b'Z\016api/assessment',
+  serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x0cmetric.proto\x12\tclouditor\x1a\x1cgoogle/protobuf/struct.proto\"\xc1\x01\n\x06Metric\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x04 \x01(\t\x12&\n\x05scale\x18\x05 \x01(\x0e\x32\x17.clouditor.Metric.Scale\x12\x1f\n\x05range\x18\x06 \x01(\x0b\x32\x10.clouditor.Range\"-\n\x05Scale\x12\x0b\n\x07NOMIMAL\x10\x00\x12\x0b\n\x07ORDINAL\x10\x01\x12\n\n\x06METRIC\x10\x02\"\x8d\x01\n\x05Range\x12\x32\n\x0e\x61llowed_values\x18\x01 \x01(\x0b\x32\x18.clouditor.AllowedValuesH\x00\x12!\n\x05order\x18\x02 \x01(\x0b\x32\x10.clouditor.OrderH\x00\x12$\n\x07min_max\x18\x03 \x01(\x0b\x32\x11.clouditor.MinMaxH\x00\x42\x07\n\x05range\"\"\n\x06MinMax\x12\x0b\n\x03min\x18\x01 \x01(\x03\x12\x0b\n\x03max\x18\x02 \x01(\x03\"7\n\rAllowedValues\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value\"/\n\x05Order\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value\"i\n\x13MetricConfiguration\x12\x10\n\x08operator\x18\x01 \x01(\t\x12,\n\x0ctarget_value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x12\n\nis_default\x18\x03 \x01(\x08\x42\x10Z\x0e\x61pi/assessmentb\x06proto3'
+  serialized_pb=b'\n\x0cmetric.proto\x12\tclouditor\x1a\x1cgoogle/protobuf/struct.proto\"\xc1\x01\n\x06Metric\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x04 \x01(\t\x12&\n\x05scale\x18\x05 \x01(\x0e\x32\x17.clouditor.Metric.Scale\x12\x1f\n\x05range\x18\x06 \x01(\x0b\x32\x10.clouditor.Range\"-\n\x05Scale\x12\x0b\n\x07NOMINAL\x10\x00\x12\x0b\n\x07ORDINAL\x10\x01\x12\n\n\x06METRIC\x10\x02\"\x8d\x01\n\x05Range\x12\x32\n\x0e\x61llowed_values\x18\x01 \x01(\x0b\x32\x18.clouditor.AllowedValuesH\x00\x12!\n\x05order\x18\x02 \x01(\x0b\x32\x10.clouditor.OrderH\x00\x12$\n\x07min_max\x18\x03 \x01(\x0b\x32\x11.clouditor.MinMaxH\x00\x42\x07\n\x05range\"\"\n\x06MinMax\x12\x0b\n\x03min\x18\x01 \x01(\x03\x12\x0b\n\x03max\x18\x02 \x01(\x03\"7\n\rAllowedValues\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value\"/\n\x05Order\x12&\n\x06values\x18\x01 \x03(\x0b\x32\x16.google.protobuf.Value\"i\n\x13MetricConfiguration\x12\x10\n\x08operator\x18\x01 \x01(\t\x12,\n\x0ctarget_value\x18\x02 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x12\n\nis_default\x18\x03 \x01(\x08\"\x90\x01\n\x14MetricImplementation\x12:\n\x08language\x18\x01 \x01(\x0e\x32(.clouditor.MetricImplementation.Language\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\".\n\x08Language\x12\x18\n\x14LANGUAGE_UNSPECIFIED\x10\x00\x12\x08\n\x04REGO\x10\x01\x62\x06proto3'
   ,
   dependencies=[google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,])
 
@@ -34,7 +34,7 @@ _METRIC_SCALE = _descriptor.EnumDescriptor(
   create_key=_descriptor._internal_create_key,
   values=[
     _descriptor.EnumValueDescriptor(
-      name='NOMIMAL', index=0, number=0,
+      name='NOMINAL', index=0, number=0,
       serialized_options=None,
       type=None,
       create_key=_descriptor._internal_create_key),
@@ -56,6 +56,31 @@ _METRIC_SCALE = _descriptor.EnumDescriptor(
 )
 _sym_db.RegisterEnumDescriptor(_METRIC_SCALE)
 
+_METRICIMPLEMENTATION_LANGUAGE = _descriptor.EnumDescriptor(
+  name='Language',
+  full_name='clouditor.MetricImplementation.Language',
+  filename=None,
+  file=DESCRIPTOR,
+  create_key=_descriptor._internal_create_key,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='LANGUAGE_UNSPECIFIED', index=0, number=0,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+    _descriptor.EnumValueDescriptor(
+      name='REGO', index=1, number=1,
+      serialized_options=None,
+      type=None,
+      create_key=_descriptor._internal_create_key),
+  ],
+  containing_type=None,
+  serialized_options=None,
+  serialized_start=745,
+  serialized_end=791,
+)
+_sym_db.RegisterEnumDescriptor(_METRICIMPLEMENTATION_LANGUAGE)
+
 
 _METRIC = _descriptor.Descriptor(
   name='Metric',
@@ -324,6 +349,46 @@ _METRICCONFIGURATION = _descriptor.Descriptor(
   serialized_end=644,
 )
 
+
+_METRICIMPLEMENTATION = _descriptor.Descriptor(
+  name='MetricImplementation',
+  full_name='clouditor.MetricImplementation',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='language', full_name='clouditor.MetricImplementation.language', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='code', full_name='clouditor.MetricImplementation.code', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+    _METRICIMPLEMENTATION_LANGUAGE,
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=647,
+  serialized_end=791,
+)
+
 _METRIC.fields_by_name['scale'].enum_type = _METRIC_SCALE
 _METRIC.fields_by_name['range'].message_type = _RANGE
 _METRIC_SCALE.containing_type = _METRIC
@@ -342,12 +407,15 @@ _RANGE.fields_by_name['min_max'].containing_oneof = _RANGE.oneofs_by_name['range
 _ALLOWEDVALUES.fields_by_name['values'].message_type = google_dot_protobuf_dot_struct__pb2._VALUE
 _ORDER.fields_by_name['values'].message_type = google_dot_protobuf_dot_struct__pb2._VALUE
 _METRICCONFIGURATION.fields_by_name['target_value'].message_type = google_dot_protobuf_dot_struct__pb2._VALUE
+_METRICIMPLEMENTATION.fields_by_name['language'].enum_type = _METRICIMPLEMENTATION_LANGUAGE
+_METRICIMPLEMENTATION_LANGUAGE.containing_type = _METRICIMPLEMENTATION
 DESCRIPTOR.message_types_by_name['Metric'] = _METRIC
 DESCRIPTOR.message_types_by_name['Range'] = _RANGE
 DESCRIPTOR.message_types_by_name['MinMax'] = _MINMAX
 DESCRIPTOR.message_types_by_name['AllowedValues'] = _ALLOWEDVALUES
 DESCRIPTOR.message_types_by_name['Order'] = _ORDER
 DESCRIPTOR.message_types_by_name['MetricConfiguration'] = _METRICCONFIGURATION
+DESCRIPTOR.message_types_by_name['MetricImplementation'] = _METRICIMPLEMENTATION
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 Metric = _reflection.GeneratedProtocolMessageType('Metric', (_message.Message,), {
@@ -392,6 +460,12 @@ MetricConfiguration = _reflection.GeneratedProtocolMessageType('MetricConfigurat
   })
 _sym_db.RegisterMessage(MetricConfiguration)
 
+MetricImplementation = _reflection.GeneratedProtocolMessageType('MetricImplementation', (_message.Message,), {
+  'DESCRIPTOR' : _METRICIMPLEMENTATION,
+  '__module__' : 'metric_pb2'
+  # @@protoc_insertion_point(class_scope:clouditor.MetricImplementation)
+  })
+_sym_db.RegisterMessage(MetricImplementation)
+
 
-DESCRIPTOR._options = None
 # @@protoc_insertion_point(module_scope)
diff --git a/proto/assessment.proto b/proto/assessment.proto
index c3002ac..69d2e8d 100644
--- a/proto/assessment.proto
+++ b/proto/assessment.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 Fraunhofer AISEC
+ * Copyright 2016-2022 Fraunhofer AISEC
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,52 +34,62 @@ import "google/protobuf/timestamp.proto";
 import "evidence.proto";
 import "metric.proto";
 
-option go_package = "api/assessment";
-
 // Representing the link between orchestrator and discovery: Assessing evidences
 // from discovery and sending results to orchestrator
 service Assessment {
-  // Triggers the assessment. Part of the private API,
-  // not exposed as REST.
+
+  // Triggers the assessment. Part of the private API. Not exposed as REST.
   rpc TriggerAssessment(TriggerAssessmentRequest)
       returns (google.protobuf.Empty) {}
 
-  // TODO(all): Part of public API because external entities (mainly
-  // discoveries) can use it? List the latest set of assessment results. Part of
-  // the public API, also exposed as REST
-  rpc ListAssessmentResults(ListAssessmentResultsRequest)
-      returns (ListAssessmentResultsResponse) {
+  // Assesses the evidence sent by the discovery. Part of the public API, also
+  // exposed as REST.
+  rpc AssessEvidence(AssessEvidenceRequest) returns (AssessEvidenceResponse) {
     option (google.api.http) = {
-      post : "/v1/assessment/results"
-      response_body : "*"
+      post : "/v1/assessment/evidences"
+      body : "evidence"
+      response_body : "status"
     };
   }
 
-  // Assesses the evidence sent by discovery. Part of the public API,
-  // also exposed as REST
-  rpc AssessEvidence(AssessEvidenceRequest) returns (AssessEvidenceResponse) {
+  // Assesses stream of evidences sent by the discovery and returns a response
+  // stream. Part of the public API. Not exposed as REST.
+  rpc AssessEvidences(stream AssessEvidenceRequest)
+      returns (stream AssessEvidenceResponse) {};
+
+  // List all assessment results. Part of the public API, also exposed as REST.
+  rpc ListAssessmentResults(ListAssessmentResultsRequest)
+      returns (ListAssessmentResultsResponse) {
     option (google.api.http) = {
-      post : "/v1/assessment/evidences"
-      response_body : "*"
+      get : "/v1/assessment/results"
     };
   }
-
-  // Assesses stream of evidences coming from the discovery. Part of the public
-  // API, not exposed as REST
-  rpc AssessEvidences(stream Evidence) returns (google.protobuf.Empty);
 };
 
-message TriggerAssessmentRequest { string someOption = 1; }
-
 message ListAssessmentResultsRequest {}
-message ListAssessmentResultsResponse { repeated Result results = 1; }
+message ListAssessmentResultsResponse { repeated AssessmentResult results = 1; }
+
+message ConfigureAssessmentRequest {}
+message ConfigureAssessmentResponse {}
+
+message TriggerAssessmentRequest { string some_option = 1; }
 
 message AssessEvidenceRequest { Evidence evidence = 1; }
-message AssessEvidenceResponse { bool status = 1; }
+message AssessEvidenceResponse {
+  enum AssessmentStatus {
+    ASSESSMENT_STATUS_UNSPECIFIED = 0;
+    WAITING_FOR_RELATED = 1;
+    ASSESSED = 2;
+    FAILED = 3;
+  }
+  AssessmentStatus status = 1;
+
+  string status_message = 2;
+}
 
 // A result resource, representing the result after assessing the cloud resource
 // with id resource_id.
-message Result {
+message AssessmentResult {
   // Assessment result id
   string id = 1;
 
@@ -90,7 +100,7 @@ message Result {
   string metric_id = 3;
 
   // Data corresponding to the metric by the given metric id
-  MetricConfiguration metric_data = 4;
+  MetricConfiguration metric_configuration = 4;
 
   // Compliant case: true or false
   bool compliant = 5;
diff --git a/proto/evidence.proto b/proto/evidence.proto
index f1f2585..5a6e5b8 100644
--- a/proto/evidence.proto
+++ b/proto/evidence.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright 2021 Fraunhofer AISEC
+ * Copyright 2016-2022 Fraunhofer AISEC
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,8 +24,6 @@
  *
  * This file is part of Clouditor Community Edition.
  */
-// ToDo(all): Change name of file to resources.proto or similar? (It is not
-// containing evidences only)
 syntax = "proto3";
 
 package clouditor;
@@ -33,8 +31,6 @@ package clouditor;
 import "google/protobuf/struct.proto";
 import "google/protobuf/timestamp.proto";
 
-option go_package = "api/evidence";
-
 // An evidence resource
 message Evidence {
   // the ID in a uuid format
diff --git a/proto/metric.proto b/proto/metric.proto
index f5f0763..33c1807 100644
--- a/proto/metric.proto
+++ b/proto/metric.proto
@@ -24,16 +24,12 @@
  *
  * This file is part of Clouditor Community Edition.
  */
-// ToDo(all): Change name of file to resources.proto or similar? (It is not
-// containing evidences only)
 syntax = "proto3";
 
 package clouditor;
 
 import "google/protobuf/struct.proto";
 
-option go_package = "api/assessment";
-
 // A metric resource
 message Metric {
   // Required. The unique identifier of the metric.
@@ -56,7 +52,7 @@ message Metric {
 
   // The values a Scale accepts
   enum Scale {
-    NOMIMAL = 0;
+    NOMINAL = 0;
     ORDINAL = 1;
     METRIC = 2;
   }
@@ -102,4 +98,18 @@ message MetricConfiguration {
 
   // Whether this configuration is a default configuration
   bool is_default = 3;
+}
+
+// MetricImplementation defines the implementation of an individual metric.
+message MetricImplementation {
+  enum Language {
+    LANGUAGE_UNSPECIFIED = 0;
+    REGO = 1;
+  };
+
+  // The language this metric is implemented in
+  Language language = 1;
+
+  // The actual implementation
+  string code = 2;
 }
\ No newline at end of file
diff --git a/wazuh_evidence_collector/wazuh_evidence_collector.py b/wazuh_evidence_collector/wazuh_evidence_collector.py
index d5a589c..694eedb 100644
--- a/wazuh_evidence_collector/wazuh_evidence_collector.py
+++ b/wazuh_evidence_collector/wazuh_evidence_collector.py
@@ -2,9 +2,9 @@ import json
 import os
 from wazuh_evidence_collector.wazuh_client import WazuhClient
 from elasticsearch import Elasticsearch
-from elasticsearch_dsl import Search
 from forward_evidence.forward_evidence import ForwardEvidence
 from forward_evidence.generate_evidence import create_resource, create_assessevidence_request, print_evidence
+from forward_evidence.clouditor_authentication import ClouditorAuthentication
 from wazuh_evidence_collector.checker import Checker
 from wazuh_evidence_collector.demo_checker import DemoChecker
 import uuid
@@ -39,6 +39,8 @@ if not DEMO:
             ssl_show_warn=False,
         )
 
+oauth_client = ClouditorAuthentication(LOGGER)
+
 forwarder = ForwardEvidence(LOGGER)
 
 # Get ID (UUID)
@@ -88,7 +90,7 @@ def run_collector():
 
     # TODO:
     for ae_req in ae_req_list:
-        forwarder.send_evidence(ae_req)
+        forwarder.send_evidence(ae_req, oauth_client.get_token())
         print_evidence(LOGGER, ae_req.evidence)
 
     return ae_req_list
@@ -119,14 +121,17 @@ def generate_evidence(agent, checker):
     else: 
         malware_protection = { "malwareProtection": { "enabled": False }}
 
+    # TODO: implement metrics
+    malware_protection["malwareProtection"].update({ "daysSinceActive": None, "numberOfThreatsFound": None})
+
     # MalwareProtectionOutput
     evidence, result_alert_integration = checker.check_alert_integrations()
     raw_evidence.append(evidence)
 
     if result_alert_integration:
-        malware_protection["malwareProtection"].update({ "output": [agent[0]] })
+        malware_protection["malwareProtection"].update({ "applicationLogging": { "enabled": True, "loggingService": ["?"], "retentionPeriod": None }})
     else: 
-        malware_protection["malwareProtection"].update({ "output": [] })
+        malware_protection["malwareProtection"].update({ "applicationLogging": { "enabled": False, "loggingService": [], "retentionPeriod": None }})
 
     # TODO: change ID
     resource = create_resource(agent[0], agent[1], None, malware_protection)
-- 
GitLab