Skip to content

Commit

Permalink
(Very) basic reading of Assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
AndersAbel committed Feb 3, 2024
1 parent a5c8b26 commit 4211c17
Show file tree
Hide file tree
Showing 23 changed files with 298 additions and 67 deletions.
7 changes: 6 additions & 1 deletion src/Sustainsys.Saml2/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ public static class Elements
/// NameID element name
/// </summary>
public const string NameID = nameof(NameID);

/// <summary>
/// Assertion element name
/// </summary>
public const string Assertion = nameof(Assertion);
}

/// <summary>
Expand All @@ -239,7 +244,7 @@ public static class Elements
/// <remarks>The naming of the constants are deriberately not following
/// casing convention in order to be exactly the same as the contents.
/// </remarks>
public static class AttributeNames
public static class Attributes
{
/// <summary>
/// entityID attribute name.
Expand Down
40 changes: 40 additions & 0 deletions src/Sustainsys.Saml2/Saml/Assertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Sustainsys.Saml2.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace Sustainsys.Saml2.Saml;

/// <summary>
/// A Saml assertion
/// </summary>
public class Assertion
{
/// <summary>
/// Id of the assertion
/// </summary>
public string Id { get; set; } = XmlHelpers.CreateId();

/// <summary>
/// Issuer of the assertion.
/// </summary>
public NameId Issuer { get; set; } = default!;

/// <summary>
/// Version. Must be 2.0
/// </summary>
public string Version { get; set; } = "2.0";

/// <summary>
/// Isssue instance of the assertion
/// </summary>
public DateTime IssueInstance { get; set; } = DateTime.UtcNow;

/// <summary>
/// Subject of the assertion
/// </summary>
public Subject Subject { get; set; } = default!;
}
18 changes: 0 additions & 18 deletions src/Sustainsys.Saml2/Saml/SamlAssertion.cs

This file was deleted.

10 changes: 10 additions & 0 deletions src/Sustainsys.Saml2/Serialization/ISamlXmlReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,14 @@ public interface ISamlXmlReader
AuthnRequest ReadAuthnRequest(
XmlTraverser source,
Action<ReadErrorInspectorContext<AuthnRequest>>? errorInspector = null);

/// <summary>
/// Read an <see cref="Assertion"/>
/// </summary>
/// <param name="source">Xml Traverser to read from</param>
/// <param name="errorInspector">Callback that can inspect and alter errors before throwing</param>
/// <returns><see cref="Assertion"/></returns>
Assertion ReadAssertion(
XmlTraverser source,
Action<ReadErrorInspectorContext<Assertion>>? errorInspector = null);
}
89 changes: 89 additions & 0 deletions src/Sustainsys.Saml2/Serialization/SamlXmlReader.Assertion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Sustainsys.Saml2.Saml;
using Sustainsys.Saml2.Xml;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Sustainsys.Saml2.Constants;

namespace Sustainsys.Saml2.Serialization;

