Skip to content

Commit dc6e77d

Browse files
authored
Add features from MX Port Leo of Factory-X project (#330)
* Bug fix: No authentification popup when API For Registry and Repository.../Connect (extended) * Add first token exchange * Add second token exchange * Return null for non-valid keys * Add third token exchange for asset fox, bug fixes * Fix compilation error * Fix typo * Token exchange: Clean up code, fix token exchange 2 * Add security token to header for POST, PUT and DELETE operations * Refactor Token exchange, add possibility to enter audience and config url in UI * Add possibility to use leo discovery servoce as Reg-of-Reg * Use well-known to get jwks and token endpoint * Try catch Well-Known Request for token server * Reg-of-Reg: Allow to load from multiple URLs for one asset id * Download of aas und submodels from registries in reg of reg: Ignore not working
1 parent 59e9724 commit dc6e77d

7 files changed

Lines changed: 510 additions & 105 deletions

File tree

src/AasxOpenidClient/AasxOpenidClient.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<PackageReference Include="IdentityModel" Version="6.0.0" />
2626
<PackageReference Include="jose-jwt" Version="4.0.1" />
2727
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
28-
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
28+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.1.2" />
2929
<PackageReference Include="System.IO.Packaging" Version="7.0.0" />
3030
<PackageReference Include="System.Text.Json" Version="9.0.2" />
3131
</ItemGroup>

src/AasxPackageExplorer/options-debug.MIHO.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
"AccessInfo": {
5454
"Method": "None" // None, Ask, Basic, CertificateStore, File, InteractiveEntry, Secret
5555
}
56+
},
57+
{
58+
"BaseAddress": "https://leo-discovery.admin-shell-io.com/api/v2/",
59+
"AccessInfo": {
60+
"Method": "None" // None, Ask, Basic, CertificateStore, File, InteractiveEntry, Secret
61+
}
5662
},
5763
{
5864
"BaseAddress": "https://aasx-server-pcf.dev.pxcio.net/",

src/AasxPackageLogic/AasxPackageLogic.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<PackageReference Include="SSharp.Net" Version="1.0.1" />
4444
<PackageReference Include="System.Data.SqlClient" Version="4.9.0" />
4545
<PackageReference Include="System.Formats.Asn1" Version="9.0.2" />
46-
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
46+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.1.2" />
4747
<PackageReference Include="System.Text.Json" Version="9.0.2" />
4848
</ItemGroup>
4949

src/AasxPackageLogic/DispEditHelperEntities.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,7 @@ public static async Task<bool> ExecuteUiForFetchOfElements(
15571557
"Error building location from fetch selection. Aborting.");
15581558
return false;
15591559
}
1560+
Options.Curr.AutoAuthenticateAsk = fetchContext.Record.AutoAuthenticate;
15601561

15611562
// more details into container options
15621563
var containerOptions = new PackageContainerHttpRepoSubset.

src/AasxPackageLogic/PackageCentral/PackageContainerHttpRepoSubset.cs

Lines changed: 151 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This source code may use other Open Source software components (see LICENSE.txt)
99

1010
using AasxIntegrationBase;
1111
using AdminShellNS;
12+
using AdminShellNS.Extensions;
1213
using AngleSharp.Dom;
1314
using AnyUi;
1415
using Extensions;
@@ -303,14 +304,14 @@ public static bool IsValidUriForRegistryAasByAssetIds(string location)
303304

