diff --git a/demos/demo2/api.py b/demos/demo2/api.py
index fb0071c6194b2f1195b1848db7e005d8cb80432f..c6c1695bf82f1e9a1997eb521c26cd8b732f3aa2 100644
--- a/demos/demo2/api.py
+++ b/demos/demo2/api.py
@@ -1,4 +1,4 @@
-from typing import Set
+from typing import Set, Callable
 from basyx.aas import model
 import base64
 
@@ -166,3 +166,4 @@ class ModelProvider:
                         return
                     if path_elems[4] == SUBMODELELEMENTS:
                         return self.submodel_api[submodel_id].set_submodel_element_value_by_path(path_elems[5], value)
+    
diff --git a/demos/demo2/broker_api.py b/demos/demo2/broker_api.py
index 38c0c674785baf63c3065fd38b6f37d7bc2fe62a..8ead5ecc667ea9b2611211c0bfd688962c46efcd 100644
--- a/demos/demo2/broker_api.py
+++ b/demos/demo2/broker_api.py
@@ -1,5 +1,6 @@
 import asyncio
 from uuid import uuid4
+from typing import Callable
 from s3i.broker import BrokerAMQP
 from s3i import broker_message
 from s3i.exception import S3IBMessageError
@@ -12,11 +13,20 @@ import traceback
 import base64
 from typing import Iterable
 from datetime import datetime
-import time
+import sys, os, inspect
 
 import api
+import opa_api
 import helpers
 
+currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+parentdir = os.path.dirname(currentdir)
+sys.path.insert(0, parentdir)
+sys.path.insert(0, os.path.dirname(parentdir))
+
+from model import security
+
+
 logger = logging.getLogger(__name__)
 ch = logging.StreamHandler()
 ch.setLevel(logging.INFO)
@@ -25,14 +35,32 @@ ch.setFormatter(formatter)
 logger.addHandler(ch)
 
 
+NOT_AUTHORIZED = "NOT_AUTHORIZED"
+s3ib_to_rest = {"getValueRequest": "READ", "setValueRequest": "WRITE", "createAttributeRequest": "WRITE", 
+                "serviceRequest": "WRITE"}
+
+
 class S3IBServer:
-    def __init__(self, access_token: str, provider: api.ModelProvider, id: str, loop):
+    def __init__(self, access_token: str, provider: api.ModelProvider, id: str, 
+                 loop,  security_id: str = None, security_enabled = False, opa_server_url="http://localhost:8181"):
         self.id = id
         self.provider = provider
         self.loop = loop
         self.broker = BrokerAMQP(access_token, "s3ibs://" + self.id, self.callback, loop)
         self.serializer = AASToJsonEncoder()
         self.deserializer = AASFromJsonDecoder()
+        self.opa = opa_api.Opa(opa_server_url)
+        self.security_id = base64.urlsafe_b64encode(security_id.encode()).decode()
+        self.security_enabled = security_enabled
+        self.callables: dict[str, Callable] = {}
+        
+        if self.security_enabled:
+            self._update_security()
+
+    def _update_security(self):
+        security_sm = self.provider.getValue(f"/aas/submodels/{self.security_id}/submodel")
+        data = security.get_dic_from_security_submodel(security_sm)
+        self.opa.update_data(data, "api")
 
     def _check_for_events(self, path) -> Iterable[BasicEventElement]:
         triggered_events = []
@@ -44,16 +72,25 @@ class S3IBServer:
             event: BasicEventElement = event
             obs_path = helpers.id_short_path_from_ref(event.observed)
             req_path = helpers.id_short_path_from_path(path)
+            print(obs_path)
+            print(req_path)
             if obs_path == req_path:
                 triggered_events.append(event)
                 logger.info(f"[Event] [{event.message_topic}] {event.id_short} was triggered")
         
         return triggered_events
