Skip to content

Commit

Permalink
Reject non-bearer assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
AndersAbel committed Apr 21, 2020
1 parent d18499c commit 186b761
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
17 changes: 17 additions & 0 deletions Sustainsys.Saml2/SAML2P/Saml2PSecurityTokenHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Tokens.Saml2;
using Sustainsys.Saml2.Configuration;
using Sustainsys.Saml2.Exceptions;
using Sustainsys.Saml2.Internal;
using Sustainsys.Saml2.Tokens;
using System;
Expand Down Expand Up @@ -98,5 +99,21 @@ public override ClaimsPrincipal ValidateToken(string token, TokenValidationParam

return new ClaimsPrincipal(identity);
}
private static readonly Uri bearerUri = new Uri("urn:oasis:names:tc:SAML:2.0:cm:bearer");

protected override void ValidateSubject(Saml2SecurityToken samlToken, TokenValidationParameters validationParameters)
{
base.ValidateSubject(samlToken, validationParameters);

if(!samlToken.Assertion.Subject.SubjectConfirmations.Any())
{
throw new Saml2ResponseFailedValidationException("No subject confirmation method found.");
}

if(!samlToken.Assertion.Subject.SubjectConfirmations.Any(sc => sc.Method == bearerUri))
{
throw new Saml2ResponseFailedValidationException("Only assertions with subject confirmation method \"bearer\" are supported.");
}
}
}
}
67 changes: 67 additions & 0 deletions Tests/Tests.Shared/Saml2P/Saml2ResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2354,6 +2354,73 @@ public void Saml2Response_GetClaims_ValidatesIdpCertificateIfConfigured()
.And.Message.Should().Be("The signature was valid, but the verification of the certificate failed. Is it expired or revoked? Are you sure you really want to enable ValidateCertificates (it's normally not needed)?");
}

[TestMethod]
public void Saml2Response_GetClaims_RejectsHolderOfKey()
{
var options = StubFactory.CreateOptions();

var responseXml =
@"<?xml version=""1.0"" encoding=""UTF-8""?>
<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
ID = """ + MethodBase.GetCurrentMethod().Name + @""" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
<saml2:Issuer>https://idp.example.com</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
</saml2p:Status>
<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
Version=""2.0"" ID=""" + MethodBase.GetCurrentMethod().Name + @"_Assertion1""
IssueInstant=""2013-09-25T00:00:00Z"">
<saml2:Issuer>https://idp.example.com</saml2:Issuer>
<saml2:Subject>
<saml2:NameID>SomeUser</saml2:NameID>
<saml2:SubjectConfirmation Method=""urn:oasis:names:tc:SAML:2.0:cm:holder-of-key"" />
</saml2:Subject>
<saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
</saml2:Assertion>
</saml2p:Response>";

responseXml = SignedXmlHelper.SignXml(responseXml);

Saml2Response.Read(responseXml).Invoking(
r => r.GetClaims(options))
.Should().Throw<Saml2Exception>()
.WithMessage("*subject confirmation*bearer*");
}

[TestMethod]
public void Saml2Response_GetClaims_RejectsMissingSubjectConfirmation()
{
var options = StubFactory.CreateOptions();

var responseXml =
@"<?xml version=""1.0"" encoding=""UTF-8""?>
<saml2p:Response xmlns:saml2p=""urn:oasis:names:tc:SAML:2.0:protocol""
xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
ID = """ + MethodBase.GetCurrentMethod().Name + @""" Version=""2.0"" IssueInstant=""2013-01-01T00:00:00Z"">
<saml2:Issuer>https://idp.example.com</saml2:Issuer>
<saml2p:Status>
<saml2p:StatusCode Value=""urn:oasis:names:tc:SAML:2.0:status:Success"" />
</saml2p:Status>
<saml2:Assertion xmlns:saml2=""urn:oasis:names:tc:SAML:2.0:assertion""
Version=""2.0"" ID=""" + MethodBase.GetCurrentMethod().Name + @"_Assertion1""
IssueInstant=""2013-09-25T00:00:00Z"">
<saml2:Issuer>https://idp.example.com</saml2:Issuer>
<saml2:Subject>
<saml2:NameID>SomeUser</saml2:NameID>
</saml2:Subject>
<saml2:Conditions NotOnOrAfter=""2100-01-01T00:00:00Z"" />
</saml2:Assertion>
</saml2p:Response>";

responseXml = SignedXmlHelper.SignXml(responseXml);

Saml2Response.Read(responseXml).Invoking(
r => r.GetClaims(options))
.Should().Throw<Saml2ResponseFailedValidationException>()
.WithMessage("*No subject confirmation*");
}

[TestMethod]
public void Saml2Response_SessionNotOnOrAfter_ExtractedFromMessage()
{
Expand Down

0 comments on commit 186b761

Please sign in to comment.