Skip to content

Commit 869131f

Browse files
Ticket #458 : Can create FAPI client
1 parent 8d4b8bc commit 869131f

File tree

14 files changed

+137
-43
lines changed

14 files changed

+137
-43
lines changed

src/IdServer/SimpleIdServer.IdServer.Startup/IdServerConfiguration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public class IdServerConfiguration
3030

3131
public static ICollection<Client> Clients => new List<Client>
3232
{
33-
ClientBuilder.BuildTraditionalWebsiteClient("website", "password", null, "https://localhost.com:5001/signin-oidc").SetClientName("Website").SetClientLogoUri("https://cdn.logo.com/hotlink-ok/logo-social.png").AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).Build(),
34-
ClientBuilder.BuildExternalAuthDeviceClient("bankWebsite", "password", null, "https://localhost.com:5001/signin-oidc").SetClientName("Bank Website").AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).Build(),
33+
ClientBuilder.BuildTraditionalWebsiteClient("website", "password", null, "https://localhost:5001/signin-oidc", "https://localhost.com:5001/signin-oidc").SetClientName("Website").SetClientLogoUri("https://cdn.logo.com/hotlink-ok/logo-social.png").AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).Build(),
34+
ClientBuilder.BuildExternalAuthDeviceClient("bankWebsite", "password", null, "https://localhost:5001/signin-oidc", "https://localhost.com:5001/signin-oidc").SetClientName("Bank Website").AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).Build(),
3535
WsClientBuilder.BuildWsFederationClient("urn:website").SetClientName("NAME").Build(),
3636
ClientBuilder.BuildUserAgentClient("oauth", "password", null, "https://oauth.tools/callback/code").AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).Build(),
3737
ClientBuilder.BuildTraditionalWebsiteClient("fapi", "password", null, "https://localhost:8443/test/(.*)").SetIdTokenSignedResponseAlg(SecurityAlgorithms.EcdsaSha256).SetRequestObjectSigning(SecurityAlgorithms.EcdsaSha256).SetSigAuthorizationResponse(SecurityAlgorithms.EcdsaSha256).AddScope(Constants.StandardScopes.OpenIdScope, Constants.StandardScopes.Profile).UseClientTlsAuthentication("CN=sidClient, O=Internet Widgits Pty Ltd, S=BE, C=BE").AddSigningKey(new SigningCredentials(PemImporter.Import(new PemResult("-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEK21CoKCA2Vk5zPM+7+vqtnrq4pIe\nsCLiWObLDFKKf3gJl0hll/ZTI5ww/oRrKIXO/uRe9AkckkKwqrqqXGnvsQ==\n-----END PUBLIC KEY-----", "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIDHtu+N0u38ZN7DF/TpycDfaUs8WfPGUB3UusR0uv3TVoAoGCCqGSM49\nAwEHoUQDQgAEK21CoKCA2Vk5zPM+7+vqtnrq4pIesCLiWObLDFKKf3gJl0hll/ZT\nI5ww/oRrKIXO/uRe9AkckkKwqrqqXGnvsQ==\n-----END EC PRIVATE KEY-----"), "keyId"), SecurityAlgorithms.EcdsaSha256), SecurityAlgorithms.EcdsaSha256, SecurityKeyTypes.ECDSA).Build()

src/IdServer/SimpleIdServer.IdServer.Startup/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
using System;
1818
using System.Collections.Generic;
1919
using System.Linq;
20+
using System.Net;
2021
using System.Reflection;
2122
using System.Security.Cryptography;
2223

24+
ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
2325
var builder = WebApplication.CreateBuilder(args);
2426
builder.Services.Configure<KestrelServerOptions>(options =>
2527
{
@@ -129,7 +131,8 @@ void SeedData(WebApplication application)
129131

130132
if(!dbContext.SerializedFileKeys.Any())
131133
{
132-
dbContext.SerializedFileKeys.Add(KeyGenerator.GenerateSigningCredentials(SimpleIdServer.IdServer.Constants.StandardRealms.Master));
134+
dbContext.SerializedFileKeys.Add(KeyGenerator.GenerateRSASigningCredentials(SimpleIdServer.IdServer.Constants.StandardRealms.Master, "rsa-1"));
135+
dbContext.SerializedFileKeys.Add(KeyGenerator.GenerateECDSASigningCredentials(SimpleIdServer.IdServer.Constants.StandardRealms.Master, "ecdsa-1"));
133136
dbContext.SerializedFileKeys.Add(WsFederationKeyGenerator.GenerateWsFederationSigningCredentials(SimpleIdServer.IdServer.Constants.StandardRealms.Master));
134137
}
135138

src/IdServer/SimpleIdServer.IdServer.Startup/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"environmentVariables": {
66
"ASPNETCORE_ENVIRONMENT": "Development"
77
},
8-
"applicationUrl": "https://localhost:5001"
8+
"applicationUrl": "https://localhost:5001;https://172.27.192.1:5001"
99
}
1010
}
1111
}

