public void Saml2SubjectExtensions_ToXElement()
        {
            var subjectName = "JohnDoe";
            var saml2Subject = new Saml2Subject(new Saml2NameIdentifier(subjectName));

            var subject = saml2Subject.ToXElement();

            subject.Element(Saml2Namespaces.Saml2 + "NameID").Value.Should().Be(subjectName);

            // Although SubjectConfirmation is optional in the SAML core spec, it is
            // mandatory in the Web Browser SSO Profile and must have a value of bearer.
            subject.Element(Saml2Namespaces.Saml2 + "SubjectConfirmation")
                .Attribute("Method").Value.Should().Be("urn:oasis:names:tc:SAML:2.0:cm:bearer");
        }
 public void ProcessSamlSubjectPublic(Saml2Subject assertionSubject, ClaimsIdentity subject, string issuer)
 {
     base.ProcessSamlSubject(assertionSubject, subject, issuer);
 }
        /// <summary>
        /// Writes the &lt;saml:Subject> element.
        /// </summary>
        /// <param name="writer">A <see cref="XmlWriter"/> to serialize the <see cref="Saml2Subject"/>.</param>
        /// <param name="data">The <see cref="Saml2Subject"/> to serialize.</param>
        protected virtual void WriteSubject(XmlWriter writer, Saml2Subject data)
        {
            if (null == writer)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }

            if (null == data)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("data");
            }

            // If there's no ID, there has to be a SubjectConfirmation
