Skip to content

Commit 4f3aea6

Browse files
committed
AuthnRequest support Subject and NameID
1 parent 6387ea7 commit 4f3aea6

File tree

7 files changed

+115
-7
lines changed

7 files changed

+115
-7
lines changed

src/ITfoxtec.Identity.Saml2/Request/Saml2AuthnRequest.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ public class Saml2AuthnRequest : Saml2Request
3131
public bool? IsPassive { get; set; }
3232

3333
/// <summary>
34+
/// [Optional]
35+
/// Specifies the requested subject of the resulting assertion(s).
36+
/// </summary>
37+
public Subject Subject { get; set; }
38+
39+
/// <summary>
40+
/// [Optional]
3441
/// Specifies constraints on the name identifier to be used to represent the requested subject. If omitted,
3542
/// then any type of identifier supported by the identity provider for the requested subject can be used,
3643
/// constrained by any relevant deployment-specific policies, with respect to privacy, for example.
@@ -103,6 +110,11 @@ protected override IEnumerable<XObject> GetXContent()
103110
yield return new XAttribute(Saml2Constants.Message.AssertionConsumerServiceURL, AssertionConsumerServiceUrl);
104111
}
105112

113+
if (Subject != null)
114+
{
115+
yield return Subject.ToXElement();
116+
}
117+
106118
if (NameIdPolicy != null)
107119
{
108120
yield return NameIdPolicy.ToXElement();
@@ -121,6 +133,8 @@ protected internal override void Read(string xml, bool validateXmlSignature = fa
121133
ForceAuthn = XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.ForceAuthn].GetValueOrNull<bool>();
122134

123135
IsPassive = XmlDocument.DocumentElement.Attributes[Saml2Constants.Message.IsPassive].GetValueOrNull<bool>();
136+
137+
Subject = XmlDocument.DocumentElement[Saml2Constants.Message.Subject, Saml2Constants.AssertionNamespace.OriginalString].GetValueOrNull<Subject>();
124138
}
125139

126140
protected override void ValidateElementName()
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Xml.Linq;
4+
5+
namespace ITfoxtec.Identity.Saml2.Schemas
6+
{
7+
/// <summary>
8+
/// The <NameID> is used when an element serves to represent an entity by a string-valued name.
9+
/// </summary>
10+
public class NameID
11+
{
12+
const string elementName = Saml2Constants.Message.NameId;
13+
14+
/// <summary>
15+
/// String content containing the actual identifier.
16+
/// </summary>
17+
public string ID { get; set; }
18+
19+
/// <summary>
20+
/// [Optional]
21+
/// A URI reference representing the classification of string-based identifier information. See Section
22+
/// 8.3 for the SAML-defined URI references that MAY be used as the value of the Format attribute
23+
/// and their associated descriptions and processing rules.Unless otherwise specified by an element
24+
/// based on this type, if no Format value is provided, then the value
25+
/// urn:oasis:names:tc:SAML:1.0:nameid-format:unspecified(see Section 8.3.1) is in effect.
26+
/// </summary>
27+
public string Format { get; set; }
28+
29+
public XElement ToXElement()
30+
{
31+
var envelope = new XElement(Saml2Constants.AssertionNamespaceX + elementName);
32+
33+
envelope.Add(GetXContent());
34+
35+
return envelope;
36+
}
37+
38+
protected IEnumerable<XObject> GetXContent()
39+
{
40+
if (!string.IsNullOrWhiteSpace(Format))
41+
{
42+
yield return new XAttribute(Saml2Constants.Message.Format, Format);
43+
}
44+
45+
yield return new XText(ID);
46+
}
47+
}
48+
}

src/ITfoxtec.Identity.Saml2/Schemas/Saml2Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public static class Message
110110
internal const string NotOnOrAfter = "NotOnOrAfter";
111111

112112
internal const string Reason = "Reason";
113-
113+
114114
internal const string NameIdPolicy = "NameIDPolicy";
115115

