Skip to content

Commit

Permalink
Merge pull request #549 from ITfoxtec/pre-master
Browse files Browse the repository at this point in the history
Pre master
  • Loading branch information
Revsgaard authored Mar 22, 2023
2 parents 44aa1fb + 0cbe24e commit b20eae5
Show file tree
Hide file tree
Showing 55 changed files with 393 additions and 102 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# FoxIDs
# [FoxIDs](https://www.foxids.com)

FoxIDs is an open-source Identity Services (IDS) supporting [login](https://www.foxids.com/docs/login), [OAuth 2.0](https://www.foxids.com/docs/oauth-2.0), [OpenID Connect 1.0](https://www.foxids.com/docs/oidc), [SAML 2.0](https://www.foxids.com/docs/saml-2.0) and convention between [OpenID Connect and SAML 2.0](https://www.foxids.com/docs/parties).
FoxIDs handles multi-factor authentication (MFA) / two-factor authentication (2FA) with support for two-factor authenticator app.

> For [Getting started](https://www.foxids.com/docs/getting-started) guide and more documentation please see the [documentation](https://www.foxids.com/docs).
FoxIDs is designed as a container with multi-tenant support. FoxIDs can be deployed and use by e.g. a single company or deployed as a shared cloud container and used by multiple organisations, companies or everyone with the need.
Separation is ensured at the tenant level and in each tenant separated by tracks. The tracks in a tenant segmentate environments, e.g. test, QA and production and e.g. trusts to external or internal IdPs.

Expand All @@ -16,8 +18,6 @@ Deployment or as a service:
- FoxIDs is a cloud service ready to be [deployed](https://www.foxids.com/docs/deployment) in you Azure tenant.
- Or you can use FoxIDs as an Identity as a Service (IDaaS) at [FoxIDs.com](https://foxids.com).

> For [Getting started](https://www.foxids.com/docs/getting-started) guide and more documentation please see the [documentation](https://www.foxids.com/docs).
> FoxIDs is .NET 7.0 and the FoxIDs Control Client is Blazor .NET 7.0.
## Deployment
Expand Down
2 changes: 2 additions & 0 deletions docs/howto-saml-2.0-context-handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Where Context Handler is either a SAML 2.0 [Identity Provider (IdP)](#configurin

Context Handler is a Danish Identity Provider (IdP) connecting the Danish municipalities in a common federation. Context Handler can be configured based on either OIOSAML 2 or OIOSAML 3. FoxIDs support both OIOSAML 2 / OIOSAML 3, issuer naming, required certificates and it is possible to support NSIS.

> Transforms the [DK privilege XML claim](claim-transform-dk-privilege.md) to a JSON claim.
Context Handler documentation and configuration:
- The [Context Handler get started](https://digitaliseringskataloget.dk/l%C3%B8sninger/adgangsstyring-brugere).
- The [Context Handler administration portal](https://serviceplatformen.dk/administration/)
Expand Down
23 changes: 12 additions & 11 deletions docs/up-party-howto-oidc-nets-eid-broker.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ This connection use OpenID Connect Authorization Code flow with PKCE, which is t
4. Add the Nets eID Broker demo secret `rnlguc7CM/wmGSti4KCgCkWBQnfslYr0lMDZeIFsCJweROTROy2ajEigEaPQFl76Py6AVWnhYofl/0oiSAgdtg==` in the Client secret field
5. Select show advanced settings
6. Add the Nets eID Broker demo client id `0a775a87-878c-4b83-abe3-ee29c720c3e7` in the Optional customer SP client ID field
7. Select use claims from ID token
7. Select to read claims from the UserInfo Endpoint instead of the access token or ID token
8. Click create

That's it, you are done.
Expand Down Expand Up @@ -70,7 +70,7 @@ This connection use OpenID Connect Authorization Code flow with PKCE, which is t
5. Add the Nets eID Broker secret in the Client secret field
6. Select show advanced settings
7. Add the Nets eID Broker client id in the Optional customer SP client ID field
8. Select use claims from ID token
8. Select to read claims from the UserInfo Endpoint instead of the access token or ID token
9. Click create

**3 - Go back to [Nets eID Broker admin portal](https://netseidbroker.dk/admin)**
Expand All @@ -90,14 +90,15 @@ The name of the scope can e.g, be `nets_eid_broker`

The most used Nets eID Broker claims:

- `identity_type`
- `idp`
- `idp_identity_id`
- `loa`
- `mitid.uuid`
- `mitid.has_cpr`
- `dk.cpr`
- `nemid.pid`
- `nemid.pid_status`
- `dk.cpr`
- `loa`
- `acr`
- `neb_sid`
- `idp`
- `idp_transaction_id`
- `transaction_id`
- `session_expiry`
- `mitid.age`
- `mitid.date_of_birth`
- `mitid.identity_name`
- `mitid.transaction_id`
2 changes: 2 additions & 0 deletions docs/up-party-howto-saml-2.0-nemlogin.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ FoxIDs can be connected to NemLog-in (Danish IdP) with a [up-party SAML 2.0](up-
NemLog-in (currently called NemLog-in3) is a Danish Identity Provider (IdP) which uses the SAML 2.0 based OIOSAML 3. FoxIDs support NemLog-in / OIOSAML 3 including logging, issuer naming, required certificates and it is possible to support NSIS.

> Transforms the [DK privilege XML claim](claim-transform-dk-privilege.md) to a JSON claim.
NemLog-in documentation and configuration:
- The [NemLog-in development portal](https://tu.nemlog-in.dk/oprettelse-og-administration-af-tjenester/) with documentation
- [test](https://tu.nemlog-in.dk/oprettelse-og-administration-af-tjenester/log-in/dokumentation-og-guides/integrationstestmiljo/), where you can find the NemLog-in IdP-metadata for test and FOCES2 / OCES3 test certificates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public MClientSettingsController(FoxIDsControlSettings settings, TelemetryScoped
{
FoxIDsEndpoint = settings.FoxIDsEndpoint,
Version = version.ToString(2),
FullVersion = version.ToString(3)
FullVersion = version.ToString(4)
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public TReadCertificateController(TelemetryScopedLogger logger, IMapper mapper)
false => new X509Certificate2(WebEncoders.Base64UrlDecode(certificateAndPassword.EncodeCertificate), certificateAndPassword.Password, keyStorageFlags: X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable),
};

if (!certificate.HasPrivateKey)
if (!certificateAndPassword.Password.IsNullOrWhiteSpace() && !certificate.HasPrivateKey)
{
throw new ValidationException("Unable to read the certificates private key. E.g, try to convert the certificate and save the certificate with 'TripleDES-SHA1'.");
}
Expand Down
2 changes: 1 addition & 1 deletion src/FoxIDs.Control/FoxIDs.Control.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Version>1.0.13</Version>
<Version>1.0.14.5</Version>
<RootNamespace>FoxIDs</RootNamespace>
<Authors>Anders Revsgaard</Authors>
<Company>ITfoxtec</Company>
Expand Down
5 changes: 5 additions & 0 deletions src/FoxIDs.Control/Logic/ValidateOAuthOidcPartyLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public bool ValidateApiModel(ModelStateDictionary modelState, Api.OidcUpParty pa
isValid = isValidRmResult;
}

if (party.Client.UseUserInfoClaims && party.Client.UseIdTokenClaims)
{
party.Client.UseIdTokenClaims = false;
}

return isValid;
}

Expand Down
11 changes: 11 additions & 0 deletions src/FoxIDs.ControlClient/Extensions/RouteBindingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ namespace FoxIDs.Client
{
public static class RouteBindingExtensions
{
public static string ToDownPartyBinding(this string downPartyName, bool addUpParty, PartyBindingPatterns partyBindingPattern)
{
return partyBindingPattern switch
{
PartyBindingPatterns.Brackets => $"{downPartyName}{(addUpParty ? $"(*)" : string.Empty)}",
PartyBindingPatterns.Tildes => $"{downPartyName}{(addUpParty ? $"~*~" : string.Empty)}",
PartyBindingPatterns.Dot => $"{downPartyName}{(addUpParty ? $".*." : string.Empty)}",
_ => throw new NotImplementedException($"Party binding pattern '{partyBindingPattern}' not implemented.")
};
}

public static string ToUpPartyBinding(this string upPartyName, PartyBindingPatterns partyBindingPattern)
{
return partyBindingPattern switch
Expand Down
2 changes: 1 addition & 1 deletion src/FoxIDs.ControlClient/FoxIDs.ControlClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Version>1.0.13</Version>
<Version>1.0.14.5</Version>
<RootNamespace>FoxIDs.Client</RootNamespace>
<Authors>Anders Revsgaard</Authors>
<Company>ITfoxtec</Company>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public class LoginUpPartyViewModel : IOAuthClaimTransformViewModel, IUpPartySess
[Display(Name = "Up-party name")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

/// <summary>
/// Default 10 hours.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public class OAuthDownPartyViewModel : IValidatableObject, IDownPartyName, IAllo
[Display(Name = "Down-party name (client ID / resource name)")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

[ValidateComplexType]
[Length(Constants.Models.DownParty.AllowUpPartyNamesMin, Constants.Models.DownParty.AllowUpPartyNamesMax, Constants.Models.Party.NameLength, Constants.Models.Party.NameRegExPattern)]
[Display(Name = "Allow up-party names (client IDs)")]
Expand All @@ -36,6 +40,12 @@ public class OAuthDownPartyViewModel : IValidatableObject, IDownPartyName, IAllo
[Length(Constants.Models.Claim.TransformsMin, Constants.Models.Claim.TransformsMax)]
public List<OAuthClaimTransformViewModel> ClaimTransforms { get; set; } = new List<OAuthClaimTransformViewModel>();

/// <summary>
/// URL party binding pattern.
/// </summary>
[Display(Name = "URL party binding pattern")]
public PartyBindingPatterns PartyBindingPattern { get; set; } = PartyBindingPatterns.Brackets;

/// <summary>
/// Allow CORS origins.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public class OidcDownPartyViewModel : IValidatableObject, IDownPartyName, IAllow
[Display(Name = "Down-party name (client ID / resource name)")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

[ValidateComplexType]
[Length(Constants.Models.DownParty.AllowUpPartyNamesMin, Constants.Models.DownParty.AllowUpPartyNamesMax, Constants.Models.Party.NameLength, Constants.Models.Party.NameRegExPattern)]
[Display(Name = "Allow up-party names (client IDs)")]
Expand All @@ -36,6 +40,12 @@ public class OidcDownPartyViewModel : IValidatableObject, IDownPartyName, IAllow
[Length(Constants.Models.Claim.TransformsMin, Constants.Models.Claim.TransformsMax)]
public List<OAuthClaimTransformViewModel> ClaimTransforms { get; set; } = new List<OAuthClaimTransformViewModel>();

/// <summary>
/// URL party binding pattern.
/// </summary>
[Display(Name = "URL party binding pattern")]
public PartyBindingPatterns PartyBindingPattern { get; set; } = PartyBindingPatterns.Brackets;

/// <summary>
/// Allow CORS origins.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class OidcUpClientViewModel : IValidatableObject
[Display(Name = "Token URL")]
public string TokenUrl { get; set; }

[MaxLength(Constants.Models.OAuthUpParty.Client.UserInfoUrlLength)]
[Display(Name = "UserInfo URL")]
public string UserInfoUrl { get; set; }

[MaxLength(Constants.Models.OAuthUpParty.Client.EndSessionUrlLength)]
[Display(Name = "End session URL")]
public string EndSessionUrl { get; set; }
Expand All @@ -54,7 +58,10 @@ public class OidcUpClientViewModel : IValidatableObject
[Display(Name = "Use PKCE")]
public bool EnablePkce { get; set; } = true;

[Display(Name = "Use claims from ID token instead of access token")]
[Display(Name = "Read claims from the UserInfo Endpoint instead of the access token or ID token")]
public bool UseUserInfoClaims { get; set; }

[Display(Name = "Read claims from the ID token instead of the access token")]
public bool UseIdTokenClaims { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public class OidcUpPartyViewModel : IOAuthClaimTransformViewModel, IUpPartySessi
[Display(Name = "Up-party name (client ID)")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

public bool IsManual { get; set; }

public bool AutomaticStopped { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public class SamlDownPartyViewModel : IValidatableObject, IAllowUpPartyNames, ID
[Display(Name = "Down-party name")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

[ValidateComplexType]
[Length(Constants.Models.DownParty.AllowUpPartyNamesMin, Constants.Models.DownParty.AllowUpPartyNamesMax, Constants.Models.Party.NameLength, Constants.Models.Party.NameRegExPattern)]
[Display(Name = "Allow up-party names")]
Expand Down Expand Up @@ -59,6 +63,12 @@ public class SamlDownPartyViewModel : IValidatableObject, IAllowUpPartyNames, ID
[Display(Name = "Signature algorithm")]
public string SignatureAlgorithm { get; set; } = Saml2SecurityAlgorithms.RsaSha256Signature;

/// <summary>
/// URL party binding pattern.
/// </summary>
[Display(Name = "URL party binding pattern")]
public PartyBindingPatterns PartyBindingPattern { get; set; } = PartyBindingPatterns.Brackets;

/// <summary>
/// Default None.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public class SamlUpPartyViewModel : IValidatableObject, ISamlClaimTransformViewM
[Display(Name = "Up-party name")]
public string Name { get; set; }

[MaxLength(Constants.Models.Party.NoteLength)]
[Display(Name = "Your notes")]
public string Note { get; set; }

public bool IsManual { get; set; }

public bool AutomaticStopped { get; set; }
Expand Down
11 changes: 7 additions & 4 deletions src/FoxIDs.ControlClient/Pages/Components/DownPartyBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using FoxIDs.Client.Models.Config;
using FoxIDs.Client.Models.ViewModels;
using FoxIDs.Client.Services;
using FoxIDs.Models.Api;
using ITfoxtec.Identity;
using ITfoxtec.Identity.BlazorWebAssembly.OpenidConnect;
using Microsoft.AspNetCore.Components;
Expand Down Expand Up @@ -100,15 +101,17 @@ public void RemoveAllowUpPartyName((IAllowUpPartyNames model, string upPartyName
arg.model.AllowUpPartyNames.Remove(arg.upPartyName);
}

public (string, string) GetAuthorityAndOIDCDiscovery(string partyName, bool addUpParty)
public (string, string) GetAuthorityAndOIDCDiscovery(string partyName, bool addUpParty, PartyBindingPatterns partyBindingPattern = PartyBindingPatterns.Brackets)
{
var authority = $"{RouteBindingLogic.GetFoxIDsTenantEndpoint()}/{(RouteBindingLogic.IsMasterTenant ? "master" : TrackSelectedLogic.Track.Name)}/{(partyName.IsNullOrEmpty() ? "--down-party-name--" : partyName.ToLower())}{(addUpParty ? $"(*)" : String.Empty)}/";
var partyBinding = (partyName.IsNullOrEmpty() ? "--down-party-name--" : partyName.ToLower()).ToDownPartyBinding(addUpParty, partyBindingPattern);
var authority = $"{RouteBindingLogic.GetFoxIDsTenantEndpoint()}/{(RouteBindingLogic.IsMasterTenant ? "master" : TrackSelectedLogic.Track.Name)}/{partyBinding}/";
return (authority, authority + IdentityConstants.OidcDiscovery.Path);
}

public string GetSamlMetadata(string partyName)
public string GetSamlMetadata(string partyName, PartyBindingPatterns partyBindingPattern)
{
return $"{RouteBindingLogic.GetFoxIDsTenantEndpoint()}/{(RouteBindingLogic.IsMasterTenant ? "master" : TrackSelectedLogic.Track.Name)}/{(partyName.IsNullOrEmpty() ? "--down-party-name--" : partyName.ToLower())}(*)/{Constants.Routes.SamlController}/{Constants.Endpoints.SamlIdPMetadata}";
var partyBinding = (partyName.IsNullOrEmpty() ? "--down-party-name--" : partyName.ToLower()).ToDownPartyBinding(true, partyBindingPattern);
return $"{RouteBindingLogic.GetFoxIDsTenantEndpoint()}/{(RouteBindingLogic.IsMasterTenant ? "master" : TrackSelectedLogic.Track.Name)}/{partyBinding}/{Constants.Routes.SamlController}/{Constants.Endpoints.SamlIdPMetadata}";
}

public async Task DownPartyCancelAsync(GeneralDownPartyViewModel downParty)
Expand Down
9 changes: 5 additions & 4 deletions src/FoxIDs.ControlClient/Pages/Components/ELoginUpParty.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
<div>
Login
</div>
@if (loginUpParty.ShowLoginTab)
{
<button type="button" class="btn btn-link btn-xs" @onclick="@(() => loginUpParty.ShowAdvanced = !loginUpParty.ShowAdvanced)">@(loginUpParty.ShowAdvanced ? "Hide" : "Show") advanced settings</button>
}
<button type="button" class="btn btn-link btn-xs" @onclick="@(() => loginUpParty.ShowAdvanced = !loginUpParty.ShowAdvanced)">@(loginUpParty.ShowAdvanced ? "Hide" : "Show") advanced settings</button>
</div>
<div class="modal-body">
@if (loginUpParty.CreateMode)
Expand All @@ -26,6 +23,10 @@
{
<FFieldText @bind-Value="loginUpParty.Form.Model.Name" For="@(() => loginUpParty.Form.Model.Name)" />
}
@if (loginUpParty.ShowAdvanced)
{
<FInputText @bind-Value="loginUpParty.Form.Model.Note" For="@(() => loginUpParty.Form.Model.Note)" />
}

<ul class="nav nav-tabs">
<li class="nav-item">
Expand Down
Loading

0 comments on commit b20eae5

Please sign in to comment.