src/IdServer/SimpleIdServer.IdServer.Website/Pages/CertificateAuthorityClients.razor

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,26 +103,39 @@
103103
contextMenuService.Open(args, new List<ContextMenuItem>
104104
{
105105
new ContextMenuItem { Text = "Delete", Value = 1 },
106-
new ContextMenuItem { Text = "Download", Value = 2 }
106+
new ContextMenuItem { Text = "Download", Value = 2 },
107+
new ContextMenuItem { Text= "View", Value = 3 }
107108
}, async (a) =>
108109
{
109-
if (a.Value.Equals(1))
110-
{
111-
var caIds = searchCertificateClientsState.Value?.ClientCertificates.Where(c => c.IsSelected).Select(c => c.Value.Id)?.ToList();
112-
if (!caIds.Contains(certificateAuthority.Value.Id)) caIds.Add(certificateAuthority.Value.Id);
113-
var act = new RemoveSelectedClientCertificatesAction { CertificateClientIds = caIds, CertificateAuthorityId = CertificateAuthority.Id };
114-
dispatcher.Dispatch(act);
115-
contextMenuService.Close();
116-
}
110+
if (a.Value.Equals(1))
111+
{
112+
var caIds = searchCertificateClientsState.Value?.ClientCertificates.Where(c => c.IsSelected).Select(c => c.Value.Id)?.ToList();
113+
if (!caIds.Contains(certificateAuthority.Value.Id)) caIds.Add(certificateAuthority.Value.Id);
114+
var act = new RemoveSelectedClientCertificatesAction { CertificateClientIds = caIds, CertificateAuthorityId = CertificateAuthority.Id };
115+
dispatcher.Dispatch(act);
116+
contextMenuService.Close();
117+
}
117118

118-
if (a.Value.Equals(2))
119-
{
120-
var memoryStream = new MemoryStream(certificateAuthority.Certificate.Export(X509ContentType.Pkcs12));
121-
var fileName = $"{certificateAuthority.Value.Name}.pfx";
122-
using var streamRef = new DotNetStreamReference(stream: memoryStream);
123-
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
124-
}
125-
});
119+
if (a.Value.Equals(2))
120+
{
121+
var memoryStream = new MemoryStream(certificateAuthority.Certificate.Export(X509ContentType.Pkcs12));
122+
var fileName = $"{certificateAuthority.Value.Name}.pfx";
123+
using var streamRef = new DotNetStreamReference(stream: memoryStream);
124+
await JS.InvokeVoidAsync("downloadFileFromStream", fileName, streamRef);
125+
}
126+
127+
if (a.Value.Equals(3))
128+
{
129+
var dic = new Dictionary<string, object> { { "ClientCertificate", certificateAuthority.Value } };
130+
await dialogService.OpenAsync<ViewClientCertificateDialog>("Client Certificate", dic, new DialogOptions
131+
{
132+
Width = "700px",
133+
Height = "512px",
134+
Resizable = true,
135+
Draggable = true
136+
});
137+
}
138+
});
126139
}
127140

128141
async void AddCertificateClient()

src/IdServer/SimpleIdServer.IdServer.Website/Shared/AddClientDialog.razor

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@
124124
</p>
125125
<RadzenRequiredValidator Component="RedirectionUris" Text="At leat one redirection URL must be specified"></RadzenRequiredValidator>
126126
</div>
127+
<div class="mb-1">
128+
<RadzenCheckBox @bind-Value=@websiteApplication.IsFAPICompliant TValue="bool" />
129+
<RadzenLabel Text="Compliant with FAPI1.0" Style="margin-left: 8px; vertical-align: middle;" />
130+
</div>
131+
@if (websiteApplication.IsFAPICompliant)
132+
{
133+
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Subject Name</RadzenText>
134+
<RadzenTextBox Name="SubjectName" @bind-Value="@websiteApplication.SubjectName" Class="w-100"></RadzenTextBox>
135+
<p class="text-muted">
136+
MTLS authentication is configured by default. <br/>
137+
Subject Name is used to check the validity of the Client Certificate.
138+
</p>
139+
}
140+
127141
<RadzenButton class="mt-1" Variant="Variant.Flat" ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Text="@(addClientState.Value.IsAdding ? "Adding..." : "Save")" Disabled="@(addClientState.Value.IsAdding)" />
128142
</RadzenTemplateForm>
129143
break;
@@ -231,6 +245,8 @@
231245
public string ClientIdentifier { get; set; } = null!;
232246
public string ClientSecret { get; set; } = null!;
233247
public string RedirectionUris { get; set; } = null!;
248+
public string SubjectName { get; set; } = null!;
249+
public bool IsFAPICompliant { get; set; } = false;
234250
}
235251

236252
record MachineApplication
@@ -307,7 +323,7 @@
307323

