private static IEnumerable<Claim> ClaimsFromSubject(NameId subject, string issuer)
 {
     if (subject == null) yield break;
     if (subject.Value != null) {
         yield return new Claim("sub", subject.Value, ClaimValueTypes.String, issuer); // openid connect
         yield return new Claim(ClaimTypes.NameIdentifier, subject.Value, ClaimValueTypes.String, issuer); // saml
     }
 }
            public void ThrowsExceptionWhenEmailInvalidForm()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Email
                                 };
                var validator = new Saml20NameIdValidator();

                var invalidEmails = new[]
                                        {
                                            "[email protected] ",
                                            "thisisnotavalidemail",
                                            "thisisnotavalidemail.com",
                                            "@thisisnotavalidemail.com",
                                            " @thisisnotavalidemail.com",
                                            "@ @thisisnotavalidemail.com",
                                            " @ @thisisnotavalidemail.com",
                                            " . @thisisnotavalidemail.com",
                                            @"\. @thisisnotavalidemail.com",
                                            @"\.\@thisisnotavalidemail.com",
                                            @"a.\@thisisnotavalidemail.com",
                                            @"<.>@thisisnotavalidemail.com",
                                            @"<[email protected]",
                                            "[email protected]",
                                            "[email protected] @",
                                            "[email protected] @ "
                                        };

                foreach (var email in invalidEmails)
                {
                    nameId.Value = email;

                    try
                    {
                        // Act
                        validator.ValidateNameId(nameId);

                        // Assert
                        Assert.Fail("Email address " + email + " is not supposed to be valid");
                    }
                    catch (Saml20FormatException sfe)
                    {
                        Assert.AreEqual(sfe.Message, "Value of NameID is not a valid email address according to the IETF RFC 2822 specification");
                    }
                }
            }
            public void ValidatesTransient()
            {
                var nameId = new NameId { Format = Saml20Constants.NameIdentifierFormats.Transient };
                var validator = new Saml20NameIdValidator();

                nameId.Value = new string('f', 256);
                validator.ValidateNameId(nameId);

                nameId.Value = new string('f', 16);
                validator.ValidateNameId(nameId);
            }
 public void ValidatesPersistent()
 {
     var nameId = new NameId
                      {
                          Format = Saml20Constants.NameIdentifierFormats.Persistent,
                          Value = new string('f', 256)
                      };
     var validator = new Saml20NameIdValidator();
     validator.ValidateNameId(nameId);
 }
            public void ValidatesKerberos()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Kerberos,
                                     Value = "[email protected]"
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ValidatesEntity()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Entity,
                                     Value = new string('f', 1024)
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ValidatesEmail()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Email,
                                     Value = "[email protected]"
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenX509SubjecNameValueEmpty()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.X509SubjectName,
                                     Value = string.Empty
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
        /// <summary>
        /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to <c>Saml20Identity.Current</c>.
        /// </summary>
        /// <param name="context">The http context.</param>
        /// <param name="endPoint">The IdP to perform the query against.</param>
        /// <param name="nameIdFormat">The name id format.</param>
        public void PerformQuery(HttpContext context, IdentityProviderElement endPoint, string nameIdFormat)
        {
            Logger.DebugFormat("{0}.{1} called", GetType(), "PerformQuery()");

            var builder = new HttpSoapBindingBuilder(context);

            var name = new NameId
                           {
                               Value = Saml20Identity.Current.Name,
                               Format = nameIdFormat
                           };
            _attrQuery.Subject.Items = new object[] { name };
            _attrQuery.SamlAttribute = _attributes.ToArray();

            var query = new XmlDocument();
            query.LoadXml(Serialization.SerializeToXmlString(_attrQuery));

            XmlSignatureUtils.SignDocument(query, Id);
            if (query.FirstChild is XmlDeclaration)
            {
                query.RemoveChild(query.FirstChild);
            }

            Logger.DebugFormat(TraceMessages.AttrQuerySent, endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml);

            Stream s;
            try
            {
                 s = builder.GetResponse(endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml, endPoint.AttributeQuery);
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }

            var parser = new HttpSoapBindingParser(s);
            var status = parser.GetStatus();
            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                Logger.ErrorFormat(ErrorMessages.AttrQueryStatusNotSuccessful, Serialization.SerializeToXmlString(status));
                throw new Saml20Exception(status.StatusMessage);
            }

            bool isEncrypted;
            var xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted);
            if (isEncrypted)
            {
                var ass = new Saml20EncryptedAssertion((RSA)Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate().PrivateKey);
                ass.LoadXml(xmlAssertion);
                ass.Decrypt();
                xmlAssertion = ass.Assertion.DocumentElement;
            }

            var assertion = new Saml20Assertion(xmlAssertion, null, Saml2Config.GetConfig().AssertionProfile.AssertionValidator, endPoint.QuirksMode);
            Logger.DebugFormat(TraceMessages.AttrQueryAssertionReceived, xmlAssertion == null ? string.Empty : xmlAssertion.OuterXml);

            if (!assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endPoint.Metadata.Keys, endPoint)))
            {
                Logger.Error(ErrorMessages.AssertionSignatureInvalid);
                throw new Saml20Exception(ErrorMessages.AssertionSignatureInvalid);
            }

            foreach (var attr in assertion.Attributes)
            {
                Saml20Identity.Current.AddAttributeFromQuery(attr.Name, attr);
            }
        }
            public void ThrowsExceptionWhenPersistentLengthTooLong()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Persistent,
                                     Value = new string('f', 257)
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenKerberosLessThanThreecharacters()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Kerberos,
                                     Value = @"b"
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenKerberosInvalidFormat()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Kerberos,
                                     Value = @"a\b"
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenEntitySPProvidedId()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Entity,
                                     Value = new string('f', 1024),
                                     SPProvidedID = "ksljdf"
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
        /// <summary>
        /// Validates the name ID.
        /// </summary>
        /// <param name="nameId">The name ID.</param>
        public void ValidateNameId(NameId nameId)
        {
            if (nameId == null)
            {
                throw new ArgumentNullException("nameId");
            }

            if (string.IsNullOrEmpty(nameId.Format))
            {
                return;
            }

            if (!Uri.IsWellFormedUriString(nameId.Format, UriKind.Absolute))
            {
                throw new Saml20FormatException("NameID element has Format attribute which is not a wellformed absolute uri.");
            }

            // The processing rules from [SAML2.0 standard] section 8.3 are implemented here
            if (nameId.Format == Saml20Constants.NameIdentifierFormats.Email)
            {
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Email Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                try
                {
                    new MailAddress(nameId.Value);
                }
                catch (FormatException fe)
                {
                    throw new Saml20FormatException("Value of NameID is not a valid email address according to the IETF RFC 2822 specification", fe);
                }
                catch (IndexOutOfRangeException ie)
                {
                    throw new Saml20FormatException("Value of NameID is not a valid email address according to the IETF RFC 2822 specification", ie);
                }
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.X509SubjectName)
            {
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with X509SubjectName Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                // TODO: Consider checking for correct encoding of the Value according to the
                // XML Signature Recommendation (http://www.w3.org/TR/xmldsig-core/) section 4.4.4
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.Windows)
            {
                // Required format is 'DomainName\UserName' but the domain name and the '\' are optional
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Windows Format attribute MUST contain a Value that contains more than whitespace characters");
                }
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.Kerberos)
            {
                // Required format is 'name[/instance]@REALM'
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Kerberos Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                if (nameId.Value.Length < 3)
                {
                    throw new Saml20FormatException("NameID with Kerberos Format attribute MUST contain a Value with at least 3 characters");
                }

                if (nameId.Value.IndexOf("@") < 0)
                {
                    throw new Saml20FormatException("NameID with Kerberos Format attribute MUST contain a Value that contains a '@'");
                }

                // TODO: Consider implementing the rules for 'name', 'instance' and 'REALM' found in IETF RFC 1510 (http://www.ietf.org/rfc/rfc1510.txt) here
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.Entity)
            {
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Entity Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                if (nameId.Value.Length > 1024)
                {
                    throw new Saml20FormatException("NameID with Entity Format attribute MUST have a Value that contains no more than 1024 characters");
                }

                if (nameId.NameQualifier != null)
                {
                    throw new Saml20FormatException("NameID with Entity Format attribute MUST NOT set the NameQualifier attribute");
                }

                if (nameId.SPNameQualifier != null)
                {
                    throw new Saml20FormatException("NameID with Entity Format attribute MUST NOT set the SPNameQualifier attribute");
                }

                if (nameId.SPProvidedID != null)
                {
                    throw new Saml20FormatException("NameID with Entity Format attribute MUST NOT set the SPProvidedID attribute");
                }
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.Persistent)
            {
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Persistent Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                if (nameId.Value.Length > 256)
                {
                    throw new Saml20FormatException("NameID with Persistent Format attribute MUST have a Value that contains no more than 256 characters");
                }
            }
            else if (nameId.Format == Saml20Constants.NameIdentifierFormats.Transient)
            {
                if (!Saml20Utils.ValidateRequiredString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Transient Format attribute MUST contain a Value that contains more than whitespace characters");
                }

                if (nameId.Value.Length > 256)
                {
                    throw new Saml20FormatException("NameID with Transient Format attribute MUST have a Value that contains no more than 256 characters");
                }

                if (!Saml20Utils.ValidateIdString(nameId.Value))
                {
                    throw new Saml20FormatException("NameID with Transient Format attribute MUST have a Value with at least 16 characters (the equivalent of 128 bits)");
                }
            }
        }
            public void ValidatesWindowsDomainQualifiedName()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Windows
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                nameId.Value = "a";
                validator.ValidateNameId(nameId);

                nameId.Value = "b\a";
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenEmailValueContainsOnlyWhitespace()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Email,
                                     Value = " "
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }
            public void ThrowsExceptionWhenTransientValueTooShort()
            {
                // Arrange
                var nameId = new NameId
                                 {
                                     Format = Saml20Constants.NameIdentifierFormats.Transient,
                                     Value = new string('f', 15)
                                 };
                var validator = new Saml20NameIdValidator();

                // Act
                validator.ValidateNameId(nameId);
            }