304305
public static bool IsValidUriForRegOfRegAasByAssetId(string location)
305306
{
306-
var m = Regex.Match(location, @"^(http(|s))://(.*?)/registry-descriptors/([-A-Za-z0-9_]{1,999})$",
307+
var m = Regex.Match(location, @"^(http(|s))://(.*?)/(?:registry-descriptors/|companies\?asset_id=)([-A-Za-z0-9_]{1,999})$",
307308
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
308309
return m.Success;
309310
}
310311

311312
public static string IsValidAndDecodeUriForRegOfRegAasByAssetId(string location)
312313
{
313-
var m = Regex.Match(location, @"^(http(|s))://(.*?)/registry-descriptors/([-A-Za-z0-9_]{1,999})$",
314+
var m = Regex.Match(location, @"^(http(|s))://(.*?)/(?:registry-descriptors/|companies\?asset_id=)([-A-Za-z0-9_]{1,999})$",
314315
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
315316
if (!m.Success)
316317
return null;
@@ -353,7 +354,7 @@ public static Uri GetBaseUri(string location)
353354
// try an explicit search for known parts of ressources
354355
// (preserves scheme, host and leading pathes)
355356
var m = Regex.Match(location, @"^(.*?)(/shells|/submodel|/concept-description|/lookup|/description"
356-
+ "|/shell-descriptor|/submodel-descriptor|/bulk|/serialization|/package)");
357+
+ "|/shell-descriptor|/submodel-descriptor|/bulk|/serialization|/package|/registry-descriptors|/companies)");
357358
if (m.Success)
358359
return new Uri(m.Groups[1].ToString() + "/");
359360

@@ -366,6 +367,10 @@ public static Uri GetBaseUri(string location)
366367
{
367368
return new Uri(location.Substring(0, p) + "/");
368369
}
370+
else
371+
{
372+
return new Uri(location);
373+
}
369374
}
370375

371376
// go to error
@@ -732,10 +737,17 @@ public static Uri BuildUriForRegOfRegAasByAssetId(Uri baseUri, string id, bool e
732737
// access
733738
if (id?.HasContent() != true)
734739
return null;
740+
var route = "registry-descriptors/";
735741

736-
// try combine
737742
var assenc = encryptIds ? AdminShellUtil.Base64UrlEncode(id) : id;
738-
return CombineUri(baseUri, $"registry-descriptors/{assenc}");
743+
744+
if (baseUri.Host.Contains("leo-discovery"))
745+
{
746+
route = "companies";
747+
assenc = $"?asset_id={assenc}";
748+
}
749+
750+
return CombineUri(baseUri, $"{route}{assenc}");
739751
}
740752

741753
//
@@ -819,7 +831,10 @@ private static async Task<bool> FromRegistryGetAasAndSubmodels(
819831
{
820832
// strictly check IFC
821833
var aasIfc = "" + ep["interface"];
822-
if (aasIfc != "AAS-1.0")
834+
if (!(aasIfc == "AAS-1.0"
835+
|| aasIfc == "AAS-2.0"
836+
|| aasIfc == "AAS-3.0"
837+
|| aasIfc == "AAS-3.1"))
823838
continue;
824839

825840
// direct access HREF
@@ -843,8 +858,11 @@ private static async Task<bool> FromRegistryGetAasAndSubmodels(
843858
{
844859
// strictly check IFC
845860
var smIfc = "" + smep["interface"];
846-
if (smIfc != "SUBMODEL-1.0")
847-
continue;
861+
if (!(aasIfc == "SUBMODEL-1.0"
862+
|| aasIfc == "SUBMODEL-2.0"
863+
|| aasIfc == "SUBMODEL-3.0"
864+
|| aasIfc == "SUBMODEL-3.1"))
865+
continue;
848866

849867
// ok
850868
string href = smep.protocolInformation.href;
@@ -969,7 +987,7 @@ private static async Task<bool> FromRegistryGetAasAndSubmodels(
969987
return true;
970988
}
971989

972-
private static async Task<bool> FromRegOfRegGetAasAndSubmodels(
990+
private static async Task FromRegOfRegGetAasAndSubmodels(
973991
OnDemandListIdentifiable<IAssetAdministrationShell> prepAas,
974992
OnDemandListIdentifiable<ISubmodel> prepSM,
975993
ConnectExtendedRecord record,
@@ -980,82 +998,141 @@ private static async Task<bool> FromRegOfRegGetAasAndSubmodels(
980998
List<Aas.IIdentifiable> trackNewIdentifiables = null,
981999
List<Aas.IIdentifiable> trackLoadedIdentifiables = null,
9821000
Action<int, int, int, int> lambdaReportProgress = null,
983-
bool compatOldAasxServer = false)
1001+
bool compatOldAasxServer = false,
1002+
bool isLeoDiscoveryServer = false)
9841003
{
9851004
// access
9861005
if (record == null || regDescriptor == null || assetId?.HasContent() != true)
987-
return false;
1006+
return;
9881007

989-
// The format is:
990-
// {
991-
// "Url": "http://example.com/6789",
992-
// "Security": "",
993-
// "Match": "LIKE",
994-
// "Pattern": "%6789%",
995-
// "Domain": "example.com",
996-
// "Id": "xxx",
997-
// "Info": "xxx"
998-
// }
999-
// However, only Url and Id are currently useful
1000-
1001-
string regUrl = "" + regDescriptor["url"];
1002-
string regInfo = "" + regDescriptor["info"];
1003-
if (regInfo == "")
1004-
regInfo = "<Unknown>";
10051008

1006-
// valid url?
1007-
if (regUrl == "")
1008-
return false;
10091009

1010-
var basicUri = GetBaseUri(regUrl);
1011-
if (basicUri == null)
1012-
return false;
1010+
List<string> regUrls = new List<string>();
10131011

1014-
// build again a set of baseUris, but only one pattern set
1015-
var baseUris = new BaseUriDict(key: "AAS-REG", value: basicUri.ToString());
1012+
if (isLeoDiscoveryServer)
1013+
{
1014+
//See: https://leo-discovery.admin-shell-io.com/
10161015

1017-
// translate to a list of AAS-Ids ..
1018-
var uriGetListOfAids = BuildUriForRegistryAasByAssetId(baseUris.GetBaseUriForAasReg(), assetId);
1019-
if (compatOldAasxServer)
1020-
uriGetListOfAids = BuildUriForRegistryAasByAssetLinkDeprecated(baseUris.GetBaseUriForAasReg(), assetId);
1021-
var listOfAids = await PackageHttpDownloadUtil.DownloadEntityToDynamicObject(
1022-
uriGetListOfAids, runtimeOptions, allowFakeResponses);
1016+
var endpoints = regDescriptor?.endpoints;
10231017

1024-
if (listOfAids == null || !(listOfAids is JArray) || (listOfAids as JArray).Count < 1)
1018+
if (endpoints != null)
1019+
{
1020+
foreach (var endpoint in endpoints)
1021+
{
1022+
if (endpoint["interface"] == "AAS-REGISTRY-3.1"
1023+
|| endpoint["interface"] == "AAS-REGISTRY-3.0")
1024+
{
1025+
var regUrl = endpoint.protocolInformation["href"];
1026+
regUrls.Add("" + regUrl);
1027+
}
1028+
}
1029+
}
1030+
}
1031+
else
1032+
{
1033+
// The format is:
1034+
// {
1035+
// "Url": "http://example.com/6789",
1036+
// "Security": "",
1037+
// "Match": "LIKE",
1038+
// "Pattern": "%6789%",
1039+
// "Domain": "example.com",
1040+
// "Id": "xxx",
1041+
// "Info": "xxx"
1042+
// }
1043+
// However, only Url and Id are currently useful
1044+
1045+
regUrls.Add("" + regDescriptor["url"]);
1046+
}
1047+
1048+
1049+
// valid url?
1050+
if (regUrls.IsNullOrEmpty())
1051+
return;
1052+
1053+
List<Uri> basicUris = new List<Uri>();
1054+
1055+
foreach (var regUrl in regUrls)
10251056
{
1026-
runtimeOptions?.Log?.Info("Registry {0} did not translate glopbalAssetId={1} to any AAS Ids. " +
1027-
"Aborting! URi was: {2}",
1028-
basicUri, assetId, uriGetListOfAids);
1029-
return false;
1057+
var basicUri = GetBaseUri(regUrl);
1058+
if (basicUri != null)
1059+
{
1060+
basicUris.Add(basicUri);
1061+
}
1062+
}
1063+
1064+
if(basicUris.IsNullOrEmpty())
1065+
{
1066+
return;
10301067
}
10311068

1032-
// take the individual AAS ids
1033-
foreach (var aid in listOfAids)
1069+
foreach (var basicUri in basicUris)
10341070
{
1035-
// prepare receiving the descriptor
1036-
var uriGetAasDescr = BuildUriForRegistrySingleAAS(baseUris.GetBaseUriForAasReg(), aid.ToString());
1037-
var resAasDescr = await PackageHttpDownloadUtil.DownloadEntityToDynamicObject(
1038-
uriGetAasDescr, runtimeOptions, allowFakeResponses);
1071+
// build again a set of baseUris, but only one pattern set
1072+
var baseUris = new BaseUriDict(key: "AAS-REG", value: basicUri.ToString());
10391073

1040-
// have directly a single descriptor?!
1041-
if (!(resAasDescr is JObject))
1074+
// translate to a list of AAS-Ids ..
1075+
var uriGetListOfAids = BuildUriForRegistryAasByAssetId(baseUris.GetBaseUriForAasReg(), assetId);
1076+
if (compatOldAasxServer)
1077+
uriGetListOfAids = BuildUriForRegistryAasByAssetLinkDeprecated(baseUris.GetBaseUriForAasReg(), assetId);
1078+
1079+
try
10421080
{
1043-
runtimeOptions?.Log?.Info("Registry did not return a single AAS descriptor! Aborting. URI was: {0}",
1044-
uriGetAasDescr);
1045-
return false;
1046-
}
1081+
var listOfAids = await PackageHttpDownloadUtil.DownloadEntityToDynamicObject(
1082+
uriGetListOfAids, runtimeOptions, allowFakeResponses);
10471083

1048-
lambdaReportProgress?.Invoke(0, 0, 0, 1);
1084+
if (listOfAids == null || !(listOfAids is JArray) || (listOfAids as JArray).Count < 1)
1085+
{
1086+
runtimeOptions?.Log?.Info("Registry {0} did not translate globalAssetId={1} to any AAS Ids. " +
1087+
"Aborting! URi was: {2}",
1088+
basicUri, assetId, uriGetListOfAids);
1089+
}
1090+
else
1091+
{
1092+
// take the individual AAS ids
1093+
foreach (var aid in listOfAids)
1094+
{
1095+
// prepare receiving the descriptor
1096+
var uriGetAasDescr = BuildUriForRegistrySingleAAS(baseUris.GetBaseUriForAasReg(), aid.ToString());
1097+
var resAasDescr = await PackageHttpDownloadUtil.DownloadEntityToDynamicObject(
1098+
uriGetAasDescr, runtimeOptions, allowFakeResponses);
1099+
1100+
// have directly a single descriptor?!
1101+
if (!(resAasDescr is JObject))
1102+
{
1103+
runtimeOptions?.Log?.Info("Registry did not return a single AAS descriptor! Aborting. URI was: {0}",
1104+
uriGetAasDescr);
1105+
}
10491106

1050-
// refer to dedicated function
1051-
await FromRegistryGetAasAndSubmodels(
1052-
prepAas, prepSM, record, runtimeOptions, allowFakeResponses, resAasDescr,
1053-
trackNewIdentifiables, trackLoadedIdentifiables,
1054-
lambdaReportProgress: lambdaReportProgress);
1107+
lambdaReportProgress?.Invoke(0, 0, 0, 1);
1108+
1109+
try
1110+
{
1111+
// refer to dedicated function
1112+
await FromRegistryGetAasAndSubmodels(
1113+
prepAas, prepSM, record, runtimeOptions, allowFakeResponses, resAasDescr,
1114+
trackNewIdentifiables, trackLoadedIdentifiables,
1115+
lambdaReportProgress: lambdaReportProgress);
1116+
}
1117+
catch (Exception e)
1118+
{
1119+
runtimeOptions?.Log?.Info("Download aas and submodels from registry {0} failed globalAssetId={1} to any AAS Ids. " +
1120+
"Aborting! AAS id was: {2}, message was {3}",
1121+
basicUri, assetId, aid, e.Message);
1122+
}
1123+
1124+
}
1125+
}
1126+
}
1127+
catch (Exception e)
1128+
{
1129+
runtimeOptions?.Log?.Info("Download descriptors from registry {0} failed globalAssetId={1} to any AAS Ids. " +
1130+
"Aborting! URi was: {2}, message was {3}",
1131+
basicUri, assetId, uriGetListOfAids, e.Message);
1132+
}
10551133
}
10561134

1057-
// OK?
1058-
return true;
1135+
return;
10591136
}
10601137

10611138
public override async Task<bool> LoadFromSourceAsync(
@@ -1221,6 +1298,12 @@ protected static async Task<AdminShellPackageEnvBase> LoadFromSourceInternalAsyn
12211298
}
12221299
else
12231300
{
1301+
bool isFXLeoDiscoveryServer = fullItemLocation.Contains("leo-discovery");
1302+
if (isFXLeoDiscoveryServer)
1303+
{
1304+
resObj = resObj["data"];
1305+
}
1306+
12241307
foreach (var res in resObj)
12251308
{
12261309
// refer to dedicated function
@@ -1230,7 +1313,8 @@ await FromRegOfRegGetAasAndSubmodels(
12301313
trackNewIdentifiables, trackLoadedIdentifiables,
12311314
lambdaReportProgress: lambdaReportAasSm,
12321315
// TODO: check!!
1233-
compatOldAasxServer: true);
1316+
compatOldAasxServer: isFXLeoDiscoveryServer ? false : true,
1317+
isLeoDiscoveryServer : isFXLeoDiscoveryServer);
12341318
}
12351319
}
12361320
}

0 commit comments

Comments
 (0)