308324
void AddWebsiteApplication(WebsiteApplication websiteApplication)
309325
{
310-
dispatcher.Dispatch(new AddWebsiteApplicationAction { ClientId = websiteApplication.ClientIdentifier, ClientName = websiteApplication.ClientName, RedirectionUrls = websiteApplication.RedirectionUris.Split(';'), ClientSecret = websiteApplication.ClientSecret });
326+
dispatcher.Dispatch(new AddWebsiteApplicationAction { SubjectName = websiteApplication.SubjectName, IsFAPICompliant = websiteApplication.IsFAPICompliant, ClientId = websiteApplication.ClientIdentifier, ClientName = websiteApplication.ClientName, RedirectionUrls = websiteApplication.RedirectionUris.Split(';'), ClientSecret = websiteApplication.ClientSecret });
311327
}
312328

313329
void AddMobileApplication(MobileApplication mobileApplication)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@using Fluxor.Blazor.Web.Components;
2+
@using SimpleIdServer.IdServer.Website.Resources;
3+
@using SimpleIdServer.IdServer.Website.Stores.CertificateAuthorityStore;
4+
5+
<!-- Public Key -->
6+
<div>
7+
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Public Key</RadzenText>
8+
<RadzenTextArea Rows=10 Name="PublicKey" @bind-Value="@ClientCertificate.PublicKey" Class="w-100"></RadzenTextArea>
9+
</div>
10+
<!-- Private Key -->
11+
<div>
12+
<RadzenText TextStyle="TextStyle.Subtitle2" TagName="TagName.H3">Private Key</RadzenText>
13+
<RadzenTextArea Rows=10 Name="PrivateKey" @bind-Value="@ClientCertificate.PrivateKey" Class="w-100"></RadzenTextArea>
14+
</div>
15+
16+
@code {
17+
[Parameter]
18+
public ClientCertificate ClientCertificate { get; set; }
19+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+


src/IdServer/SimpleIdServer.IdServer.Website/Stores/CertificateAuthorityStore/CertificateAuthorityEffects.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public async Task Handle(AddClientCertificateAction action, IDispatcher dispatch
140140
{
141141
var ca = await _certificateAuthorityRepository.Query().Include(c => c.ClientCertificates).FirstAsync(c => c.Id == action.CertificateAuthorityId);
142142
var certificate = _certificateAuthorityStore.Get(ca);
143-
var pem = KeyGenerator.GenerateClientCertificate(certificate, action.SubjectName, action.NbDays, CancellationToken.None);
143+
var pem = KeyGenerator.GenerateClientCertificate(certificate, action.SubjectName, action.NbDays);
144144
var record = new ClientCertificate
145145
{
146146
Id = Guid.NewGuid().ToString(),

src/IdServer/SimpleIdServer.IdServer.Website/Stores/ClientStore/ClientEffects.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ public async Task Handle(AddWebsiteApplicationAction action, IDispatcher dispatc
9898
.AddScope(scopes.ToArray());
9999
if (!string.IsNullOrWhiteSpace(action.ClientName))
100100
newClientBuilder.SetClientName(action.ClientName);
101+
if(action.IsFAPICompliant)
102+
{
103+
newClientBuilder.UseClientTlsAuthentication(action.SubjectName);
104+
newClientBuilder.SetSigAuthorizationResponse(SecurityAlgorithms.EcdsaSha256);
105+
newClientBuilder.SetIdTokenSignedResponseAlg(SecurityAlgorithms.EcdsaSha256);
106+
newClientBuilder.SetRequestObjectSigning(SecurityAlgorithms.EcdsaSha256);
107+
}
108+
101109
var newClient = newClientBuilder.Build();
102110
dbContext.Clients.Add(newClient);
103111
await dbContext.SaveChangesAsync(CancellationToken.None);
@@ -474,6 +482,8 @@ public class AddWebsiteApplicationAction
474482
public string ClientId { get; set; } = null!;
475483
public string ClientSecret { get; set; } = null!;
476484
public string? ClientName { get; set; } = null;
485+
public bool IsFAPICompliant { get; set; } = false;
486+
public string? SubjectName { get; set; } = null;
477487
}
478488

479489
public class AddMobileApplicationAction

src/IdServer/SimpleIdServer.IdServer.WsFederation/Auth/ConfigureWsFederationOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ public class ConfigureWsFederationOptions : IPostConfigureOptions<WsFederationOp
1111
{
1212
public void PostConfigure(string name, WsFederationOptions options)
1313
{
14+
var handler = new HttpClientHandler();
15+
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => {
16+
return true;
17+
};
18+
var httpClient = new HttpClient(handler);
19+
options.Backchannel = httpClient;
1420
options.ConfigurationManager = new IdServerWsFederationConfigurationManager(options.MetadataAddress, new WsFederationConfigurationRetriever(),
1521
new HttpDocumentRetriever(options.Backchannel) { RequireHttps = options.RequireHttpsMetadata });
1622
}

0 commit comments

Comments
 (0)