Skip to content

Commit

Permalink
Merge pull request #178 from ITfoxtec/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Revsgaard authored Mar 12, 2024
2 parents 4b61e13 + d907326 commit 8cb248a
Show file tree
Hide file tree
Showing 27 changed files with 297 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ Support the Danish NemLog-in 2 / OIOSAML 2 and NemLog-in 3 / OIOSAML 3.</Descrip
<PackageTags>SAML SAML 2.0 SAML2.0 SAML2 SAML 2 SAML-P SAMLP SSO Identity Provider (IdP) and Relying Party (RP) Authentication Metadata OIOSAML OIOSAML 2 OIOSAML 3 NemLogin NemLog-in 2 NemLog-in 3 ASP.NET MVC</PackageTags>
<NeutralLanguage>en-US</NeutralLanguage>
<PackageIconUrl>https://itfoxtec.com/favicon.ico</PackageIconUrl>
<AssemblyVersion>4.10.8.0</AssemblyVersion>
<FileVersion>4.10.8.0</FileVersion>
<AssemblyVersion>4.10.9.1</AssemblyVersion>
<FileVersion>4.10.9.1</FileVersion>
<Copyright>Copyright © 2023</Copyright>
<Version>4.10.8.0</Version>
<Version>4.10.9-beta1</Version>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>ITfoxtec.SAML2.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ Support the Danish NemLog-in 2 / OIOSAML 2 and NemLog-in 3 / OIOSAML 3.</Descrip
<PackageTags>SAML SAML 2.0 SAML2.0 SAML2 SAML 2 SAML-P SAMLP SSO Identity Provider (IdP) Relying Party (RP) Authentication Metadata OIOSAML OIOSAML 2 OIOSAML 3 NemLogin NemLog-in 2 NemLog-in 3 ASP.NET MVC Core</PackageTags>
<NeutralLanguage>en-US</NeutralLanguage>
<PackageIconUrl>https://itfoxtec.com/favicon.ico</PackageIconUrl>
<AssemblyVersion>4.10.8.0</AssemblyVersion>
<FileVersion>4.10.8.0</FileVersion>
<AssemblyVersion>4.10.9.1</AssemblyVersion>
<FileVersion>4.10.9.1</FileVersion>
<Copyright>Copyright © 2023</Copyright>
<Version>4.10.8.0</Version>
<Version>4.10.9-beta1</Version>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>ITfoxtec.SAML2.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public Saml2ArtifactBinding()
CertificateIncludeOption = X509IncludeOption.EndCertOnly;
}

