Compare commits
5 Commits
c4f1a9498b
...
0a61586e39
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a61586e39 | ||
|
|
47aeb49a40 | ||
|
|
a1f996b328 | ||
|
|
110b102926 | ||
|
|
ddc55e0fd9 |
@@ -28,5 +28,20 @@
|
|||||||
public required string Issuer { get; init; }
|
public required string Issuer { get; init; }
|
||||||
|
|
||||||
public bool RequireHttpsMetadata { get; init; } = true;
|
public bool RequireHttpsMetadata { get; init; } = true;
|
||||||
|
|
||||||
|
public class Consumer
|
||||||
|
{
|
||||||
|
public required string Route { get; init; }
|
||||||
|
|
||||||
|
public required string Audience { get; init; }
|
||||||
|
|
||||||
|
private CookieOptionsProvider? _cookieOptions;
|
||||||
|
|
||||||
|
#pragma warning disable CS8603 // Possible null reference return.
|
||||||
|
public CookieOptionsProvider CookieOptions { get => _cookieOptions ?? Parent?.DefaultCookieOptions; init => _cookieOptions = value; }
|
||||||
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
|
|
||||||
|
internal AuthApiParams? Parent { private get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace DigitalData.Auth.API.Config
|
using static DigitalData.Auth.API.Config.AuthApiParams;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.API.Config
|
||||||
{
|
{
|
||||||
public static class ConfigExtensions
|
public static class ConfigExtensions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace DigitalData.Auth.API.Config
|
|
||||||
{
|
|
||||||
public class Consumer
|
|
||||||
{
|
|
||||||
public required string Route { get; init; }
|
|
||||||
|
|
||||||
public required string Audience { get; init; }
|
|
||||||
|
|
||||||
private CookieOptionsProvider? _cookieOptions;
|
|
||||||
|
|
||||||
public CookieOptionsProvider CookieOptions { get => _cookieOptions ?? Parent?.DefaultCookieOptions; init => _cookieOptions = value; }
|
|
||||||
|
|
||||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
|
||||||
public AuthApiParams Parent { private get; set; }
|
|
||||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
39
src/DigitalData.Auth.API/Config/DependentExtensions.cs
Normal file
39
src/DigitalData.Auth.API/Config/DependentExtensions.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using DigitalData.Core.Abstractions.Security;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.API.Config
|
||||||
|
{
|
||||||
|
public static class DependentExtensions
|
||||||
|
{
|
||||||
|
private static AuthApiParams? _authApiParams;
|
||||||
|
|
||||||
|
private static AuthApiParams AuthApiParams
|
||||||
|
{
|
||||||
|
get => _authApiParams
|
||||||
|
?? throw new InvalidOperationException(
|
||||||
|
$"DependentExtensions have not been added to the application or are not configured correctly. {typeof(AuthApiParams)} cannot be provided."
|
||||||
|
);
|
||||||
|
set => _authApiParams = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IApplicationBuilder AddDependentExtensions(this IApplicationBuilder application)
|
||||||
|
{
|
||||||
|
var authApiParamOptions = application.ApplicationServices.GetRequiredService<IOptions<AuthApiParams>>();
|
||||||
|
_authApiParams = authApiParamOptions.Value;
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetByRoute(this IEnumerable<IAsymmetricTokenDescriptor> descriptors, string consumerRoute, out IAsymmetricTokenDescriptor descriptor)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||||
|
descriptor = null;
|
||||||
|
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
|
||||||
|
if (!AuthApiParams.Consumers.TryGetByRoute(consumerRoute, out var consumer)
|
||||||
|
|| !descriptors.TryGet(AuthApiParams.Issuer, consumer.Audience, out var _descriptor))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
descriptor = _descriptor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
{
|
{
|
||||||
private readonly IJwtSignatureHandler<UserReadDto> _userSignatureHandler;
|
private readonly IJwtSignatureHandler<UserReadDto> _userSignatureHandler;
|
||||||
|
|
||||||
private readonly IJwtSignatureHandler<ConsumerApi> _apiSignatureHandler;
|
private readonly IJwtSignatureHandler<Consumer> _consumerSignatureHandler;
|
||||||
|
|
||||||
private readonly AuthApiParams _apiParams;
|
private readonly AuthApiParams _apiParams;
|
||||||
|
|
||||||
@@ -31,9 +31,9 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
|
|
||||||
private readonly IDirectorySearchService _dirSearchService;
|
private readonly IDirectorySearchService _dirSearchService;
|
||||||
|
|
||||||
private readonly IConsumerApiService _consumerApiService;
|
private readonly IConsumerService _consumerService;
|
||||||
|
|
||||||
public AuthController(IJwtSignatureHandler<UserReadDto> userSignatureHandler, IOptions<AuthApiParams> cookieParamsOptions, ICryptoFactory cryptoFactory, ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IConsumerApiService consumerApiService, IJwtSignatureHandler<ConsumerApi> apiSignatureHandler)
|
public AuthController(IJwtSignatureHandler<UserReadDto> userSignatureHandler, IOptions<AuthApiParams> cookieParamsOptions, ICryptoFactory cryptoFactory, ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IConsumerService consumerService, IJwtSignatureHandler<Consumer> apiSignatureHandler)
|
||||||
{
|
{
|
||||||
_apiParams = cookieParamsOptions.Value;
|
_apiParams = cookieParamsOptions.Value;
|
||||||
_userSignatureHandler = userSignatureHandler;
|
_userSignatureHandler = userSignatureHandler;
|
||||||
@@ -41,8 +41,8 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
_dirSearchService = dirSearchService;
|
_dirSearchService = dirSearchService;
|
||||||
_consumerApiService = consumerApiService;
|
_consumerService = consumerService;
|
||||||
_apiSignatureHandler = apiSignatureHandler;
|
_consumerSignatureHandler = apiSignatureHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IActionResult> CreateTokenAsync(LogInDto login, string consumerRoute, bool cookie = true)
|
private async Task<IActionResult> CreateTokenAsync(LogInDto login, string consumerRoute, bool cookie = true)
|
||||||
@@ -72,9 +72,9 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
return Ok(token);
|
return Ok(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IActionResult> CreateTokenAsync(ConsumerApiLogin login, bool cookie = true)
|
private async Task<IActionResult> CreateTokenAsync(ConsumerLogin login, bool cookie = true)
|
||||||
{
|
{
|
||||||
var api = await _consumerApiService.ReadByNameAsync(login.Name);
|
var api = await _consumerService.ReadByIdAsync(login.Id);
|
||||||
|
|
||||||
if (api is null || api.Password != login.Password)
|
if (api is null || api.Password != login.Password)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
@@ -82,7 +82,7 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
if (!_cryptoFactory.TokenDescriptors.TryGet(_apiParams.Issuer, _apiParams.DefaultConsumer.Audience, out var descriptor))
|
if (!_cryptoFactory.TokenDescriptors.TryGet(_apiParams.Issuer, _apiParams.DefaultConsumer.Audience, out var descriptor))
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
|
||||||
var token = _apiSignatureHandler.WriteToken(api, descriptor);
|
var token = _consumerSignatureHandler.WriteToken(api, descriptor);
|
||||||
|
|
||||||
//set cookie
|
//set cookie
|
||||||
if (cookie)
|
if (cookie)
|
||||||
@@ -112,7 +112,7 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
|
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public async Task<IActionResult> Login([FromForm] ConsumerApiLogin login)
|
public async Task<IActionResult> Login([FromForm] ConsumerLogin login)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -155,7 +155,7 @@ namespace DigitalData.Auth.API.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> CreateTokenViaBody([FromBody] ConsumerApiLogin login, [FromQuery] bool cookie = false)
|
public async Task<IActionResult> CreateTokenViaBody([FromBody] ConsumerLogin login, [FromQuery] bool cookie = false)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
17
src/DigitalData.Auth.API/Controllers/ClaimExtensions.cs
Normal file
17
src/DigitalData.Auth.API/Controllers/ClaimExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.API.Controllers
|
||||||
|
{
|
||||||
|
public static class ClaimExtensions
|
||||||
|
{
|
||||||
|
public static string? GetName(this ClaimsPrincipal user) => user.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
|
||||||
|
public static bool TryGetName(this ClaimsPrincipal user, out string name)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||||
|
name = user.GetName();
|
||||||
|
#pragma warning restore CS8601 // Possible null reference assignment.
|
||||||
|
return name is not null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,9 @@
|
|||||||
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="3.2.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Security" Version="1.0.0" />
|
<PackageReference Include="DigitalData.Core.Security" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.12" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.0" />
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.3.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.3.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.2.0" />
|
||||||
<PackageReference Include="UserManager.Application" Version="3.1.2" />
|
<PackageReference Include="UserManager.Application" Version="3.1.2" />
|
||||||
<PackageReference Include="UserManager.Domain" Version="3.0.1" />
|
<PackageReference Include="UserManager.Domain" Version="3.0.1" />
|
||||||
<PackageReference Include="UserManager.Infrastructure" Version="3.0.1" />
|
<PackageReference Include="UserManager.Infrastructure" Version="3.0.1" />
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace DigitalData.Auth.API.Dto
|
|
||||||
{
|
|
||||||
public record ConsumerApiLogin(string Name, string Password);
|
|
||||||
}
|
|
||||||
4
src/DigitalData.Auth.API/Dto/ConsumerLogin.cs
Normal file
4
src/DigitalData.Auth.API/Dto/ConsumerLogin.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
namespace DigitalData.Auth.API.Dto
|
||||||
|
{
|
||||||
|
public record ConsumerLogin(string Id, string Password);
|
||||||
|
}
|
||||||
4
src/DigitalData.Auth.API/Entities/Consumer.cs
Normal file
4
src/DigitalData.Auth.API/Entities/Consumer.cs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
namespace DigitalData.Auth.API.Entities
|
||||||
|
{
|
||||||
|
public record Consumer(string Id, string Password, string Audience);
|
||||||
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
namespace DigitalData.Auth.API.Entities
|
|
||||||
{
|
|
||||||
public record ConsumerApi(string Name, string Password);
|
|
||||||
}
|
|
||||||
@@ -6,16 +6,14 @@ using DigitalData.Core.Application;
|
|||||||
using DigitalData.Core.Security;
|
using DigitalData.Core.Security;
|
||||||
using DigitalData.UserManager.Application;
|
using DigitalData.UserManager.Application;
|
||||||
using DigitalData.UserManager.Application.DTOs.User;
|
using DigitalData.UserManager.Application.DTOs.User;
|
||||||
using DigitalData.UserManager.Application.Services;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.IdentityModel.JsonWebTokens;
|
using Microsoft.IdentityModel.JsonWebTokens;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Configuration.AddJsonFile("consumers-api.json", true, true);
|
builder.Configuration.AddJsonFile("consumer-repository.json", true, true);
|
||||||
|
|
||||||
var config = builder.Configuration;
|
var config = builder.Configuration;
|
||||||
|
|
||||||
@@ -23,11 +21,11 @@ var apiParams = config.Get<AuthApiParams>() ?? throw new InvalidOperationExcepti
|
|||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.Configure<AuthApiParams>(config);
|
builder.Services.Configure<AuthApiParams>(config);
|
||||||
builder.Services.AddConsumerApiServiceFromConfiguration(config);
|
builder.Services.AddConsumerApiService(config);
|
||||||
builder.Services.AddCryptoFactory(config.GetSection("CryptParams"));
|
builder.Services.AddCryptoFactory(config.GetSection("CryptParams"));
|
||||||
builder.Services.AddJwtSignatureHandler<ConsumerApi>(api => new Dictionary<string, object>
|
builder.Services.AddJwtSignatureHandler<Consumer>(api => new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ JwtRegisteredClaimNames.Sub, api.Name },
|
{ JwtRegisteredClaimNames.Sub, api.Id },
|
||||||
{ JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
|
{ JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
|
||||||
});
|
});
|
||||||
builder.Services.AddJwtSignatureHandler<UserReadDto>(user => new Dictionary<string, object>
|
builder.Services.AddJwtSignatureHandler<UserReadDto>(user => new Dictionary<string, object>
|
||||||
@@ -95,9 +93,7 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|||||||
ValidateAudience = true,
|
ValidateAudience = true,
|
||||||
ValidAudience = apiParams!.DefaultConsumer.Audience,
|
ValidAudience = apiParams!.DefaultConsumer.Audience,
|
||||||
ValidateLifetime = true,
|
ValidateLifetime = true,
|
||||||
IssuerSigningKey = issuerSigningKeyInitiator?.Value,
|
IssuerSigningKey = issuerSigningKeyInitiator?.Value
|
||||||
NameClaimType = JwtRegisteredClaimNames.Name,
|
|
||||||
RoleClaimType = ClaimTypes.Role
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options.Events = new JwtBearerEvents
|
options.Events = new JwtBearerEvents
|
||||||
@@ -116,6 +112,8 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
|||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
app.AddDependentExtensions();
|
||||||
|
|
||||||
issuerSigningKeyInitiator = new Lazy<SecurityKey>(() =>
|
issuerSigningKeyInitiator = new Lazy<SecurityKey>(() =>
|
||||||
{
|
{
|
||||||
var factory = app.Services.GetRequiredService<ICryptoFactory>();
|
var factory = app.Services.GetRequiredService<ICryptoFactory>();
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
using DigitalData.Auth.API.Entities;
|
|
||||||
using DigitalData.Auth.API.Services.Contracts;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace DigitalData.Auth.API.Services
|
|
||||||
{
|
|
||||||
public class ConfiguredConsumerApiService : IConsumerApiService
|
|
||||||
{
|
|
||||||
private readonly IEnumerable<ConsumerApi> _consumerAPIs;
|
|
||||||
public ConfiguredConsumerApiService(IOptions<IEnumerable<ConsumerApi>> options)
|
|
||||||
{
|
|
||||||
_consumerAPIs = options.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<ConsumerApi?> ReadByNameAsync(string name) => Task.Run(() => _consumerAPIs.FirstOrDefault(api => api.Name == name));
|
|
||||||
|
|
||||||
public async Task<bool> VerifyAsync(string name, string password) => (await ReadByNameAsync(name))?.Password == password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using DigitalData.Auth.API.Entities;
|
||||||
|
using DigitalData.Auth.API.Services.Contracts;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.API.Services
|
||||||
|
{
|
||||||
|
public class ConfiguredConsumerService : IConsumerService
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<Consumer> _consumerAPIs;
|
||||||
|
public ConfiguredConsumerService(IOptions<IEnumerable<Consumer>> options)
|
||||||
|
{
|
||||||
|
_consumerAPIs = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Consumer?> ReadByIdAsync(string id) => Task.Run(() => _consumerAPIs.FirstOrDefault(api => api.Id == id));
|
||||||
|
|
||||||
|
public async Task<bool> VerifyAsync(string id, string password) => (await ReadByIdAsync(id))?.Password == password;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using DigitalData.Auth.API.Entities;
|
|
||||||
|
|
||||||
namespace DigitalData.Auth.API.Services.Contracts
|
|
||||||
{
|
|
||||||
public interface IConsumerApiService
|
|
||||||
{
|
|
||||||
public Task<ConsumerApi?> ReadByNameAsync(string name);
|
|
||||||
|
|
||||||
public Task<bool> VerifyAsync(string name, string password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using DigitalData.Auth.API.Entities;
|
||||||
|
|
||||||
|
namespace DigitalData.Auth.API.Services.Contracts
|
||||||
|
{
|
||||||
|
public interface IConsumerService
|
||||||
|
{
|
||||||
|
public Task<Consumer?> ReadByIdAsync(string id);
|
||||||
|
|
||||||
|
public Task<bool> VerifyAsync(string id, string password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,11 +6,11 @@ namespace DigitalData.Auth.API.Services
|
|||||||
{
|
{
|
||||||
public static class DIExtensions
|
public static class DIExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddConsumerApiServiceFromConfiguration(this IServiceCollection services, IConfiguration configuration, string key = "ConsumerAPIs")
|
public static IServiceCollection AddConsumerApiService(this IServiceCollection services, IConfiguration configuration, string key = "ConsumerAPIs")
|
||||||
{
|
{
|
||||||
var consumerApis = configuration.GetSection(key).Get<IEnumerable<ConsumerApi>>() ?? throw new InvalidOperationException($"No Consumer list found in {key} in configuration.");
|
var consumers = configuration.GetSection(key).Get<IEnumerable<Consumer>>() ?? throw new InvalidOperationException($"No Consumer list found in {key} in configuration.");
|
||||||
services.AddSingleton(Options.Create(consumerApis));
|
services.AddSingleton(Options.Create(consumers));
|
||||||
services.AddSingleton<IConsumerApiService, ConfiguredConsumerApiService>();
|
services.AddSingleton<IConsumerService, ConfiguredConsumerService>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/DigitalData.Auth.API/consumer-repository.json
Normal file
19
src/DigitalData.Auth.API/consumer-repository.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"ConsumerAPIs": [
|
||||||
|
{
|
||||||
|
"Id": "auth",
|
||||||
|
"Audience": "auth.digitaldata.works",
|
||||||
|
"Password": "aQ9z!2@TgY7b#fHcD3pLmV1$wX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "work-flow",
|
||||||
|
"Audience": "work-flow.digitaldata.works",
|
||||||
|
"Password": "t3B|aiJ'i-snLzNRj3B{9=&:lM5P@'iL"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "user-manager",
|
||||||
|
"Audience": "user-manager.digitaldata.works",
|
||||||
|
"Password": "a098Hvu1-y29ep{KPQO]#>8TK+fk{O`_d"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"ConsumerAPIs": [
|
|
||||||
{
|
|
||||||
"Name": "WorkFlow.API",
|
|
||||||
"Password": "t3B|aiJ'i-snLzNRj3B{9=&:lM5P@'iL"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Name": "DigitalData.UserManager.API",
|
|
||||||
"Password": "a098Hvu1-y29ep{KPQO]#>8TK+fk{O`_d"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user