public partial class SamlXmlReader
{
/// <summary>
/// Create an empty Assertion instances
/// </summary>
/// <returns>Assertion</returns>
protected virtual Assertion CreateAssertion() => new();

/// <inheritdoc/>
public Assertion ReadAssertion(
XmlTraverser source,
Action<ReadErrorInspectorContext<Assertion>>? errorInspector = null)
{
var assertion = ReadAssertion(source);

CallErrorInspector(errorInspector, assertion, source);

source.ThrowOnErrors();

return assertion;
}

/// <summary>
/// Read an <see cref="Assertion"/>
/// </summary>
/// <param name="source">Xml Traverser to read from</param>
protected virtual Assertion ReadAssertion(XmlTraverser source)
{
var assertion = CreateAssertion();

if (source.EnsureName(Namespaces.SamlUri, Elements.Assertion))
{
ReadAttributes(source, assertion);
ReadElements(source.GetChildren(), assertion);

source.MoveNext(true);
}

return assertion;
}

/// <summary>
/// Read attributes of an assertion
/// </summary>
/// <param name="source">Xml Traverser to read from</param>
/// <param name="assertion"></param>
protected virtual void ReadAttributes(XmlTraverser source, Assertion assertion)
{
assertion.Id = source.GetRequiredAttribute(Attributes.ID);
assertion.IssueInstance = source.GetRequiredDateTimeAttribute(Attributes.IssueInstant);
assertion.Version = source.GetRequiredAttribute(Attributes.Version);
}

/// <summary>
/// Read elements of an assertion
/// </summary>
/// <param name="source"></param>
/// <param name="assertion"></param>
protected virtual void ReadElements(XmlTraverser source, Assertion assertion)
{
source.MoveNext();

if (source.EnsureName(Namespaces.SamlUri, Elements.Issuer))
{
assertion.Issuer = ReadNameId(source);
source.MoveNext();
}

// Status is optional on XML schema level, but Core 2.3.3. says that
// "an assertion without a subject has no defined meaning in this specification."
if (source.EnsureName(Namespaces.SamlUri, Elements.Subject))
{
assertion.Subject = ReadSubject(source);
source.MoveNext(true);
}
}
}
12 changes: 6 additions & 6 deletions src/Sustainsys.Saml2/Serialization/SamlXmlReader.AuthnRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public partial class SamlXmlReader
/// <returns>AuthnRequest</returns>
protected virtual AuthnRequest CreateAuthnRequest() => new();

//TODO: Convert other reads to follow this pattern with a callback for errors
// TODO: Convert other reads to follow this pattern with a callback for errors

