/// <summary>
        /// Creates an instance of CustomSecurityTokenServiceConfiguration.
        /// </summary>
        public CustomSecurityTokenServiceConfiguration(string idp) : base(idp)
        {
            CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.CustomSecurityTokenServiceConfiguration.CustomSecurityTokenServiceConfiguration",
               "AdsTraceSource", SourceLevels.Information);

            SecurityTokenService = typeof(CustomSecurityTokenService);

            // GFIPM S2S 8.8.2.6.e Modify the "NotOnOrAfter"
            this.DefaultTokenLifetime = TimeSpan.FromSeconds(Constants.AdsAssertionValidityPeriod);

            ts.TraceInformation("DefaultTokenLifetime: " + this.DefaultTokenLifetime.TotalSeconds.ToString());
        }
        //private DelegationRestrictionType ReadDelegates(XmlReader reader)
        //{
        //    CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.ReadDelegates",
        //        "AdsTraceSource", SourceLevels.Information);

        //    DelegationRestrictionType delegate2 = null;

        //    if (reader == null)
        //    {
        //        throw new ArgumentNullException("reader");
        //    }
        //    bool requireDeclaration = false;
        //    if (reader.IsStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //    {
        //        reader.Read();
        //        requireDeclaration = true;
        //    }
        //    else if (!reader.IsStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation"))
        //    {
        //        reader.ReadStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation");
        //    }

        //    try
        //    {
        //        bool isEmptyElement = reader.IsEmptyElement;
        //        XmlUtil.ValidateXsiType(reader, "DelegationRestrictionType", "urn:oasis:names:tc:SAML:2.0:conditions:delegation", requireDeclaration);

        //        if (isEmptyElement)
        //        {
        //            string errorMsg = string.Format("The given element ('{0}','{1}') is empty.", reader.LocalName, reader.NamespaceURI);

        //            throw DiagnosticUtil.ThrowHelperXml(reader, errorMsg);
        //        }

        //        List<DelegateType> delegates = new List<DelegateType>();

        //        while (reader.IsStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation"))
        //        {
        //            DelegateType delegateType = new DelegateType();

        //            string attribute = reader.GetAttribute("DelegationInstant");

        //            if (!string.IsNullOrEmpty(attribute))
        //            {
        //                delegateType.DelegationInstant = XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted);
        //            }

        //            // What does this do?
        //            reader.Read();

        //            if (!reader.IsStartElement("NameID", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //            {
        //                reader.ReadStartElement("NameID", "urn:oasis:names:tc:SAML:2.0:assertion");
        //            }

        //            // TODO: Investgate the proper way to read this
        //            delegateType.Item = ReadSimpleUriElement(reader, UriKind.RelativeOrAbsolute, true);
        //            delegates.Add(delegateType);

        //            reader.ReadEndElement();
        //        }

        //        DelegationRestrictionType delegate1 = new DelegationRestrictionType();
        //        delegate1.Delegate = delegates.ToArray();

        //        delegate2 = delegate1;
        //    }
        //    catch (Exception exception)
        //    {
        //        Exception exception2 = DiagnosticUtil.TryWrapReadException(reader, exception);
        //        if (exception2 == null)
        //        {
        //            throw;
        //        }

        //        throw exception2;
        //    }

        //    return delegate2;
        //}

        //protected override Saml2Conditions ReadConditions(XmlReader reader)
        //{
        //    CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.ReadConditions",
        //        "AdsTraceSource", SourceLevels.Information);

        //    //Saml2Conditions conditions2 = null;

        //    if (reader == null)
        //    {
        //        throw new ArgumentNullException("reader");
        //    }
        //    if (!reader.IsStartElement("Conditions", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //    {
        //        reader.ReadStartElement("Conditions", "urn:oasis:names:tc:SAML:2.0:assertion");
        //    }
            
        //    // TODO: Seems this needs to be declared below at "conditions.Delegates = ReadDelegates(reader);"
        //    // Let's assume that from now on, Saml2ConditionsDelegateWrapper is the right type and test for the 
        //    // existence of Condition/Delegate elements!
        //    Saml2ConditionsDelegateWrapper conditions = new Saml2ConditionsDelegateWrapper();
        //    bool isEmptyElement = reader.IsEmptyElement;

        //    XmlUtil.ValidateXsiType(reader, "ConditionsType", "urn:oasis:names:tc:SAML:2.0:assertion", false);
        //    string attribute = reader.GetAttribute("NotBefore");
        //    if (!string.IsNullOrEmpty(attribute))
        //    {
        //        conditions.NotBefore = new DateTime?(XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted));
        //    }
        //    attribute = reader.GetAttribute("NotOnOrAfter");
        //    if (!string.IsNullOrEmpty(attribute))
        //    {
        //        conditions.NotOnOrAfter = new DateTime?(XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted));
        //    }

        //    reader.ReadStartElement();
        //    if (!isEmptyElement)
        //    {
        //        while (reader.IsStartElement())
        //        {
        //            if (reader.IsStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //            {
        //                XmlQualifiedName xsiType = XmlUtil.GetXsiType(reader);

        //                if ((null == xsiType) || XmlUtil.EqualsQName(xsiType, "ConditionAbstractType", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                {
        //                    string errorMsg = string.Format("An abstract element was encountered which does not specify its concrete type. " +
        //                        "Element name: '{0}' Element namespace: '{1}'", reader.LocalName, reader.NamespaceURI);
        //                    throw DiagnosticUtil.ThrowHelperXml(reader, errorMsg);
        //                }

        //                reader.ReadStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion");

        //                // TODO: VALIDATION!!!
        //                // Seems that Validation is done in ValidateToken.VsalidateConditions above
        //                conditions.Delegates = ReadDelegates(reader);

        //                reader.ReadEndElement();

        //                /////////////////////////////////

        //                // Need to investigate why this is disabled!!!!!
        //                // This looks like it is invalid here

        //                //if (EqualsQName(xsiType, "AudienceRestrictionType", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                //{
        //                //    conditions.AudienceRestrictions.Add(this.ReadAudienceRestriction(reader));
        //                //}
        //                //else if (EqualsQName(xsiType, "OneTimeUseType", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                //{
        //                //    if (conditions.OneTimeUse)
        //                //    {
        //                //        throw new InvalidOperationException("ID4115: OneTimeUse");
        //                //    }
        //                //    ReadEmptyContentElement(reader);
        //                //    conditions.OneTimeUse = true;
        //                //}
        //                //else
        //                //{
        //                //    if (!EqualsQName(xsiType, "ProxyRestrictionType", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                //    {
        //                //        throw new InvalidOperationException("ID4113");
        //                //    }
        //                //    if (conditions.ProxyRestriction != null)
        //                //    {
        //                //        throw new InvalidOperationException("ID4115: ProxyRestriction");
        //                //    }
        //                //    conditions.ProxyRestriction = this.ReadProxyRestriction(reader);
        //                //}
        //                ////////////////////////////////////
        //            }
        //            else if (reader.IsStartElement("AudienceRestriction", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //            {
        //                XmlQualifiedName xsiType = XmlUtil.GetXsiType(reader);

        //                conditions.AudienceRestrictions.Add(this.ReadAudienceRestriction(reader));
        //            }
        //            else
        //            {
        //                //if (reader.IsStartElement("OneTimeUse", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                //{
        //                //    if (conditions.OneTimeUse)
        //                //    {
        //                //        throw DiagnosticUtil.ThrowHelperXml(reader, SR.GetString("ID4115", new object[] { "OneTimeUse" }));
        //                //    }
        //                //    ReadEmptyContentElement(reader);
        //                //    conditions.OneTimeUse = true;
        //                //    continue;
        //                //}
        //                if (!reader.IsStartElement("ProxyRestriction", "urn:oasis:names:tc:SAML:2.0:assertion"))
        //                {
        //                    break;
        //                }
        //                if (conditions.ProxyRestriction != null)
        //                {
        //                    throw DiagnosticUtil.ThrowHelperXml(reader,
        //                        "A <saml:Conditions> element contained more than one ProxyRestriction condition.");
        //                }
        //                conditions.ProxyRestriction = this.ReadProxyRestriction(reader);
        //            }
        //        }

        //        reader.ReadEndElement();
        //    }

        //    return conditions as Saml2Conditions;
        //}
        #endregion

        protected override Saml2Conditions ReadConditions(XmlReader reader)
        {
            CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.ReadConditions",
                "AdsTraceSource", SourceLevels.Information);

            Saml2Conditions conditions2 = null;

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            if (!reader.IsStartElement("Conditions", "urn:oasis:names:tc:SAML:2.0:assertion"))
            {
                reader.ReadStartElement("Conditions", "urn:oasis:names:tc:SAML:2.0:assertion");
            }
            try
            {
                // TODO: Seems this needs to be declared below at "conditions.Delegates = ReadDelegates(reader);"
                // Let's assume that from now on, Saml2ConditionsDelegateWrapper is the right type and test for the 
                // existence of Condition/Delegate elements!
                Saml2ConditionsDelegateWrapper conditions = new Saml2ConditionsDelegateWrapper();
                bool isEmptyElement = reader.IsEmptyElement;

                XmlUtil.ValidateXsiType(reader, "ConditionsType", "urn:oasis:names:tc:SAML:2.0:assertion", false);
                string attribute = reader.GetAttribute("NotBefore");
                if (!string.IsNullOrEmpty(attribute))
                {
                    conditions.NotBefore = new DateTime?(XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted));
                }
                attribute = reader.GetAttribute("NotOnOrAfter");
                if (!string.IsNullOrEmpty(attribute))
                {
                    conditions.NotOnOrAfter = new DateTime?(XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted));
                }

                reader.ReadStartElement();
                if (!isEmptyElement)
                {
                    while (reader.IsStartElement())
                    {
                        if (reader.IsStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion"))
                        {
                            XmlQualifiedName xsiType = XmlUtil.GetXsiType(reader);

                            if ((null == xsiType) || XmlUtil.EqualsQName(xsiType, "ConditionAbstractType", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            {
                                string errorMsg = string.Format("An abstract element was encountered which does not specify its concrete type. " +
                                    "Element name: '{0}' Element namespace: '{1}'", reader.LocalName, reader.NamespaceURI);
                                throw DiagnosticUtil.ThrowHelperXml(reader, errorMsg);
                            }

                            reader.ReadStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion");

                            // TODO: VALIDATION!!!
                            // Seems that Validation is done in ValidateToken.VsalidateConditions above
                            conditions.Delegates = ReadDelegates(reader);

                            reader.ReadEndElement();

                            /////////////////////////////////

                            // Need to investigate why this is disabled!!!!!
                            // This looks like it is invalid here

                            //if (EqualsQName(xsiType, "AudienceRestrictionType", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            //{
                            //    conditions.AudienceRestrictions.Add(this.ReadAudienceRestriction(reader));
                            //}
                            //else if (EqualsQName(xsiType, "OneTimeUseType", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            //{
                            //    if (conditions.OneTimeUse)
                            //    {
                            //        throw new InvalidOperationException("ID4115: OneTimeUse");
                            //    }
                            //    ReadEmptyContentElement(reader);
                            //    conditions.OneTimeUse = true;
                            //}
                            //else
                            //{
                            //    if (!EqualsQName(xsiType, "ProxyRestrictionType", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            //    {
                            //        throw new InvalidOperationException("ID4113");
                            //    }
                            //    if (conditions.ProxyRestriction != null)
                            //    {
                            //        throw new InvalidOperationException("ID4115: ProxyRestriction");
                            //    }
                            //    conditions.ProxyRestriction = this.ReadProxyRestriction(reader);
                            //}
                            ////////////////////////////////////
                        }
                        else if (reader.IsStartElement("AudienceRestriction", "urn:oasis:names:tc:SAML:2.0:assertion"))
                        {
                            XmlQualifiedName xsiType = XmlUtil.GetXsiType(reader);

                            conditions.AudienceRestrictions.Add(this.ReadAudienceRestriction(reader));
                        }
                        else
                        {
                            //if (reader.IsStartElement("OneTimeUse", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            //{
                            //    if (conditions.OneTimeUse)
                            //    {
                            //        throw DiagnosticUtil.ThrowHelperXml(reader, SR.GetString("ID4115", new object[] { "OneTimeUse" }));
                            //    }
                            //    ReadEmptyContentElement(reader);
                            //    conditions.OneTimeUse = true;
                            //    continue;
                            //}
                            if (!reader.IsStartElement("ProxyRestriction", "urn:oasis:names:tc:SAML:2.0:assertion"))
                            {
                                break;
                            }
                            if (conditions.ProxyRestriction != null)
                            {
                                throw DiagnosticUtil.ThrowHelperXml(reader,
                                    "A <saml:Conditions> element contained more than one ProxyRestriction condition.");
                            }
                            conditions.ProxyRestriction = this.ReadProxyRestriction(reader);
                        }
                    }

                    reader.ReadEndElement();
                }
                conditions2 = conditions;
            }
            catch (Exception exception)
            {
                Exception exception2 = DiagnosticUtil.TryWrapReadException(reader, exception);
                if (exception2 == null)
                {
                    throw;
                }

                throw exception2;
            }

            return conditions2;
        }
        private DelegationRestrictionType ReadDelegates(XmlReader reader)
        {
            CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.ReadDelegates",
                "AdsTraceSource", SourceLevels.Information);

            //DelegationRestrictionType delegate2 = null;

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            bool requireDeclaration = false;
            if (reader.IsStartElement("Condition", "urn:oasis:names:tc:SAML:2.0:assertion"))
            {
                reader.Read();
                requireDeclaration = true;
            }
            else if (!reader.IsStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation"))
            {
                reader.ReadStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation");
            }
                        
            bool isEmptyElement = reader.IsEmptyElement;
            XmlUtil.ValidateXsiType(reader, "DelegationRestrictionType", "urn:oasis:names:tc:SAML:2.0:conditions:delegation", requireDeclaration);

            if (isEmptyElement)
            {
                string errorMsg = string.Format("The given element ('{0}','{1}') is empty.", reader.LocalName, reader.NamespaceURI);

                throw DiagnosticUtil.ThrowHelperXml(reader, errorMsg);
            }

            List<DelegateType> delegates = new List<DelegateType>();

            while (reader.IsStartElement("Delegate", "urn:oasis:names:tc:SAML:2.0:conditions:delegation"))
            {
                DelegateType delegateType = new DelegateType();

                string attribute = reader.GetAttribute("DelegationInstant");

                if (!string.IsNullOrEmpty(attribute))
                {
                    delegateType.DelegationInstant = XmlConvert.ToDateTime(attribute, DateTimeFormats.Accepted);
                }

                // What does this do?
                reader.Read();

                if (!reader.IsStartElement("NameID", "urn:oasis:names:tc:SAML:2.0:assertion"))
                {
                    reader.ReadStartElement("NameID", "urn:oasis:names:tc:SAML:2.0:assertion");
                }

                // TODO: Investgate the proper way to read this
                delegateType.Item = ReadSimpleUriElement(reader, UriKind.RelativeOrAbsolute, true);
                delegates.Add(delegateType);

                reader.ReadEndElement();
            }

            DelegationRestrictionType delegateRestriction = new DelegationRestrictionType();
            delegateRestriction.Delegate = delegates.ToArray();

            //delegate2 = delegate1;
            return delegateRestriction;
        

            //return delegate2;
        }
        // Handle Condition/Delegates
        protected override IClaimsIdentity CreateClaims(Saml2SecurityToken samlToken)
        {
            CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.CreateClaims",
                "AdsTraceSource", SourceLevels.Information);

   
            // process subject in base 
            IClaimsIdentity subject = base.CreateClaims(samlToken);
            
            Saml2Assertion assertion = samlToken.Assertion;

            // process Condition/Delegation            
            ts.TraceInformation("assertion.Conditions Type: " + assertion.Conditions.GetType().Name);

            if (assertion.Conditions is Saml2ConditionsDelegateWrapper)
            {
                Saml2ConditionsDelegateWrapper delegateData = assertion.Conditions as Saml2ConditionsDelegateWrapper;

                 //iterate over the Condition delegate elements
                 //Check if there are delegates within an incoming assertion                                
                IClaimsIdentity currentSubject = subject;
               
                if (delegateData != null && delegateData.Delegates != null)
                {
                    // Add the delegates in the DelegationRestrictionType
                    ts.TraceInformation("Number of Delegates: " + delegateData.Delegates.Delegate.Length);
                    for (int i = 0; i < delegateData.Delegates.Delegate.Length; i++)
                    {
                        DelegateType del = delegateData.Delegates.Delegate[i];
                                                                        
                        if (del != null)
                        {
                            string nameId = del.Item.ToString();

                            var claims = new List<Claim>();
                            claims.Add(new Claim(ClaimTypes.Name, nameId));
                            claims.Add(new Claim(ClaimTypes.AuthenticationInstant, XmlConvert.ToString(del.DelegationInstant, DateTimeFormats.Generated)));

                            // now add to current subject
                            currentSubject.Actor = new ClaimsIdentity(claims);

                            currentSubject = currentSubject.Actor;
                        }
                    }
                }
            }

            return subject;
        }
        //string TokenToString(SecurityToken token)
        //{
        //    StringBuilder stringBuilder = new StringBuilder();
        //    XmlWriter xr = XmlWriter.Create(new StringWriter(stringBuilder), new XmlWriterSettings { OmitXmlDeclaration = true });
        //    this.WriteToken(xr, token);
        //    xr.Flush();

        //    return stringBuilder.ToString();
        //}

        //void SerializeTokenToStream(Saml2SecurityToken saml2Token, StreamWriter file, string section)
        //{
        //    // serialize the token
        //    file.WriteLine(section);

        //    if (saml2Token.Assertion.Issuer != null)
        //    {
        //        file.WriteLine("\tIssuer: " + saml2Token.Assertion.Issuer.Value);
        //    }
        //    else
        //    {
        //        file.WriteLine("Saml 2 Assertion Issuer: NULL");
        //    }

        //    if (saml2Token.Assertion.Issuer != null)
        //    {
        //        file.WriteLine("\tSigningCredentials: " + saml2Token.Assertion.SigningCredentials.ToString());
        //    }
        //    else
        //    {
        //        file.WriteLine("Saml 2 Assertion SigningCredentials: NULL");
        //    }

        //    if (saml2Token.Assertion.Subject != null)
        //    {
        //        if (saml2Token.Assertion.Subject.NameId != null)
        //        {
        //            file.WriteLine("\tSubject NameId: " + saml2Token.Assertion.Subject.NameId.Value);
        //        }
        //        else
        //        {
        //            file.WriteLine("\tSubject NameId: NULL");
        //        }
        //    }
        //    else
        //    {
        //        file.WriteLine("Saml 2 Assertion Subject: NULL");
        //    }

        //    file.WriteLine("Saml Token:\n");

        //    file.WriteLine(TokenToString(saml2Token));

        //}
        #endregion

        public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
        {
            CustomAdsTextTraceSource ts = new CustomAdsTextTraceSource("IdpAds.OnBehalfOfSaml2SecurityTokenHandler.ValidateToken",
                "AdsTraceSource", SourceLevels.Information);

            Saml2SecurityToken saml2Token = token as Saml2SecurityToken;
            if (saml2Token != null && saml2Token.Assertion != null)
            {
                // GFIPM S2S 8.8.2.5.a.v
                Saml2AuthenticationStatement authnStatement = null;

                foreach (Saml2Statement st in saml2Token.Assertion.Statements)
                {
                    authnStatement = st as Saml2AuthenticationStatement;
                    if (authnStatement != null)
                    {
                        break;
                    }
                }

                if (authnStatement != null)
                {
                    ts.TraceInformation("Assertion Age: " + DateTime.UtcNow.Subtract(authnStatement.AuthenticationInstant).TotalSeconds.ToString() + " seconds");
                    ts.TraceInformation("Max Assertion Age:" + TimeSpan.FromSeconds(Constants.AdsMaxAssertionAge).TotalHours.ToString() + " hours");

                    if (DateTime.UtcNow.Subtract(authnStatement.AuthenticationInstant) > TimeSpan.FromSeconds(Constants.AdsMaxAssertionAge))
                    {
                        throw new SecurityTokenException("The authentication instant of the SAML2 assertion cannot be older than " 
                            + TimeSpan.FromSeconds(Constants.AdsMaxAssertionAge).TotalHours.ToString() + " hours");
                    }
                }
                else
                {
                    ts.TraceInformation("authnStatement: NULL");
                }


                // TODO: Refactor

                X509Certificate2 signingCert = Common.CertificateUtil.GetCertificate(StoreName.My, 
                    StoreLocation.LocalMachine, WebConfigurationManager.AppSettings["SigningCertificateName"]);

                // TODO: What if the KeyIdentifierClause changes?
                // How to prevent recompiling?

                SecurityKeyIdentifier secKeyIdentifier = saml2Token.Assertion.SigningCredentials.SigningKeyIdentifier;

                SecurityKeyIdentifierClause keyIdentifierClause = secKeyIdentifier.Find<X509RawDataKeyIdentifierClause>();

                if (keyIdentifierClause is X509RawDataKeyIdentifierClause)
                {
                    //X509SubjectKeyIdentifierClause x509IdentClause = keyIdentifierClause as X509SubjectKeyIdentifierClause;
                    X509RawDataKeyIdentifierClause x509IdentClause = keyIdentifierClause as X509RawDataKeyIdentifierClause;
            
                    // GFIPM S2S 8.8.2.5.a.iv
                    if (!x509IdentClause.Matches(signingCert))
                    {
                        ts.TraceInformation("The OnBehalfOf SAML 2 assertion was not signed by this IDP");

                        throw new SecurityTokenException("The OnBehalfOf SAML 2 assertion was not signed by this IDP");
                    }
                }

                // Seems this is not needed! See note below
                #region Deprecate?
                if (saml2Token.Assertion.Subject != null && saml2Token.Assertion.Subject.SubjectConfirmations != null)
                {
                    // first serialize before
                    //SerializeTokenToStream(saml2Token, file, "Saml 2 Assertion Before Removing: ");

                    ts.TraceInformation("Saml 2 Assertion: SubjectConfirmations");

                    // GFIPM S2S 8.8.2.6.b: Remove <SubjectConfirmationData> if present
                    // TODO: Need to test Holder-Of-Key confirmation method to make sure this works.
                    // TODO: This is actually not needed. When the new assertion is created, the 
                    // <SubjectConfirmationData> element is not created which is the same effect as deleting it.
                    for (int i = 0; i < saml2Token.Assertion.Subject.SubjectConfirmations.Count; i++)
                    {                        
                        saml2Token.Assertion.Subject.SubjectConfirmations[i].SubjectConfirmationData = null;
                    }
                }
                #endregion
            }
                        
            return base.ValidateToken(token);
        }