-
+    
+    def add_callable(self, id: str, callable: Callable):
+        self.callables[id] = callable
+    
+    def _invoke_callable(self, id: str, **kwargs):
+        callable = self.callables[id]
+        return callable(**kwargs)
+    
     def callback(self, ch, method, properties, body):
         try:
             msg = broker_message.Message(base_msg=body)
-            path = msg.base_msg["attributePath"]
+            path = msg.base_msg.get("attributePath", msg.base_msg.get("serviceType"))
             receiver_endpoint = msg.base_msg["replyToEndpoint"]
             receiver_id = msg.base_msg["sender"]
             received_msg_id = msg.base_msg["identifier"]
@@ -61,7 +98,20 @@ class S3IBServer:
 
             logger.info(f"[S3I] Received {message_type} from {receiver_id}")
 
-            if message_type == "getValueRequest":
+            if self.security_enabled and not self.opa.query(receiver_id, s3ib_to_rest[message_type], helpers.id_short_path_from_path(path)):
+                reply = broker_message.UserMessage()
+                reply.fillUserMessage(
+                    sender=self.id,
+                    receivers=[receiver_id], 
+                    message_id="s3i:" + str(uuid4()),
+                    subject=NOT_AUTHORIZED,
+                    text=NOT_AUTHORIZED,
+                    replying_to_msg=received_msg_id,
+                    reply_to_endpoint="s3ibs://" + self.id
+                    )
+                self.broker.send([receiver_endpoint], json.dumps(reply.base_msg))
+
+            elif message_type == "getValueRequest":
                 value = self.provider.getValue(path)
                 reply = broker_message.GetValueReply()
                 reply.fillGetValueReply(
@@ -100,6 +150,10 @@ class S3IBServer:
                         content={path: self.deserializer.decode(new_value)}
                     )
                     self.broker.publish_event(json.dumps(evt_msg.base_msg), event.message_topic)
+                
+                # update opa server if security overwrittem
+                if self.security_enabled and path.startswith(self.security_id):
+                    self._update_security()
                     
 
             elif message_type == "createAttributeRequest":
@@ -114,6 +168,24 @@ class S3IBServer:
                 reply.base_msg["replyingToMessage"] = received_msg_id
                 reply.base_msg["ok"] = True
                 self.broker.send([receiver_endpoint], json.dumps(reply.base_msg))
+            
+            elif message_type == "serviceRequest":
+                callable_id = msg.base_msg["serviceType"]
+                parameters = msg.base_msg["parameters"]
+                service_type = msg.base_msg["serviceType"]
+                res = self.callables.get(callable_id)(**parameters)
+                reply = broker_message.ServiceReply()
+                reply.fillServiceReply(
+                    sender=self.id,
+                    receivers=[receiver_id],
+                    message_id="s3i:" + str(uuid4()),
+                    reply_to_endpoint="s3ibs://" + self.id,
+                    replying_to_msg=received_msg_id,
+                    service_type=service_type,
+                    results=res
+                )
+                self.broker.send([receiver_endpoint], json.dumps(reply.base_msg))
+
         except S3IBMessageError as e:
             self.broker.send([receiver_endpoint], json.dumps(e.error_msg))
         except Exception as e:
@@ -150,6 +222,7 @@ class S3IBAsyncClient:
             message_type = msg.base_msg["messageType"]
             value = msg.base_msg.get("value")
             ok = msg.base_msg.get("ok")
+            results = msg.base_msg.get("results")
 
             logger.info(f"[S3I] Received {message_type} from {sender}")
 
@@ -160,14 +233,18 @@ class S3IBAsyncClient:
                 logger.info(f"[Event] [{topic}] [{datetime.fromtimestamp(timestamp)}] {content}")
                 self.requests[topic].set_result(content)
             else:
