/// <summary>
        /// Authenticates the specified message.
        /// </summary>
        /// <returns>
        /// Returns <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1"/>.
        /// </returns>
        /// <param name="authPolicy">The authorization policy.</param><param name="listenUri">The URI at which the message was received.</param><param name="message">The message to be authenticated.</param>
        public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
        {
            if (WebOperationContext.Current != null && WebOperationContext.Current.IncomingRequest.Headers["fedAuth"] != null)
            {

                var tokenString = WebOperationContext.Current.IncomingRequest.Headers["fedAuth"];
                var handler = new Saml2SecurityTokenHandler();
                var token = handler.ReadToken(tokenString);
                var identities = handler.ValidateToken(token);
                var principal = new ClaimsPrincipal(identities);
                Thread.CurrentPrincipal = principal;
            }
            return base.Authenticate(authPolicy, listenUri, ref message);
        }
        static void Main(string[] args)
        {
            Console.SetWindowSize(Console.LargestWindowWidth / 2, Console.LargestWindowHeight / 2);

            Console.WriteLine("Requesting security token from \"{0}\" for resource \"{1}\"...", PF_IP_STS_Endpoint, IPSTS_appliesTo);
            Console.WriteLine();

            try
            {
                // To Issue the initial token (ie the Web Services Client (WSC) doing its thing, we are going to auth with a username and a password

                // Issue the initial SAML token
                RequestSecurityTokenResponse RSTR_Issue;
                SecurityToken token = IssueTokenWithUserNamePassword(subject_username, subject_password, PF_IP_STS_Endpoint, IPSTS_appliesTo, out RSTR_Issue, KeyTypes.Bearer);

                // When using Asymmetric Key (HoK) - we need to supply a UseKey
                // When using Symmetric Key (HoK) - SP Encryption cert is not defined - unless encryption key available to use as subj confirmation

                if (token != null)
                {
                    //show the token
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("{0}", token);
                    Console.WriteLine();
                    Console.WriteLine("{0}", RSTR_Issue.RequestedSecurityToken.SecurityTokenXml.InnerXml);
                    Console.WriteLine();

                    // At this point we received a token from our STS.  We can now use it to authenticate to our web service using it as an IssuedToken.
                    // ... here is where the WSP kicks in...
                    //
                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine();
                    Console.WriteLine("Do you want to validate the security token? [Y]");

                    if (Console.ReadKey(true).Key == ConsoleKey.Y)
                    {
                        Console.WriteLine("Validating security token with \"{0}\"...", PF_RP_STS_Endpoint);
                        Console.WriteLine();

                        // We are acting as the WSP now.  We want to Validate the SAML token against PingFederate's STS
                        RequestSecurityTokenResponse RSTR_Validate = ValidateSecurityToken(token, PF_RP_STS_Endpoint);

                        // This will return:
                        // http://docs.oasis-open.org/ws-sx/ws-trust/200512/status/valid or
                        // http://docs.oasis-open.org/ws-sx/ws-trust/200512/status/invalid
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("{0}", RSTR_Validate.Status.Code);
                        Console.WriteLine();

                        // So we have a valid token supplied by the web services client.... we can grab the claims from there and do as we wish... or.. we can issue a local token
                        Console.ForegroundColor = ConsoleColor.Gray;
                        Console.WriteLine();
                        Console.WriteLine("Do you want to issue a local security token? [Y]");

                        if (Console.ReadKey(true).Key == ConsoleKey.Y)
                        {
                            Console.WriteLine("Requesting \"{0}\" security token from \"{1}\"...", tokenType, PF_RP_STS_Endpoint);
                            Console.WriteLine();

                            // We need to make a call to our RP-STS (SP side of PF) to issue a local token (according to our Token Generator)
                            //SecurityToken localToken = IssueLocalSecurityToken(token, RPSTS_issuerUri, RPSTS_appliesTo, tokenType, keyType);

                            // I'm going to receive it as a GenericXmlSecurityToken so we can parse it easier later on...
                            RequestSecurityTokenResponse RSTR_LocalToken;
                            GenericXmlSecurityToken xmlToken = (GenericXmlSecurityToken)IssueLocalSecurityToken(token, PF_RP_STS_Endpoint, tokenType, out RSTR_LocalToken);

                            if (xmlToken != null)
                            {
                                //show the token
                                Console.ForegroundColor = ConsoleColor.Green;
                                Console.WriteLine("{0}", xmlToken);

                                // parse token to grab the attributes:
                                if (tokenType == "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0")
                                {

                                    // Configure the IssuerNameRegistry
                                    ConfigurationBasedIssuerNameRegistry myIssuerNameRegistry = new ConfigurationBasedIssuerNameRegistry();
                                    myIssuerNameRegistry.AddTrustedIssuer(PF_Signing_Cert_Thumbprint, "RP-STS"); // this is the dsig cert (of my RP-STS) SHA1 thumbprint | name
                                    //inr.AddTrustedIssuer("97463668CD4482AFAC7F341A1C3ABB1010757800", "localhost"); // this is the encryption cert (of my RP-STS - bearer token isn't encrypted tho)

                                    // Define the "verification configuration"
                                    SecurityTokenHandlerConfiguration securityTokenHanderConfig = new SecurityTokenHandlerConfiguration();
                                    securityTokenHanderConfig.AudienceRestriction.AllowedAudienceUris.Add(new Uri("https://www.app.com")); // the Audience defined in the Token Generator
                                    Saml2SecurityTokenHandler saml2TokenHandler = new Saml2SecurityTokenHandler();
                                    securityTokenHanderConfig.IssuerNameRegistry = myIssuerNameRegistry;
                                    saml2TokenHandler.Configuration = securityTokenHanderConfig;

                                    // Parse the token and return a Claims Identity
                                    SecurityToken saml2Token = saml2TokenHandler.ReadToken(new XmlTextReader(new StringReader(xmlToken.TokenXml.OuterXml)));
                                    ClaimsIdentity identity = saml2TokenHandler.ValidateToken(saml2Token).First();

                                    // Spit out the Claims
                                    Console.WriteLine("Attributes in the Assertion.....");
                                    Console.WriteLine("{0}", identity.Name);
                                    foreach (Claim theClaim in identity.Claims)
                                    {
                                        Console.WriteLine("{0} : {1}", theClaim.Type, theClaim.Value);
                                    }
                                }
                                else if (tokenType == "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0")
                                {

                                }

                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ConsoleColor PreviousColor = Console.ForegroundColor;

                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);

                if (ex.InnerException != null)
                {
                    Console.WriteLine();
                    Console.WriteLine(ex.InnerException.Message);
                }

                Console.ForegroundColor = PreviousColor;
            }

            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Press <enter> to close.");
            Console.Read();
        }
        private void RunValidationTests( SecurityTokenDescriptor tokenDescriptor, SecurityToken securityToken, SecurityKey key, int iterations, bool display = true )
        {
            // Create jwts using wif
            // Create Saml2 tokens
            // Create Saml tokens

            DateTime started;
            string validating = "Validating, signed: '{0}', '{1}' Tokens. Time: '{2}'";

            SetReturnSecurityTokenResolver str = new Test.SetReturnSecurityTokenResolver( securityToken, key );
            
            SecurityTokenHandlerConfiguration tokenHandlerConfiguration = new SecurityTokenHandlerConfiguration()
            {
                IssuerTokenResolver = str,
                SaveBootstrapContext = true,
                CertificateValidator = AlwaysSucceedCertificateValidator.New,
                AudienceRestriction = new AudienceRestriction( AudienceUriMode.Never ),
                IssuerNameRegistry = new SetNameIssuerNameRegistry( Issuers.GotJwt ),
            };

            Saml2SecurityTokenHandler samlTokenHandler = new Saml2SecurityTokenHandler();
            Saml2SecurityToken token = samlTokenHandler.CreateToken( tokenDescriptor ) as Saml2SecurityToken;
            StringBuilder sb = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(sb);
            samlTokenHandler.WriteToken( writer, token );                                    
            writer.Flush();
            writer.Close();
            string tokenXml = sb.ToString();

            samlTokenHandler.Configuration = tokenHandlerConfiguration;
            started = DateTime.UtcNow;
            for ( int i = 0; i < iterations; i++ )
            {
                StringReader sr = new StringReader( tokenXml );
                XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader( XmlReader.Create( sr ) );
                reader.MoveToContent();
                SecurityToken saml2Token = samlTokenHandler.ReadToken( reader );
                samlTokenHandler.ValidateToken( saml2Token );
            }
            if ( display )
            {
                Console.WriteLine( string.Format( validating, "Saml2SecurityTokenHandler", iterations, DateTime.UtcNow - started ) );
            }

            JwtSecurityTokenHandler jwtTokenHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwt = jwtTokenHandler.CreateToken( tokenDescriptor ) as JwtSecurityToken;
            jwtTokenHandler.Configuration = tokenHandlerConfiguration;
            started = DateTime.UtcNow;
            for ( int i = 0; i < iterations; i++ )
            {
                jwtTokenHandler.ValidateToken( jwt.RawData );
            }

            if ( display )
            {
                Console.WriteLine( string.Format( validating, "JwtSecurityTokenHandle - ValidateToken( jwt.RawData )", iterations, DateTime.UtcNow - started ) );
            }

            jwt = jwtTokenHandler.CreateToken( tokenDescriptor ) as JwtSecurityToken;
            sb = new StringBuilder();
            writer = XmlWriter.Create(sb);
            jwtTokenHandler.WriteToken( writer, jwt );                                    
            writer.Flush();
            writer.Close();
            tokenXml = sb.ToString();

            started = DateTime.UtcNow;
            for ( int i = 0; i<iterations; i++ )
            {
                StringReader sr = new StringReader( tokenXml );
                XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader( XmlReader.Create( sr ) );
                reader.MoveToContent();
                SecurityToken jwtToken = jwtTokenHandler.ReadToken( reader );
                jwtTokenHandler.ValidateToken( jwtToken );
            }

            if ( display )
            {
                Console.WriteLine( string.Format( validating, "JwtSecurityTokenHandle - ReadToken( reader ), ValidateToken( jwtToken )", iterations, DateTime.UtcNow - started ) );
            }

            started = DateTime.UtcNow;
            for ( int i = 0; i < iterations; i++ )
            {
                StringReader sr = new StringReader( tokenXml );
                XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader( XmlReader.Create( sr ) );
                reader.MoveToContent();
                JwtSecurityToken jwtToken = jwtTokenHandler.ReadToken( reader ) as JwtSecurityToken;
                jwtTokenHandler.ValidateToken( jwtToken.RawData );
            }

            if ( display )
            {
                Console.WriteLine( string.Format( validating, "JwtSecurityTokenHandle - ReadToken( reader ), ValidateToken( jwtToken.RawData )", iterations, DateTime.UtcNow - started ) );
            }
        }