Unicode username & password

173 views
Skip to first unread message

Sigurd Høgsbro

unread,
Oct 10, 2010, 9:25:44 PM10/10/10
to ASIHTTPRequest
I'm trying to pass a Unicode username/password into ASIHttpRequest,
for authentication against a HTTP Digest service, and found that it
fails.

From testing in other languages this should work as long as these
strings are represented in UTF-8.

Could ASI be made to handle encoding automatically, or should I
convert the username/password strings to UTF-8 before calling
setUsername()/setPassword()? If the latter, any suggest for how to do
this efficiently with NSString?

Thanks,

Sigurd

Ben Copsey

unread,
Oct 11, 2010, 2:11:46 AM10/11/10
to asihttp...@googlegroups.com
Hi Sigurd

Hmm. For digest authentication CFNetwork handles building the authorization header, so I fear it may be outside of our control.

From this page:

http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in-http-basic-auth-username/3534558#3534558

"Safari and Chrome encode to ISO-8859-1, and fail to send the authorization header at all when a non-8859-1 character is used."

and

"HTTP Digest authentication is no solution for this problem, either. It suffers from the same problem of the client being unable to tell the server what character set it's using and the server being unable to correctly assume what the client used."

It sounds like it's not safe to use unicode for basic or digest authentication credentials. It may be that other clients/apis you've tested with do use utf-8, and your server is assuming utf-8, but CFNetwork is using iso-8859-1, so it breaks.

Perhaps someone else can make a suggestion, otherwise, it might be better to use a different approach (eg POST the credentials and use a session cookie).

Best,

Ben

Joseph Heenan

unread,
Oct 11, 2010, 3:25:48 AM10/11/10
to asihttp...@googlegroups.com
You've got to love standards :-)

Given it should be impossible for CFNetwork to tell you've given it
UTF-8 when it was expecting iso-8859-1, you could try something like this:

NSString *username = @"flibble";
const char *utf8String = [username UTF8String];
NSString *usernameUtf8 = [NSString stringWithCString utf8String
encoding:NSISOLatin1StringEncoding];

Completely untested, but I can't think of a reason it wouldn't work.
Essentially we'd be giving a UTF8 string to CFNetwork, but telling it
that it's Latin1 - so when it converts it back to Latin1 to send to the
server it'll end up with UTF8. This only works because they're 8 bit
encodings, and Latin1 (essentially[*]) defines all 256 possible
characters to be valid, meaning that UTF8 is "valid" Latin1.

Joseph


[*] There's complications as Latin1 has been extended by Microsoft and
other people to add extra characters, so technically "pure" "as per
standard" ISO-8559-1 doesn't define some of the 256 characters.

Sigurd Høgsbro

unread,
Oct 11, 2010, 4:52:59 AM10/11/10
to ASIHTTPRequest
Hi Ben,

Thanks for the quick response, and the sleuthing to uncover the real
problem.

As we control both client & server, we could encode any non ISO-8859-1
chars into HEX or Base64, as long as we consistently apply that
algorithm on both ends. Alternatively, is there a way to use ASI in
which we would receive the 401 and can calculate the Authentication
header ourselves?

Cheers,

Sigurd

On Oct 11, 7:11 am, Ben Copsey <b...@allseeing-i.com> wrote:
> Hi Sigurd
>
> > I'm trying to pass a Unicode username/password into ASIHttpRequest,
> > for authentication against a HTTP Digest service, and found that it
> > fails.
>
> > From testing in other languages this should work as long as these
> > strings are represented in UTF-8.
>
> > Could ASI be made to handle encoding automatically, or should I
> > convert the username/password strings to UTF-8 before calling
> > setUsername()/setPassword()? If the latter, any suggest for how to do
> > this efficiently with NSString?
>
> Hmm. For digest authentication CFNetwork handles building the authorization header, so I fear it may be outside of our control.
>
> From this page:
>
> http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in...

Sigurd Høgsbro

unread,
Oct 11, 2010, 9:03:18 AM10/11/10
to ASIHTTPRequest
Hi Joseph,

Excellent, that worked! Working code:

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:authURL];
const char *utf8Username = [username UTF8String];
const char *utf8Password = [password UTF8String];
NSString *encodedUsername = [NSString stringWithCString:utf8Username
encoding:NSISOLatin1StringEncoding];
NSString *encodedPassword = [NSString stringWithCString:utf8Password
encoding:NSISOLatin1StringEncoding];
[request setDelegate:self];
[request setShouldPresentCredentialsBeforeChallenge:NO];
[request setUsername:encodedUsername];
[request setPassword:encodedPassword];
[request startAsynchronous];

Thanks for the help,

Sigurd

On Oct 11, 8:25 am, Joseph Heenan <jos...@heenan.me.uk> wrote:
>   On 11/10/2010 07:11, Ben Copsey wrote:
>
>
>
> > Hi Sigurd
>
> >> I'm trying to pass a Unicode username/password into ASIHttpRequest,
> >> for authentication against a HTTP Digest service, and found that it
> >> fails.
>
> >>  From testing in other languages this should work as long as these
> >> strings are represented in UTF-8.
>
> >> Could ASI be made to handle encoding automatically, or should I
> >> convert the username/password strings to UTF-8 before calling
> >> setUsername()/setPassword()? If the latter, any suggest for how to do
> >> this efficiently with NSString?
> > Hmm. For digest authentication CFNetwork handles building the authorization header, so I fear it may be outside of our control.
>
> >  From this page:
>
> >http://stackoverflow.com/questions/702629/utf-8-characters-mangled-in...

Ben Copsey

unread,
Oct 12, 2010, 6:18:54 AM10/12/10
to asihttp...@googlegroups.com
> Excellent, that worked! Working code:
>
> ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:authURL];
> const char *utf8Username = [username UTF8String];
> const char *utf8Password = [password UTF8String];
> NSString *encodedUsername = [NSString stringWithCString:utf8Username
> encoding:NSISOLatin1StringEncoding];
> NSString *encodedPassword = [NSString stringWithCString:utf8Password
> encoding:NSISOLatin1StringEncoding];
> [request setDelegate:self];
> [request setShouldPresentCredentialsBeforeChallenge:NO];
> [request setUsername:encodedUsername];
> [request setPassword:encodedPassword];
> [request startAsynchronous];
>
>> Completely untested, but I can't think of a reason it wouldn't work.
>> Essentially we'd be giving a UTF8 string to CFNetwork, but telling it
>> that it's Latin1 - so when it converts it back to Latin1 to send to the
>> server it'll end up with UTF8. This only works because they're 8 bit
>> encodings, and Latin1 (essentially[*]) defines all 256 possible
>> characters to be valid, meaning that UTF8 is "valid" Latin1.

That's a neat solution! :)

Glad you got it working anyhow.

Best

Ben

Reply all
Reply to author
Forward
0 new messages