-                future: asyncio.Future = self.requests[msg_id]
-                if value:
-                    future.set_result(self.deserializer.decode(value))
-                else:
-                    future.set_result(ok)
+                future: asyncio.Future = self.requests.get(msg_id)
+                if future:
+                    if value:
+                        future.set_result(self.deserializer.decode(value))
+                    elif results:
+                        future.set_result(results)
+                    else:
+                        future.set_result(ok)
 
-        except S3IBMessageError as e:
-            raise Exception(body)
+        except Exception as e:
+            print(traceback.format_exc())
+            print(e.args)
 
     async def getValue(self, receiver_id: str, endpoint: str, path: str):
         if not self.channel_open.done():
@@ -230,10 +307,34 @@ class S3IBAsyncClient:
         await reply
         return reply.result()
     
-    async def subscribeToEvent(self, topic: str):
+    async def awaitEvent(self, topic: str):
         if not self.channel_open.done():
             await self.channel_open
-        self.broker.subscribe_topic(topic)
         handle = self.loop.create_future()
-        self.requests[topic] = handle
-        return handle
\ No newline at end of file
+        if not self.requests.get(topic):
+            self.broker.subscribe_topic(topic)
+            self.requests[topic] = handle
+        return handle
+    
+    async def invokeOperation(self, receiver_id: str, endpoint: str, service_path: str, parameters: dict):
+        if not self.channel_open.done():
+            await self.channel_open
+        msg = broker_message.ServiceRequest()
+        receiver_endpoint = endpoint
+        my_endpoint = "s3ibs://" + self.id
+        msg_id = "s3i:" + str(uuid4())
+        msg.fillServiceRequest(
+            sender=self.id,
+            receivers=[receiver_id],
+            message_id=msg_id,
+            service_type=service_path,
+            parameters=parameters,
+            reply_to_endpoint=my_endpoint,
+        )
+        self.broker.send([receiver_endpoint], json.dumps(msg.base_msg))
+        reply = self.loop.create_future()
+        self.requests[msg_id] = reply
+        await reply
+        return reply.result()
+    
+
diff --git a/demos/demo2/demo2_dzwald.py b/demos/demo2/demo2_dzwald.py
index 19c1e074f2581c40b99ae809aeba5815d98bb661..be8f5ebedd1458b0f533565a8871726daff5c80c 100644
--- a/demos/demo2/demo2_dzwald.py
+++ b/demos/demo2/demo2_dzwald.py
@@ -11,6 +11,7 @@ import logging
 import datetime
 import base64
 from urllib.parse import quote
+import time
 
 import api
 import broker_api
@@ -21,7 +22,7 @@ parentdir = os.path.dirname(currentdir)
 sys.path.insert(0, parentdir)
 sys.path.insert(0, os.path.dirname(parentdir))
 
-from model import enums, models, configs
+from model import enums, models, configs, security, utils
 
 # print info logs to console
 logger = logging.getLogger("broker_api")
@@ -382,6 +383,8 @@ def create_aas():
 
     events.add_referable(event)
 
+    security_sm = security.Security("https://www.company.com/security") 
+
     submodels = [
         arbeitsauftrag,
         beobachtung,
@@ -391,9 +394,12 @@ def create_aas():
         verkaufslos,
         waldweg,
         zu_faellende_baeume,
-        events
+        events,
+        security_sm
     ]
 
+    """
+
     def remove_iteration_ending(val: str):
         # remove iteration ending like {00}
         val = re.sub(r'\{\d+\}$', '', val)
@@ -431,6 +437,8 @@ def create_aas():
     for submodel in submodels:
         set_semantic_id_for_each_in(submodel)
 
+    """
+
     aas_dz_wald = models.DZWald(
         dzwald_id="https://www.company.com/dz_wald/1",
         asset=basyx.aas.model.AssetInformation(),
@@ -445,6 +453,34 @@ def create_aas():
         holzpreisbereiche=basyx.aas.model.ModelReference.from_referable(
             holzpreisbereiche),
     )