/// <inheritdoc/>
public AuthnRequest ReadAuthnRequest(
Expand Down Expand Up @@ -72,10 +72,10 @@ protected virtual void ReadAttributes(XmlTraverser source, AuthnRequest authnReq
{
ReadAttributes(source, (RequestAbstractType)authnRequest);

authnRequest.ForceAuthn = source.GetBoolAttribute(AttributeNames.ForceAuthn) ?? authnRequest.ForceAuthn;
authnRequest.IsPassive = source.GetBoolAttribute(AttributeNames.IsPassive) ?? authnRequest.IsPassive;
authnRequest.AssertionConsumerServiceIndex = source.GetIntAttribute(AttributeNames.AssertionConsumerServiceIndex);
authnRequest.AssertionConsumerServiceUrl = source.GetAttribute(AttributeNames.AssertionConsumerServiceURL);
authnRequest.ProtocolBinding = source.GetAttribute(AttributeNames.ProtocolBinding);
authnRequest.ForceAuthn = source.GetBoolAttribute(Attributes.ForceAuthn) ?? authnRequest.ForceAuthn;
authnRequest.IsPassive = source.GetBoolAttribute(Attributes.IsPassive) ?? authnRequest.IsPassive;
authnRequest.AssertionConsumerServiceIndex = source.GetIntAttribute(Attributes.AssertionConsumerServiceIndex);
authnRequest.AssertionConsumerServiceUrl = source.GetAttribute(Attributes.AssertionConsumerServiceURL);
authnRequest.ProtocolBinding = source.GetAttribute(Attributes.ProtocolBinding);
}
}
8 changes: 4 additions & 4 deletions src/Sustainsys.Saml2/Serialization/SamlXmlReader.EndPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ protected virtual Endpoint ReadEndpoint(XmlTraverser source)
/// <param name="endpoint">Endpoint</param>
protected virtual void ReadAttributes(XmlTraverser source, Endpoint endpoint)
{
endpoint.Binding = source.GetRequiredAbsoluteUriAttribute(AttributeNames.Binding) ?? "";
endpoint.Location = source.GetRequiredAttribute(AttributeNames.Location) ?? "";
endpoint.Binding = source.GetRequiredAbsoluteUriAttribute(Attributes.Binding) ?? "";
endpoint.Location = source.GetRequiredAttribute(Attributes.Location) ?? "";
}

/// <summary>
Expand All @@ -49,8 +49,8 @@ protected virtual void ReadAttributes(XmlTraverser source, Endpoint endpoint)
protected virtual IndexedEndpoint ReadIndexedEndpoint(XmlTraverser source)
{
var result = CreateIndexedEndpoint();
result.Index = source.GetRequiredIntAttribute(AttributeNames.index);
result.IsDefault = source.GetBoolAttribute(AttributeNames.isDefault) ?? false;
result.Index = source.GetRequiredIntAttribute(Attributes.index);
result.IsDefault = source.GetBoolAttribute(Attributes.isDefault) ?? false;

ReadAttributes(source, result);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ public virtual EntityDescriptor ReadEntityDescriptor(XmlTraverser source)
/// <param name="entityDescriptor">EntityDescriptor</param>
protected virtual void ReadAttributes(XmlTraverser source, EntityDescriptor entityDescriptor)
{
entityDescriptor.EntityId = source.GetRequiredAbsoluteUriAttribute(AttributeNames.entityID) ?? "";
entityDescriptor.Id = source.GetAttribute(AttributeNames.ID);
entityDescriptor.CacheDuraton = source.GetTimeSpanAttribute(AttributeNames.cacheDuration);
entityDescriptor.ValidUntil = source.GetDateTimeAttribute(AttributeNames.validUntil);
entityDescriptor.EntityId = source.GetRequiredAbsoluteUriAttribute(Attributes.entityID) ?? "";
entityDescriptor.Id = source.GetAttribute(Attributes.ID);
entityDescriptor.CacheDuraton = source.GetTimeSpanAttribute(Attributes.cacheDuration);
entityDescriptor.ValidUntil = source.GetDateTimeAttribute(Attributes.validUntil);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ protected virtual void ReadAttributes(XmlTraverser source, IDPSSODescriptor resu
{
ReadAttributes(source, (SSODescriptor)result);

result.WantAuthnRequestsSigned = source.GetBoolAttribute(AttributeNames.WantAuthnRequestsSigned) ?? false;
result.WantAuthnRequestsSigned = source.GetBoolAttribute(Attributes.WantAuthnRequestsSigned) ?? false;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected virtual KeyDescriptor ReadKeyDescriptor(XmlTraverser source)
{
var result = CreateKeyDescriptor();

result.Use = source.GetEnumAttribute<KeyUse>(AttributeNames.use, true) ?? KeyUse.Both;
result.Use = source.GetEnumAttribute<KeyUse>(Attributes.use, true) ?? KeyUse.Both;

var children = source.GetChildren();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ public partial class SamlXmlReader
/// <param name="request">RequestAbstractType</param>
protected virtual void ReadAttributes(XmlTraverser source, RequestAbstractType request)
{
request.Id = source.GetRequiredAttribute(AttributeNames.ID);
request.IssueInstant = source.GetRequiredDateTimeAttribute(AttributeNames.IssueInstant);
request.Version = source.GetRequiredAttribute(AttributeNames.Version);
request.Destination = source.GetAttribute(AttributeNames.Destination);
request.Consent = source.GetAttribute(AttributeNames.Consent);
request.Id = source.GetRequiredAttribute(Attributes.ID);
request.IssueInstant = source.GetRequiredDateTimeAttribute(Attributes.IssueInstant);
request.Version = source.GetRequiredAttribute(Attributes.Version);
request.Destination = source.GetAttribute(Attributes.Destination);
request.Consent = source.GetAttribute(Attributes.Consent);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected virtual RoleDescriptor ReadRoleDescriptor(XmlTraverser source)
protected virtual void ReadAttributes(XmlTraverser source, RoleDescriptor result)
{
result.ProtocolSupportEnumeration =
source.GetRequiredAbsoluteUriAttribute(AttributeNames.protocolSupportEnumeration);
source.GetRequiredAbsoluteUriAttribute(Attributes.protocolSupportEnumeration);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Sustainsys.Saml2/Serialization/SamlXmlReader.Status.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected virtual StatusCode ReadStatusCode(XmlTraverser source)
/// <param name="statusCode"></param>
protected virtual void ReadAttributes(XmlTraverser source, StatusCode statusCode)
{
statusCode.Value = source.GetRequiredAbsoluteUriAttribute(AttributeNames.Value)!;
statusCode.Value = source.GetRequiredAbsoluteUriAttribute(Attributes.Value)!;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ partial class SamlXmlReader
/// <param name="response">StatusResponse</param>
protected virtual void ReadAttributes(XmlTraverser source, StatusResponseType response)
{
response.Id = source.GetRequiredAttribute(AttributeNames.ID);
response.Version = source.GetRequiredAttribute(AttributeNames.Version);
response.IssueInstant = source.GetRequiredDateTimeAttribute(AttributeNames.IssueInstant);
response.InResponseTo = source.GetAttribute(AttributeNames.InResponseTo);
response.Destination = source.GetAttribute(AttributeNames.Destination);
response.Id = source.GetRequiredAttribute(Attributes.ID);
response.Version = source.GetRequiredAttribute(Attributes.Version);
response.IssueInstant = source.GetRequiredDateTimeAttribute(Attributes.IssueInstant);
response.InResponseTo = source.GetAttribute(Attributes.InResponseTo);
response.Destination = source.GetAttribute(Attributes.Destination);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public virtual XmlDocument Write(AuthnRequest authnRequest)
protected virtual void Append(XmlNode node, AuthnRequest authnRequest)
{
var xe = Append(node, authnRequest, Elements.AuthnRequest);
xe.SetAttributeIfValue(AttributeNames.AssertionConsumerServiceURL, authnRequest.AssertionConsumerServiceUrl);
xe.SetAttributeIfValue(Attributes.AssertionConsumerServiceURL, authnRequest.AssertionConsumerServiceUrl);
AppendIfValue(xe, authnRequest.Issuer, Namespaces.Saml, Elements.Issuer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ partial class SamlXmlWriter
protected virtual XmlElement Append(XmlNode parent, RequestAbstractType request, string localName)
{
var element = Append(parent, Namespaces.Samlp, localName);
element.SetAttribute(AttributeNames.ID, request.Id);
element.SetAttribute(AttributeNames.IssueInstant, XmlConvert.ToString(request.IssueInstant, XmlDateTimeSerializationMode.RoundtripKind));
element.SetAttribute(AttributeNames.Version, request.Version);
element.SetAttribute(Attributes.ID, request.Id);
element.SetAttribute(Attributes.IssueInstant, XmlConvert.ToString(request.IssueInstant, XmlDateTimeSerializationMode.RoundtripKind));
element.SetAttribute(Attributes.Version, request.Version);

return element;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Sustainsys.Saml2/Validation/ISamlAssertionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public interface ISamlAssertionValidator
/// </summary>
/// <param name="assertion"></param>
/// <param name="parameters"></param>
void Validate(SamlAssertion assertion, SamlAssertionValidationParameters parameters);
void Validate(Assertion assertion, SamlAssertionValidationParameters parameters);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Sustainsys.Saml2/Validation/SamlAssertionValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class SamlAssertionValidator : ISamlAssertionValidator
{
/// <inheritdoc/>
public void Validate(
SamlAssertion assertion,
Assertion assertion,
SamlAssertionValidationParameters parameters)
{
// TODO: Remember to validate issuer.
Expand Down
5 changes: 3 additions & 2 deletions src/Sustainsys.Saml2/Validation/SamlResponseValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public void Validate(
SamlResponse samlResponse,
SamlResponseValidationParameters validationParameters)
{
// TODO: Validate Version
ValidateIssuer(samlResponse, validationParameters);
ValidateStatusCode(samlResponse);
}
Expand All @@ -26,7 +27,7 @@ public void Validate(
/// Validate that the status code is <see cref="Constants.StatusCodes.Success"/>
/// </summary>
/// <param name="samlResponse">Saml Response</param>
public virtual void ValidateStatusCode(SamlResponse samlResponse)
protected void ValidateStatusCode(SamlResponse samlResponse)
{
if (samlResponse.Status?.StatusCode?.Value != Constants.StatusCodes.Success)
{
Expand All @@ -39,7 +40,7 @@ public virtual void ValidateStatusCode(SamlResponse samlResponse)
/// </summary>
/// <param name="samlResponse">Saml response</param>
/// <param name="validationParameters">Validation parameters</param>
public virtual void ValidateIssuer(
protected virtual void ValidateIssuer(
SamlResponse samlResponse,
SamlResponseValidationParameters validationParameters)
{
Expand Down
Loading

0 comments on commit 4211c17

Please sign in to comment.