diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..38bece4
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,25 @@
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/.idea
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/Samples/HttpDataplane-Keycloak/HttpDataplane-Keycloak.csproj b/Samples/HttpDataplane-Keycloak/HttpDataplane-Keycloak.csproj
index c1960a5..bc691a2 100644
--- a/Samples/HttpDataplane-Keycloak/HttpDataplane-Keycloak.csproj
+++ b/Samples/HttpDataplane-Keycloak/HttpDataplane-Keycloak.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/Samples/Streaming/Consumer/Consumer.csproj b/Samples/Streaming/Consumer/Consumer.csproj
new file mode 100644
index 0000000..2da95bc
--- /dev/null
+++ b/Samples/Streaming/Consumer/Consumer.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Linux
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Streaming/Consumer/Dockerfile b/Samples/Streaming/Consumer/Dockerfile
new file mode 100644
index 0000000..97510c7
--- /dev/null
+++ b/Samples/Streaming/Consumer/Dockerfile
@@ -0,0 +1,40 @@
+# syntax=docker/dockerfile:1
+
+# Build stage
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
+WORKDIR /src
+
+# Copy everything and restore
+# (Assumes this Dockerfile sits in the project directory next to the .csproj)
+COPY . .
+
+ARG NUGET_USERNAME
+ARG NUGET_PASSWORD
+
+RUN dotnet nuget add source "https://nuget.pkg.github.com/eclipse-dataplane-core/index.json" \
+ --name dcore \
+ --username $NUGET_USERNAME \
+ --password $NUGET_PASSWORD \
+ --store-password-in-clear-text \
+ && dotnet restore Consumer.csproj \
+ && dotnet nuget remove source dcore
+
+# Publish (framework-dependent)
+RUN dotnet publish Consumer.csproj -c Release -o /app/publish --no-restore
+
+# Runtime stage
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
+WORKDIR /app
+
+# Configure ASP.NET Core to listen on port 8080 and set environment
+ENV ASPNETCORE_URLS=http://+:8080 \
+ ASPNETCORE_ENVIRONMENT=Production
+
+# Copy published output
+COPY --from=build /app/publish ./
+
+# Expose HTTP
+EXPOSE 8080
+
+# Start the app
+ENTRYPOINT ["dotnet", "./Consumer.dll"]
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Extensions.cs b/Samples/Streaming/Consumer/Extensions.cs
new file mode 100644
index 0000000..8fd15b7
--- /dev/null
+++ b/Samples/Streaming/Consumer/Extensions.cs
@@ -0,0 +1,81 @@
+using Consumer.Nats;
+using DataPlane.Sdk.Api;
+using DataPlane.Sdk.Core;
+using DataPlane.Sdk.Core.Domain.Model;
+using Microsoft.IdentityModel.Tokens;
+using static DataPlane.Sdk.Core.Data.DataFlowContextFactory;
+
+namespace Consumer;
+
+public static class Extensions
+{
+ public static void AddDataPlaneSdk(this IServiceCollection services, IConfiguration configuration)
+ {
+ // initialize and configure the DataPlaneSdk
+ var dataplaneConfig = configuration.GetSection("DataPlaneSdk");
+ var config = dataplaneConfig.Get() ?? throw new ArgumentException("Configuration invalid!");
+ var dataFlowContext = () => CreatePostgres(configuration, config.RuntimeId);
+
+
+ var sdk = new DataPlaneSdk
+ {
+ DataFlowStore = dataFlowContext,
+ RuntimeId = config.RuntimeId,
+ OnStart = dataFlow =>
+ {
+ if (dataFlow.Destination == null)
+ {
+ return StatusResult.BadRequest("DataFlow.Destination cannot be null");
+ }
+
+ var dataService = services.BuildServiceProvider().GetRequiredService();
+ dataService.Start(NatsDataAddress.Create(dataFlow.Destination)).Wait();
+ return StatusResult.Success(dataFlow);
+ },
+ OnTerminate = df => StatusResult.Success(),
+ OnSuspend = _ => StatusResult.Success(),
+ OnPrepare = f =>
+ {
+ f.IsConsumer = true;
+ f.State = DataFlowState.Prepared;
+ return StatusResult.Success(f);
+ },
+ OnComplete = _ => StatusResult.Success()
+ };
+
+ services.AddSingleton();
+
+
+ // add SDK core services
+ services.AddSdkServices(sdk, dataplaneConfig);
+
+ // Configuration for keycloak. Effectively, this sets the default authentication scheme to "KeycloakJWT",
+ // foregoing the SDK default authentication scheme and using Keycloak as the identity provider.
+ // This assumes that Keycloak is running on http://keycloak:8080, which is the default if launched with docker-compose.
+
+ var jwtSettings = configuration.GetSection("JwtSettings");
+
+ services.AddAuthentication("KeycloakJWT")
+ .AddJwtBearer("KeycloakJWT", options =>
+ {
+ // Configure Keycloak as the Identity Provider
+ options.Authority = jwtSettings["Authority"];
+ options.RequireHttpsMetadata = false; // Only for develop
+
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidIssuer = jwtSettings["Issuer"],
+ ValidateAudience = true,
+ ValidAudience = jwtSettings["Audience"],
+ ValidateIssuerSigningKey = true,
+ ValidateLifetime = true,
+ ValidateActor = false,
+ ValidateTokenReplay = true
+ };
+ });
+
+ // wire up ASP.net authorization handlers
+ services.AddSdkAuthorization();
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Nats/Constants.cs b/Samples/Streaming/Consumer/Nats/Constants.cs
new file mode 100644
index 0000000..c135755
--- /dev/null
+++ b/Samples/Streaming/Consumer/Nats/Constants.cs
@@ -0,0 +1,8 @@
+namespace Consumer.Nats;
+
+public static class Constants
+{
+ public static readonly string DataAddressType = "NatsStream";
+ public static readonly string ForwardChannelSuffix = "forward";
+ public static readonly string ReplyChannelSuffix = "reply";
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Nats/NatsDataAddress.cs b/Samples/Streaming/Consumer/Nats/NatsDataAddress.cs
new file mode 100644
index 0000000..316257d
--- /dev/null
+++ b/Samples/Streaming/Consumer/Nats/NatsDataAddress.cs
@@ -0,0 +1,91 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using DataPlane.Sdk.Core.Domain.Model;
+
+namespace Consumer.Nats;
+
+public class NatsDataAddress : DataAddress
+{
+ public NatsDataAddress() : base(Constants.DataAddressType)
+ {
+ Properties["endpointType"] = "https://example.com/natsdp/v1/nats";
+ }
+
+ public string NatsEndpoint
+ {
+ init => Properties["endpoint"] = value;
+ get => Properties["endpoint"].ToString() ?? throw new InvalidOperationException("No 'endpoint' endpointProperty found");
+ }
+
+ public string Channel
+ {
+ get
+ {
+ var property = GetEndpointProperty("channel");
+ return (property?.Value ?? null) ?? throw new InvalidOperationException("No 'channel' endpointProperty found");
+ }
+ init => StringEndpointProperty("channel", value);
+ }
+
+ public string ReplyChannel
+ {
+ init => StringEndpointProperty("replyChannel", value);
+ }
+
+ private EndpointProperty? GetEndpointProperty(string key)
+ {
+ var props = Properties["endpointProperties"];
+
+ List epp;
+ if (props is JsonElement)
+ {
+ epp = JsonSerializer.Deserialize>(props.ToString());
+ }
+ else
+ {
+ epp = props as List;
+ }
+
+
+ var property = epp?.Find(p => p.Key.Equals(key));
+ return property;
+ }
+
+ public static NatsDataAddress Create(DataAddress rawSource)
+ {
+ return new NatsDataAddress
+ {
+ Properties = rawSource.Properties,
+ Id = rawSource.Id
+ };
+ }
+
+ private void StringEndpointProperty(string key, string endpointPropertyValue)
+ {
+ if (!Properties.TryGetValue("endpointProperties", out var existing))
+ {
+ existing = new List();
+ Properties["endpointProperties"] = existing;
+ }
+
+ var epProps = existing as List;
+ epProps!.Add(new EndpointProperty
+ {
+ Key = key,
+ Type = "string",
+ Value = endpointPropertyValue
+ });
+ }
+
+ public class EndpointProperty
+ {
+ [JsonPropertyName("key")]
+ public required string Key { get; init; }
+
+ [JsonPropertyName("type")]
+ public required string Type { get; init; }
+
+ [JsonPropertyName("value")]
+ public required string Value { get; init; }
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Nats/NatsSubscriber.cs b/Samples/Streaming/Consumer/Nats/NatsSubscriber.cs
new file mode 100644
index 0000000..d73854b
--- /dev/null
+++ b/Samples/Streaming/Consumer/Nats/NatsSubscriber.cs
@@ -0,0 +1,54 @@
+using NATS.Client.Core;
+
+namespace Consumer.Nats;
+
+public class NatsSubscriber(ILogger logger)
+{
+ private static readonly IDictionary BackgroundTasks = new Dictionary();
+ private static readonly IDictionary CancellationTokens = new Dictionary();
+
+ public async Task Start(NatsDataAddress nats)
+ {
+ var channel = nats.Channel;
+ var cts = new CancellationTokenSource();
+
+ BackgroundTasks.Add(channel, Task.Run(async () =>
+ {
+ await using var conn = new NatsConnection(new NatsOpts
+ {
+ Url = nats.NatsEndpoint
+ });
+
+ while (!cts.Token.IsCancellationRequested)
+ {
+ await foreach (var mesg in conn.SubscribeAsync(channel, cancellationToken: cts.Token))
+ {
+ var data = mesg.Data;
+ logger.LogInformation("Received {Data}", data);
+ }
+ }
+ }, cts.Token));
+
+ CancellationTokens.Add(channel, cts);
+ }
+
+
+ public async Task Stop(NatsDataAddress nats)
+ {
+ var channel = nats.Channel;
+
+ if (CancellationTokens.TryGetValue(channel, out var ct))
+ {
+ await ct.CancelAsync();
+ logger.LogDebug("Stopping {Channel}", channel);
+ CancellationTokens.Remove(channel);
+ }
+
+ if (BackgroundTasks.TryGetValue(channel, out var task))
+ {
+ await task;
+ BackgroundTasks.Remove(channel);
+ logger.LogDebug("Stopped {Channel}", channel);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Program.cs b/Samples/Streaming/Consumer/Program.cs
new file mode 100644
index 0000000..9e6309a
--- /dev/null
+++ b/Samples/Streaming/Consumer/Program.cs
@@ -0,0 +1,33 @@
+using Consumer;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+builder.Services.AddControllers();
+// SDK: add all services, read configuration etc.
+builder.Services.AddDataPlaneSdk(builder.Configuration);
+
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+
+
+// Configure the HTTP request pipeline.
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
+{
+ app.MapOpenApi();
+}
+
+
+app.UseHttpsRedirection();
+
+
+app.UseAuthentication();
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Run();
\ No newline at end of file
diff --git a/Samples/Streaming/Consumer/Properties/launchSettings.json b/Samples/Streaming/Consumer/Properties/launchSettings.json
new file mode 100644
index 0000000..b8d5e1a
--- /dev/null
+++ b/Samples/Streaming/Consumer/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:8081",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Local"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "https://localhost:7118;http://localhost:5252",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Samples/Streaming/Consumer/appsettings.Local.json b/Samples/Streaming/Consumer/appsettings.Local.json
new file mode 100644
index 0000000..f074503
--- /dev/null
+++ b/Samples/Streaming/Consumer/appsettings.Local.json
@@ -0,0 +1,20 @@
+{
+ "AllowedHosts": "*",
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=localhost;Port=5432;Database=Consumer;Username=postgres;Password=postgres"
+ },
+ "JwtSettings": {
+ "Authority": "http://localhost:8088/realms/dataplane-signaling-api",
+ "Issuer": "http://keycloak:8088/realms/dataplane-signaling-api",
+ "Audience": "dataplane-signaling-api"
+ },
+ "Nats": {
+ "NatsEndpoint": "nats://localhost:4222"
+ }
+}
diff --git a/Samples/Streaming/Consumer/appsettings.json b/Samples/Streaming/Consumer/appsettings.json
new file mode 100644
index 0000000..0ae73ef
--- /dev/null
+++ b/Samples/Streaming/Consumer/appsettings.json
@@ -0,0 +1,36 @@
+{
+ "AllowedHosts": "*",
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=postgres;Port=5432;Database=Consumer;Username=postgres;Password=postgres"
+ },
+ "Database": {
+ "AutoMigrate": true
+ },
+ "DataPlaneSdk": {
+ "ControlApi": {
+ "BaseUrl": "http://localhost:8083/api/control"
+ },
+ "DataplaneId": "consumer-1",
+ "RuntimeId": "consumer-dataplane-1",
+ "AllowedSourceTypes": [
+ "test-source-type"
+ ],
+ "AllowedTransferTypes": [
+ "test-transfer-type"
+ ]
+ },
+ "Nats": {
+ "NatsEndpoint": "nats://nats:4222"
+ },
+ "JwtSettings": {
+ "Authority": "http://keycloak:8088/realms/dataplane-signaling-api",
+ "Issuer": "http://localhost:8088/realms/dataplane-signaling-api",
+ "Audience": "dataplane-signaling-api"
+ }
+}
diff --git a/Samples/Streaming/Provider/Dockerfile b/Samples/Streaming/Provider/Dockerfile
new file mode 100644
index 0000000..2e38b3a
--- /dev/null
+++ b/Samples/Streaming/Provider/Dockerfile
@@ -0,0 +1,40 @@
+# syntax=docker/dockerfile:1
+
+# Build stage
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
+WORKDIR /src
+
+# Copy everything and restore
+# (Assumes this Dockerfile sits in the project directory next to the .csproj)
+COPY . .
+
+ARG NUGET_USERNAME
+ARG NUGET_PASSWORD
+
+RUN dotnet nuget add source "https://nuget.pkg.github.com/eclipse-dataplane-core/index.json" \
+ --name dcore \
+ --username $NUGET_USERNAME \
+ --password $NUGET_PASSWORD \
+ --store-password-in-clear-text \
+ && dotnet restore Provider.csproj \
+ && dotnet nuget remove source dcore
+
+# Publish (framework-dependent)
+RUN dotnet publish Provider.csproj -c Release -o /app/publish --no-restore
+
+# Runtime stage
+FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final
+WORKDIR /app
+
+# Configure ASP.NET Core to listen on port 8080 and set environment
+ENV ASPNETCORE_URLS=http://+:8080 \
+ ASPNETCORE_ENVIRONMENT=Production
+
+# Copy published output
+COPY --from=build /app/publish ./
+
+# Expose HTTP
+EXPOSE 8080
+
+# Start the app
+ENTRYPOINT ["dotnet", "./Provider.dll"]
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Extensions.cs b/Samples/Streaming/Provider/Extensions.cs
new file mode 100644
index 0000000..06ebda5
--- /dev/null
+++ b/Samples/Streaming/Provider/Extensions.cs
@@ -0,0 +1,78 @@
+using DataPlane.Sdk.Api;
+using DataPlane.Sdk.Core;
+using DataPlane.Sdk.Core.Domain.Model;
+using Microsoft.IdentityModel.Tokens;
+using Provider.Nats;
+using Provider.Services;
+using static DataPlane.Sdk.Core.Data.DataFlowContextFactory;
+
+namespace Provider;
+
+public static class Extensions
+{
+ public static void AddDataPlaneSdk(this IServiceCollection services, IConfiguration configuration)
+ {
+ // initialize and configure the DataPlaneSdk
+ var dataplaneConfig = configuration.GetSection("DataPlaneSdk");
+ var config = dataplaneConfig.Get() ?? throw new ArgumentException("Configuration invalid!");
+ var dataFlowContext = () => CreatePostgres(configuration, config.RuntimeId);
+
+
+ var sdk = new DataPlaneSdk
+ {
+ DataFlowStore = dataFlowContext,
+ RuntimeId = config.RuntimeId,
+ OnStart = dataFlow =>
+ {
+ var dataService = services.BuildServiceProvider().GetRequiredService();
+ return dataService.ProcessStart(dataFlow);
+ },
+ OnTerminate = df =>
+ {
+ var dataService = services.BuildServiceProvider().GetRequiredService();
+ var task = dataService.ProcessTerminate(df);
+ task.Wait();
+ return task.Result;
+ },
+ OnSuspend = _ => StatusResult.Success(),
+ OnPrepare = _ => throw new NotImplementedException("Cannot call /prepare on a provider data plane"),
+ OnComplete = _ => StatusResult.Success()
+ };
+
+ services.AddSingleton();
+ services.AddSingleton();
+
+
+ // add SDK core services
+ services.AddSdkServices(sdk, dataplaneConfig);
+
+ // Configuration for keycloak. Effectively, this sets the default authentication scheme to "KeycloakJWT",
+ // foregoing the SDK default authentication scheme and using Keycloak as the identity provider.
+ // This assumes that Keycloak is running on http://keycloak:8080, which is the default if launched with docker-compose.
+
+ var jwtSettings = configuration.GetSection("JwtSettings");
+
+ services.AddAuthentication("KeycloakJWT")
+ .AddJwtBearer("KeycloakJWT", options =>
+ {
+ // Configure Keycloak as the Identity Provider
+ options.Authority = jwtSettings["Authority"];
+ options.RequireHttpsMetadata = false; // Only for develop
+
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidIssuer = jwtSettings["Issuer"],
+ ValidateAudience = true,
+ ValidAudience = jwtSettings["Audience"],
+ ValidateIssuerSigningKey = true,
+ ValidateLifetime = true,
+ ValidateActor = false,
+ ValidateTokenReplay = true
+ };
+ });
+
+ // wire up ASP.net authorization handlers
+ services.AddSdkAuthorization();
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Nats/Constants.cs b/Samples/Streaming/Provider/Nats/Constants.cs
new file mode 100644
index 0000000..ade0520
--- /dev/null
+++ b/Samples/Streaming/Provider/Nats/Constants.cs
@@ -0,0 +1,8 @@
+namespace Provider.Nats;
+
+public static class Constants
+{
+ public static readonly string DataAddressType = "NatsStream";
+ public static readonly string ForwardChannelSuffix = "forward";
+ public static readonly string ReplyChannelSuffix = "reply";
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Nats/INatsPublisherService.cs b/Samples/Streaming/Provider/Nats/INatsPublisherService.cs
new file mode 100644
index 0000000..e1054d9
--- /dev/null
+++ b/Samples/Streaming/Provider/Nats/INatsPublisherService.cs
@@ -0,0 +1,7 @@
+namespace Provider.Nats;
+
+public interface INatsPublisherService
+{
+ void Start(string channel);
+ Task StopAsync(string channel);
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Nats/NatsDataAddress.cs b/Samples/Streaming/Provider/Nats/NatsDataAddress.cs
new file mode 100644
index 0000000..be203bc
--- /dev/null
+++ b/Samples/Streaming/Provider/Nats/NatsDataAddress.cs
@@ -0,0 +1,91 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using DataPlane.Sdk.Core.Domain.Model;
+
+namespace Provider.Nats;
+
+public class NatsDataAddress : DataAddress
+{
+ public NatsDataAddress() : base(Constants.DataAddressType)
+ {
+ Properties["endpointType"] = "https://example.com/natsdp/v1/nats";
+ }
+
+ public string NatsEndpoint
+ {
+ init => Properties["endpoint"] = value;
+ get => Properties["endpoint"] as string ?? throw new InvalidOperationException("No 'endpoint' endpointProperty found");
+ }
+
+ public string Channel
+ {
+ get
+ {
+ var property = GetEndpointProperty("channel");
+ return (property?.Value ?? null) ?? throw new InvalidOperationException("No 'channel' endpointProperty found");
+ }
+ init => StringEndpointProperty("channel", value);
+ }
+
+ public string ReplyChannel
+ {
+ init => StringEndpointProperty("replyChannel", value);
+ }
+
+ private EndpointProperty? GetEndpointProperty(string key)
+ {
+ var props = Properties["endpointProperties"];
+
+ List epp;
+ if (props is JsonElement)
+ {
+ epp = JsonSerializer.Deserialize>(props.ToString());
+ }
+ else
+ {
+ epp = props as List;
+ }
+
+
+ var property = epp?.Find(p => p.Key.Equals(key));
+ return property;
+ }
+
+ public static NatsDataAddress Create(DataAddress rawSource)
+ {
+ return new NatsDataAddress
+ {
+ Properties = rawSource.Properties,
+ Id = rawSource.Id
+ };
+ }
+
+ private void StringEndpointProperty(string key, string endpointPropertyValue)
+ {
+ if (!Properties.TryGetValue("endpointProperties", out var existing))
+ {
+ existing = new List();
+ Properties["endpointProperties"] = existing;
+ }
+
+ var epProps = existing as List;
+ epProps!.Add(new EndpointProperty
+ {
+ Key = key,
+ Type = "string",
+ Value = endpointPropertyValue
+ });
+ }
+
+ public class EndpointProperty
+ {
+ [JsonPropertyName("key")]
+ public required string Key { get; init; }
+
+ [JsonPropertyName("type")]
+ public required string Type { get; init; }
+
+ [JsonPropertyName("value")]
+ public required string Value { get; init; }
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Nats/NatsOptions.cs b/Samples/Streaming/Provider/Nats/NatsOptions.cs
new file mode 100644
index 0000000..6c7400e
--- /dev/null
+++ b/Samples/Streaming/Provider/Nats/NatsOptions.cs
@@ -0,0 +1,6 @@
+namespace Provider.Nats;
+
+public class NatsOptions
+{
+ public required string NatsEndpoint { get; set; }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Nats/NatsPublisherService.cs b/Samples/Streaming/Provider/Nats/NatsPublisherService.cs
new file mode 100644
index 0000000..6d35219
--- /dev/null
+++ b/Samples/Streaming/Provider/Nats/NatsPublisherService.cs
@@ -0,0 +1,63 @@
+using System.Text.Json;
+using Microsoft.Extensions.Options;
+using NATS.Client.Core;
+
+namespace Provider.Nats;
+
+public class NatsPublisherService(ILogger logger, IOptions options) : INatsPublisherService
+{
+ private static readonly IDictionary BackgroundTasks = new Dictionary();
+ private static readonly IDictionary CancellationTokenSource = new Dictionary();
+
+ public void Start(string channel)
+ {
+ var ct = new CancellationTokenSource();
+ CancellationTokenSource.Add(channel, ct);
+
+ BackgroundTasks.Add(channel, Task.Run(async () =>
+ {
+ await using var nats = new NatsConnection(new NatsOpts
+ {
+ Url = options.Value.NatsEndpoint
+ });
+
+ var num = 0;
+ while (!ct.Token.IsCancellationRequested)
+ {
+ try
+ {
+ var eventData = new { data = $"Event {num++}", num };
+ var json = JsonSerializer.Serialize(eventData);
+ await nats.PublishAsync(channel, json, cancellationToken: ct.Token);
+ logger.LogInformation("Publish {Json}", json);
+ await Task.Delay(2000, ct.Token);
+ }
+ catch (OperationCanceledException)
+ {
+ break;
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "Error publishing to NATS");
+ }
+ }
+ }, ct.Token));
+ }
+
+ public async Task StopAsync(string channel)
+ {
+ if (CancellationTokenSource.TryGetValue(channel, out var cts))
+ {
+ logger.LogDebug("Stopping {Channel}", channel);
+ await cts.CancelAsync();
+ CancellationTokenSource.Remove(channel);
+ }
+
+ if (BackgroundTasks.TryGetValue(channel, out var task))
+ {
+ await task;
+ logger.LogDebug("Stopped {Channel}", channel);
+ BackgroundTasks.Remove(channel);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Program.cs b/Samples/Streaming/Provider/Program.cs
new file mode 100644
index 0000000..17b1bfb
--- /dev/null
+++ b/Samples/Streaming/Provider/Program.cs
@@ -0,0 +1,35 @@
+using Provider;
+using Provider.Nats;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+builder.Services.AddControllers();
+// SDK: add all services, read configuration etc.
+builder.Services.Configure(builder.Configuration.GetSection("Nats"));
+builder.Services.AddDataPlaneSdk(builder.Configuration);
+
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+
+
+// Configure the HTTP request pipeline.
+var app = builder.Build();
+
+if (app.Environment.IsDevelopment())
+{
+ app.MapOpenApi();
+}
+
+
+app.UseHttpsRedirection();
+
+
+app.UseAuthentication();
+app.UseAuthorization();
+
+app.MapControllers();
+
+app.Run();
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Properties/launchSettings.json b/Samples/Streaming/Provider/Properties/launchSettings.json
new file mode 100644
index 0000000..3763145
--- /dev/null
+++ b/Samples/Streaming/Provider/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:8080",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Local"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "https://localhost:7118;http://localhost:5252",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Samples/Streaming/Provider/Provider.csproj b/Samples/Streaming/Provider/Provider.csproj
new file mode 100644
index 0000000..44e4c07
--- /dev/null
+++ b/Samples/Streaming/Provider/Provider.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net9.0
+ enable
+ enable
+ Linux
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/Streaming/Provider/Resources/Postman/dps.postman_collection.json b/Samples/Streaming/Provider/Resources/Postman/dps.postman_collection.json
new file mode 100644
index 0000000..6b8d3e3
--- /dev/null
+++ b/Samples/Streaming/Provider/Resources/Postman/dps.postman_collection.json
@@ -0,0 +1,109 @@
+{
+ "info": {
+ "_postman_id": "ad21ada1-e71d-45b9-a5f5-9264972b8d62",
+ "name": "Dataplane Signaling API - Samples",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "647585",
+ "_collection_link": "https://galactic-star-228409.postman.co/workspace/Dataplane-work~d820e7a7-8273-4d79-986e-96754a31f467/collection/647585-ad21ada1-e71d-45b9-a5f5-9264972b8d62?action=share&source=collection_link&creator=647585"
+ },
+ "item": [
+ {
+ "name": "HttpDataplane",
+ "item": []
+ }
+ ],
+ "auth": {
+ "type": "oauth2",
+ "oauth2": [
+ {
+ "key": "accessTokenUrl",
+ "value": "http://localhost:8088/realms/dataplane-signaling-api/protocol/openid-connect/token",
+ "type": "string"
+ },
+ {
+ "key": "tokenName",
+ "value": "dps-token",
+ "type": "string"
+ },
+ {
+ "key": "clientId",
+ "value": "{{CLIENT_ID}}",
+ "type": "string"
+ },
+ {
+ "key": "client_authentication",
+ "value": "body",
+ "type": "string"
+ },
+ {
+ "key": "clientSecret",
+ "value": "{{CLIENT_SECRET}}",
+ "type": "string"
+ },
+ {
+ "key": "grant_type",
+ "value": "client_credentials",
+ "type": "string"
+ },
+ {
+ "key": "addTokenTo",
+ "value": "header",
+ "type": "string"
+ }
+ ]
+ },
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {},
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {},
+ "exec": [
+ ""
+ ]
+ }
+ }
+ ],
+ "variable": [
+ {
+ "key": "CLIENT_SECRET",
+ "value": ""
+ },
+ {
+ "key": "CLIENT_ID",
+ "value": ""
+ },
+ {
+ "key": "PARTICIPANT_ID",
+ "value": ""
+ },
+ {
+ "key": "DATAFLOW_ID",
+ "value": ""
+ },
+ {
+ "key": "DATAPLANE_HOST",
+ "value": ""
+ },
+ {
+ "key": "PUBLIC_URL",
+ "value": ""
+ },
+ {
+ "key": "API_KEY",
+ "value": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Services/DataService.cs b/Samples/Streaming/Provider/Services/DataService.cs
new file mode 100644
index 0000000..7d11e3a
--- /dev/null
+++ b/Samples/Streaming/Provider/Services/DataService.cs
@@ -0,0 +1,51 @@
+using DataPlane.Sdk.Core.Domain.Model;
+using Microsoft.Extensions.Options;
+using Provider.Nats;
+
+namespace Provider.Services;
+
+public class DataService(IOptions options, INatsPublisherService publisherService) : IDataService
+{
+ public Task IsPermitted(string apiKey, DataFlow dataFlow)
+ {
+ return Task.FromResult(dataFlow.Destination?.Properties["token"] as string == apiKey);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public StatusResult ProcessStart(DataFlow flow)
+ {
+ // create a data address for the NATS endpoint
+ var channel = flow.Id + "." + Constants.ForwardChannelSuffix;
+ var replyChannel = flow.Id + "." + Constants.ReplyChannelSuffix;
+
+
+ var dataAddress = new NatsDataAddress
+ {
+ NatsEndpoint = options.Value.NatsEndpoint,
+ Channel = channel,
+ ReplyChannel = replyChannel
+ };
+
+ flow.Destination = dataAddress;
+
+ // start publishing events
+ publisherService.Start(channel);
+
+ return StatusResult.Success(flow);
+ }
+
+ public async Task ProcessTerminate(DataFlow dataFlow)
+ {
+ if (dataFlow.Destination != null)
+ {
+ var nda = NatsDataAddress.Create(dataFlow.Destination);
+ await publisherService.StopAsync(nda.Channel);
+ return StatusResult.Success();
+ }
+
+ return StatusResult.Failed(new StatusFailure { Message = "DataAddress is not a valid NATS DataAddress", Reason = FailureReason.InternalError });
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/Services/IDataService.cs b/Samples/Streaming/Provider/Services/IDataService.cs
new file mode 100644
index 0000000..9986d2e
--- /dev/null
+++ b/Samples/Streaming/Provider/Services/IDataService.cs
@@ -0,0 +1,28 @@
+using DataPlane.Sdk.Core.Domain.Model;
+
+namespace Provider.Services;
+
+///
+/// Represents a service for managing data flows, permissions, and public endpoint configuration.
+///
+public interface IDataService
+{
+ ///
+ /// Determines whether the specified API key has permission to access the given data flow.
+ ///
+ /// The API key to be checked for permissions.
+ /// The data flow object for which the permission is being verified.
+ ///
+ /// Returns a task representing the asynchronous operation, containing a boolean value that indicates whether the
+ /// permission is granted.
+ ///
+ Task IsPermitted(string apiKey, DataFlow dataFlow);
+
+ ///
+ ///
+ ///
+ ///
+ StatusResult ProcessStart(DataFlow flow);
+
+ Task ProcessTerminate(DataFlow dataFlow);
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Provider/appsettings.Local.json b/Samples/Streaming/Provider/appsettings.Local.json
new file mode 100644
index 0000000..d205a4a
--- /dev/null
+++ b/Samples/Streaming/Provider/appsettings.Local.json
@@ -0,0 +1,20 @@
+{
+ "AllowedHosts": "*",
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=localhost;Port=5432;Database=Provider;Username=postgres;Password=postgres"
+ },
+ "JwtSettings": {
+ "Authority": "http://localhost:8088/realms/dataplane-signaling-api",
+ "Issuer": "http://keycloak:8088/realms/dataplane-signaling-api",
+ "Audience": "dataplane-signaling-api"
+ },
+ "Nats": {
+ "NatsEndpoint": "nats://localhost:4222"
+ }
+}
diff --git a/Samples/Streaming/Provider/appsettings.json b/Samples/Streaming/Provider/appsettings.json
new file mode 100644
index 0000000..2610a9c
--- /dev/null
+++ b/Samples/Streaming/Provider/appsettings.json
@@ -0,0 +1,36 @@
+{
+ "AllowedHosts": "*",
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=postgres;Port=5432;Database=Provider;Username=postgres;Password=postgres"
+ },
+ "Database": {
+ "AutoMigrate": true
+ },
+ "DataPlaneSdk": {
+ "ControlApi": {
+ "BaseUrl": "http://localhost:8083/api/control"
+ },
+ "DataplaneId": "provider-1",
+ "RuntimeId": "provider-dataplane-1",
+ "AllowedSourceTypes": [
+ "test-source-type"
+ ],
+ "AllowedTransferTypes": [
+ "test-transfer-type"
+ ]
+ },
+ "Nats": {
+ "NatsEndpoint": "nats://nats:4222"
+ },
+ "JwtSettings": {
+ "Authority": "http://keycloak:8088/realms/dataplane-signaling-api",
+ "Issuer": "http://localhost:8088/realms/dataplane-signaling-api",
+ "Audience": "dataplane-signaling-api"
+ }
+}
diff --git a/Samples/Streaming/Resources/Keycloak/dataplane-api-realm.json b/Samples/Streaming/Resources/Keycloak/dataplane-api-realm.json
new file mode 100644
index 0000000..be8bcaa
--- /dev/null
+++ b/Samples/Streaming/Resources/Keycloak/dataplane-api-realm.json
@@ -0,0 +1,2553 @@
+{
+ "id": "5d1d7e90-1961-49ad-83dc-7c1c0c406acb",
+ "realm": "dataplane-signaling-api",
+ "notBefore": 0,
+ "defaultSignatureAlgorithm": "RS256",
+ "revokeRefreshToken": false,
+ "refreshTokenMaxReuse": 0,
+ "accessTokenLifespan": 300,
+ "accessTokenLifespanForImplicitFlow": 900,
+ "ssoSessionIdleTimeout": 1800,
+ "ssoSessionMaxLifespan": 36000,
+ "ssoSessionIdleTimeoutRememberMe": 0,
+ "ssoSessionMaxLifespanRememberMe": 0,
+ "offlineSessionIdleTimeout": 2592000,
+ "offlineSessionMaxLifespanEnabled": false,
+ "offlineSessionMaxLifespan": 5184000,
+ "clientSessionIdleTimeout": 0,
+ "clientSessionMaxLifespan": 0,
+ "clientOfflineSessionIdleTimeout": 0,
+ "clientOfflineSessionMaxLifespan": 0,
+ "accessCodeLifespan": 60,
+ "accessCodeLifespanUserAction": 300,
+ "accessCodeLifespanLogin": 1800,
+ "actionTokenGeneratedByAdminLifespan": 43200,
+ "actionTokenGeneratedByUserLifespan": 300,
+ "oauth2DeviceCodeLifespan": 600,
+ "oauth2DevicePollingInterval": 5,
+ "enabled": true,
+ "sslRequired": "NONE",
+ "registrationAllowed": false,
+ "registrationEmailAsUsername": false,
+ "rememberMe": false,
+ "verifyEmail": false,
+ "loginWithEmailAllowed": true,
+ "duplicateEmailsAllowed": false,
+ "resetPasswordAllowed": false,
+ "editUsernameAllowed": false,
+ "bruteForceProtected": false,
+ "permanentLockout": false,
+ "maxTemporaryLockouts": 0,
+ "bruteForceStrategy": "MULTIPLE",
+ "maxFailureWaitSeconds": 900,
+ "minimumQuickLoginWaitSeconds": 60,
+ "waitIncrementSeconds": 60,
+ "quickLoginCheckMilliSeconds": 1000,
+ "maxDeltaTimeSeconds": 43200,
+ "failureFactor": 30,
+ "roles": {
+ "realm": [
+ {
+ "id": "fbf281d1-19f3-4048-bcf1-4418f68ab92a",
+ "name": "default-roles-dataplane-signaling-api",
+ "description": "${role_default-roles}",
+ "composite": true,
+ "composites": {
+ "realm": [
+ "offline_access",
+ "uma_authorization"
+ ],
+ "client": {
+ "account": [
+ "view-profile",
+ "manage-account"
+ ]
+ }
+ },
+ "clientRole": false,
+ "containerId": "5d1d7e90-1961-49ad-83dc-7c1c0c406acb",
+ "attributes": {}
+ },
+ {
+ "id": "415ce9bd-ba22-4c92-bff6-b74bd890681e",
+ "name": "offline_access",
+ "description": "${role_offline-access}",
+ "composite": false,
+ "clientRole": false,
+ "containerId": "5d1d7e90-1961-49ad-83dc-7c1c0c406acb",
+ "attributes": {}
+ },
+ {
+ "id": "06e979b6-df99-4ef6-91cf-8e6f8cfa0e70",
+ "name": "uma_authorization",
+ "description": "${role_uma_authorization}",
+ "composite": false,
+ "clientRole": false,
+ "containerId": "5d1d7e90-1961-49ad-83dc-7c1c0c406acb",
+ "attributes": {}
+ }
+ ],
+ "client": {
+ "realm-management": [
+ {
+ "id": "b3c3a5da-b11d-42bc-8fc5-b3d07c0f20d8",
+ "name": "view-clients",
+ "description": "${role_view-clients}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": [
+ "query-clients"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "9009f3f4-a171-4864-b545-71ba9ab88ec0",
+ "name": "view-users",
+ "description": "${role_view-users}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": [
+ "query-groups",
+ "query-users"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "23bf933a-42f7-4926-91af-58a26aa0d4ad",
+ "name": "query-groups",
+ "description": "${role_query-groups}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "e8a4364c-50a7-42fe-8736-8cdc7d266235",
+ "name": "create-client",
+ "description": "${role_create-client}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "274103e4-24ad-42e1-b75d-dc7eaab4b56e",
+ "name": "manage-authorization",
+ "description": "${role_manage-authorization}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "b83766d4-0fbe-40fa-ba4d-547d98650ddc",
+ "name": "view-identity-providers",
+ "description": "${role_view-identity-providers}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "ea0f0df2-ebae-4e08-a22a-bfc3ed381d52",
+ "name": "realm-admin",
+ "description": "${role_realm-admin}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": [
+ "view-clients",
+ "view-users",
+ "query-groups",
+ "create-client",
+ "manage-authorization",
+ "view-identity-providers",
+ "view-events",
+ "manage-clients",
+ "manage-realm",
+ "query-users",
+ "query-clients",
+ "impersonation",
+ "view-authorization",
+ "manage-identity-providers",
+ "manage-users",
+ "query-realms",
+ "manage-events",
+ "view-realm"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "0528515b-e60f-4f42-acc6-cf7394ac0d3d",
+ "name": "view-events",
+ "description": "${role_view-events}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "014d8cfe-fe48-4181-85b8-990899d02d2b",
+ "name": "manage-clients",
+ "description": "${role_manage-clients}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "6818751f-b287-4b56-9a16-5370b784163e",
+ "name": "manage-realm",
+ "description": "${role_manage-realm}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "c1039afd-adb3-4fff-b738-ac1ae72f0c14",
+ "name": "query-users",
+ "description": "${role_query-users}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "c44b128a-91da-4937-80d6-7cf2ada2caf1",
+ "name": "query-clients",
+ "description": "${role_query-clients}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "430c75c9-bde4-49e6-b8e1-f06e25d04bb2",
+ "name": "impersonation",
+ "description": "${role_impersonation}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "e52c3adf-c5fe-48ee-9e5a-945059091392",
+ "name": "view-authorization",
+ "description": "${role_view-authorization}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "0b66b24f-e035-4726-b7a3-4ea99fcebd0c",
+ "name": "manage-identity-providers",
+ "description": "${role_manage-identity-providers}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "43d0363c-0908-4b14-9b52-4f6909b64a7d",
+ "name": "manage-users",
+ "description": "${role_manage-users}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "b327aaae-8545-40ac-9938-7422048eb336",
+ "name": "query-realms",
+ "description": "${role_query-realms}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "845d32e5-3faa-4054-a6b5-d9dce02f68a2",
+ "name": "manage-events",
+ "description": "${role_manage-events}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ },
+ {
+ "id": "66a14daa-97b0-4087-95dd-937131f1f8f7",
+ "name": "view-realm",
+ "description": "${role_view-realm}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "681c27c6-e429-4c38-9862-709fc873851d",
+ "attributes": {}
+ }
+ ],
+ "dataplane-signaling-api": [
+ {
+ "id": "785871d1-d882-4ae3-9a91-7ea6d8c4eb48",
+ "name": "uma_protection",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "cc2c64b6-f0f6-4a91-b877-9dd45f88e5a0",
+ "attributes": {}
+ }
+ ],
+ "security-admin-console": [],
+ "admin-cli": [],
+ "account-console": [],
+ "broker": [
+ {
+ "id": "bdf2113c-3072-4f63-b682-7de5b958a134",
+ "name": "read-token",
+ "description": "${role_read-token}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "8581b577-e99b-4f67-a09c-a5ddf4a112fd",
+ "attributes": {}
+ }
+ ],
+ "account": [
+ {
+ "id": "bc97e926-36f8-4bbb-8fc5-f50019fd58a4",
+ "name": "view-groups",
+ "description": "${role_view-groups}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "e144fa17-49d7-4ca3-a6f5-ea6aace7eb36",
+ "name": "view-profile",
+ "description": "${role_view-profile}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "aa45a0b7-b596-4afc-8583-0ad92c8bc4f3",
+ "name": "view-applications",
+ "description": "${role_view-applications}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "8dc76cc2-6dd4-4b2a-87b0-4825dccb3dd3",
+ "name": "manage-account-links",
+ "description": "${role_manage-account-links}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "790982e6-6c50-4c82-b92d-24e978ba8e91",
+ "name": "manage-account",
+ "description": "${role_manage-account}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "account": [
+ "manage-account-links"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "6386e24c-5e1c-4be8-9729-889a0cf1de79",
+ "name": "manage-consent",
+ "description": "${role_manage-consent}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "account": [
+ "view-consent"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "d99fa073-7a39-4832-bf2e-d36565c0a165",
+ "name": "delete-account",
+ "description": "${role_delete-account}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ },
+ {
+ "id": "fc0c7190-b21f-4e3a-9ada-d18377458950",
+ "name": "view-consent",
+ "description": "${role_view-consent}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "attributes": {}
+ }
+ ]
+ }
+ },
+ "groups": [],
+ "defaultRole": {
+ "id": "fbf281d1-19f3-4048-bcf1-4418f68ab92a",
+ "name": "default-roles-dataplane-signaling-api",
+ "description": "${role_default-roles}",
+ "composite": true,
+ "clientRole": false,
+ "containerId": "5d1d7e90-1961-49ad-83dc-7c1c0c406acb"
+ },
+ "requiredCredentials": [
+ "password"
+ ],
+ "otpPolicyType": "totp",
+ "otpPolicyAlgorithm": "HmacSHA1",
+ "otpPolicyInitialCounter": 0,
+ "otpPolicyDigits": 6,
+ "otpPolicyLookAheadWindow": 1,
+ "otpPolicyPeriod": 30,
+ "otpPolicyCodeReusable": false,
+ "otpSupportedApplications": [
+ "totpAppFreeOTPName",
+ "totpAppGoogleName",
+ "totpAppMicrosoftAuthenticatorName"
+ ],
+ "localizationTexts": {},
+ "webAuthnPolicyRpEntityName": "keycloak",
+ "webAuthnPolicySignatureAlgorithms": [
+ "ES256",
+ "RS256"
+ ],
+ "webAuthnPolicyRpId": "",
+ "webAuthnPolicyAttestationConveyancePreference": "not specified",
+ "webAuthnPolicyAuthenticatorAttachment": "not specified",
+ "webAuthnPolicyRequireResidentKey": "not specified",
+ "webAuthnPolicyUserVerificationRequirement": "not specified",
+ "webAuthnPolicyCreateTimeout": 0,
+ "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
+ "webAuthnPolicyAcceptableAaguids": [],
+ "webAuthnPolicyExtraOrigins": [],
+ "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
+ "webAuthnPolicyPasswordlessSignatureAlgorithms": [
+ "ES256",
+ "RS256"
+ ],
+ "webAuthnPolicyPasswordlessRpId": "",
+ "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
+ "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
+ "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
+ "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
+ "webAuthnPolicyPasswordlessCreateTimeout": 0,
+ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
+ "webAuthnPolicyPasswordlessAcceptableAaguids": [],
+ "webAuthnPolicyPasswordlessExtraOrigins": [],
+ "users": [
+ {
+ "id": "4363900f-3451-48a1-b2eb-b92dbc47677e",
+ "username": "service-account-dataplane-signaling-api",
+ "emailVerified": false,
+ "createdTimestamp": 1756373486363,
+ "enabled": true,
+ "totp": false,
+ "serviceAccountClientId": "dataplane-signaling-api",
+ "disableableCredentialTypes": [],
+ "requiredActions": [],
+ "realmRoles": [
+ "default-roles-dataplane-signaling-api"
+ ],
+ "clientRoles": {
+ "dataplane-signaling-api": [
+ "uma_protection"
+ ]
+ },
+ "notBefore": 0,
+ "groups": []
+ }
+ ],
+ "scopeMappings": [
+ {
+ "clientScope": "offline_access",
+ "roles": [
+ "offline_access"
+ ]
+ }
+ ],
+ "clientScopeMappings": {
+ "account": [
+ {
+ "client": "account-console",
+ "roles": [
+ "manage-account",
+ "view-groups"
+ ]
+ }
+ ]
+ },
+ "clients": [
+ {
+ "id": "a7aede34-ff0a-455b-9fc0-80f6bd55aa61",
+ "clientId": "account",
+ "name": "${client_account}",
+ "rootUrl": "${authBaseUrl}",
+ "baseUrl": "/realms/dataplane-signaling-api/account/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "/realms/dataplane-signaling-api/account/*"
+ ],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "false",
+ "post.logout.redirect.uris": "+"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "8cc5d84a-fe7b-494e-84ac-e0014f12d243",
+ "clientId": "account-console",
+ "name": "${client_account-console}",
+ "rootUrl": "${authBaseUrl}",
+ "baseUrl": "/realms/dataplane-signaling-api/account/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "/realms/dataplane-signaling-api/account/*"
+ ],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "false",
+ "post.logout.redirect.uris": "+",
+ "pkce.code.challenge.method": "S256"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "protocolMappers": [
+ {
+ "id": "2d80cc17-73ca-415d-a1bc-14993e449425",
+ "name": "audience resolve",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-resolve-mapper",
+ "consentRequired": false,
+ "config": {}
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "69374220-beb4-41a5-803e-edb15d80ba5a",
+ "clientId": "admin-cli",
+ "name": "${client_admin-cli}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "false",
+ "client.use.lightweight.access.token.enabled": "true"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "8581b577-e99b-4f67-a09c-a5ddf4a112fd",
+ "clientId": "broker",
+ "name": "${client_broker}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": true,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "true"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "cc2c64b6-f0f6-4a91-b877-9dd45f88e5a0",
+ "clientId": "dataplane-signaling-api",
+ "name": "",
+ "description": "",
+ "rootUrl": "",
+ "adminUrl": "",
+ "baseUrl": "",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "mpoTntIrYjsBqhqo0xuzqRUtCWQCWjG3",
+ "redirectUris": [
+ "/*"
+ ],
+ "webOrigins": [
+ "/*"
+ ],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": true,
+ "authorizationServicesEnabled": true,
+ "publicClient": false,
+ "frontchannelLogout": true,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "false",
+ "oidc.ciba.grant.enabled": "false",
+ "client.secret.creation.time": "1751356476",
+ "backchannel.logout.session.required": "true",
+ "standard.token.exchange.enabled": "false",
+ "oauth2.device.authorization.grant.enabled": "false",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": -1,
+ "protocolMappers": [
+ {
+ "id": "c24d369e-f3dc-440f-b85b-afdd72dac3d9",
+ "name": "audience mapper",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-mapper",
+ "consentRequired": false,
+ "config": {
+ "id.token.claim": "false",
+ "lightweight.claim": "false",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "included.custom.audience": "dataplane-signaling-api",
+ "userinfo.token.claim": "false"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "service_account",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "681c27c6-e429-4c38-9862-709fc873851d",
+ "clientId": "realm-management",
+ "name": "${client_realm-management}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": true,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "true"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "05f13fb8-9f23-4399-8574-6824d786cd88",
+ "clientId": "security-admin-console",
+ "name": "${client_security-admin-console}",
+ "rootUrl": "${authAdminUrl}",
+ "baseUrl": "/admin/dataplane-signaling-api/console/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "redirectUris": [
+ "/admin/dataplane-signaling-api/console/*"
+ ],
+ "webOrigins": [
+ "+"
+ ],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "realm_client": "false",
+ "client.use.lightweight.access.token.enabled": "true",
+ "post.logout.redirect.uris": "+",
+ "pkce.code.challenge.method": "S256"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": 0,
+ "protocolMappers": [
+ {
+ "id": "d34c1faa-5bc9-4d6d-86e7-3474ef20e61b",
+ "name": "locale",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "locale",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "locale",
+ "jsonType.label": "String"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "acr",
+ "roles",
+ "profile",
+ "basic",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "organization",
+ "microprofile-jwt"
+ ]
+ }
+ ],
+ "clientScopes": [
+ {
+ "id": "f7241ee8-571a-4d9b-9549-659d62799aa4",
+ "name": "web-origins",
+ "description": "OpenID Connect scope for add allowed web origins to the access token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "consent.screen.text": "",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "d9f774d5-b344-4253-b2be-b3f9f8c7e3cb",
+ "name": "allowed web origins",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-allowed-origins-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "access.token.claim": "true"
+ }
+ }
+ ]
+ },
+ {
+ "id": "e86e245a-f543-4f72-bb6c-d1cf84ed7cea",
+ "name": "address",
+ "description": "OpenID Connect built-in scope: address",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "consent.screen.text": "${addressScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "4bd47b6f-ee53-48ba-9b84-1865e44f1063",
+ "name": "address",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-address-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute.formatted": "formatted",
+ "user.attribute.country": "country",
+ "introspection.token.claim": "true",
+ "user.attribute.postal_code": "postal_code",
+ "userinfo.token.claim": "true",
+ "user.attribute.street": "street",
+ "id.token.claim": "true",
+ "user.attribute.region": "region",
+ "access.token.claim": "true",
+ "user.attribute.locality": "locality"
+ }
+ }
+ ]
+ },
+ {
+ "id": "a6b5fe2c-f4e3-4fc6-ab0d-a3ac57bf6519",
+ "name": "service_account",
+ "description": "Specific scope for a client enabled for service accounts",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "6936ac03-a67c-497a-9fb3-8f49487e9805",
+ "name": "Client IP Address",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usersessionmodel-note-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.session.note": "clientAddress",
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "clientAddress",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "208c538c-db34-46d3-b0ec-bcad1617b995",
+ "name": "Client ID",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usersessionmodel-note-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.session.note": "client_id",
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "client_id",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "d28762ec-7971-47af-95e7-a417085e21d9",
+ "name": "Client Host",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usersessionmodel-note-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.session.note": "clientHost",
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "clientHost",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "a0f91a77-ef05-4540-abaf-6ba183d9ff8e",
+ "name": "sub-clientid-scope",
+ "description": "",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "true",
+ "gui.order": "",
+ "consent.screen.text": ""
+ },
+ "protocolMappers": [
+ {
+ "id": "57d52720-4f23-495f-b58b-e18921cba698",
+ "name": "client-id-to-sub",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-hardcoded-claim-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "claim.value": "4363900f-3451-48a1-b2eb-b92dbc47677e",
+ "userinfo.token.claim": "true",
+ "id.token.claim": "true",
+ "lightweight.claim": "false",
+ "access.token.claim": "true",
+ "claim.name": "sub",
+ "jsonType.label": "String",
+ "access.tokenResponse.claim": "false"
+ }
+ }
+ ]
+ },
+ {
+ "id": "6b5625a1-2c54-4bd5-a36e-40ee80c14de9",
+ "name": "profile",
+ "description": "OpenID Connect built-in scope: profile",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "consent.screen.text": "${profileScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "ea214f9b-39ed-4f52-bd76-0b35e98c5035",
+ "name": "locale",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "locale",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "locale",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "43aee751-f7ab-46dc-93ea-416d986ecd96",
+ "name": "zoneinfo",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "zoneinfo",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "zoneinfo",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "7dc65ce0-c429-4263-b242-07788a9bd1ba",
+ "name": "family name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "lastName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "family_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "1365ec38-c83a-4ab4-8b52-b0d3b88cb50e",
+ "name": "website",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "website",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "website",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "c8826c96-e0dc-4bc4-b0a1-99a5d4a06dfb",
+ "name": "nickname",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "nickname",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "nickname",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "6e64c656-d74e-49c5-aff6-813c554efde5",
+ "name": "picture",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "picture",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "picture",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "50a63f8d-cf95-4bd3-a323-8178d74231f4",
+ "name": "middle name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "middleName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "middle_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "e95063d1-d852-4697-83cc-0dae94f8422b",
+ "name": "updated at",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "updatedAt",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "updated_at",
+ "jsonType.label": "long"
+ }
+ },
+ {
+ "id": "f454b80f-382a-4ea8-8370-5f16c2eebe1a",
+ "name": "profile",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "profile",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "profile",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "a7cbcd6b-1dd2-45db-8bb8-e6f7b64e071b",
+ "name": "gender",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "gender",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "gender",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "23dd6e5f-6c8e-4883-bff8-8848be743adf",
+ "name": "birthdate",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "birthdate",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "birthdate",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "f4be685e-5ec5-4448-b4dc-af00d4830d43",
+ "name": "full name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-full-name-mapper",
+ "consentRequired": false,
+ "config": {
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "userinfo.token.claim": "true"
+ }
+ },
+ {
+ "id": "21176d65-b342-4f21-9b4e-72b75bdd4422",
+ "name": "given name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "firstName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "given_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "cf9092e6-b2ae-4e1b-bc76-97a22e862b4a",
+ "name": "username",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "username",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "preferred_username",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "52d0366c-f197-4cdf-a060-5b2fed56f05f",
+ "name": "basic",
+ "description": "OpenID Connect scope for add all basic claims to the token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "7484a288-b5aa-4ad5-979d-13fb48894a5b",
+ "name": "sub",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-sub-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "access.token.claim": "true"
+ }
+ },
+ {
+ "id": "28bfdba4-6599-4f53-9d29-7a431c4fe105",
+ "name": "auth_time",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usersessionmodel-note-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.session.note": "AUTH_TIME",
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "auth_time",
+ "jsonType.label": "long"
+ }
+ }
+ ]
+ },
+ {
+ "id": "303d73e7-f8de-4092-879a-04192020153b",
+ "name": "saml_organization",
+ "description": "Organization Membership",
+ "protocol": "saml",
+ "attributes": {
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "1b1680fb-3fd6-40a1-9c4b-4ac3aea1f08d",
+ "name": "organization",
+ "protocol": "saml",
+ "protocolMapper": "saml-organization-membership-mapper",
+ "consentRequired": false,
+ "config": {}
+ }
+ ]
+ },
+ {
+ "id": "11622d4f-a665-4364-ab2e-d459c1f787e7",
+ "name": "microprofile-jwt",
+ "description": "Microprofile - JWT built-in scope",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "b555408c-59a6-4f63-a354-c48a9d61dd57",
+ "name": "upn",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "username",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "upn",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "82746c3f-5674-4876-b4ad-9a69e8db2223",
+ "name": "groups",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-realm-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "multivalued": "true",
+ "user.attribute": "foo",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "groups",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "ebe8d3e9-9320-4cc3-92ff-fb2735d8b0e1",
+ "name": "organization",
+ "description": "Additional claims about the organization a subject belongs to",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "consent.screen.text": "${organizationScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "cc50de7f-9dd2-4e02-8026-100e1b9f14f2",
+ "name": "organization",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-organization-membership-mapper",
+ "consentRequired": false,
+ "config": {
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "organization",
+ "jsonType.label": "String",
+ "multivalued": "true"
+ }
+ }
+ ]
+ },
+ {
+ "id": "540e11a8-0f9f-43c7-b437-55434fb3b295",
+ "name": "roles",
+ "description": "OpenID Connect scope for add user roles to the access token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "consent.screen.text": "${rolesScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "5aee1dca-2127-40b3-b821-5885eb1eccd9",
+ "name": "realm roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-realm-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute": "foo",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "realm_access.roles",
+ "jsonType.label": "String",
+ "multivalued": "true"
+ }
+ },
+ {
+ "id": "3388ee40-df0e-49f8-828e-a09d4cd301eb",
+ "name": "audience resolve",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-resolve-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "access.token.claim": "true"
+ }
+ },
+ {
+ "id": "5c6a1763-73b6-4202-8862-43bbdcf81814",
+ "name": "client roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-client-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute": "foo",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "resource_access.${client_id}.roles",
+ "jsonType.label": "String",
+ "multivalued": "true"
+ }
+ }
+ ]
+ },
+ {
+ "id": "d6a27161-c68d-437f-9356-70c667ca54a1",
+ "name": "offline_access",
+ "description": "OpenID Connect built-in scope: offline_access",
+ "protocol": "openid-connect",
+ "attributes": {
+ "consent.screen.text": "${offlineAccessScopeConsentText}",
+ "display.on.consent.screen": "true"
+ }
+ },
+ {
+ "id": "e5bc9a75-67f3-4cd7-a0a9-a3d5869bc678",
+ "name": "acr",
+ "description": "OpenID Connect scope for add acr (authentication context class reference) to the token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "65d172e9-6fd9-4017-89e6-d0187e1329a7",
+ "name": "acr loa level",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-acr-mapper",
+ "consentRequired": false,
+ "config": {
+ "id.token.claim": "true",
+ "introspection.token.claim": "true",
+ "access.token.claim": "true"
+ }
+ }
+ ]
+ },
+ {
+ "id": "7f2a85ad-b039-442d-b0ab-736b4b329268",
+ "name": "phone",
+ "description": "OpenID Connect built-in scope: phone",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "consent.screen.text": "${phoneScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "ab984d8e-f002-4e51-80d9-3333cba9d34d",
+ "name": "phone number verified",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "phoneNumberVerified",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "phone_number_verified",
+ "jsonType.label": "boolean"
+ }
+ },
+ {
+ "id": "5c9340e5-1737-4a4d-88f5-af3243e8a932",
+ "name": "phone number",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "phoneNumber",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "phone_number",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "f440bb0a-6802-4327-9ff8-59306beecc53",
+ "name": "role_list",
+ "description": "SAML role list",
+ "protocol": "saml",
+ "attributes": {
+ "consent.screen.text": "${samlRoleListScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "8b182426-4dfa-42ea-913e-5a863ea868af",
+ "name": "role list",
+ "protocol": "saml",
+ "protocolMapper": "saml-role-list-mapper",
+ "consentRequired": false,
+ "config": {
+ "single": "false",
+ "attribute.nameformat": "Basic",
+ "attribute.name": "Role"
+ }
+ }
+ ]
+ },
+ {
+ "id": "8b65c105-fd98-41e5-8573-1a4f9629fcff",
+ "name": "email",
+ "description": "OpenID Connect built-in scope: email",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "consent.screen.text": "${emailScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "4286bfd1-f709-4329-b9fe-e400773c44cd",
+ "name": "email verified",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "emailVerified",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "email_verified",
+ "jsonType.label": "boolean"
+ }
+ },
+ {
+ "id": "cea71b50-ac2f-49d3-8cf7-8bad3a32b992",
+ "name": "email",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "introspection.token.claim": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "email",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "email",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ }
+ ],
+ "defaultDefaultClientScopes": [
+ "role_list",
+ "saml_organization",
+ "profile",
+ "email",
+ "roles",
+ "web-origins",
+ "acr",
+ "basic"
+ ],
+ "defaultOptionalClientScopes": [
+ "offline_access",
+ "address",
+ "phone",
+ "microprofile-jwt",
+ "organization"
+ ],
+ "browserSecurityHeaders": {
+ "contentSecurityPolicyReportOnly": "",
+ "xContentTypeOptions": "nosniff",
+ "referrerPolicy": "no-referrer",
+ "xRobotsTag": "none",
+ "xFrameOptions": "SAMEORIGIN",
+ "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+ "strictTransportSecurity": "max-age=31536000; includeSubDomains"
+ },
+ "smtpServer": {},
+ "eventsEnabled": false,
+ "eventsListeners": [
+ "jboss-logging"
+ ],
+ "enabledEventTypes": [],
+ "adminEventsEnabled": false,
+ "adminEventsDetailsEnabled": false,
+ "identityProviders": [],
+ "identityProviderMappers": [],
+ "components": {
+ "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
+ {
+ "id": "c3e4b6dc-af5b-4298-bbe7-47795b47542d",
+ "name": "Trusted Hosts",
+ "providerId": "trusted-hosts",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "host-sending-registration-request-must-match": [
+ "true"
+ ],
+ "client-uris-must-match": [
+ "true"
+ ]
+ }
+ },
+ {
+ "id": "b21ea286-879b-42ac-8233-65ebd03dcafb",
+ "name": "Consent Required",
+ "providerId": "consent-required",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {}
+ },
+ {
+ "id": "1d15c63f-4132-4afa-9d9a-a6f698e2781b",
+ "name": "Allowed Protocol Mapper Types",
+ "providerId": "allowed-protocol-mappers",
+ "subType": "authenticated",
+ "subComponents": {},
+ "config": {
+ "allowed-protocol-mapper-types": [
+ "saml-role-list-mapper",
+ "oidc-sha256-pairwise-sub-mapper",
+ "oidc-address-mapper",
+ "oidc-usermodel-attribute-mapper",
+ "oidc-full-name-mapper",
+ "oidc-usermodel-property-mapper",
+ "saml-user-attribute-mapper",
+ "saml-user-property-mapper"
+ ]
+ }
+ },
+ {
+ "id": "659d9881-2437-4d23-9bfc-b2c58e543fdf",
+ "name": "Allowed Protocol Mapper Types",
+ "providerId": "allowed-protocol-mappers",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "allowed-protocol-mapper-types": [
+ "oidc-full-name-mapper",
+ "oidc-usermodel-property-mapper",
+ "oidc-sha256-pairwise-sub-mapper",
+ "saml-user-property-mapper",
+ "saml-user-attribute-mapper",
+ "oidc-address-mapper",
+ "oidc-usermodel-attribute-mapper",
+ "saml-role-list-mapper"
+ ]
+ }
+ },
+ {
+ "id": "4e57c4bc-a48b-4c4a-ac0f-033af8ec5193",
+ "name": "Full Scope Disabled",
+ "providerId": "scope",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {}
+ },
+ {
+ "id": "bb178118-fed2-4163-a431-e36ffd1dd72a",
+ "name": "Max Clients Limit",
+ "providerId": "max-clients",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "max-clients": [
+ "200"
+ ]
+ }
+ },
+ {
+ "id": "7ac7bf14-f181-4913-80b1-a672c33dafc4",
+ "name": "Allowed Client Scopes",
+ "providerId": "allowed-client-templates",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "allow-default-scopes": [
+ "true"
+ ]
+ }
+ },
+ {
+ "id": "4cb5d288-0f7a-4597-9272-9822243a6507",
+ "name": "Allowed Client Scopes",
+ "providerId": "allowed-client-templates",
+ "subType": "authenticated",
+ "subComponents": {},
+ "config": {
+ "allow-default-scopes": [
+ "true"
+ ]
+ }
+ }
+ ],
+ "org.keycloak.keys.KeyProvider": [
+ {
+ "id": "23a38bd4-901e-4922-ad7d-9f913cfbb6a3",
+ "name": "rsa-generated",
+ "providerId": "rsa-generated",
+ "subComponents": {},
+ "config": {
+ "priority": [
+ "100"
+ ]
+ }
+ },
+ {
+ "id": "ae79441c-d444-47f9-a3fb-a4570e8c0bfe",
+ "name": "rsa-enc-generated",
+ "providerId": "rsa-enc-generated",
+ "subComponents": {},
+ "config": {
+ "priority": [
+ "100"
+ ],
+ "algorithm": [
+ "RSA-OAEP"
+ ]
+ }
+ },
+ {
+ "id": "812c12b2-f1c0-41be-a184-9db0db6f73a2",
+ "name": "aes-generated",
+ "providerId": "aes-generated",
+ "subComponents": {},
+ "config": {
+ "priority": [
+ "100"
+ ]
+ }
+ },
+ {
+ "id": "2007f44d-fb3d-4ce6-b7f5-e7a48def705c",
+ "name": "hmac-generated-hs512",
+ "providerId": "hmac-generated",
+ "subComponents": {},
+ "config": {
+ "priority": [
+ "100"
+ ],
+ "algorithm": [
+ "HS512"
+ ]
+ }
+ }
+ ]
+ },
+ "internationalizationEnabled": false,
+ "supportedLocales": [],
+ "authenticationFlows": [
+ {
+ "id": "40e877dd-4b50-4be9-898e-20224d64da8c",
+ "alias": "Account verification options",
+ "description": "Method with which to verity the existing account",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-email-verification",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "Verify Existing Account by Re-authentication",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "27d92516-ad33-48a9-8e8d-eeeb5618552b",
+ "alias": "Browser - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "auth-otp-form",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "4743da93-d772-4c69-a5a8-2c3f7a17c161",
+ "alias": "Browser - Conditional Organization",
+ "description": "Flow to determine if the organization identity-first login is to be used",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "organization",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "9acb8ad1-4326-465e-8658-038a9e8403b7",
+ "alias": "Direct Grant - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "direct-grant-validate-otp",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "23f43398-8df6-4045-8602-dbeaa97635d2",
+ "alias": "First Broker Login - Conditional Organization",
+ "description": "Flow to determine if the authenticator that adds organization members is to be used",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "idp-add-organization-member",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "793d9754-edb6-4ecf-a772-accf047b701d",
+ "alias": "First broker login - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "auth-otp-form",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "bb4ed01c-323c-42a7-8c3f-a51a521017c7",
+ "alias": "Handle Existing Account",
+ "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-confirm-link",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "Account verification options",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "9e307086-9642-4b8c-b9b9-c10801c911c0",
+ "alias": "Organization",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 10,
+ "autheticatorFlow": true,
+ "flowAlias": "Browser - Conditional Organization",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "f0aa3fac-1029-47a2-89e1-b251de47b07f",
+ "alias": "Reset - Conditional OTP",
+ "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "reset-otp",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "216b281f-f3c5-49c0-8212-0fcbc1cd0eea",
+ "alias": "User creation or linking",
+ "description": "Flow for the existing/non-existing user alternatives",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticatorConfig": "create unique user config",
+ "authenticator": "idp-create-user-if-unique",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "Handle Existing Account",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "5f981e15-6f9a-434a-980f-2002d3f7cf98",
+ "alias": "Verify Existing Account by Re-authentication",
+ "description": "Reauthentication of existing account",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-username-password-form",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "First broker login - Conditional OTP",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "04a37523-5837-4b0c-8799-6e08af277814",
+ "alias": "browser",
+ "description": "Browser based authentication",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "auth-cookie",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "auth-spnego",
+ "authenticatorFlow": false,
+ "requirement": "DISABLED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "identity-provider-redirector",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 25,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "ALTERNATIVE",
+ "priority": 26,
+ "autheticatorFlow": true,
+ "flowAlias": "Organization",
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "ALTERNATIVE",
+ "priority": 30,
+ "autheticatorFlow": true,
+ "flowAlias": "forms",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "9ea5ee33-be35-49fa-b10d-1322e1e6538c",
+ "alias": "clients",
+ "description": "Base authentication for clients",
+ "providerId": "client-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "client-secret",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "client-jwt",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "client-secret-jwt",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 30,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "client-x509",
+ "authenticatorFlow": false,
+ "requirement": "ALTERNATIVE",
+ "priority": 40,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "70165b4a-34c7-4c4d-85aa-56442cc01d08",
+ "alias": "direct grant",
+ "description": "OpenID Connect Resource Owner Grant",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "direct-grant-validate-username",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "direct-grant-validate-password",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 30,
+ "autheticatorFlow": true,
+ "flowAlias": "Direct Grant - Conditional OTP",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "5acbfb24-530c-40d6-89ab-1a8175b111dd",
+ "alias": "docker auth",
+ "description": "Used by Docker clients to authenticate against the IDP",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "docker-http-basic-authenticator",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "85aa471e-104c-4b94-85af-24b93620bfbc",
+ "alias": "first broker login",
+ "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticatorConfig": "review profile config",
+ "authenticator": "idp-review-profile",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "User creation or linking",
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 50,
+ "autheticatorFlow": true,
+ "flowAlias": "First Broker Login - Conditional Organization",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "8cdf50fc-9e15-4739-9837-6aad51e23d1d",
+ "alias": "forms",
+ "description": "Username, password, otp and other auth forms.",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "auth-username-password-form",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 20,
+ "autheticatorFlow": true,
+ "flowAlias": "Browser - Conditional OTP",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "bbf5be69-f0d6-4204-8878-7371a2addb50",
+ "alias": "registration",
+ "description": "Registration flow",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "registration-page-form",
+ "authenticatorFlow": true,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": true,
+ "flowAlias": "registration form",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "f6fc4443-8c44-4736-87a2-357e81e8fda7",
+ "alias": "registration form",
+ "description": "Registration form",
+ "providerId": "form-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "registration-user-creation",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "registration-password-action",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 50,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "registration-recaptcha-action",
+ "authenticatorFlow": false,
+ "requirement": "DISABLED",
+ "priority": 60,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "registration-terms-and-conditions",
+ "authenticatorFlow": false,
+ "requirement": "DISABLED",
+ "priority": 70,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "e1aac4d3-7482-420c-b2cc-87fd01ec7f60",
+ "alias": "reset credentials",
+ "description": "Reset credentials for a user if they forgot their password or something",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "reset-credentials-choose-user",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "reset-credential-email",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticator": "reset-password",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 30,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ },
+ {
+ "authenticatorFlow": true,
+ "requirement": "CONDITIONAL",
+ "priority": 40,
+ "autheticatorFlow": true,
+ "flowAlias": "Reset - Conditional OTP",
+ "userSetupAllowed": false
+ }
+ ]
+ },
+ {
+ "id": "19b83646-bb26-447a-9f91-9b9914744174",
+ "alias": "saml ecp",
+ "description": "SAML ECP Profile Authentication Flow",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "http-basic-authenticator",
+ "authenticatorFlow": false,
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "autheticatorFlow": false,
+ "userSetupAllowed": false
+ }
+ ]
+ }
+ ],
+ "authenticatorConfig": [
+ {
+ "id": "9bf41a41-e73e-48f8-935b-205ea7b39922",
+ "alias": "create unique user config",
+ "config": {
+ "require.password.update.after.registration": "false"
+ }
+ },
+ {
+ "id": "14e18262-b5e1-4743-b5da-e2c48a55b8ce",
+ "alias": "review profile config",
+ "config": {
+ "update.profile.on.first.login": "missing"
+ }
+ }
+ ],
+ "requiredActions": [
+ {
+ "alias": "CONFIGURE_TOTP",
+ "name": "Configure OTP",
+ "providerId": "CONFIGURE_TOTP",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 10,
+ "config": {}
+ },
+ {
+ "alias": "TERMS_AND_CONDITIONS",
+ "name": "Terms and Conditions",
+ "providerId": "TERMS_AND_CONDITIONS",
+ "enabled": false,
+ "defaultAction": false,
+ "priority": 20,
+ "config": {}
+ },
+ {
+ "alias": "UPDATE_PASSWORD",
+ "name": "Update Password",
+ "providerId": "UPDATE_PASSWORD",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 30,
+ "config": {}
+ },
+ {
+ "alias": "UPDATE_PROFILE",
+ "name": "Update Profile",
+ "providerId": "UPDATE_PROFILE",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 40,
+ "config": {}
+ },
+ {
+ "alias": "VERIFY_EMAIL",
+ "name": "Verify Email",
+ "providerId": "VERIFY_EMAIL",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 50,
+ "config": {}
+ },
+ {
+ "alias": "delete_account",
+ "name": "Delete Account",
+ "providerId": "delete_account",
+ "enabled": false,
+ "defaultAction": false,
+ "priority": 60,
+ "config": {}
+ },
+ {
+ "alias": "webauthn-register",
+ "name": "Webauthn Register",
+ "providerId": "webauthn-register",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 70,
+ "config": {}
+ },
+ {
+ "alias": "webauthn-register-passwordless",
+ "name": "Webauthn Register Passwordless",
+ "providerId": "webauthn-register-passwordless",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 80,
+ "config": {}
+ },
+ {
+ "alias": "VERIFY_PROFILE",
+ "name": "Verify Profile",
+ "providerId": "VERIFY_PROFILE",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 90,
+ "config": {}
+ },
+ {
+ "alias": "delete_credential",
+ "name": "Delete Credential",
+ "providerId": "delete_credential",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 100,
+ "config": {}
+ },
+ {
+ "alias": "update_user_locale",
+ "name": "Update User Locale",
+ "providerId": "update_user_locale",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 1000,
+ "config": {}
+ }
+ ],
+ "browserFlow": "browser",
+ "registrationFlow": "registration",
+ "directGrantFlow": "direct grant",
+ "resetCredentialsFlow": "reset credentials",
+ "clientAuthenticationFlow": "clients",
+ "dockerAuthenticationFlow": "docker auth",
+ "firstBrokerLoginFlow": "first broker login",
+ "attributes": {
+ "cibaBackchannelTokenDeliveryMode": "poll",
+ "cibaExpiresIn": "120",
+ "cibaAuthRequestedUserHint": "login_hint",
+ "oauth2DeviceCodeLifespan": "600",
+ "oauth2DevicePollingInterval": "5",
+ "parRequestUriLifespan": "60",
+ "cibaInterval": "5",
+ "realmReusableOtpCode": "false"
+ },
+ "keycloakVersion": "26.2.5",
+ "userManagedAccessAllowed": false,
+ "organizationsEnabled": false,
+ "verifiableCredentialsEnabled": false,
+ "adminPermissionsEnabled": false,
+ "clientProfiles": {
+ "profiles": []
+ },
+ "clientPolicies": {
+ "policies": []
+ }
+}
\ No newline at end of file
diff --git a/Samples/Streaming/Resources/Postman/StreamingPull.postman_collection.json b/Samples/Streaming/Resources/Postman/StreamingPull.postman_collection.json
new file mode 100644
index 0000000..eabf6dc
--- /dev/null
+++ b/Samples/Streaming/Resources/Postman/StreamingPull.postman_collection.json
@@ -0,0 +1,342 @@
+{
+ "info": {
+ "_postman_id": "84fd9da2-29f2-405d-9f51-f28fdf4c532b",
+ "name": "Streaming Pull",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "647585",
+ "_collection_link": "https://galactic-star-228409.postman.co/workspace/Dataplane-work~d820e7a7-8273-4d79-986e-96754a31f467/collection/647585-84fd9da2-29f2-405d-9f51-f28fdf4c532b?action=share&source=collection_link&creator=647585"
+ },
+ "item": [
+ {
+ "name": "Consumer - Prepare",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"processId\": \"{{DATAFLOW_ID}}\",\n \"datasetId\": \"test-asset\",\n \"participantId\": \"{{PARTICIPANT_ID}}\",\n \"agreementId\": \"test-agreement\",\n \"transferType\": {\n \"flowType\": \"pull\",\n \"destinationType\": \"NatsStream\"\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "http://localhost:8081/api/v1/{{PARTICIPANT_ID}}/dataflows/prepare",
+ "protocol": "http",
+ "host": [
+ "localhost"
+ ],
+ "port": "8081",
+ "path": [
+ "api",
+ "v1",
+ "{{PARTICIPANT_ID}}",
+ "dataflows",
+ "prepare"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Provider - Start Dataflow",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"processId\": \"{{DATAFLOW_ID}}\",\n \"datasetId\": \"test-asset\",\n \"participantId\": \"{{PARTICIPANT_ID}}\",\n \"agreementId\": \"test-agreement\",\n \"dataAddress\": {\n \"@type\": \"DataAddress\",\n \"properties\":{\n \n }\n },\n \"transferType\": {\n \"flowType\": \"pull\",\n \"destinationType\": \"NatsStream\"\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{DATAPLANE_HOST}}/api/v1/{{PARTICIPANT_ID}}/dataflows/start",
+ "host": [
+ "{{DATAPLANE_HOST}}"
+ ],
+ "path": [
+ "api",
+ "v1",
+ "{{PARTICIPANT_ID}}",
+ "dataflows",
+ "start"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Consumer - Notify Started",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "if (pm.response.code < 300 && pm.response.code >= 200) {",
+ " const responseJson = pm.response.json();",
+ " pm.expect(responseJson).to.have.property('dataAddress');",
+ " pm.expect(responseJson.dataAddress).to.have.property('properties');",
+ " pm.expect(responseJson.dataAddress.properties).to.have.property('url');",
+ " pm.expect(responseJson.dataAddress.properties.url).to.exist;",
+ "",
+ " const url = responseJson.dataAddress.properties.url;",
+ " pm.collectionVariables.set(\"PUBLIC_URL\", url);",
+ "",
+ " pm.expect(responseJson.dataAddress.properties).to.have.property('token');",
+ " const token = responseJson.dataAddress.properties.token;",
+ " pm.collectionVariables.set(\"API_KEY\", token);",
+ "}",
+ "",
+ "pm.test(\"Status code is >=200 and <300\", function () {",
+ " pm.expect(pm.response.code < 300 && pm.response.code >= 200).to.be.true",
+ "});",
+ "pm.test(\"Public URL is set\", function(){",
+ " pm.expect(pm.collectionVariables.get(\"PUBLIC_URL\")).not.to.be.undefined",
+ "})",
+ "",
+ "",
+ "pm.test(\"API is set\", function(){",
+ " pm.expect(pm.collectionVariables.get(\"API_KEY\")).not.to.be.undefined",
+ "})",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"processId\": \"{{DATAFLOW_ID}}\",\n \"datasetId\": \"test-asset\",\n \"participantId\": \"{{PARTICIPANT_ID}}\",\n \"agreementId\": \"test-agreement\",\n \"dataAddress\": {\n \"@type\": \"HttpData\",\n \"properties\":{\n \"baseUrl\": \"https://jsonplaceholder.typicode.com/comments/22\"\n }\n },\n \"transferType\": {\n \"flowType\": \"pull\",\n \"destinationType\": \"HttpData\"\n }\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{DATAPLANE_HOST}}/api/v1/{{PARTICIPANT_ID}}/dataflows/{{CONSUMER_DATAFLOW_ID}}//started",
+ "host": [
+ "{{DATAPLANE_HOST}}"
+ ],
+ "path": [
+ "api",
+ "v1",
+ "{{PARTICIPANT_ID}}",
+ "dataflows",
+ "{{CONSUMER_DATAFLOW_ID}}",
+ "",
+ "started"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Access Public API",
+ "request": {
+ "auth": {
+ "type": "apikey",
+ "apikey": [
+ {
+ "key": "value",
+ "value": "{{API_KEY}}",
+ "type": "string"
+ },
+ {
+ "key": "key",
+ "value": "x-api-key",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{PUBLIC_URL}}",
+ "host": [
+ "{{PUBLIC_URL}}"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Complete Dataflow",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{DATAPLANE_HOST}}/api/v1/{{PARTICIPANT_ID}}/dataflows/{{DATAFLOW_ID}}/completed",
+ "host": [
+ "{{DATAPLANE_HOST}}"
+ ],
+ "path": [
+ "api",
+ "v1",
+ "{{PARTICIPANT_ID}}",
+ "dataflows",
+ "{{DATAFLOW_ID}}",
+ "completed"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Terminate Dataflow",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {},
+ "requests": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\n \"reason\": \"done\"\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{DATAPLANE_HOST}}/api/v1/{{PARTICIPANT_ID}}/dataflows/{{DATAFLOW_ID}}/terminate",
+ "host": [
+ "{{DATAPLANE_HOST}}"
+ ],
+ "path": [
+ "api",
+ "v1",
+ "{{PARTICIPANT_ID}}",
+ "dataflows",
+ "{{DATAFLOW_ID}}",
+ "terminate"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Samples/Streaming/docker-compose.yaml b/Samples/Streaming/docker-compose.yaml
new file mode 100644
index 0000000..6c4a029
--- /dev/null
+++ b/Samples/Streaming/docker-compose.yaml
@@ -0,0 +1,84 @@
+services:
+
+ provider-dataplane:
+ build:
+ context: ./Provider
+ dockerfile: Dockerfile
+ args:
+ NUGET_USERNAME: ${NUGET_USERNAME}
+ NUGET_PASSWORD: ${NUGET_PASSWORD}
+
+ ports:
+ - "8080:8080"
+ depends_on:
+ postgres:
+ condition: service_healthy
+ nats:
+ condition: service_started
+ networks:
+ - sample-network
+
+ consumer-dataplane:
+ build:
+ context: ./Consumer
+ dockerfile: Dockerfile
+ args:
+ NUGET_USERNAME: ${NUGET_USERNAME}
+ NUGET_PASSWORD: ${NUGET_PASSWORD}
+
+ ports:
+ - "8081:8080"
+ depends_on:
+ postgres:
+ condition: service_healthy
+ nats:
+ condition: service_started
+ networks:
+ - sample-network
+
+ postgres:
+ image: postgres:17-alpine
+ environment:
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ - POSTGRES_DB=SdkApi
+ ports:
+ - "5432:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ healthcheck:
+ test: [ "CMD-SHELL", "pg_isready -U postgres -d SdkApi" ]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+ networks:
+ - sample-network
+
+ keycloak:
+ image: quay.io/keycloak/keycloak:latest
+ environment:
+ KC_BOOTSTRAP_ADMIN_USERNAME: admin
+ KC_BOOTSTRAP_ADMIN_PASSWORD: admin
+ KC_HEALTH_ENABLED: "true"
+ KC_LOG_LEVEL: info
+ command: [ "start-dev", "--http-port", "8088", "--import-realm" ]
+ ports:
+ - "8088:8088"
+ networks:
+ - sample-network
+ volumes:
+ - ./Resources/Keycloak/dataplane-api-realm.json:/opt/keycloak/data/import/realm-export.json
+
+ nats:
+ image: nats:latest
+ ports:
+ - "4222:4222"
+ networks:
+ - sample-network
+
+volumes:
+ postgres_data:
+
+networks:
+ sample-network:
+ driver: bridge
diff --git a/compose.yaml b/compose.yaml
deleted file mode 100644
index 323351b..0000000
--- a/compose.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-services:
- sdk.example:
- image: sdk.example
- build:
- context: .
- dockerfile: Sdk.Example/Dockerfile
- environment:
- - DOTNET_ENVIRONMENT=test # contains configuration for docker compose setup
- depends_on:
- controlplane:
- condition: service_healthy
- postgres:
- condition: service_healthy
- links:
- - postgres
- - controlplane
-
-
-
- postgres:
- image: postgres:15
- environment:
- POSTGRES_USER: postgres
- POSTGRES_PASSWORD: postgres
- POSTGRES_DB: SdkApi
- ports:
- - "15432:5432"
- healthcheck:
- test: [ "CMD-SHELL", "pg_isready -U postgres -d SdkApi" ]
- interval: 10s
- timeout: 5s
- retries: 5
-
- controlplane:
- image: "mvd-controlplane"
- volumes:
- - ./Sdk.Example/res/configuration.properties:/app/configuration.properties
- - ./Sdk.Example/res/deployment/assets/participants/participants.local.json:/app/deployment/assets/participants/participants.local.json
-
- healthcheck:
- test: [ "CMD", "curl", "-f", "http://localhost:8080/check/readiness" ]
- interval: 11s
- timeout: 5s
- retries: 5
diff --git a/dataplane-sdk-dotnet.sln b/dataplane-sdk-dotnet.sln
index b1b46db..4c3313b 100644
--- a/dataplane-sdk-dotnet.sln
+++ b/dataplane-sdk-dotnet.sln
@@ -1,62 +1,150 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Api", "DataPlane.Sdk.Api\DataPlane.Sdk.Api.csproj", "{0E3D4901-133A-46D3-B1CB-7400C65BED32}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Core", "DataPlane.Sdk.Core\DataPlane.Sdk.Core.csproj", "{8B194066-A67B-44D9-945F-88A4EC1EBEBF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Core.Test", "DataPlane.Sdk.Core.Test\DataPlane.Sdk.Core.Test.csproj", "{C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A4B4E17A-8E91-45A0-BD5B-70EA9CA1B76D}"
- ProjectSection(SolutionItems) = preProject
- compose.yaml = compose.yaml
- EndProjectSection
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Api.Test", "DataPlane.Sdk.Api.Test\DataPlane.Sdk.Api.Test.csproj", "{C95272D3-3046-4C26-A422-C19EC45C7800}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{32055AC6-C4BE-4B7C-A829-F268AB12E577}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpDataplane-Keycloak", "Samples\HttpDataplane-Keycloak\HttpDataplane-Keycloak.csproj", "{534284F6-8E17-4774-95FA-7E133AF346F7}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Test.Utils", "DataPlane.Sdk.Test.Utils\DataPlane.Sdk.Test.Utils.csproj", "{391E2C8C-7806-40CC-A847-2ECD25FE73CC}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|Any CPU.Build.0 = Release|Any CPU
- {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|Any CPU.Build.0 = Release|Any CPU
- {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|Any CPU.Build.0 = Release|Any CPU
- {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|Any CPU.Build.0 = Release|Any CPU
- {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|Any CPU.Build.0 = Release|Any CPU
- {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {534284F6-8E17-4774-95FA-7E133AF346F7} = {32055AC6-C4BE-4B7C-A829-F268AB12E577}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Api", "DataPlane.Sdk.Api\DataPlane.Sdk.Api.csproj", "{0E3D4901-133A-46D3-B1CB-7400C65BED32}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Core", "DataPlane.Sdk.Core\DataPlane.Sdk.Core.csproj", "{8B194066-A67B-44D9-945F-88A4EC1EBEBF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Core.Test", "DataPlane.Sdk.Core.Test\DataPlane.Sdk.Core.Test.csproj", "{C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A4B4E17A-8E91-45A0-BD5B-70EA9CA1B76D}"
+ ProjectSection(SolutionItems) = preProject
+ compose.yaml = compose.yaml
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Api.Test", "DataPlane.Sdk.Api.Test\DataPlane.Sdk.Api.Test.csproj", "{C95272D3-3046-4C26-A422-C19EC45C7800}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{32055AC6-C4BE-4B7C-A829-F268AB12E577}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpDataplane-Keycloak", "Samples\HttpDataplane-Keycloak\HttpDataplane-Keycloak.csproj", "{534284F6-8E17-4774-95FA-7E133AF346F7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataPlane.Sdk.Test.Utils", "DataPlane.Sdk.Test.Utils\DataPlane.Sdk.Test.Utils.csproj", "{391E2C8C-7806-40CC-A847-2ECD25FE73CC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Streaming", "Streaming", "{9B7B836B-426D-4F48-8467-98E24CE4FCB1}"
+ ProjectSection(SolutionItems) = preProject
+ Samples\Streaming\docker-compose.yaml = Samples\Streaming\docker-compose.yaml
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Provider", "Samples\Streaming\Provider\Provider.csproj", "{C1B9F93E-4499-4506-A654-9B19601D8FA2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Consumer", "Samples\Streaming\Consumer\Consumer.csproj", "{0219D903-F6B5-4E22-BF08-BAFF5EB1895D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|x64.Build.0 = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Debug|x86.Build.0 = Debug|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|x64.ActiveCfg = Release|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|x64.Build.0 = Release|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|x86.ActiveCfg = Release|Any CPU
+ {0E3D4901-133A-46D3-B1CB-7400C65BED32}.Release|x86.Build.0 = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|x64.Build.0 = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Debug|x86.Build.0 = Debug|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|x64.ActiveCfg = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|x64.Build.0 = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|x86.ActiveCfg = Release|Any CPU
+ {8B194066-A67B-44D9-945F-88A4EC1EBEBF}.Release|x86.Build.0 = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|x64.Build.0 = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Debug|x86.Build.0 = Debug|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|x64.ActiveCfg = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|x64.Build.0 = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|x86.ActiveCfg = Release|Any CPU
+ {C9F8CEE9-F96C-41B5-B58D-3D0B82B87258}.Release|x86.Build.0 = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|x64.Build.0 = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Debug|x86.Build.0 = Debug|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|x64.ActiveCfg = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|x64.Build.0 = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|x86.ActiveCfg = Release|Any CPU
+ {C95272D3-3046-4C26-A422-C19EC45C7800}.Release|x86.Build.0 = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|x64.Build.0 = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Debug|x86.Build.0 = Debug|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|x64.ActiveCfg = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|x64.Build.0 = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|x86.ActiveCfg = Release|Any CPU
+ {534284F6-8E17-4774-95FA-7E133AF346F7}.Release|x86.Build.0 = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|x64.Build.0 = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Debug|x86.Build.0 = Debug|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|x64.ActiveCfg = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|x64.Build.0 = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|x86.ActiveCfg = Release|Any CPU
+ {391E2C8C-7806-40CC-A847-2ECD25FE73CC}.Release|x86.Build.0 = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|x64.Build.0 = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Debug|x86.Build.0 = Debug|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|x64.ActiveCfg = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|x64.Build.0 = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|x86.ActiveCfg = Release|Any CPU
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2}.Release|x86.Build.0 = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|x64.Build.0 = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Debug|x86.Build.0 = Debug|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|x64.ActiveCfg = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|x64.Build.0 = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|x86.ActiveCfg = Release|Any CPU
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {534284F6-8E17-4774-95FA-7E133AF346F7} = {32055AC6-C4BE-4B7C-A829-F268AB12E577}
+ {9B7B836B-426D-4F48-8467-98E24CE4FCB1} = {32055AC6-C4BE-4B7C-A829-F268AB12E577}
+ {C1B9F93E-4499-4506-A654-9B19601D8FA2} = {9B7B836B-426D-4F48-8467-98E24CE4FCB1}
+ {0219D903-F6B5-4E22-BF08-BAFF5EB1895D} = {9B7B836B-426D-4F48-8467-98E24CE4FCB1}
+ EndGlobalSection
+EndGlobal