SimpleSaml.Assertion (simple_saml v1.2.0)
A struct for representing a SAML assertion.
Use from_node/1
to instantiate an Assertion
from an XML node. Then use
validate_time_conditions/1
to validate that the time constraints within the assertion are still
valid.
IMPORTANT: It is up to the user of the assertion to validate the issuer, recipient and audience fields based on (typically) stored records about the part making the assertion.
Summary
Functions
Given an assertion XML node, this function returns an Assertion struct that represents the data within the node.
Validates that the timestamp constraints within the given assertion are still valid.
Types
@type t() :: %SimpleSaml.Assertion{ attributes: %{required(String.t()) => [String.t()]}, audience: String.t(), issuer: String.t(), name_id: String.t(), name_id_not_on_or_after: DateTime.t(), not_before: DateTime.t(), not_on_or_after: DateTime.t(), recipient: String.t() }
@type xml_node() :: SimpleXml.xml_node()
Functions
Given an assertion XML node, this function returns an Assertion struct that represents the data within the node.
Note that this function does not validate the conditions within the assertion. Use
validate_time_conditions/1
for checking that the assertion's time constraints are still valid.
Examples
Assertion can be loaded from XML
iex> xml = ~S{<saml2:Assertion ID="id2812939747337372346813126" IssueInstant="2023-07-14T12:16:55.216Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exka5ha6bknY6Okd85d7</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="2023-07-14T12:21:55.216Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2023-07-14T12:11:55.216Z" NotOnOrAfter="2023-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> SimpleSaml.Assertion.from_node(assertion_node)
{:ok,
%SimpleSaml.Assertion{
issuer: "http://www.okta.com/exka5ha6bknY6Okd85d7",
name_id: "dj.jain",
name_id_not_on_or_after: ~U[2023-07-14 12:21:55.216Z],
recipient: "https://local.mbx.com:4001/auth/ahead/sso",
not_before: ~U[2023-07-14 12:11:55.216Z],
not_on_or_after: ~U[2023-07-14 12:21:55.216Z],
audience: "xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr"
}}
Attributes are returned from the XML
iex> xml = ~S{<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75" Version="2.0" IssueInstant="2014-07-17T01:01:48Z"> <saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer> <saml:Subject> <saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z"> <saml:AudienceRestriction> <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93"> <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> <saml:AttributeStatement> <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">test@example.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"> <saml:AttributeValue xsi:type="xs:string">users</saml:AttributeValue> <saml:AttributeValue xsi:type="xs:string">examplerole1</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> SimpleSaml.Assertion.from_node(assertion_node)
{:ok,
%SimpleSaml.Assertion{
attributes: %{
"eduPersonAffiliation" => ["users", "examplerole1"],
"mail" => ["test@example.com"],
"uid" => ["test"]
},
audience: "http://sp.example.com/demo1/metadata.php",
issuer: "http://idp.example.com/metadata.php",
name_id: "_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7",
name_id_not_on_or_after: ~U[2024-01-18 06:21:48Z],
not_before: ~U[2014-07-17 01:01:18Z],
not_on_or_after: ~U[2024-01-18 06:21:48Z],
recipient: "http://sp.example.com/demo1/index.php?acs"
}}
An error is generated if a field is missing
iex> xml = ~S{<saml2:Assertion ID="id2812939747337372346813126" IssueInstant="2023-07-14T12:16:55.216Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="2023-07-14T12:21:55.216Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2023-07-14T12:11:55.216Z" NotOnOrAfter="2023-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> {:error, {:child_not_found, [child_name: ~r/.*:?Issuer$/i, actual_children: _]}} = SimpleSaml.Assertion.from_node(assertion_node)
Validates that the timestamp constraints within the given assertion are still valid.
Examples
Assertion can be loaded from XML
iex> xml = ~S{<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exka5ha6bknY6Okd85d7</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="3000-07-14T12:21:55.216Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2023-07-14T12:11:55.216Z" NotOnOrAfter="3000-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> {:ok, assertion} = SimpleSaml.Assertion.from_node(assertion_node)
iex> SimpleSaml.Assertion.validate_time_conditions(assertion)
:ok
Validation fails if name_id_not_on_or_after
matches or is before current time.
iex> xml = ~s{<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exka5ha6bknY6Okd85d7</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="2023-07-14T16:13:18.963Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2023-07-14T12:11:55.216Z" NotOnOrAfter="3000-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> {:ok, assertion} = SimpleSaml.Assertion.from_node(assertion_node)
iex> SimpleSaml.Assertion.validate_time_conditions(assertion)
{:error, :assertion_validation_failed}
Validation fails if not_before
is after the current time.
iex> xml = ~S{<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exka5ha6bknY6Okd85d7</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="3000-07-14T12:21:55.216Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="3000-07-14T12:11:55.216Z" NotOnOrAfter="3000-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> {:ok, assertion} = SimpleSaml.Assertion.from_node(assertion_node)
iex> SimpleSaml.Assertion.validate_time_conditions(assertion)
{:error, :assertion_validation_failed}
Validation fails if not_on_or_after
matches or is before the current time.
iex> xml = ~S{<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exka5ha6bknY6Okd85d7</saml2:Issuer><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">dj.jain</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="3000-07-14T12:21:55.216Z" Recipient="https://local.mbx.com:4001/auth/ahead/sso"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2023-07-14T12:11:55.216Z" NotOnOrAfter="2000-07-14T12:21:55.216Z"><saml2:AudienceRestriction><saml2:Audience>xqO52CNELd0hVB9vaX1d_dcwuYAxGUSr</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2023-07-14T12:16:55.216Z" SessionIndex="id1689337015214.1284590967"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>}
iex> {:ok, assertion_node} = SimpleXml.parse(xml)
iex> {:ok, assertion} = SimpleSaml.Assertion.from_node(assertion_node)
iex> SimpleSaml.Assertion.validate_time_conditions(assertion)
{:error, :assertion_validation_failed}