using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.Serialization;

namespace BusinessCommon
{
    public class AuthenticationExtension : SoapExtension
    {
        public override object GetInitializer(Type serviceType)
        {
            return null;
        }

        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return null;
        }

        public override void Initialize(object initializer)
        {
            /* nop */
        }

        public override void ProcessMessage(SoapMessage message)
        {
            if (message is SoapClientMessage && message.Stage == SoapMessageStage.BeforeSerialize)
            {
                AddTicket(message);
            }

            if (message is SoapServerMessage && message.Stage == SoapMessageStage.AfterDeserialize)
            {
                CheckTicket(message);
            }
        }

        private void AddTicket(SoapMessage message)
        {
            MyPrincipal principal = Thread.CurrentPrincipal as MyPrincipal;
            if (principal == null || !principal.Identity.IsAuthenticated)
            {
                return;
            }
            AuthenticationHeader header = new AuthenticationHeader();
            header.Name = principal.Identity.Ticket.Name;
            header.Expiration = principal.Identity.Ticket.Expiration;
            header.Roles = principal.Identity.Ticket.Roles;
            header.UserData = principal.Identity.Ticket.UserData;
            message.Headers.Add(header);
        }

        private void CheckTicket(SoapMessage message)
        {
            foreach (SoapHeader header in message.Headers)
            {
                SoapUnknownHeader unknownHeader = header as SoapUnknownHeader;
                if (unknownHeader.Element.NamespaceURI != AuthenticationHeader.HeaderName)
                {
                    continue;
                }
                XmlSerializer serializer = new XmlSerializer(typeof(AuthenticationHeader));
                XmlNodeReader reader = new XmlNodeReader(unknownHeader.Element);
                AuthenticationHeader authHeader = serializer.Deserialize(reader) as AuthenticationHeader;
                GenericIdentity identity = new GenericIdentity(authHeader.Name);
                Thread.CurrentPrincipal = new GenericPrincipal(identity, authHeader.Roles);
            }
        }
    }
}