#pragma warning suppress 56506 // SubjectConfirmations is never null
            if (null == data.NameId && 0 == data.SubjectConfirmations.Count)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4108)));
            }

            // <Subject>
            writer.WriteStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace);

            // no attributes

            // <NameID> 0-1
            if (null != data.NameId)
            {
                this.WriteNameId(writer, data.NameId);
            }

            // <SubjectConfirmation> 0-OO
            foreach (Saml2SubjectConfirmation subjectConfirmation in data.SubjectConfirmations)
            {
                this.WriteSubjectConfirmation(writer, subjectConfirmation);
            }

            // </Subject>
            writer.WriteEndElement();
        }
        /// <summary>
        /// Reads the &lt;saml:Subject> element.
        /// </summary>
        /// <param name="reader">A <see cref="XmlReader"/> positioned at a <see cref="Saml2Subject"/> element.</param>
        /// <returns>An instance of <see cref="Saml2Subject"/> .</returns>
        /// <remarks>
        /// The default implementation does not handle the optional
        /// &lt;EncryptedID> element. To handle encryped IDs in the Subject,
        /// override this method.
        /// </remarks>
        protected virtual Saml2Subject ReadSubject(XmlReader reader)
        {
            if (null == reader)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            // throw if wrong element
            if (!reader.IsStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace))
            {
                reader.ReadStartElement(Saml2Constants.Elements.Subject, Saml2Constants.Namespace);
            }

            try
            {
                // disallow empty
                if (reader.IsEmptyElement)
                {
#pragma warning suppress 56504 // bogus - thinks reader.LocalName, reader.NamespaceURI need validation
                    throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID3061, reader.LocalName, reader.NamespaceURI));
                }

                // @attributes

                // @xsi:type
                XmlUtil.ValidateXsiType(reader, Saml2Constants.Types.SubjectType, Saml2Constants.Namespace);

                // <elements>
                Saml2Subject subject = new Saml2Subject();
                reader.Read();

                // <NameID> | <EncryptedID> | <BaseID> 0-1
                subject.NameId = this.ReadSubjectId(reader, Saml2Constants.Elements.Subject);

                // <SubjectConfirmation> 0-OO
                while (reader.IsStartElement(Saml2Constants.Elements.SubjectConfirmation, Saml2Constants.Namespace))
                {
                    subject.SubjectConfirmations.Add(this.ReadSubjectConfirmation(reader));
                }

                reader.ReadEndElement();

                // Must have a NameID or a SubjectConfirmation
                if (null == subject.NameId && 0 == subject.SubjectConfirmations.Count)
                {
                    throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4108));
                }

                return subject;
            }
            catch (Exception e)
            {
                if (System.Runtime.Fx.IsFatal(e))
                    throw;
                
                Exception wrapped = TryWrapReadException(reader, e);
                if (null == wrapped)
                {
                    throw;
                }
                else
                {
                    throw wrapped;
                }
            }
        }
        /// <summary>
        /// Creates claims from the Saml2Subject.
        /// </summary>
        /// <param name="assertionSubject">The Saml2Subject.</param>
        /// <param name="subject">The ClaimsIdentity subject.</param>
        /// <param name="issuer">The issuer.</param>
        protected virtual void ProcessSamlSubject(Saml2Subject assertionSubject, ClaimsIdentity subject, string issuer)
        {
            if (assertionSubject == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("assertionSubject");
            }

            if (subject == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("subject");
            }

            Saml2NameIdentifier nameId = assertionSubject.NameId;

            if (nameId != null)
            {
                Claim claim = new Claim(ClaimTypes.NameIdentifier, nameId.Value, ClaimValueTypes.String, issuer);

                if (nameId.Format != null)
                {
                    claim.Properties[ClaimProperties.SamlNameIdentifierFormat] = nameId.Format.AbsoluteUri;
                }

                if (nameId.NameQualifier != null)
                {
                    claim.Properties[ClaimProperties.SamlNameIdentifierNameQualifier] = nameId.NameQualifier;
                }

                if (nameId.SPNameQualifier != null)
                {
                    claim.Properties[ClaimProperties.SamlNameIdentifierSPNameQualifier] = nameId.SPNameQualifier;
                }

                if (nameId.SPProvidedId != null)
                {
                    claim.Properties[ClaimProperties.SamlNameIdentifierSPProvidedId] = nameId.SPProvidedId;
                }

                subject.AddClaim(claim);
            }
        }
        /// <summary>
        /// Creates a SAML2 subject of the assertion.
        /// </summary>
        /// <param name="tokenDescriptor">The security token descriptor to create the subject.</param>
        /// <exception cref="ArgumentNullException">Thrown when 'tokenDescriptor' is null.</exception>
        /// <returns>A Saml2Subject.</returns>
        protected virtual Saml2Subject CreateSamlSubject(SecurityTokenDescriptor tokenDescriptor)
        {
            if (null == tokenDescriptor)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenDescriptor");
            }

            Saml2Subject saml2Subject = new Saml2Subject();

            // Look for name identifier claims
            string nameIdentifierClaim = null;
            string nameIdentifierFormat = null;
            string nameIdentifierNameQualifier = null;
            string nameIdentifierSpProviderId = null;
            string nameIdentifierSpNameQualifier = null;

            if (tokenDescriptor.Subject != null && tokenDescriptor.Subject.Claims != null)
            {
                foreach (Claim claim in tokenDescriptor.Subject.Claims)
                {
                    if (claim.Type == ClaimTypes.NameIdentifier)
                    {
                        // Do not allow multiple name identifier claim.
                        if (null != nameIdentifierClaim)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4139)));
                        }

                        nameIdentifierClaim = claim.Value;

                        if (claim.Properties.ContainsKey(ClaimProperties.SamlNameIdentifierFormat))
                        {
                            nameIdentifierFormat = claim.Properties[ClaimProperties.SamlNameIdentifierFormat];
                        }

                        if (claim.Properties.ContainsKey(ClaimProperties.SamlNameIdentifierNameQualifier))
                        {
                            nameIdentifierNameQualifier = claim.Properties[ClaimProperties.SamlNameIdentifierNameQualifier];
                        }

                        if (claim.Properties.ContainsKey(ClaimProperties.SamlNameIdentifierSPNameQualifier))
                        {
                            nameIdentifierSpNameQualifier = claim.Properties[ClaimProperties.SamlNameIdentifierSPNameQualifier];
                        }

                        if (claim.Properties.ContainsKey(ClaimProperties.SamlNameIdentifierSPProvidedId))
                        {
                            nameIdentifierSpProviderId = claim.Properties[ClaimProperties.SamlNameIdentifierSPProvidedId];
                        }
                    }
                }
            }

            if (nameIdentifierClaim != null)
            {
                Saml2NameIdentifier nameIdentifier = new Saml2NameIdentifier(nameIdentifierClaim);

                if (nameIdentifierFormat != null && UriUtil.CanCreateValidUri(nameIdentifierFormat, UriKind.Absolute))
                {
                    nameIdentifier.Format = new Uri(nameIdentifierFormat);
                }

                nameIdentifier.NameQualifier = nameIdentifierNameQualifier;
                nameIdentifier.SPNameQualifier = nameIdentifierSpNameQualifier;
                nameIdentifier.SPProvidedId = nameIdentifierSpProviderId;

                saml2Subject.NameId = nameIdentifier;
            }

            // Add subject confirmation data
            Saml2SubjectConfirmation subjectConfirmation;
            if (null == tokenDescriptor.Proof)
            {
                subjectConfirmation = new Saml2SubjectConfirmation(Saml2Constants.ConfirmationMethods.Bearer);
            }
            else
            {
                subjectConfirmation = new Saml2SubjectConfirmation(Saml2Constants.ConfirmationMethods.HolderOfKey, new Saml2SubjectConfirmationData());
                subjectConfirmation.SubjectConfirmationData.KeyIdentifiers.Add(tokenDescriptor.Proof.KeyIdentifier);
            }

            saml2Subject.SubjectConfirmations.Add(subjectConfirmation);

            return saml2Subject;
        }
        protected override Saml2Subject CreateSamlSubject(SecurityTokenDescriptor tokenDescriptor)
        {
            Saml2SubjectConfirmation confirmation;
            if (tokenDescriptor == null)
            {
                throw new ArgumentNullException("tokenDescriptor");
            }
            Saml2Subject subject = new Saml2Subject();
            string name = null;
            string uriString = null;

            if ((tokenDescriptor.Subject != null) && (tokenDescriptor.Subject.Claims != null))
            {
                foreach (Claim claim in tokenDescriptor.Subject.Claims)
                {
                    if (claim.ClaimType == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")
                    {
                        if (name != null)
                        {
                            throw new InvalidOperationException(
                                "No suitable Saml2NameIdentifier could be created for the SAML2:Subject because more than one Claim of type NameIdentifier was supplied.");
                        }
                        name = claim.Value;
                        if (claim.Properties.ContainsKey("http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"))
                        {
                            uriString = claim.Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"];
                        }                        
                    }
                }
            }
            if (name != null)
            {
                Saml2NameIdentifier identifier = new Saml2NameIdentifier(name);

                if ((uriString != null) && UriUtil.CanCreateValidUri(uriString, UriKind.Absolute))
                {
                    identifier.Format = new Uri(uriString);
                }
                subject.NameId = identifier;
            }

            // IGNORE SAML confirmation and just create the SenderVouches

            // GFIPM S2S 8.8.2.6.c
            confirmation = new Saml2SubjectConfirmation(Saml2Constants.ConfirmationMethods.SenderVouches);

            // SAML V2.0 Condition for Delegation Restriction Version 1.0
            // 2.5 Use of Identifiers Within <saml:SubjectConfirmation>
            string lastDelegateNameId = tokenDescriptor.Subject.Actor.Name;
            confirmation.NameIdentifier = new Saml2NameIdentifier(lastDelegateNameId);

            subject.SubjectConfirmations.Add(confirmation);

            return subject;
        }