+
+    rules = [security.AccessPermissionRule(forestmanager_hmi_id, 
+                                           security.PermissionKind.ALLOW, 
+                                           security.Permission.READ),
+            security.AccessPermissionRule(forestmanager_hmi_id, 
+                                          security.PermissionKind.ALLOW, 
+                                          security.Permission.WRITE)]
+
+    rules_smc = security.AccessPermissionCollection(
+        target=model.ModelReference.from_referable(aas_dz_wald),
+        rules=rules
+    )
+
+    # print(rules_smc.get_referable("Target").value)
+
+    access_control = security.AccessControl(permissions=[rules_smc])
+    security_sm.add_referable(access_control)
+    # print(security.get_dic_from_security_submodel(security_sm))
+
+    getHolzpreisbereich_op = model.Operation(
+        id_short="getHolzpreisbereich", 
+        input_variable=[model.OperationVariable(model.Property(
+            id_short="HolzlisteId",
+            value_type=model.datatypes.String
+        ))]
+    )
+    holzliste.add_referable(getHolzpreisbereich_op)
+
     return aas_dz_wald, submodels
 
 
@@ -457,6 +493,44 @@ def write_aas():
     with open("dz_wald_example.json", "w", encoding='utf-8') as file:
         json_serialization.write_aas_json_file(file, objstore)
 
+# Function corrosponding to the "getHolzpreisbereich" operation.
+# Note that the function's parameters are named after the operation's 
+# input variables. 
+def getHolzpreisbereich(provider: api.ModelProvider, HolzlisteId: str):
+    holzliste_sm = provider.getValue(f"/aas/submodels/{helpers.encode_id(HolzlisteId)}/submodel")
+    # TODO: REST
+    # CALL to Forstify
+    # create a placeholder reply for now
+    reply = {
+        "Baumart": "kie",
+        "PreisVon": 14500.0,
+        "PreisBis": 14500.0,
+        "Sorte": "ab",
+        "MittendurchmesserVon": 100.0,
+        "MittendurchmesserBis": 200.0,
+        "Datum": "8/4/2023, 10:56:39 AM",
+        "Quelle": "Forstify Marktplatz Angebote"
+    }
+    date_format = '%m/%d/%Y, %H:%M:%S %p'
+    holzpreisbereich = models.Holzpreisbereich(
+        baumart=enums.Holzart(reply["Baumart"]),
+        preis_von=reply["PreisVon"],
+        preis_bis=reply["PreisBis"],
+        sorte=enums.Sorte(reply["Sorte"]),
+        mittendurchmesser_bis=reply["MittendurchmesserBis"],
+        mittendurchmesser_von=reply["MittendurchmesserVon"],
+        datum=datetime.datetime.strptime(reply["Datum"], date_format),
+        quelle=reply["Quelle"], 
+        holzliste=model.ModelReference.from_referable(holzliste_sm)
+    )
+    holzpreisbereiche_id = "https://www.company.com/submodels/holzpreisbereiche"
+    holzpreisbereiche: model.SubmodelElementList =  provider.getValue(
+        f"/aas/submodels/{helpers.encode_id(holzpreisbereiche_id)}/submodel"
+        )
+    utils.add_items_to_se_list(holzpreisbereiche, [holzpreisbereich])
+    return reply
+    
+
 
 def main():
     # obtain access token
@@ -466,8 +540,8 @@ def main():
     # update policy for other things to read the S3I-Directory entry of your thing
     # view helpers.py for a better insight
     # function call is commented because it needs to be done a single time
-    s3i_dir = Directory("https://dir.s3i.vswf.dev/api/2/", access_token)
-    helpers.grant_entry_read_permissions(s3i_dir, dzwald_id, [forestmanager_hmi_id, forstify_hmi_id])
+    # s3i_dir = Directory("https://dir.s3i.vswf.dev/api/2/", access_token)
+    # helpers.grant_entry_read_permissions(s3i_dir, dzwald_id, [forestmanager_hmi_id, forstify_hmi_id])
 
     # create AAS
     aas, submodels = create_aas()
