Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BasicHttpMessageSecurity #2211

Closed
LEsperanca opened this issue Aug 18, 2017 · 10 comments
Closed

BasicHttpMessageSecurity #2211

LEsperanca opened this issue Aug 18, 2017 · 10 comments
Assignees
Milestone

Comments

@LEsperanca
Copy link

This is not really a issue, when will BasicHttpMessageSecurity be supported by .net core 2.0?

@zhenlan
Copy link
Member

zhenlan commented Aug 19, 2017

@LEsperanca please refer to 2.0 release notes:

At this point we don't have a plan to support message security due to lack of dependent functionalities in System.IdentityModel on .NET Core.

@zhenlan zhenlan closed this as completed Aug 19, 2017
@zhenlan zhenlan self-assigned this Aug 19, 2017
@zhenlan zhenlan added this to the S123 milestone Aug 19, 2017
@hugoterelle
Copy link

How can we help?

@LEsperanca
Copy link
Author

I need to have or emulate BasicHttpMessageSecurity in a .net core service and i don't know how... @hugoterelle

@hugoterelle
Copy link

hugoterelle commented Aug 30, 2017

@zhenlan my question was for you. I could help improve your library if needed.

@LEsperanca
To solve this problem, I created my own SOAP Header (as a temporary solution). Find an example below using username/password in clear text but the method will remain the same for other security protocols

    public class SoapSecurityHeader : MessageHeader
    {
        private readonly string _username;
        private readonly string _password;

        public SoapSecurityHeader(string username, string password)
        {
            _username = username;
            _password = password;
        }

        public override string Name { get; } = "Security";

        public override string Namespace { get; } = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
                                                     
        private const string WsuNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteStartElement("wsse", "UsernameToken", Namespace);
            writer.WriteAttributeString("wsu", "Id", WsuNamespace, Guid.NewGuid().ToString());

            writer.WriteStartElement("wsse", "Username", Namespace);
            writer.WriteValue(_username);
            writer.WriteEndElement();

            writer.WriteStartElement("wsse", "Password", Namespace);
            writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
            writer.WriteValue(_password);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }

        protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteStartElement("wsse", Name, Namespace);
            writer.WriteXmlnsAttribute("wsse", Namespace);
        }
    }

    public class SoapSecurityHeaderInspector : IClientMessageInspector
    {
        private readonly string _username;
        private readonly string _password;

        public SoapSecurityHeaderInspector(string username, string password)
        {
            _username = username;
            _password = password;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {

        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            request.Headers.Add(new SoapSecurityHeader(_username, _password));

            return null;
        }
    }

    public class SoapSecurityHeaderBehavior : IEndpointBehavior
    {
        private readonly string _username;
        private readonly string _password;

        public SoapSecurityHeaderBehavior(string username, string password)
        {
            _username = username;
            _password = password;
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {

        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.ClientMessageInspectors.Add(new SoapSecurityHeaderInspector(_username, _password));
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {

        }

        public void Validate(ServiceEndpoint endpoint)
        {

        }
    }

And then, I created a channel factory (used by Autofac)

        private static ChannelFactory<T> CreateSecuredChannel<T>(string url, string username, string password)
        {
            var binding = new BasicHttpsBinding
            {
                TextEncoding = Encoding.UTF8,
                UseDefaultWebProxy = true,
                BypassProxyOnLocal = false,
                Security =
                {
                    Mode = BasicHttpsSecurityMode.Transport,
                    Transport =
                    {
                        ClientCredentialType = HttpClientCredentialType.None,
                        ProxyCredentialType = HttpProxyCredentialType.None
                    }
                }
            };

            var channel = new ChannelFactory<T>(binding, new EndpointAddress(url));
            channel.Endpoint.EndpointBehaviors.Add(new SoapSecurityHeaderBehavior(username, password));

            channel.Credentials.UserName.UserName = username; // not sure if needed
            channel.Credentials.UserName.Password = password;
            return channel;
        }

@atanevski atanevski mentioned this issue Dec 1, 2017
@nickcoad
Copy link

@hugoterelle I'm not sure how to actually use the ChannelFactory you've created, can you tell me how I inject this into the WCF service so it uses the correct channelfactory?

@hugoterelle
Copy link

@nickcoad
I use autofac to register the channel factory:

builder.Register(c => CreateSecuredChannel("myurl", "myuser", "mypassword")).SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory>().CreateChannel())
.As()
.UseWcfSafeRelease();

Then, you just need to inject your IMySoapService to use it.

And for the UseWcfSafeRelease used by Autofac, just refer to the issue I raised on the Autofac github
autofac/Autofac.Wcf#11

@edenprairie
Copy link

Any ETA on this issue? This is important feature to support for a lot of WCF service migration projects for us.

@Soopster
Copy link

Soopster commented Aug 1, 2018

@hugoterelle Thank you for your code. I managed to get Basic Auth Message level security working using your code.

@mkhatuntcov-korewireless
Copy link

mkhatuntcov-korewireless commented Nov 7, 2018

@hugoterelle Your code works for me. Thank you very much! Do you wanna make a nuget package till MS do it properly?

@nickcoad FYI You don't have to use Autofac. You able to use any DI or simply:

 client.Endpoint.EndpointBehaviors.Add(new SoapSecurityHeaderBehavior("user", "pass"));

@isabasan
Copy link

@hugoterelle Thank you very much for your work. It saved my day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants