Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

password cannot contain british pound in WCF?

Have I discovered a bug in the .NET framework or am I doing something wrong?

Here is the story.

I was trying to set a password on the WCF channel yesterday like that:

channelFactory.Credentials.UserName.UserName = credentials.Username;
channelFactory.Credentials.UserName.Password = credentials.Password;

and then invoke the web service method when I got this error:

System.ServiceModel.CommunicationException
   Message=An error (The request was aborted: The request was canceled.) occurred while transmitting data over the HTTP channel.
   Source=mscorlib
   StackTrace:
     Server stack trace: 
        at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
        at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
        at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
        at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
        at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
        at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
        at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
        at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
     Exception rethrown at [0]: 
        at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
        at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
        at PocketKings.Tools.Services.PopulationManager.Client.PopulationService.IPopulationService.ResolvePopulationMember(ResolveRealmMemberQuery request)
   InnerException: System.Net.WebException
        Message=The request was aborted: The request was canceled.
        Source=System
        StackTrace:
             at System.Net.HttpWebRequest.GetResponse()
             at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
        InnerException: System.NotSupportedException
             Message=This method is not supported by this class.
             Source=System
             StackTrace:
                  at System.Net.BasicClient.EncodingRightGetBytes(String rawString)
                  at System.Net.BasicClient.Lookup(HttpWebRequest httpWebRequest, ICredentials credentials)
                  at System.Net.BasicClient.Authenticate(String challenge, WebRequest webRequest, ICredentials credentials)
                  at System.Net.AuthenticationManager.Authenticate(String challenge, WebRequest request, ICredentials credentials)
                  at System.Net.AuthenticationState.AttemptAuthenticate(HttpWebRequest httpWebRequest, ICredentials authInfo)
                  at System.Net.HttpWebRequest.CheckResubmitForAuth()
                  at System.Net.HttpWebRequest.CheckResubmit(Exception& e)
                  at System.Net.HttpWebRequest.DoSubmitRequestProcessing(Exception& exception)
                  at System.Net.HttpWebRequest.ProcessResponse()
                  at System.Net.HttpWebRequest.SetResponse(CoreResponseData coreResponseData)

So i started looking at it and the logs show that I don't even get as far as the server. It turns out that the .NET framework method, which throws an exception (System.Net.BasicClient.EncodingRightGetBytes(String rawString)) doesn't like the british pound sign (£).

I copied the method from the reflector and wrote a quick unit test and pound is the only character that it doesnt like from all I could type on a keyboard:

    internal static byte[] EncodingRightGetBytes(string rawString)
    {
            byte[] bytes = Encoding.Default.GetBytes(rawString);
            string strB = Encoding.Default.GetString(bytes);

            if (string.Compare(rawString, strB, StringComparison.Ordinal) != 0)
        {
            throw ExceptionHelper.MethodNotSupportedException;
        }
        return bytes;
}

This is my unit test to check this method:

[Test]
public void test123()
{
       string domain = "localhost";
       string userName = "lukk";

       string charactersToCheck = @"¬`!£$%^&*()_+={}[]:;@'~#<>,.?/|\";

       foreach (var character in charactersToCheck.ToCharArray())
       {
              string internalGetPassword = character.ToString();

              try
              {
                     // begin - this assignement was copied from System.Net.BasicClient.Lookup method
                     byte[] inArray = EncodingRightGetBytes(
                           (!string.IsNullOrEmpty(domain) ? (domain + @"\") : "")
                           + userName
                           + ":"
                           + internalGetPassword);
                     //end
              }
              catch (Exception ex)
              {
                     Console.WriteLine(string.Format("this character is bad: {0}", internalGetPassword));
              }
       }
}

As you can see EncodingRightGetBytes compares two strings and they are different if the original string (rawString) contains british pound.

EncodingRightGetBytes works fine when I replace the “Encoding.Default.” with “Encoding.UTF8.”…

Googling this method name brings back very few links, one of them being this: http://support.microsoft.com/kb/943511

I am using VS 2010 with an asp.net project set to use .net 3.5.

So would that be a bug in the .NET framework or am I doing something wrong?

Edit: When I query the Encoding.Default in the Immediate window while running my test I get this:

?Encoding.Default
    {System.Text.SBCSCodePageEncoding}
    [System.Text.SBCSCodePageEncoding]: {System.Text.SBCSCodePageEncoding}
    BodyName: "iso-8859-2"
    CodePage: 1250
    dataItem: {System.Globalization.CodePageDataItem}
    decoderFallback: {System.Text.InternalDecoderBestFitFallback}
    DecoderFallback: {System.Text.InternalDecoderBestFitFallback}
    EncoderFallback: {System.Text.InternalEncoderBestFitFallback}
    encoderFallback: {System.Text.InternalEncoderBestFitFallback}
    EncodingName: "Central European (Windows)"
    HeaderName: "windows-1250"
    IsBrowserDisplay: true
    IsBrowserSave: true
    IsMailNewsDisplay: true
    IsMailNewsSave: true
    IsReadOnly: true
    IsSingleByte: true
    m_codePage: 1250
    m_deserializedFromEverett: false
    m_isReadOnly: true
    WebName: "windows-1250"
    WindowsCodePage: 1250
like image 643
lukk Avatar asked Aug 18 '11 10:08

lukk


1 Answers

I have experienced something similar with asp, I managed to get around the issue by using the following config.

<system.web>    
<globalization
 fileEncoding="utf-8"
 requestEncoding="utf-8"      
 responseEncoding="utf-8"
 culture="en-GB"
 uiCulture="en-GB"/>
...

To my knowledge the globalization tag works the same for WCF when you set the

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

Update: Just checked MSDN at the bottom of the page it states the following:

The ASP.NET configuration language allows you to specify the culture for individual services. The WCF does not support that configuration setting except in ASP.NET compatibility mode. To localize a WCF service that does not use ASP.NET compatibility mode, compile the service type into culture-specific assemblies, and have separate culture-specific endpoints for each culture-specific assembly.

like image 115
AJ. Avatar answered Oct 04 '22 00:10

AJ.