@@ -496,8 +570,16 @@ def main():
     # now create a server instance that will translate incoming S3I-B messages
     # to methods exposed by the ModelProvider
     
+    HolzlisteId = 'https://www.company.com/holzliste/1'
     loop = asyncio.get_event_loop()
-    server = broker_api.S3IBServer(access_token, provider, dzwald_id, loop)
+
+    # set last flag to True to enable security
+    server = broker_api.S3IBServer(access_token, provider, dzwald_id, loop, "https://www.company.com/security", False)
+
+    # add callable associated with operation 'getHolzpreisbereich' to server
+    callable = lambda **kwargs : getHolzpreisbereich(provider, **kwargs)
+    operation_path = f"/aas/submodels/{helpers.encode_id(HolzlisteId)}/submodel/submodelElements/getHolzpreisbereich"
+    server.add_callable(operation_path, callable)
 
     try:
         server.run()
@@ -506,5 +588,7 @@ def main():
 
 
 
+
 if __name__ == "__main__":
     main()
+    #create_aas()
diff --git a/demos/demo2/demo2_forestmanager.py b/demos/demo2/demo2_forestmanager.py
index 6bbc5d997ff8540e9bd4244cf8c83a8d59664c55..1a6f09f868a2b04d09f15505c46fbadf86e7f3a0 100644
--- a/demos/demo2/demo2_forestmanager.py
+++ b/demos/demo2/demo2_forestmanager.py
@@ -6,6 +6,7 @@ import os, sys, inspect
 import base64
 
 import broker_api
+import helpers
 
 currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
 parentdir = os.path.dirname(currentdir)
@@ -44,11 +45,11 @@ async def main():
     access_token = idp.get_token(TokenType.ACCESS_TOKEN)
 
     # obtain dzwald's endpoint by checking its entry within the S3I-Directory
-    s3i_dir = Directory("https://dir.s3i.vswf.dev/api/2/", access_token)
-    dzwald_dir_entry = s3i_dir.queryThingIDBased(dzwald_id)
-    s3ib_endpoints = [i for i in dzwald_dir_entry["attributes"]["allEndpoints"] if
-                      i.startswith('s3ib')]
-    dzwald_endpoint = s3ib_endpoints[0]
+    #s3i_dir = Directory("https://dir.s3i.vswf.dev/api/2/", access_token)
+    #dzwald_dir_entry = s3i_dir.queryThingIDBased(dzwald_id)
+    #s3ib_endpoints = [i for i in dzwald_dir_entry["attributes"]["allEndpoints"] if
+    #                  i.startswith('s3ib')]
+    dzwald_endpoint = "s3ib://s3i:bc30c279-02c5-4918-a2ad-761e927214dd"
 
     # use async client to access AAS and its submodels through their REST API asynchronously
     client = broker_api.S3IBAsyncClient(access_token, forestmanager_hmi_id, loop)    
@@ -62,11 +63,10 @@ async def main():
     # listen on event "Auftragsstatus_Updated"
     events_submodel_id = "https://www.company.com/submodels/events"
     events_submodel_id_encoded = base64.urlsafe_b64encode(events_submodel_id.encode()).decode()
-    print(events_submodel_id_encoded)
     event: model.BasicEventElement = await client.getValue(dzwald_id, dzwald_endpoint,
                                                            f"/aas/submodels/{events_submodel_id_encoded} \
                                                            /submodel/submodelElements/Auftragsstatus_Updated")
-    auftragsstatus_updated = await client.subscribeToEvent(event.message_topic)
+    auftragsstatus_updated = await client.awaitEvent(event.message_topic)
 
     # Speichern eines Waldweges
     waldweg_submodel = create_waldweg()
@@ -114,6 +114,17 @@ async def main():
     print(
         f"{auftragsstatus.id_short}: {enums.Auftragsstatus(int(auftragsstatus.value))}")
     