116116
internal const string AllowCreate = "AllowCreate";
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Generic;
2+
using System.Xml.Linq;
3+
4+
namespace ITfoxtec.Identity.Saml2.Schemas
5+
{
6+
/// <summary>
7+
/// The <Subject> element specifies the principal that is the subject of all of the (zero or more) statements in the assertion.
8+
/// </summary>
9+
public class Subject
10+
{
11+
const string elementName = Saml2Constants.Message.Subject;
12+
13+
/// <summary>
14+
/// Contains an identifier.
15+
/// </summary>
16+
public NameID NameID { get; set; }
17+
18+
public XElement ToXElement()
19+
{
20+
var envelope = new XElement(Saml2Constants.AssertionNamespaceX + elementName);
21+
22+
envelope.Add(GetXContent());
23+
24+
return envelope;
25+
}
26+
27+
protected virtual IEnumerable<XObject> GetXContent()
28+
{
29+
if (NameID != null)
30+
{
31+
yield return NameID.ToXElement();
32+
}
33+
}
34+
}
35+
}

src/ITfoxtec.Identity.Saml2/Util/GenericTypeConverter.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.Globalization;
44
using System.Xml;
5+
using ITfoxtec.Identity.Saml2.Schemas;
56
#if NETFULL
67
using System.IdentityModel.Tokens;
78
#else
@@ -36,11 +37,19 @@ internal static T ConvertValue<T>(string value, XmlNode xmlNode)
3637
{
3738
return GenericConvertValue<T, Saml2NameIdentifier>(new Saml2NameIdentifier(value, ConvertValue<Uri>(xmlNode.Attributes[Schemas.Saml2Constants.Message.Format]?.Value, xmlNode)));
3839
}
40+
if (genericType == typeof(NameID))
41+
{
42+
return GenericConvertValue<T, NameID>(new NameID { ID = value, Format = xmlNode.Attributes[Schemas.Saml2Constants.Message.Format]?.Value });
43+
}
44+
if (genericType == typeof(Subject))
45+
{
46+
return GenericConvertValue<T, Subject>(new Subject { NameID = ConvertValue<NameID>(xmlNode[Schemas.Saml2Constants.Message.NameId, Schemas.Saml2Constants.AssertionNamespace.OriginalString]?.InnerText?.Trim(), xmlNode) });
47+
}
3948
else
4049
{
4150
return GenericConvertValue<T, string>(value);
4251
}
43-
}
52+
}
4453

4554
static T GenericConvertValue<T, U>(U value)
4655
{

test/TestIdPCore/Controllers/AuthController.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public IActionResult Login()
4242
// **** Handle user login e.g. in GUI ****
4343
// Test user with session index and claims
4444
var sessionIndex = Guid.NewGuid().ToString();
45-
var claims = CreateTestUserClaims();
45+
var claims = CreateTestUserClaims(saml2AuthnRequest.Subject?.NameID?.ID);
4646

4747
return LoginResponse(saml2AuthnRequest.Id, Saml2StatusCodes.Success, requestBinding.RelayState, relyingParty, sessionIndex, claims);
4848
}
@@ -170,11 +170,12 @@ class RelyingParty
170170
public X509Certificate2 SignatureValidationCertificate { get; set; }
171171
}
172172

173-
private IEnumerable<Claim> CreateTestUserClaims()
173+
private IEnumerable<Claim> CreateTestUserClaims(string selectedNameID)
174174
{
175-
yield return new Claim(ClaimTypes.NameIdentifier, "12345");
176-
yield return new Claim(ClaimTypes.Upn, "[email protected]");
177-
yield return new Claim(ClaimTypes.Email, "[email protected]");
175+
var userId = selectedNameID ?? "12345";
176+
yield return new Claim(ClaimTypes.NameIdentifier, userId);
177+
yield return new Claim(ClaimTypes.Upn, $"{userId}@email.test");
178+
yield return new Claim(ClaimTypes.Email, $"{userId}@someemail.test");
178179
}
179180
}
180181
}

test/TestWebAppCore/Controllers/AuthController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public IActionResult Login(string returnUrl = null)
3434
return binding.Bind(new Saml2AuthnRequest(config)
3535
{
3636
//ForceAuthn = true,
37+
Subject = new Subject { NameID = new NameID { ID = "abcd" } },
3738
//NameIdPolicy = new NameIdPolicy { AllowCreate = true, Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" },
3839
//RequestedAuthnContext = new RequestedAuthnContext
3940
//{

0 commit comments

Comments
 (0)