aas-http-client 0.4.1__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aas-http-client might be problematic. Click here for more details.
- aas_http_client/classes/auth_classes.py +21 -0
- aas_http_client/client.py +222 -26
- aas_http_client/demo/demo_process.py +23 -10
- aas_http_client/wrapper/sdk_wrapper.py +16 -2
- {aas_http_client-0.4.1.dist-info → aas_http_client-0.4.3.dist-info}/METADATA +1 -1
- {aas_http_client-0.4.1.dist-info → aas_http_client-0.4.3.dist-info}/RECORD +9 -8
- {aas_http_client-0.4.1.dist-info → aas_http_client-0.4.3.dist-info}/WHEEL +0 -0
- {aas_http_client-0.4.1.dist-info → aas_http_client-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {aas_http_client-0.4.1.dist-info → aas_http_client-0.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pydantic import BaseModel, PrivateAttr, ValidationError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BasicAuthConfig(BaseModel):
|
|
5
|
+
username: str
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ServiceProviderAuthConfig(BaseModel):
|
|
9
|
+
token_url: str
|
|
10
|
+
client_id: str
|
|
11
|
+
grant_type: str = "client_credentials"
|
|
12
|
+
header_name: str = "Authorization"
|
|
13
|
+
_client_secret: str = PrivateAttr(default=None)
|
|
14
|
+
|
|
15
|
+
def set_client_secret(self, client_secret: str) -> None:
|
|
16
|
+
self._client_secret = client_secret
|
|
17
|
+
|
|
18
|
+
def get_client_secret(self) -> str:
|
|
19
|
+
if self._client_secret is None:
|
|
20
|
+
raise ValueError("Client secret has not been set.")
|
|
21
|
+
return self._client_secret
|
aas_http_client/client.py
CHANGED
|
@@ -4,10 +4,8 @@ import json
|
|
|
4
4
|
import logging
|
|
5
5
|
import time
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
8
7
|
|
|
9
8
|
import basyx.aas.adapter.json
|
|
10
|
-
import basyx.aas.adapter.json.json_serialization as js
|
|
11
9
|
import requests
|
|
12
10
|
from basyx.aas.model import Reference, Submodel
|
|
13
11
|
from pydantic import BaseModel, PrivateAttr, ValidationError
|
|
@@ -15,6 +13,7 @@ from requests import Session
|
|
|
15
13
|
from requests.auth import HTTPBasicAuth
|
|
16
14
|
from requests.models import Response
|
|
17
15
|
|
|
16
|
+
from aas_http_client.classes.auth_classes import BasicAuthConfig, ServiceProviderAuthConfig
|
|
18
17
|
from aas_http_client.core.encoder import decode_base_64
|
|
19
18
|
|
|
20
19
|
logger = logging.getLogger(__name__)
|
|
@@ -74,16 +73,22 @@ class AasHttpClient(BaseModel):
|
|
|
74
73
|
"""Represents a AasHttpClient to communicate with a REST API."""
|
|
75
74
|
|
|
76
75
|
base_url: str = "http://javaaasserver:5060/"
|
|
77
|
-
|
|
76
|
+
basic_auth: BasicAuthConfig | None = None
|
|
77
|
+
service_provider_auth: ServiceProviderAuthConfig | None = None
|
|
78
78
|
https_proxy: str | None = None
|
|
79
79
|
http_proxy: str | None = None
|
|
80
80
|
time_out: int = 200
|
|
81
81
|
connection_time_out: int = 100
|
|
82
82
|
ssl_verify: bool = True
|
|
83
83
|
trust_env: bool = True
|
|
84
|
+
auth_service_provider: str | None = None
|
|
84
85
|
_session: Session = PrivateAttr(default=None)
|
|
85
86
|
|
|
86
|
-
def initialize(
|
|
87
|
+
def initialize(
|
|
88
|
+
self,
|
|
89
|
+
basic_auth_password: str,
|
|
90
|
+
service_provider_auth_client_secret: str,
|
|
91
|
+
):
|
|
87
92
|
"""Initialize the AasHttpClient with the given URL, username and password.
|
|
88
93
|
|
|
89
94
|
:param password: password
|
|
@@ -92,10 +97,17 @@ class AasHttpClient(BaseModel):
|
|
|
92
97
|
self.base_url = self.base_url[:-1]
|
|
93
98
|
|
|
94
99
|
self._session = requests.Session()
|
|
95
|
-
|
|
100
|
+
|
|
101
|
+
self._session.auth = HTTPBasicAuth("", "")
|
|
102
|
+
if self.basic_auth:
|
|
103
|
+
self._session.auth = HTTPBasicAuth(self.basic_auth.username, basic_auth_password)
|
|
104
|
+
|
|
96
105
|
self._session.verify = self.ssl_verify
|
|
97
106
|
self._session.trust_env = self.trust_env
|
|
98
107
|
|
|
108
|
+
if self.service_provider_auth:
|
|
109
|
+
self.service_provider_auth.set_client_secret(service_provider_auth_client_secret)
|
|
110
|
+
|
|
99
111
|
if self.https_proxy:
|
|
100
112
|
self._session.proxies.update({"https": self.https_proxy})
|
|
101
113
|
if self.http_proxy:
|
|
@@ -108,6 +120,9 @@ class AasHttpClient(BaseModel):
|
|
|
108
120
|
"""
|
|
109
121
|
url = f"{self.base_url}/shells"
|
|
110
122
|
|
|
123
|
+
if self.service_provider_auth:
|
|
124
|
+
self._set_token_by_client_credentials()
|
|
125
|
+
|
|
111
126
|
try:
|
|
112
127
|
response = self._session.get(url, headers=HEADERS, timeout=10)
|
|
113
128
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -123,6 +138,29 @@ class AasHttpClient(BaseModel):
|
|
|
123
138
|
content = response.content.decode("utf-8")
|
|
124
139
|
return json.loads(content)
|
|
125
140
|
|
|
141
|
+
def _set_token_by_client_credentials(self) -> dict | None:
|
|
142
|
+
if self.service_provider_auth is None:
|
|
143
|
+
logger.error("Service provider authentication is not configured.")
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
if self.service_provider_auth.grant_type == "password":
|
|
147
|
+
token = get_token_by_password(
|
|
148
|
+
self.service_provider_auth.token_url,
|
|
149
|
+
self.service_provider_auth.client_id,
|
|
150
|
+
self.service_provider_auth.get_client_secret(),
|
|
151
|
+
self.time_out,
|
|
152
|
+
)
|
|
153
|
+
else:
|
|
154
|
+
token = get_token_by_basic_auth(
|
|
155
|
+
self.service_provider_auth.token_url,
|
|
156
|
+
self.service_provider_auth.client_id,
|
|
157
|
+
self.service_provider_auth.get_client_secret(),
|
|
158
|
+
self.time_out,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if token:
|
|
162
|
+
self._session.headers.update({self.service_provider_auth.auth_header_name: f"Bearer {token}"})
|
|
163
|
+
|
|
126
164
|
# region shells
|
|
127
165
|
|
|
128
166
|
def post_asset_administration_shell(self, aas_data: dict) -> dict | None:
|
|
@@ -134,6 +172,9 @@ class AasHttpClient(BaseModel):
|
|
|
134
172
|
url = f"{self.base_url}/shells"
|
|
135
173
|
logger.debug(f"Call REST API url '{url}'")
|
|
136
174
|
|
|
175
|
+
if self.service_provider_auth:
|
|
176
|
+
self._set_token_by_client_credentials()
|
|
177
|
+
|
|
137
178
|
try:
|
|
138
179
|
response = self._session.post(url, headers=HEADERS, json=aas_data, timeout=self.time_out)
|
|
139
180
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -159,6 +200,9 @@ class AasHttpClient(BaseModel):
|
|
|
159
200
|
decoded_identifier: str = decode_base_64(identifier)
|
|
160
201
|
url = f"{self.base_url}/shells/{decoded_identifier}"
|
|
161
202
|
|
|
203
|
+
if self.service_provider_auth:
|
|
204
|
+
self._set_token_by_client_credentials()
|
|
205
|
+
|
|
162
206
|
try:
|
|
163
207
|
response = self._session.put(url, headers=HEADERS, json=aas_data, timeout=self.time_out)
|
|
164
208
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -184,6 +228,9 @@ class AasHttpClient(BaseModel):
|
|
|
184
228
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
185
229
|
url = f"{self.base_url}/shells/{decoded_aas_id}/submodels/{decoded_submodel_id}"
|
|
186
230
|
|
|
231
|
+
if self.service_provider_auth:
|
|
232
|
+
self._set_token_by_client_credentials()
|
|
233
|
+
|
|
187
234
|
try:
|
|
188
235
|
response = self._session.put(url, headers=HEADERS, json=submodel_data, timeout=self.time_out)
|
|
189
236
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -205,6 +252,9 @@ class AasHttpClient(BaseModel):
|
|
|
205
252
|
"""
|
|
206
253
|
url = f"{self.base_url}/shells"
|
|
207
254
|
|
|
255
|
+
if self.service_provider_auth:
|
|
256
|
+
self._set_token_by_client_credentials()
|
|
257
|
+
|
|
208
258
|
try:
|
|
209
259
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
210
260
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -229,6 +279,9 @@ class AasHttpClient(BaseModel):
|
|
|
229
279
|
decoded_aas_id: str = decode_base_64(aas_id)
|
|
230
280
|
url = f"{self.base_url}/shells/{decoded_aas_id}"
|
|
231
281
|
|
|
282
|
+
if self.service_provider_auth:
|
|
283
|
+
self._set_token_by_client_credentials()
|
|
284
|
+
|
|
232
285
|
try:
|
|
233
286
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
234
287
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -253,6 +306,9 @@ class AasHttpClient(BaseModel):
|
|
|
253
306
|
decoded_aas_id: str = decode_base_64(aas_id)
|
|
254
307
|
url = f"{self.base_url}/shells/{decoded_aas_id}/$reference"
|
|
255
308
|
|
|
309
|
+
if self.service_provider_auth:
|
|
310
|
+
self._set_token_by_client_credentials()
|
|
311
|
+
|
|
256
312
|
try:
|
|
257
313
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
258
314
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -279,7 +335,9 @@ class AasHttpClient(BaseModel):
|
|
|
279
335
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
280
336
|
|
|
281
337
|
url = f"{self.base_url}/shells/{decoded_aas_id}/submodels/{decoded_submodel_id}"
|
|
282
|
-
|
|
338
|
+
|
|
339
|
+
if self.service_provider_auth:
|
|
340
|
+
self._set_token_by_client_credentials()
|
|
283
341
|
|
|
284
342
|
try:
|
|
285
343
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
@@ -305,6 +363,9 @@ class AasHttpClient(BaseModel):
|
|
|
305
363
|
decoded_aas_id: str = decode_base_64(aas_id)
|
|
306
364
|
url = f"{self.base_url}/shells/{decoded_aas_id}"
|
|
307
365
|
|
|
366
|
+
if self.service_provider_auth:
|
|
367
|
+
self._set_token_by_client_credentials()
|
|
368
|
+
|
|
308
369
|
try:
|
|
309
370
|
response = self._session.delete(url, headers=HEADERS, timeout=self.time_out)
|
|
310
371
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -331,6 +392,9 @@ class AasHttpClient(BaseModel):
|
|
|
331
392
|
"""
|
|
332
393
|
url = f"{self.base_url}/submodels"
|
|
333
394
|
|
|
395
|
+
if self.service_provider_auth:
|
|
396
|
+
self._set_token_by_client_credentials()
|
|
397
|
+
|
|
334
398
|
try:
|
|
335
399
|
response = self._session.post(url, headers=HEADERS, json=submodel_data, timeout=self.time_out)
|
|
336
400
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -356,6 +420,9 @@ class AasHttpClient(BaseModel):
|
|
|
356
420
|
decoded_identifier: str = decode_base_64(identifier)
|
|
357
421
|
url = f"{self.base_url}/submodels/{decoded_identifier}"
|
|
358
422
|
|
|
423
|
+
if self.service_provider_auth:
|
|
424
|
+
self._set_token_by_client_credentials()
|
|
425
|
+
|
|
359
426
|
try:
|
|
360
427
|
response = self._session.put(url, headers=HEADERS, json=submodel_data, timeout=self.time_out)
|
|
361
428
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -377,6 +444,9 @@ class AasHttpClient(BaseModel):
|
|
|
377
444
|
"""
|
|
378
445
|
url = f"{self.base_url}/submodels"
|
|
379
446
|
|
|
447
|
+
if self.service_provider_auth:
|
|
448
|
+
self._set_token_by_client_credentials()
|
|
449
|
+
|
|
380
450
|
try:
|
|
381
451
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
382
452
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -401,6 +471,9 @@ class AasHttpClient(BaseModel):
|
|
|
401
471
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
402
472
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}"
|
|
403
473
|
|
|
474
|
+
if self.service_provider_auth:
|
|
475
|
+
self._set_token_by_client_credentials()
|
|
476
|
+
|
|
404
477
|
try:
|
|
405
478
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
406
479
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -425,6 +498,9 @@ class AasHttpClient(BaseModel):
|
|
|
425
498
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
426
499
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}"
|
|
427
500
|
|
|
501
|
+
if self.service_provider_auth:
|
|
502
|
+
self._set_token_by_client_credentials()
|
|
503
|
+
|
|
428
504
|
try:
|
|
429
505
|
response = self._session.patch(url, headers=HEADERS, json=submodel_data, timeout=self.time_out)
|
|
430
506
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -448,6 +524,9 @@ class AasHttpClient(BaseModel):
|
|
|
448
524
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
449
525
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}"
|
|
450
526
|
|
|
527
|
+
if self.service_provider_auth:
|
|
528
|
+
self._set_token_by_client_credentials()
|
|
529
|
+
|
|
451
530
|
try:
|
|
452
531
|
response = self._session.delete(url, headers=HEADERS, timeout=self.time_out)
|
|
453
532
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -471,6 +550,9 @@ class AasHttpClient(BaseModel):
|
|
|
471
550
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
472
551
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements"
|
|
473
552
|
|
|
553
|
+
if self.service_provider_auth:
|
|
554
|
+
self._set_token_by_client_credentials()
|
|
555
|
+
|
|
474
556
|
try:
|
|
475
557
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
476
558
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -495,6 +577,38 @@ class AasHttpClient(BaseModel):
|
|
|
495
577
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
496
578
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements"
|
|
497
579
|
|
|
580
|
+
if self.service_provider_auth:
|
|
581
|
+
self._set_token_by_client_credentials()
|
|
582
|
+
|
|
583
|
+
try:
|
|
584
|
+
response = self._session.post(url, headers=HEADERS, json=submodel_element_data, timeout=self.time_out)
|
|
585
|
+
logger.debug(f"Call REST API url '{response.url}'")
|
|
586
|
+
|
|
587
|
+
if response.status_code != STATUS_CODE_201:
|
|
588
|
+
log_response_errors(response)
|
|
589
|
+
return None
|
|
590
|
+
|
|
591
|
+
except requests.exceptions.RequestException as e:
|
|
592
|
+
logger.error(f"Error call REST API: {e}")
|
|
593
|
+
return None
|
|
594
|
+
|
|
595
|
+
content = response.content.decode("utf-8")
|
|
596
|
+
return json.loads(content)
|
|
597
|
+
|
|
598
|
+
def post_submodel_element_by_path_submodel_repo(self, submodel_id: str, submodel_element_path: str, submodel_element_data: dict) -> dict | None:
|
|
599
|
+
"""Creates a new submodel element at a specified path within submodel elements hierarchy.
|
|
600
|
+
|
|
601
|
+
:param submodel_id: Encoded ID of the Submodel to create elements for
|
|
602
|
+
:param submodel_element_path: Path within the Submodel elements hierarchy
|
|
603
|
+
:param submodel_element_data: Data for the new Submodel element
|
|
604
|
+
:return: Submodel element data or None if an error occurred
|
|
605
|
+
"""
|
|
606
|
+
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
607
|
+
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}"
|
|
608
|
+
|
|
609
|
+
if self.service_provider_auth:
|
|
610
|
+
self._set_token_by_client_credentials()
|
|
611
|
+
|
|
498
612
|
try:
|
|
499
613
|
response = self._session.post(url, headers=HEADERS, json=submodel_element_data, timeout=self.time_out)
|
|
500
614
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -521,6 +635,9 @@ class AasHttpClient(BaseModel):
|
|
|
521
635
|
|
|
522
636
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}"
|
|
523
637
|
|
|
638
|
+
if self.service_provider_auth:
|
|
639
|
+
self._set_token_by_client_credentials()
|
|
640
|
+
|
|
524
641
|
try:
|
|
525
642
|
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
526
643
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -547,6 +664,9 @@ class AasHttpClient(BaseModel):
|
|
|
547
664
|
|
|
548
665
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}"
|
|
549
666
|
|
|
667
|
+
if self.service_provider_auth:
|
|
668
|
+
self._set_token_by_client_credentials()
|
|
669
|
+
|
|
550
670
|
try:
|
|
551
671
|
response = self._session.delete(url, headers=HEADERS, timeout=self.time_out)
|
|
552
672
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -573,6 +693,9 @@ class AasHttpClient(BaseModel):
|
|
|
573
693
|
|
|
574
694
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements/{submodel_element_path}/$value"
|
|
575
695
|
|
|
696
|
+
if self.service_provider_auth:
|
|
697
|
+
self._set_token_by_client_credentials()
|
|
698
|
+
|
|
576
699
|
try:
|
|
577
700
|
response = self._session.patch(url, headers=HEADERS, json=value, timeout=self.time_out)
|
|
578
701
|
logger.debug(f"Call REST API url '{response.url}'")
|
|
@@ -593,10 +716,68 @@ class AasHttpClient(BaseModel):
|
|
|
593
716
|
# region client
|
|
594
717
|
|
|
595
718
|
|
|
719
|
+
def get_token_by_basic_auth(endpoint: str, username: str, password: str, timeout=200) -> dict | None:
|
|
720
|
+
"""Get token from a specific authentication service provider by basic authentication.
|
|
721
|
+
|
|
722
|
+
:param endpoint: Get token endpoint for the authentication service provider
|
|
723
|
+
:param username: Username for the authentication service provider
|
|
724
|
+
:param password: Password for the authentication service provider
|
|
725
|
+
:param timeout: Timeout for the API calls, defaults to 200
|
|
726
|
+
:return: Access token or None if an error occurred
|
|
727
|
+
"""
|
|
728
|
+
data = {"grant_type": "client_credentials"}
|
|
729
|
+
|
|
730
|
+
auth = HTTPBasicAuth(username, password)
|
|
731
|
+
|
|
732
|
+
try:
|
|
733
|
+
response = requests.post(endpoint, auth=auth, data=data, timeout=timeout)
|
|
734
|
+
logger.info(f"Request URL: {response.url}")
|
|
735
|
+
response.raise_for_status()
|
|
736
|
+
return response.json().get("access_token")
|
|
737
|
+
except requests.RequestException as e:
|
|
738
|
+
logger.error(f"Error getting token: {e}")
|
|
739
|
+
return None
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def get_token_by_password(endpoint: str, username: str, password: str, timeout=200) -> dict | None:
|
|
743
|
+
"""Get token from a specific authentication service provider by username and password.
|
|
744
|
+
|
|
745
|
+
:param endpoint: Get token endpoint for the authentication service provider
|
|
746
|
+
:param username: Username for the authentication service provider
|
|
747
|
+
:param password: Password for the authentication service provider
|
|
748
|
+
:param timeout: Timeout for the API calls, defaults to 200
|
|
749
|
+
:return: Access token or None if an error occurred
|
|
750
|
+
"""
|
|
751
|
+
data = {"grant_type": "password", "username": username, "password": password}
|
|
752
|
+
|
|
753
|
+
return _get_token(endpoint, data, timeout)
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def _get_token(endpoint: str, data: dict[str, str], timeout: int = 200) -> dict | None:
|
|
757
|
+
"""Get token from a specific authentication service provider.
|
|
758
|
+
|
|
759
|
+
:param endpoint: Get token endpoint for the authentication service provider
|
|
760
|
+
:param data: Data for the authentication service provider
|
|
761
|
+
:param timeout: Timeout for the API calls, defaults to 200
|
|
762
|
+
:return: Access token or None if an error occurred
|
|
763
|
+
"""
|
|
764
|
+
try:
|
|
765
|
+
response = requests.post(endpoint, json=data, timeout=timeout)
|
|
766
|
+
logger.info(f"Request URL: {response.url}")
|
|
767
|
+
response.raise_for_status()
|
|
768
|
+
return response.json().get("access_token")
|
|
769
|
+
except requests.RequestException as e:
|
|
770
|
+
logger.error(f"Error getting token: {e}")
|
|
771
|
+
return None
|
|
772
|
+
|
|
773
|
+
|
|
596
774
|
def create_client_by_url(
|
|
597
775
|
base_url: str,
|
|
598
|
-
|
|
599
|
-
|
|
776
|
+
basic_auth_username: str = "",
|
|
777
|
+
basic_auth_password: str = "",
|
|
778
|
+
service_provider_auth_client_id: str = "",
|
|
779
|
+
service_provider_auth_client_secret: str = "",
|
|
780
|
+
service_provider_auth_token_url: str = "",
|
|
600
781
|
http_proxy: str = "",
|
|
601
782
|
https_proxy: str = "",
|
|
602
783
|
time_out: int = 200,
|
|
@@ -620,34 +801,45 @@ def create_client_by_url(
|
|
|
620
801
|
logger.info(f"Create AAS server http client from URL '{base_url}'.")
|
|
621
802
|
config_dict: dict[str, str] = {}
|
|
622
803
|
config_dict["base_url"] = base_url
|
|
623
|
-
config_dict["username"] = username
|
|
624
804
|
config_dict["http_proxy"] = http_proxy
|
|
625
805
|
config_dict["https_proxy"] = https_proxy
|
|
626
806
|
config_dict["time_out"] = time_out
|
|
627
807
|
config_dict["connection_time_out"] = connection_time_out
|
|
628
808
|
config_dict["ssl_verify"] = ssl_verify
|
|
629
809
|
config_dict["trust_env"] = trust_env
|
|
630
|
-
|
|
810
|
+
config_dict["basic_auth"] = None
|
|
811
|
+
config_dict["service_provider_auth"] = None
|
|
812
|
+
|
|
813
|
+
if basic_auth_password and basic_auth_username:
|
|
814
|
+
config_dict["basic_auth"] = {"username": basic_auth_username}
|
|
815
|
+
|
|
816
|
+
if service_provider_auth_client_id and service_provider_auth_client_secret and service_provider_auth_token_url:
|
|
817
|
+
config_dict["service_provider_auth"] = {
|
|
818
|
+
"client_id": service_provider_auth_client_id,
|
|
819
|
+
"token_url": service_provider_auth_token_url,
|
|
820
|
+
}
|
|
631
821
|
|
|
822
|
+
return create_client_by_dict(config_dict, basic_auth_password, service_provider_auth_client_secret)
|
|
632
823
|
|
|
633
|
-
|
|
824
|
+
|
|
825
|
+
def create_client_by_dict(configuration: dict, basic_auth_password: str = "", service_provider_auth_client_secret: str = "") -> AasHttpClient | None:
|
|
634
826
|
"""Create a HTTP client for a AAS server connection from the given configuration.
|
|
635
827
|
|
|
636
828
|
:param configuration: Dictionary containing the BaSyx server connection settings.
|
|
637
|
-
:param
|
|
829
|
+
:param basic_auth_password: Password for the AAS server basic auth, defaults to ""
|
|
638
830
|
:return: An instance of Http client initialized with the provided parameters.
|
|
639
831
|
"""
|
|
640
832
|
logger.info("Create AAS server http client from dictionary.")
|
|
641
833
|
config_string = json.dumps(configuration, indent=4)
|
|
642
834
|
|
|
643
|
-
return _create_client(config_string,
|
|
835
|
+
return _create_client(config_string, basic_auth_password, service_provider_auth_client_secret)
|
|
644
836
|
|
|
645
837
|
|
|
646
|
-
def create_client_by_config(config_file: Path,
|
|
838
|
+
def create_client_by_config(config_file: Path, basic_auth_password: str = "", service_provider_auth_client_secret: str = "") -> AasHttpClient | None:
|
|
647
839
|
"""Create a HTTP client for a AAS server connection from a given configuration file.
|
|
648
840
|
|
|
649
841
|
:param config_file: Path to the configuration file containing the AAS server connection settings.
|
|
650
|
-
:param
|
|
842
|
+
:param basic_auth_password: password for the BaSyx server basic auth, defaults to ""
|
|
651
843
|
:return: An instance of Http client initialized with the provided parameters.
|
|
652
844
|
"""
|
|
653
845
|
config_file = config_file.resolve()
|
|
@@ -659,24 +851,28 @@ def create_client_by_config(config_file: Path, password: str = "") -> AasHttpCli
|
|
|
659
851
|
config_string = config_file.read_text(encoding="utf-8")
|
|
660
852
|
logger.debug(f"Configuration file '{config_file}' found.")
|
|
661
853
|
|
|
662
|
-
return _create_client(config_string,
|
|
854
|
+
return _create_client(config_string, basic_auth_password, service_provider_auth_client_secret)
|
|
663
855
|
|
|
664
856
|
|
|
665
|
-
def _create_client(config_string: str,
|
|
857
|
+
def _create_client(config_string: str, basic_auth_password: str, service_provider_auth_client_secret: str) -> AasHttpClient | None:
|
|
666
858
|
try:
|
|
667
859
|
client = AasHttpClient.model_validate_json(config_string)
|
|
668
860
|
except ValidationError as ve:
|
|
669
861
|
raise ValidationError(f"Invalid BaSyx server configuration file: {ve}") from ve
|
|
670
862
|
|
|
671
|
-
logger.info(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
f"
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
863
|
+
logger.info("Using server configuration:")
|
|
864
|
+
logger.info(f"base_url: '{client.base_url}'")
|
|
865
|
+
logger.info(f"timeout: '{client.time_out}'")
|
|
866
|
+
|
|
867
|
+
if client.basic_auth:
|
|
868
|
+
logger.info(f"basic_auth: '{client.basic_auth.username}'")
|
|
869
|
+
if client.service_provider_auth:
|
|
870
|
+
logger.info(f"service_provider_auth: '{client.service_provider_auth.token_url}': {client.service_provider_auth.client_id}'")
|
|
871
|
+
|
|
872
|
+
logger.info(f"https_proxy: '{client.https_proxy}'")
|
|
873
|
+
logger.info(f"http_proxy: '{client.http_proxy}'")
|
|
874
|
+
logger.info(f"connection_timeout: '{client.connection_time_out}'.")
|
|
875
|
+
client.initialize(basic_auth_password, service_provider_auth_client_secret)
|
|
680
876
|
|
|
681
877
|
# test the connection to the REST API
|
|
682
878
|
connected = _connect_to_api(client)
|
|
@@ -5,9 +5,9 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
from basyx.aas import model
|
|
7
7
|
|
|
8
|
-
from aas_http_client
|
|
8
|
+
from aas_http_client import client as aas_client
|
|
9
9
|
from aas_http_client.utilities import model_builder, sdk_tools
|
|
10
|
-
from aas_http_client.wrapper
|
|
10
|
+
from aas_http_client.wrapper import sdk_wrapper
|
|
11
11
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
@@ -21,20 +21,33 @@ def start() -> None:
|
|
|
21
21
|
|
|
22
22
|
# create a submodel
|
|
23
23
|
sm_short_id: str = model_builder.create_unique_short_id("poc_sm")
|
|
24
|
-
submodel = model_builder.create_base_submodel(sm_short_id)
|
|
24
|
+
submodel = model_builder.create_base_submodel(sm_short_id, sm_short_id)
|
|
25
25
|
# add submodel element to submodel
|
|
26
26
|
# submodel.submodel_element.add(sme)
|
|
27
27
|
|
|
28
28
|
# create an AAS
|
|
29
29
|
aas_short_id: str = model_builder.create_unique_short_id("poc_aas")
|
|
30
|
-
aas = model_builder.create_base_ass(aas_short_id)
|
|
30
|
+
aas = model_builder.create_base_ass(aas_short_id, aas_short_id)
|
|
31
31
|
|
|
32
32
|
# add submodel to AAS
|
|
33
33
|
sdk_tools.add_submodel_to_aas(aas, submodel)
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
client = aas_client.create_client_by_url(
|
|
36
|
+
"http://javaaasserver:8075/",
|
|
37
|
+
service_provider_auth_client_id="fluid40",
|
|
38
|
+
service_provider_auth_client_secret="LdFB4jRrMMkgcVWgFkOVdDVDXtQ5os8w",
|
|
39
|
+
service_provider_auth_token_url="https://aurora-fluid40.iqstruct-engineering.de/auth/realms/BaSyx/protocol/openid-connect/token",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
client = aas_client.create_client_by_config(Path("./aas_http_client/demo/java_server_config.yml"))
|
|
37
43
|
|
|
44
|
+
# tmp = get_token_by_basic_auth(
|
|
45
|
+
# "https://aurora-fluid40.iqstruct-engineering.de/auth/realms/BaSyx/protocol/openid-connect/token",
|
|
46
|
+
# "fluid40",
|
|
47
|
+
# "LdFB4jRrMMkgcVWgFkOVdDVDXtQ5os8w",
|
|
48
|
+
# )
|
|
49
|
+
|
|
50
|
+
wrapper = _create_sdk_wrapper(Path("./aas_http_client/demo/python_server_config.yml"))
|
|
38
51
|
for existing_shell in wrapper.get_all_asset_administration_shells():
|
|
39
52
|
logger.warning(f"Delete shell '{existing_shell.id}'")
|
|
40
53
|
wrapper.delete_asset_administration_shell_by_id(existing_shell.id)
|
|
@@ -64,7 +77,7 @@ def start() -> None:
|
|
|
64
77
|
wrapper.delete_submodel_by_id(existing_submodel.id)
|
|
65
78
|
|
|
66
79
|
|
|
67
|
-
def _create_client(config: Path) -> AasHttpClient:
|
|
80
|
+
def _create_client(config: Path) -> aas_client.AasHttpClient:
|
|
68
81
|
"""Create a HTTP client from a given configuration file.
|
|
69
82
|
|
|
70
83
|
:param config: Given configuration file
|
|
@@ -72,7 +85,7 @@ def _create_client(config: Path) -> AasHttpClient:
|
|
|
72
85
|
"""
|
|
73
86
|
try:
|
|
74
87
|
file = config
|
|
75
|
-
client = create_client_by_config(file, password="")
|
|
88
|
+
client = aas_client.create_client_by_config(file, password="")
|
|
76
89
|
|
|
77
90
|
except Exception as e:
|
|
78
91
|
logger.error(f"Failed to create client for {file}: {e}")
|
|
@@ -80,7 +93,7 @@ def _create_client(config: Path) -> AasHttpClient:
|
|
|
80
93
|
return client
|
|
81
94
|
|
|
82
95
|
|
|
83
|
-
def _create_sdk_wrapper(config: Path) -> SdkWrapper:
|
|
96
|
+
def _create_sdk_wrapper(config: Path) -> sdk_wrapper.SdkWrapper:
|
|
84
97
|
"""Create a SDK wrapper from a given configuration file.
|
|
85
98
|
|
|
86
99
|
:param config: Given configuration file
|
|
@@ -88,7 +101,7 @@ def _create_sdk_wrapper(config: Path) -> SdkWrapper:
|
|
|
88
101
|
"""
|
|
89
102
|
try:
|
|
90
103
|
file = config
|
|
91
|
-
client = create_wrapper_by_config(file, password="")
|
|
104
|
+
client = sdk_wrapper.create_wrapper_by_config(file, password="")
|
|
92
105
|
|
|
93
106
|
except Exception as e:
|
|
94
107
|
logger.error(f"Failed to create client for {file}: {e}")
|
|
@@ -25,7 +25,7 @@ class SdkWrapper:
|
|
|
25
25
|
:param config_string: Configuration string for the BaSyx server connection.
|
|
26
26
|
:param password: Password for the BaSyx server interface client, defaults to "".
|
|
27
27
|
"""
|
|
28
|
-
client = _create_client(config_string, password)
|
|
28
|
+
client = _create_client(config_string, password, "")
|
|
29
29
|
|
|
30
30
|
if not client:
|
|
31
31
|
raise ValueError("Failed to create AAS HTTP client with the provided configuration.")
|
|
@@ -257,7 +257,7 @@ class SdkWrapper:
|
|
|
257
257
|
return submodel_elements
|
|
258
258
|
|
|
259
259
|
def post_submodel_element_submodel_repo(self, submodel_id: str, submodel_element: model.SubmodelElement) -> model.SubmodelElement | None:
|
|
260
|
-
"""Creates a new submodel element.
|
|
260
|
+
"""Creates a new submodel element.
|
|
261
261
|
|
|
262
262
|
:param submodel_id: Encoded ID of the submodel to create elements for
|
|
263
263
|
:param submodel_element: Submodel element to create
|
|
@@ -267,6 +267,20 @@ class SdkWrapper:
|
|
|
267
267
|
content: dict = self._client.post_submodel_element_submodel_repo(submodel_id, sme_data)
|
|
268
268
|
return _to_object(content)
|
|
269
269
|
|
|
270
|
+
def post_submodel_element_by_path_submodel_repo(
|
|
271
|
+
self, submodel_id: str, submodel_element_path: str, submodel_element: model.SubmodelElement
|
|
272
|
+
) -> model.SubmodelElement | None:
|
|
273
|
+
"""Creates a new submodel element at a specified path within submodel elements hierarchy.
|
|
274
|
+
|
|
275
|
+
:param submodel_id: Encoded ID of the submodel to create elements for
|
|
276
|
+
:param submodel_element_path: Path within the Submodel elements hierarchy
|
|
277
|
+
:param submodel_element: The new Submodel element
|
|
278
|
+
:return: Submodel element object or None if an error occurred
|
|
279
|
+
"""
|
|
280
|
+
sme_data = _to_dict(submodel_element)
|
|
281
|
+
content: dict = self._client.post_submodel_element_by_path_submodel_repo(submodel_id, submodel_element_path, sme_data)
|
|
282
|
+
return _to_object(content)
|
|
283
|
+
|
|
270
284
|
def get_submodel_element_by_path_submodel_repo(self, submodel_id: str, submodel_element_path: str) -> model.SubmodelElement | None:
|
|
271
285
|
"""Returns a specific submodel element from the Submodel at a specified path.
|
|
272
286
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aas-http-client
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Generic python HTTP client for communication with various types of AAS servers
|
|
5
5
|
Author-email: Daniel Klein <daniel.klein@em.ag>
|
|
6
6
|
License: # :em engineering methods AG Software License
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
aas_http_client/__init__.py,sha256=bBfrdXUHvukisXIj0CcnNUHUw8_7nrdnfQRve8nM_3U,982
|
|
2
|
-
aas_http_client/client.py,sha256=
|
|
2
|
+
aas_http_client/client.py,sha256=KL1xT6ZIfjdz4EVZXEPrMyIgPbN622zetr_lr7gWW1k,35438
|
|
3
|
+
aas_http_client/classes/auth_classes.py,sha256=us1oDlBpI7R3xp2pcr9ZJ_AAaM65J-g8neq-d1M2FHw,619
|
|
3
4
|
aas_http_client/core/encoder.py,sha256=FS7P0FPakzFsGz70eRFDHQZFA_2nlKLlWIxavtnFrPg,660
|
|
4
5
|
aas_http_client/core/version_check.py,sha256=9dR0Q6jCFygH_ctj4vyrjerpHvolT87ayengZFlBWCw,708
|
|
5
|
-
aas_http_client/demo/demo_process.py,sha256=
|
|
6
|
+
aas_http_client/demo/demo_process.py,sha256=WBTdiVf1CD3qHCCIFo__JE5ljL5yuCR1DibWO_NM1HA,3960
|
|
6
7
|
aas_http_client/demo/logging_handler.py,sha256=VJtZ4u3x_LhYZQtfNck7FuXhGFZm7gid0uDhvf9GjJ8,5596
|
|
7
8
|
aas_http_client/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
9
|
aas_http_client/utilities/model_builder.py,sha256=SxAv8DJkKksykw_2gtTV2jHu-MRzevOVzspn807_7VA,4680
|
|
9
10
|
aas_http_client/utilities/sdk_tools.py,sha256=CDD0mus8jOi-irgPO6dQHulmEyu8BSG_05Mol_nirK0,2008
|
|
10
|
-
aas_http_client/wrapper/sdk_wrapper.py,sha256=
|
|
11
|
-
aas_http_client-0.4.
|
|
12
|
-
aas_http_client-0.4.
|
|
13
|
-
aas_http_client-0.4.
|
|
14
|
-
aas_http_client-0.4.
|
|
15
|
-
aas_http_client-0.4.
|
|
11
|
+
aas_http_client/wrapper/sdk_wrapper.py,sha256=GUftL_FiK7FMHhKifD-Y-zMSrmhd3fXysA-ycPxh_0s,15544
|
|
12
|
+
aas_http_client-0.4.3.dist-info/licenses/LICENSE,sha256=ayt4HY-Tjoe1Uvj47j6UdNq8mEufKcKFangurChIHxQ,5990
|
|
13
|
+
aas_http_client-0.4.3.dist-info/METADATA,sha256=aTEPdPs4Uj-Ffzny_XFuRmyCI1L70cpGEfzwfak63B0,10467
|
|
14
|
+
aas_http_client-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
aas_http_client-0.4.3.dist-info/top_level.txt,sha256=vzvoz2vjeTLwpuz-Y-eEfoQ7T3byoaKshVlFMFH5NaM,16
|
|
16
|
+
aas_http_client-0.4.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|