+    # Invoke Operation 'getHolzpreisbereich'
+    HolzlisteId = "https://www.company.com/holzliste/1"
+    reply4 = await client.invokeOperation(
+        dzwald_id,
+        dzwald_endpoint,
+        f"/aas/submodels/{helpers.encode_id(HolzlisteId)}/submodel/submodelElements/getHolzpreisbereich",
+        {"HolzlisteId": HolzlisteId}
+    )
+    print(f"result of operation 'getHolzpreisbereich': {reply4}")
+
+    # await event
     await asyncio.wait([auftragsstatus_updated])
     
 
diff --git a/demos/demo2/helpers.py b/demos/demo2/helpers.py
index a012abaee2f094df040a427113274842a1e60ab0..5e032ad36d690b77509de3bf5a3a2b410efa48a4 100644
--- a/demos/demo2/helpers.py
+++ b/demos/demo2/helpers.py
@@ -4,7 +4,7 @@ from urllib.parse import unquote
 from basyx.aas import model
 from s3i import Directory
 
-from api import SUBMODELS, SUBMODELELEMENTS
+from api import SUBMODELS, SUBMODELELEMENTS, SUBMODEL, AAS
 
 
 def add_aas_to_dir_entry(aas: model.AssetAdministrationShell, dir: Directory, thing_id: str):
@@ -52,12 +52,14 @@ def grant_entry_read_permissions(dir: Directory, thing_id, receivers: list):
 
 
 def id_short_path_from_ref(ref: model.ModelReference):
-    arr = []
+    arr = ["aas"]
     for i, key in enumerate(ref.key):
         if key.value.isnumeric():
             arr[i-1] = f"{arr[i-1]}[{key.value}]"
         elif key.type == model.KeyTypes.SUBMODEL:
             arr.append(base64.urlsafe_b64encode(key.value.encode()).decode())
+        elif key.type == model.KeyTypes.ASSET_ADMINISTRATION_SHELL:
+            continue
         else:
             arr.append(key.value)
     return ".".join(arr)
@@ -65,12 +67,18 @@ def id_short_path_from_ref(ref: model.ModelReference):
 
 def id_short_path_from_path(path: str):
     arr = path.split("/")
-    try:
-        submodel_id_index = arr.index(SUBMODELS) + 1
-        id_short_path_index = arr.index(SUBMODELELEMENTS) + 1
-    except:
-        return ""
-    return f"{arr[submodel_id_index]}.{unquote(arr[id_short_path_index])}"
+    submodel_id_index = arr.index(SUBMODEL) - 1 if SUBMODEL in arr else None 
+    id_short_path_index = arr.index(SUBMODELELEMENTS) + 1 if SUBMODELELEMENTS in arr else None
+    if id_short_path_index:
+        return f"{AAS}.{arr[submodel_id_index]}.{unquote(arr[id_short_path_index])}"
+    elif submodel_id_index:
+        return f"{AAS}.{arr[submodel_id_index]}"
+    else:
+        return AAS
+
+def encode_id(id: str):
+    return base64.urlsafe_b64encode(id.encode()).decode()
+
 
 
 