protected internal override void BindInternal(Saml2Request saml2Request, string messageName)
protected override void BindInternal(Saml2Request saml2Request, string messageName)
{
if (!(saml2Request is Saml2ArtifactResolve saml2ArtifactResolve))
throw new ArgumentException("Only Saml2ArtifactResolve is supported");
Expand Down
9 changes: 7 additions & 2 deletions src/ITfoxtec.Identity.Saml2/Bindings/Saml2Binding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public abstract class Saml2Binding
public Saml2Binding()
{ }

protected internal virtual void BindInternal(Saml2Request saml2RequestResponse, bool createXml = true)
protected virtual void BindInternal(Saml2Request saml2RequestResponse, bool createXml = true)
{
if (saml2RequestResponse == null)
throw new ArgumentNullException(nameof(saml2RequestResponse));
Expand All @@ -54,7 +54,12 @@ protected internal virtual void BindInternal(Saml2Request saml2RequestResponse,
}
}

protected internal abstract void BindInternal(Saml2Request saml2RequestResponse, string messageName);
internal void ApplyBinding(Saml2Request saml2RequestResponse, string messageName)
{
BindInternal(saml2RequestResponse, messageName);
}

protected abstract void BindInternal(Saml2Request saml2RequestResponse, string messageName);

public Saml2Request Unbind(HttpRequest request, Saml2Request saml2Request)
{
Expand Down
2 changes: 1 addition & 1 deletion src/ITfoxtec.Identity.Saml2/Bindings/Saml2PostBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public Saml2PostBinding()
CertificateIncludeOption = X509IncludeOption.EndCertOnly;
}

protected internal override void BindInternal(Saml2Request saml2RequestResponse, string messageName)
protected override void BindInternal(Saml2Request saml2RequestResponse, string messageName)
{
BindInternal(saml2RequestResponse);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class Saml2RedirectBinding : Saml2Binding

public string Signature { get; protected set; }

protected internal override void BindInternal(Saml2Request saml2RequestResponse, string messageName)
protected override void BindInternal(Saml2Request saml2RequestResponse, string messageName)
{
base.BindInternal(saml2RequestResponse);

Expand Down
2 changes: 1 addition & 1 deletion src/ITfoxtec.Identity.Saml2/Bindings/Saml2SoapEnvelope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class Saml2SoapEnvelope : Saml2Binding
/// </summary>
public string SoapResponseXml { get; set; }

protected internal override void BindInternal(Saml2Request saml2Request, string messageName)
protected override void BindInternal(Saml2Request saml2Request, string messageName)
{
if (!(saml2Request is Saml2ArtifactResponse))
throw new ArgumentException("Only Saml2ArtifactResponse is supported");
Expand Down
2 changes: 2 additions & 0 deletions src/ITfoxtec.Identity.Saml2/Claims/Saml2ClaimTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ public static class Saml2ClaimTypes
{
public const string NameId = "http://schemas.itfoxtec.com/ws/2014/02/identity/claims/saml2nameid";
public const string NameIdFormat = "http://schemas.itfoxtec.com/ws/2014/02/identity/claims/saml2nameidformat";
public const string NameQualifier = "http://schemas.itfoxtec.com/ws/2014/02/identity/claims/saml2namequalifier";
public const string SPNameQualifier = "http://schemas.itfoxtec.com/ws/2014/02/identity/claims/saml2spnamequalifier";
public const string SessionIndex = "http://schemas.itfoxtec.com/ws/2014/02/identity/claims/saml2sessionindex";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ public static class Saml2BindingExtensions
{
public static T Bind<T>(this T binding, Saml2Request saml2Request) where T : Saml2Binding
{
binding.BindInternal(saml2Request, Saml2Constants.Message.SamlRequest);
binding.ApplyBinding(saml2Request, Saml2Constants.Message.SamlRequest);
return binding;
}

public static T Bind<T>(this T binding, Saml2Response saml2Response) where T : Saml2Binding
{
binding.BindInternal(saml2Response, Saml2Constants.Message.SamlResponse);
binding.ApplyBinding(saml2Response, Saml2Constants.Message.SamlResponse);
return binding;
}

public static T Bind<T>(this T binding, Saml2ArtifactResolve saml2ArtifactResolve) where T : Saml2Binding
{
binding.BindInternal(saml2ArtifactResolve, Saml2Constants.Message.SamlArt);
binding.ApplyBinding(saml2ArtifactResolve, Saml2Constants.Message.SamlArt);
return binding;
}

Expand Down
6 changes: 3 additions & 3 deletions src/ITfoxtec.Identity.Saml2/ITfoxtec.Identity.Saml2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ Support the Danish NemLog-in 2 / OIOSAML 2 and NemLog-in 3 / OIOSAML 3.</Descrip
<PackageTags>SAML SAML 2.0 SAML2.0 SAML2 SAML 2 SAML-P SAMLP SSO Identity Provider (IdP) Relying Party (RP) Authentication Metadata OIOSAML OIOSAML 2 OIOSAML 3 NemLogin NemLog-in 2 NemLog-in 3</PackageTags>
<NeutralLanguage>en-US</NeutralLanguage>
<PackageIconUrl>https://itfoxtec.com/favicon.ico</PackageIconUrl>
<AssemblyVersion>4.10.8.0</AssemblyVersion>
<FileVersion>4.10.8.0</FileVersion>
<AssemblyVersion>4.10.9.1</AssemblyVersion>
<FileVersion>4.10.9.1</FileVersion>
<Copyright>Copyright © 2023</Copyright>
<Version>4.10.8.0</Version>
<Version>4.10.9-beta1</Version>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>ITfoxtec.SAML2.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
Expand Down
18 changes: 17 additions & 1 deletion src/ITfoxtec.Identity.Saml2/Request/Saml2AuthnRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,19 @@ public class Saml2AuthnRequest : Saml2Request
/// <summary>
/// [Optional]
/// If present, specifies an Audience
/// Part of the OIOSAML standard used for conditions on request.
/// Specifies the SAML conditions the requester expects to limit the validity and/or use of the resulting
/// assertion(s).
/// </summary>
public Condition Conditions { get; set; }

/// <summary>
/// [Optional]
/// Specifies a set of identity providers trusted by the requester to authenticate the presenter, as well as
/// limitations and context related to proxying of the &lt;AuthnRequest&gt; message to subsequent identity
/// providers by the responder.
/// </summary>
public Scoping Scoping { get; set; }

public Saml2AuthnRequest(Saml2Configuration config) : base(config)
{
if (config == null) throw new ArgumentNullException(nameof(config));
Expand Down Expand Up @@ -185,6 +194,11 @@ protected override IEnumerable<XObject> GetXContent()
{
yield return RequestedAuthnContext.ToXElement();
}

if (Scoping != null)
{
yield return Scoping.ToXElement();
}
}

protected internal override void Read(string xml, bool validate = false, bool detectReplayedTokens = true)
Expand All @@ -208,6 +222,8 @@ protected internal override void Read(string xml, bool validate = false, bool de
NameIdPolicy = XmlDocument.DocumentElement[Saml2Constants.Message.NameIdPolicy, Saml2Constants.ProtocolNamespace.OriginalString].GetElementOrNull<NameIdPolicy>();

RequestedAuthnContext = XmlDocument.DocumentElement[Saml2Constants.Message.RequestedAuthnContext, Saml2Constants.ProtocolNamespace.OriginalString].GetElementOrNull<RequestedAuthnContext>();

Scoping = XmlDocument.DocumentElement[Saml2Constants.Message.Scoping, Saml2Constants.ProtocolNamespace.OriginalString].GetElementOrNull<Scoping>();
}

protected override void ValidateElementName()
Expand Down
2 changes: 1 addition & 1 deletion src/ITfoxtec.Identity.Saml2/Request/Saml2AuthnResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ protected override XmlElement GetAssertionElement()
return assertionElementCache;
}

private XmlElement GetAssertionElementReference()
protected XmlElement GetAssertionElementReference()
{
var assertionElements = XmlDocument.DocumentElement.SelectNodes($"//*[local-name()='{Schemas.Saml2Constants.Message.Assertion}']");
if (assertionElements.Count != 1)
Expand Down
25 changes: 21 additions & 4 deletions src/ITfoxtec.Identity.Saml2/Request/Saml2LogoutRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ public Saml2LogoutRequest(Saml2Configuration config, ClaimsPrincipal currentPrin
NameId = new Saml2NameIdentifier(ReadClaimValue(identity, Saml2ClaimTypes.NameId), new Uri(nameIdFormat));

}
var nameIdNameQualifier = ReadClaimValue(identity, Saml2ClaimTypes.NameQualifier, false);
if (!string.IsNullOrEmpty(nameIdNameQualifier))
{
NameId.NameQualifier = nameIdNameQualifier;
}
var nameIdSPNameQualifier = ReadClaimValue(identity, Saml2ClaimTypes.SPNameQualifier, false);
if (!string.IsNullOrEmpty(nameIdSPNameQualifier))
{
NameId.SPNameQualifier = nameIdSPNameQualifier;
}
SessionIndex = ReadClaimValue(identity, Saml2ClaimTypes.SessionIndex, false);
}
}
Expand Down Expand Up @@ -103,15 +113,20 @@ protected override IEnumerable<XObject> GetXContent()

if (NameId != null)
{
object[] nameIdContent;
var nameIdContent = new List<object>() { NameId.Value };
if (NameId.Format != null)
{
nameIdContent = new object[] { NameId.Value, new XAttribute(Schemas.Saml2Constants.Message.Format, NameId.Format) };
nameIdContent.Add(new XAttribute(Schemas.Saml2Constants.Message.Format, NameId.Format));
}
else
if (NameId.NameQualifier != null)
{
nameIdContent.Add(new XAttribute(Schemas.Saml2Constants.Message.NameQualifier, NameId.NameQualifier));
}
if (NameId.SPNameQualifier != null)
{
nameIdContent = new object[] { NameId.Value };
nameIdContent.Add(new XAttribute(Schemas.Saml2Constants.Message.SpNameQualifier, NameId.SPNameQualifier));
}

yield return new XElement(Schemas.Saml2Constants.AssertionNamespaceX + Schemas.Saml2Constants.Message.NameId, nameIdContent);
}

Expand All @@ -126,6 +141,8 @@ protected internal override void Read(string xml, bool validate = false, bool de
base.Read(xml, validate, detectReplayedTokens);

NameId = XmlDocument.DocumentElement[Schemas.Saml2Constants.Message.NameId, Schemas.Saml2Constants.AssertionNamespace.OriginalString].GetValueOrNull<Saml2NameIdentifier>();
NameId.NameQualifier = XmlDocument.DocumentElement[Schemas.Saml2Constants.Message.NameId, Schemas.Saml2Constants.AssertionNamespace.OriginalString].GetAttribute(Schemas.Saml2Constants.Message.NameQualifier);
NameId.SPNameQualifier = XmlDocument.DocumentElement[Schemas.Saml2Constants.Message.NameId, Schemas.Saml2Constants.AssertionNamespace.OriginalString].GetAttribute(Schemas.Saml2Constants.Message.SpNameQualifier);

SessionIndex = XmlDocument.DocumentElement[Schemas.Saml2Constants.Message.SessionIndex, Schemas.Saml2Constants.ProtocolNamespace.OriginalString].GetValueOrNull<string>();
}
Expand Down
14 changes: 13 additions & 1 deletion src/ITfoxtec.Identity.Saml2/Schemas/Condition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,22 @@ public class Condition
/// </summary>
public const string elementName = Saml2Constants.Message.Conditions;

public List<ICondition> Items { get; set; }
/// <summary>
/// [Any Number]
/// A condition of a type defined in an extension schema.
/// </summary>
public IEnumerable<ICondition> Items { get; set; }

/// <summary>
/// [Optional]
/// Specifies the earliest time instant at which the assertion is valid.
/// </summary>
public DateTimeOffset? NotOnOrAfter { get; set; }

/// <summary>
/// [Optional]
/// Specifies the time instant at which the assertion has expired.
/// </summary>
public DateTimeOffset? NotBefore { get; set; }

public XElement ToXElement()
Expand Down
62 changes: 62 additions & 0 deletions src/ITfoxtec.Identity.Saml2/Schemas/IDPEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Xml.Linq;

namespace ITfoxtec.Identity.Saml2.Schemas
{
/// <summary>
/// The IDPEntry element specifies a single identity provider trusted by the requester to authenticate the
/// presenter.Its IDPEntryType complex type defines the following attributes:
/// </summary>
public class IDPEntry
{
public const string elementName = Saml2Constants.Message.IDPEntry;

/// <summary>
/// [Required]
/// The unique identifier of the identity provider.See Section 8.3.6 for a description of such identifiers.
/// </summary>
public string ProviderID { get; set; }

/// <summary>
/// [Optional]
/// A human-readable name for the identity provider.
/// </summary>
public string Name { get; set; }

/// <summary>
/// [Optional]
/// A URI reference representing the location of a profile-specific endpoint supporting the authentication
/// request protocol.The binding to be used must be understood from the profile of use.
/// </summary>
public string Loc { get; set; }

public XElement ToXElement()
{
var envelope = new XElement(Saml2Constants.AssertionNamespaceX + elementName);

envelope.Add(GetXContent());

return envelope;
}

protected virtual IEnumerable<XObject> GetXContent()
{
yield return new XAttribute(Saml2Constants.AssertionNamespaceNameX, Saml2Constants.AssertionNamespaceX);

if (ProviderID != null)
{
yield return new XAttribute(Saml2Constants.Message.ProviderID, ProviderID);
}

if (Name != null)
{
yield return new XAttribute(Saml2Constants.Message.Name, Name);
}

if (Loc != null)
{
yield return new XAttribute(Saml2Constants.Message.Loc, Loc);
}
}
}
}
53 changes: 53 additions & 0 deletions src/ITfoxtec.Identity.Saml2/Schemas/IDPList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Xml.Linq;

namespace ITfoxtec.Identity.Saml2.Schemas
{
/// <summary>
/// The element specifies the identity providers trusted by the requester to authenticate the presenter.
/// </summary>
public class IDPList
{
public const string elementName = Saml2Constants.Message.IDPList;

/// <summary>
/// [One or More]
/// Information about a single identity provider.
/// </summary>
public IEnumerable<IDPEntry> IDPEntry { get; set; }

/// <summary>
/// [Optional]
/// If the IDPList is not complete, using this element specifies a URI reference that can be used to
/// retrieve the complete list.
/// </summary>
public string GetComplete { get; set; }

public XElement ToXElement()
{
var envelope = new XElement(Saml2Constants.AssertionNamespaceX + elementName);

envelope.Add(GetXContent());

return envelope;
}

protected virtual IEnumerable<XObject> GetXContent()
{
yield return new XAttribute(Saml2Constants.AssertionNamespaceNameX, Saml2Constants.AssertionNamespaceX);

if (GetComplete != null)
{
yield return new XAttribute(Saml2Constants.Message.GetComplete, GetComplete);
}

if (IDPEntry != null)
{
foreach (var entry in IDPEntry)
{
yield return entry.ToXElement();
}
}
}
}
}
Loading

0 comments on commit 8cb248a

Please sign in to comment.