diff --git a/demos/demo2/opa/data.json b/demos/demo2/opa/data.json
new file mode 100644
index 0000000000000000000000000000000000000000..2bd77f702821c4297c4fc35978bdb797022d8030
--- /dev/null
+++ b/demos/demo2/opa/data.json
@@ -0,0 +1,12 @@
+{
+    "api": {
+        "https://www.company.com/holzliste/1": {
+            "READ": [
+                "s3i:e8ef672c-109b-4c36-8999-f4ababa0bffc"
+            ],
+            "WRITE": [
+                "s3i:e8ef672c-109b-4c36-8999-f4ababa0bffc"
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/demos/demo2/opa/input.json b/demos/demo2/opa/input.json
new file mode 100644
index 0000000000000000000000000000000000000000..c0e22092f60925f16c5a5fbfa68a43cc2fe41f8b
--- /dev/null
+++ b/demos/demo2/opa/input.json
@@ -0,0 +1,5 @@
+{
+    "user": "s3i:e8ef672c-109b-4c36-8999-f4ababa0bffc",
+    "method": "WRITE",
+    "path": "https://www.company.com/holzliste/1"
+}
\ No newline at end of file
diff --git a/demos/demo2/opa/opa.exe b/demos/demo2/opa/opa.exe
new file mode 100644
index 0000000000000000000000000000000000000000..ea0fe2f7596b71b4f0e0c2808f1fd61235fe0f98
Binary files /dev/null and b/demos/demo2/opa/opa.exe differ
diff --git a/demos/demo2/opa/policy.rego b/demos/demo2/opa/policy.rego
new file mode 100644
index 0000000000000000000000000000000000000000..6f7ca43e50d98f3f89721aaad01a5cf4e488db89
--- /dev/null
+++ b/demos/demo2/opa/policy.rego
@@ -0,0 +1,23 @@
+package policy
+
+import future.keywords.in
+import input
+
+default allow = false
+
+allow {
+    path_arr := split(input.path, "/")
+    print(path_arr)
+    path_id_short := split(path_arr[count(path_arr)-1], ".")
+    z := array.slice(path_arr, 0, count(path_arr)-1)
+    path_full := array.concat(z, path_id_short)
+    print(path_id_short)
+    print(path_full)
+    some i, _ in path_full
+    path_arr_slice := array.slice(path_full, 0, i+1)
+    path := concat("/", path_arr_slice)
+    print(path)
+    print(data.api[path])
+    some user in data.api[path][input.method]
+    user == input.user
+}
diff --git a/demos/demo2/opa_api.py b/demos/demo2/opa_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..b7f05f6cdd122bb09e1c93e3790c6ca2d20dba11
--- /dev/null
+++ b/demos/demo2/opa_api.py
@@ -0,0 +1,28 @@
+import requests
+import json
+
+class Opa:
+
+    def __init__(self, server_url="http://localhost:8181"):
+        self.server_url = server_url
+    
+    def query(self, user, method, path):
+        body = {"input": {"user": user, "method": method, "path": path}}
+        url = f"{self.server_url}/v1/data/policy/allow"
+        response = requests.post(url=url, data=json.dumps(body))
+        result = json.loads(response.text)["result"]
+        return result
+    
+    def get_data(self, path=""):
+        url = f"{self.server_url}/v1/data/{path}"
+        response = requests.get(url=url)
+        result = json.loads(response.text)["result"]
+        return result
+
+    def update_data(self, data, path=""):
+        url = f"{self.server_url}/v1/data/{path}"
+        response = requests.put(url=url, data=json.dumps(data))
+        return response.status_code
+        #result = json.loads(response.text)["result"]
+        #return result
+    
diff --git a/model/security.py b/model/security.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a7a50f1195d6edb6b2137c8ae1739a84403aba0
--- /dev/null
+++ b/model/security.py
@@ -0,0 +1,120 @@
+import base64
+import json
+from enum import Enum, IntEnum
+from typing import Iterable, Optional
+from basyx.aas import model
+from basyx.aas.model import base
+from basyx.aas.model.submodel import SubmodelElement
+from model import utils 
+
+
+class PermissionKind(IntEnum):
+    ALLOW = 0,
+    DENY = 1,
+    IN_APPLICABLE = 3,
+    UNDEFINED = 4
+
+
+class Permission(str, Enum):
+    READ = "READ",
+    WRITE = "WRITE"
+
+
+class AccessPermissionRule(model.SubmodelElementCollection):
+
+    def __init__(self,
+                 user_id: str,
+                 permission_kind: PermissionKind,
+                 permission: Permission):
+      super().__init__(id_short="AccessPermissionRule")
+      self.add_referable(model.Property(id_short="User", value_type=model.datatypes.String, value=user_id))
+      self.add_referable(model.Property(id_short="PermissionKind", value_type=model.datatypes.Integer, value=permission_kind))
+      self.add_referable(model.Property(id_short="Permission", value_type=model.datatypes.String, value=permission))
+
+
+class AccessPermissionCollection(model.SubmodelElementCollection):
+
+    def __init__(self,
+                 target: model.ModelReference,
+                 rules: Optional[Iterable[AccessPermissionRule]] = None):
+        super().__init__(
+            id_short="AccessPermissionCollection", 
+        )
+        self.add_referable(model.ReferenceElement(id_short="Target", value=target))
+        rules_se_list = model.SubmodelElementList(id_short="Rules", type_value_list_element=AccessPermissionRule)
+        utils.add_items_to_se_list(rules_se_list, rules)
+        self.add_referable(rules_se_list)
+    
+    def add_rules(self,
+                  rules: Iterable[AccessPermissionRule]):
+        rules_se_list: model.SubmodelElementList = self.get_referable("Rules")
+        for i in rules:
+            rules_se_list.add_referable(i)
+
+
+class AccessControl(model.SubmodelElementList):
+
+    def __init__(self,
+                 permissions: Optional[Iterable[AccessPermissionCollection]] = None):
+        super().__init__(id_short="AccessControl", type_value_list_element=AccessPermissionCollection)
+        utils.add_items_to_se_list(self, permissions)
+
+class Security(model.Submodel):
+
+     def __init__(self,
+                 id: model.Identifier,
+                 access_control: Optional[AccessControl] = None
+                 ):
+        super().__init__(id_=id, id_short="Security")
+        if access_control:
+            self.add_referable(access_control)
+
+"""
+def id_short_path_from_ref(ref: model.ModelReference):
+    arr = []
+    for i, key in enumerate(ref.key):
+        if key.value.isnumeric():
+            arr[i-1] = f"{arr[i-1]}[{key.value}]"
+        elif key.type == model.KeyTypes.SUBMODEL:
+            arr.append(base64.urlsafe_b64encode(key.value.encode()).decode())
+        elif key.type == model.KeyTypes.ASSET_ADMINISTRATION_SHELL:
+            arr.append("aas")
+        else:
+            arr.append(key.value)
+    return ".".join(arr)
+"""
+
+def id_short_path_from_ref(ref: model.ModelReference):
+    arr = ["aas"]
+    for i, key in enumerate(ref.key):
+        if key.value.isnumeric():
+            arr[i-1] = f"{arr[i-1]}[{key.value}]"
+        elif key.type == model.KeyTypes.SUBMODEL:
+            arr.append(base64.urlsafe_b64encode(key.value.encode()).decode())
+        elif key.type == model.KeyTypes.ASSET_ADMINISTRATION_SHELL:
+            continue
+        else:
+            arr.append(key.value)
+    return ".".join(arr)
+
+def get_dic_from_security_submodel(security_sm: Security):
+    dic = {}
+    access_control: AccessControl = security_sm.get_referable("AccessControl")
+    for permission in access_control.value:
+        permission: AccessPermissionCollection = permission
+        target: model.ReferenceElement = permission.get_referable("Target")
+        id_short_path = id_short_path_from_ref(target.value)
+        rules: model.SubmodelElementList = permission.get_referable("Rules")
+        for rule in rules:
+            user: model.Property = rule.get_referable("User")
+            grant: model.Property = rule.get_referable("Permission")
+            if not dic.get(id_short_path):
+                dic[id_short_path] = {}
+                dic[id_short_path][Permission.READ.value] = []
+                dic[id_short_path][Permission.WRITE.value] = []
+            dic[id_short_path][grant.value].append(user.value)
+    return dic
+    
+
+
+