You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by ol...@notes.uni-paderborn.de on 2003/11/12 21:32:41 UTC

Problem with Basic Authentification and non ASCII characters

Hi,

today an administrator reported a password related problem within one of
our applications to me. I tracked down the problem that the user had used
the german "Umlaute" äöü in his password.

Our application tried to log in to another web site using a get method from
HTTPClient 2.0 rc2 setting basic authentification, but authentification
failed because of the non ASCII characters.

We used the password "ä-ö-ü" for testing and it turned out that HTTPClient
translates this to "ZGg6Py0/LT8=". Internet Explorer and Mozilla translates
this to "ZGg65C32Lfw=". Using
org.apache.commons.httpclient.util.Base64.decode with the wrong string
results in "?-?-?" where the second string results in the correct "ä-ö-ü",
so encode and decode are not symetric.

Using the code below (I found some time ago on the internet) to translate
the password into the base64 version results in the correct string.

For me the question is, if a password with non ASCII characters is not
allowed at all (in the HTTPClient documentation I could not find a hint in
this direction or I have missed it), but even if not, browsers seem to
support it, so the used Base64-encoding class seems to be bugy and should
be fixed in 2.0, before it is completely replaced for 2.1.

Any thoughts or hints are welcome.

Regards,
Olaf





public class Base64
{
static String BaseTable[] = {
      "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P",
      "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
"e", "f",
      "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
"u", "v",
      "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"+", "/"
  };

  public static String encode(String text) {
    int n = text.length();
    if (n < 1)
      return text; // no bytes to encode!?!
    StringBuffer output = new StringBuffer(n);

    // read the entire file into the byte array
    byte bytes[] = new byte[ (n)];
    bytes = text.getBytes();

    byte buf[] = new byte[4]; // array of base64 characters

    int n3byt = n / 3; // how 3 bytes groups?
    int nrest = n % 3; // the remaining bytes from the grouping
    int k = n3byt * 3; // we are doing 3 bytes at a time
    int linelength = 0; // current linelength
    int i = 0; // index

    // do the 3-bytes groups ...
    while (i < k) {
      buf[0] = (byte) ( (bytes[i] & 0xFC) >> 2);
      buf[1] = (byte) ( ( (bytes[i] & 0x03) << 4) |
                       ( (bytes[i + 1] & 0xF0) >> 4));
      buf[2] = (byte) ( ( (bytes[i + 1] & 0x0F) << 2) |
                       ( (bytes[i + 2] & 0xC0) >> 6));
      buf[3] = (byte) (bytes[i + 2] & 0x3F);

      output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]).append(
          BaseTable[buf[2]]).append(BaseTable[buf[3]]);

      if ( (linelength += 4) >= 76) {
        output.append("\r\n");
        linelength = 0;
      }
      i += 3;
    }

    // deals with with the padding ...
    if (nrest == 2) {
      // 2 bytes left
      buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
      buf[1] = (byte) ( ( (bytes[k] & 0x03) << 4) |
                       ( (bytes[k + 1] & 0xF0) >> 4));
      buf[2] = (byte) ( (bytes[k + 1] & 0x0F) << 2);
    }
    else if (nrest == 1) {
      // 1 byte left
      buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
      buf[1] = (byte) ( (bytes[k] & 0x03) << 4);
    }

    if (nrest > 0) {
      // send the padding
      if ( (linelength += 4) >= 76)
        output.append("\r\n");
      output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]);
      // Thanks to R. Claerman for the bug fix here!
      if (nrest == 2) {
        output.append(BaseTable[buf[2]]);
      }
      else {
        output.append("=");
      }
      output.append("=");
    }
    return output.toString();
  }
}


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org


Re: Problem with Basic Authentification and non ASCII characters

Posted by Michael Becke <be...@u.washington.edu>.
As per usual the patch was stripped.  I will attach it to bugzilla.

Mike

On Nov 12, 2003, at 9:59 PM, Michael Becke wrote:

> Hello Olaf,
>
> Here's a quick patch that fixes the immediate problem.  From reading 
> RFC 2616 and 2617 it seems to me that we should have been using 
> ISO-8859-1 as the encoding instead of US-ASCII.  Please give this 
> patch a try.
>
> Mike
>
>
>
>
> On Nov 12, 2003, at 3:32 PM, olaf.hahnl@notes.uni-paderborn.de wrote:
>
>> Hi,
>>
>> today an administrator reported a password related problem within one 
>> of
>> our applications to me. I tracked down the problem that the user had 
>> used
>> the german "Umlaute" äöü in his password.
>>
>> Our application tried to log in to another web site using a get 
>> method from
>> HTTPClient 2.0 rc2 setting basic authentification, but 
>> authentification
>> failed because of the non ASCII characters.
>>
>> We used the password "ä-ö-ü" for testing and it turned out that 
>> HTTPClient
>> translates this to "ZGg6Py0/LT8=". Internet Explorer and Mozilla 
>> translates
>> this to "ZGg65C32Lfw=". Using
>> org.apache.commons.httpclient.util.Base64.decode with the wrong string
>> results in "?-?-?" where the second string results in the correct 
>> "ä-ö-ü",
>> so encode and decode are not symetric.
>>
>> Using the code below (I found some time ago on the internet) to 
>> translate
>> the password into the base64 version results in the correct string.
>>
>> For me the question is, if a password with non ASCII characters is not
>> allowed at all (in the HTTPClient documentation I could not find a 
>> hint in
>> this direction or I have missed it), but even if not, browsers seem to
>> support it, so the used Base64-encoding class seems to be bugy and 
>> should
>> be fixed in 2.0, before it is completely replaced for 2.1.
>>
>> Any thoughts or hints are welcome.
>>
>> Regards,
>> Olaf
>>
>>
>>
>>
>>
>> public class Base64
>> {
>> static String BaseTable[] = {
>>       "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", 
>> "M", "N",
>> "O", "P",
>>       "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", 
>> "c", "d",
>> "e", "f",
>>       "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", 
>> "s", "t",
>> "u", "v",
>>       "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", 
>> "8", "9",
>> "+", "/"
>>   };
>>
>>   public static String encode(String text) {
>>     int n = text.length();
>>     if (n < 1)
>>       return text; // no bytes to encode!?!
>>     StringBuffer output = new StringBuffer(n);
>>
>>     // read the entire file into the byte array
>>     byte bytes[] = new byte[ (n)];
>>     bytes = text.getBytes();
>>
>>     byte buf[] = new byte[4]; // array of base64 characters
>>
>>     int n3byt = n / 3; // how 3 bytes groups?
>>     int nrest = n % 3; // the remaining bytes from the grouping
>>     int k = n3byt * 3; // we are doing 3 bytes at a time
>>     int linelength = 0; // current linelength
>>     int i = 0; // index
>>
>>     // do the 3-bytes groups ...
>>     while (i < k) {
>>       buf[0] = (byte) ( (bytes[i] & 0xFC) >> 2);
>>       buf[1] = (byte) ( ( (bytes[i] & 0x03) << 4) |
>>                        ( (bytes[i + 1] & 0xF0) >> 4));
>>       buf[2] = (byte) ( ( (bytes[i + 1] & 0x0F) << 2) |
>>                        ( (bytes[i + 2] & 0xC0) >> 6));
>>       buf[3] = (byte) (bytes[i + 2] & 0x3F);
>>
>>       
>> output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]).append(
>>           BaseTable[buf[2]]).append(BaseTable[buf[3]]);
>>
>>       if ( (linelength += 4) >= 76) {
>>         output.append("\r\n");
>>         linelength = 0;
>>       }
>>       i += 3;
>>     }
>>
>>     // deals with with the padding ...
>>     if (nrest == 2) {
>>       // 2 bytes left
>>       buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
>>       buf[1] = (byte) ( ( (bytes[k] & 0x03) << 4) |
>>                        ( (bytes[k + 1] & 0xF0) >> 4));
>>       buf[2] = (byte) ( (bytes[k + 1] & 0x0F) << 2);
>>     }
>>     else if (nrest == 1) {
>>       // 1 byte left
>>       buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
>>       buf[1] = (byte) ( (bytes[k] & 0x03) << 4);
>>     }
>>
>>     if (nrest > 0) {
>>       // send the padding
>>       if ( (linelength += 4) >= 76)
>>         output.append("\r\n");
>>       output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]);
>>       // Thanks to R. Claerman for the bug fix here!
>>       if (nrest == 2) {
>>         output.append(BaseTable[buf[2]]);
>>       }
>>       else {
>>         output.append("=");
>>       }
>>       output.append("=");
>>     }
>>     return output.toString();
>>   }
>> }
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: 
>> commons-httpclient-dev-unsubscribe@jakarta.apache.org
>> For additional commands, e-mail: 
>> commons-httpclient-dev-help@jakarta.apache.org
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: 
> commons-httpclient-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: 
> commons-httpclient-dev-help@jakarta.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org


Re: Problem with Basic Authentification and non ASCII characters

Posted by ol...@notes.uni-paderborn.de.
Hi Mike,

your quick and easy patch fixes the problem right away. For my problem it
is good to go!

Thanks for the quick response and solution.

Olaf

P.S. Using UTF-8 does no good, I had tried this before.

Michael Becke <be...@u.washington.edu> wrote on 13.11.2003 03:59:43:

> Hello Olaf,
>
> Here's a quick patch that fixes the immediate problem.  From reading
> RFC 2616 and 2617 it seems to me that we should have been using
> ISO-8859-1 as the encoding instead of US-ASCII.  Please give this patch
> a try.
>
> Mike
>
>
>
>
> On Nov 12, 2003, at 3:32 PM, olaf.hahnl@notes.uni-paderborn.de wrote:
>
> > Hi,
> >
> > today an administrator reported a password related problem within one
> > of
> > our applications to me. I tracked down the problem that the user had
> > used
> > the german "Umlaute" äöü in his password.
> >
> > Our application tried to log in to another web site using a get method
> > from
> > HTTPClient 2.0 rc2 setting basic authentification, but authentification
> > failed because of the non ASCII characters.
> >
> > We used the password "ä-ö-ü" for testing and it turned out that
> > HTTPClient
> > translates this to "ZGg6Py0/LT8=". Internet Explorer and Mozilla
> > translates
> > this to "ZGg65C32Lfw=". Using
> > org.apache.commons.httpclient.util.Base64.decode with the wrong string
> > results in "?-?-?" where the second string results in the correct
> > "ä-ö-ü",
> > so encode and decode are not symetric.
> >
> > Using the code below (I found some time ago on the internet) to
> > translate
> > the password into the base64 version results in the correct string.
> >
> > For me the question is, if a password with non ASCII characters is not
> > allowed at all (in the HTTPClient documentation I could not find a
> > hint in
> > this direction or I have missed it), but even if not, browsers seem to
> > support it, so the used Base64-encoding class seems to be bugy and
> > should
> > be fixed in 2.0, before it is completely replaced for 2.1.
> >
> > Any thoughts or hints are welcome.
> >
> > Regards,
> > Olaf
> >
> >
> >
> >
> >
> > public class Base64
> > {
> > static String BaseTable[] = {
> >       "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
> > "N",
> > "O", "P",
> >       "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c",
> > "d",
> > "e", "f",
> >       "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
> > "t",
> > "u", "v",
> >       "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8",
> > "9",
> > "+", "/"
> >   };
> >
> >   public static String encode(String text) {
> >     int n = text.length();
> >     if (n < 1)
> >       return text; // no bytes to encode!?!
> >     StringBuffer output = new StringBuffer(n);
> >
> >     // read the entire file into the byte array
> >     byte bytes[] = new byte[ (n)];
> >     bytes = text.getBytes();
> >
> >     byte buf[] = new byte[4]; // array of base64 characters
> >
> >     int n3byt = n / 3; // how 3 bytes groups?
> >     int nrest = n % 3; // the remaining bytes from the grouping
> >     int k = n3byt * 3; // we are doing 3 bytes at a time
> >     int linelength = 0; // current linelength
> >     int i = 0; // index
> >
> >     // do the 3-bytes groups ...
> >     while (i < k) {
> >       buf[0] = (byte) ( (bytes[i] & 0xFC) >> 2);
> >       buf[1] = (byte) ( ( (bytes[i] & 0x03) << 4) |
> >                        ( (bytes[i + 1] & 0xF0) >> 4));
> >       buf[2] = (byte) ( ( (bytes[i + 1] & 0x0F) << 2) |
> >                        ( (bytes[i + 2] & 0xC0) >> 6));
> >       buf[3] = (byte) (bytes[i + 2] & 0x3F);
> >
> >
> > output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]).append(
> >           BaseTable[buf[2]]).append(BaseTable[buf[3]]);
> >
> >       if ( (linelength += 4) >= 76) {
> >         output.append("\r\n");
> >         linelength = 0;
> >       }
> >       i += 3;
> >     }
> >
> >     // deals with with the padding ...
> >     if (nrest == 2) {
> >       // 2 bytes left
> >       buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
> >       buf[1] = (byte) ( ( (bytes[k] & 0x03) << 4) |
> >                        ( (bytes[k + 1] & 0xF0) >> 4));
> >       buf[2] = (byte) ( (bytes[k + 1] & 0x0F) << 2);
> >     }
> >     else if (nrest == 1) {
> >       // 1 byte left
> >       buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
> >       buf[1] = (byte) ( (bytes[k] & 0x03) << 4);
> >     }
> >
> >     if (nrest > 0) {
> >       // send the padding
> >       if ( (linelength += 4) >= 76)
> >         output.append("\r\n");
> >       output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]);
> >       // Thanks to R. Claerman for the bug fix here!
> >       if (nrest == 2) {
> >         output.append(BaseTable[buf[2]]);
> >       }
> >       else {
> >         output.append("=");
> >       }
> >       output.append("=");
> >     }
> >     return output.toString();
> >   }
> > }
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail:
> > commons-httpclient-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail:
> > commons-httpclient-dev-help@jakarta.apache.org
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
commons-httpclient-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-httpclient-dev-
> help@jakarta.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org


Re: Problem with Basic Authentification and non ASCII characters

Posted by Michael Becke <be...@u.washington.edu>.
Hello Olaf,

Here's a quick patch that fixes the immediate problem.  From reading 
RFC 2616 and 2617 it seems to me that we should have been using 
ISO-8859-1 as the encoding instead of US-ASCII.  Please give this patch 
a try.

Mike


Re: Problem with Basic Authentification and non ASCII characters

Posted by Ortwin Glück <or...@nose.ch>.

olaf.hahnl@notes.uni-paderborn.de wrote:
>     byte bytes[] = new byte[ (n)];
>     bytes = text.getBytes();


Bravo, the above code couldn't be worse...


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org


Re: Problem with Basic Authentification and non ASCII characters

Posted by Eric Johnson <er...@tibco.com>.
This would appear to be a character encoding issue.

In BasicScheme.authenticate, it currently does this:

return "Basic " + HttpConstants.getAsciiString(
    Base64.encode(HttpConstants.getBytes(buffer.toString())));

I suspect it should be doing something like this:

return "Basic " + HttpConstants.getAsciiString(
    Base64.encode(buffer.toString().getBytes("UTF-8") ) );

RFC 2617 appears to be mum on the issue.

Anyone else have a better clue?

-Eric.

P.S. I found this email which might be a useful place to start, but I 
couldn't figure out the answer from a quick read of it or its 
surrounding emails on the topic.

http://lists.w3.org/Archives/Public/ietf-http-wg/2003AprJun/0015.html

olaf.hahnl@notes.uni-paderborn.de wrote:

>Hi,
>
>today an administrator reported a password related problem within one of
>our applications to me. I tracked down the problem that the user had used
>the german "Umlaute" äöü in his password.
>
>Our application tried to log in to another web site using a get method from
>HTTPClient 2.0 rc2 setting basic authentification, but authentification
>failed because of the non ASCII characters.
>
>We used the password "ä-ö-ü" for testing and it turned out that HTTPClient
>translates this to "ZGg6Py0/LT8=". Internet Explorer and Mozilla translates
>this to "ZGg65C32Lfw=". Using
>org.apache.commons.httpclient.util.Base64.decode with the wrong string
>results in "?-?-?" where the second string results in the correct "ä-ö-ü",
>so encode and decode are not symetric.
>
>Using the code below (I found some time ago on the internet) to translate
>the password into the base64 version results in the correct string.
>
>For me the question is, if a password with non ASCII characters is not
>allowed at all (in the HTTPClient documentation I could not find a hint in
>this direction or I have missed it), but even if not, browsers seem to
>support it, so the used Base64-encoding class seems to be bugy and should
>be fixed in 2.0, before it is completely replaced for 2.1.
>
>Any thoughts or hints are welcome.
>
>Regards,
>Olaf
>
>
>
>
>
>public class Base64
>{
>static String BaseTable[] = {
>      "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
>"O", "P",
>      "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
>"e", "f",
>      "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
>"u", "v",
>      "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
>"+", "/"
>  };
>
>  public static String encode(String text) {
>    int n = text.length();
>    if (n < 1)
>      return text; // no bytes to encode!?!
>    StringBuffer output = new StringBuffer(n);
>
>    // read the entire file into the byte array
>    byte bytes[] = new byte[ (n)];
>    bytes = text.getBytes();
>
>    byte buf[] = new byte[4]; // array of base64 characters
>
>    int n3byt = n / 3; // how 3 bytes groups?
>    int nrest = n % 3; // the remaining bytes from the grouping
>    int k = n3byt * 3; // we are doing 3 bytes at a time
>    int linelength = 0; // current linelength
>    int i = 0; // index
>
>    // do the 3-bytes groups ...
>    while (i < k) {
>      buf[0] = (byte) ( (bytes[i] & 0xFC) >> 2);
>      buf[1] = (byte) ( ( (bytes[i] & 0x03) << 4) |
>                       ( (bytes[i + 1] & 0xF0) >> 4));
>      buf[2] = (byte) ( ( (bytes[i + 1] & 0x0F) << 2) |
>                       ( (bytes[i + 2] & 0xC0) >> 6));
>      buf[3] = (byte) (bytes[i + 2] & 0x3F);
>
>      output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]).append(
>          BaseTable[buf[2]]).append(BaseTable[buf[3]]);
>
>      if ( (linelength += 4) >= 76) {
>        output.append("\r\n");
>        linelength = 0;
>      }
>      i += 3;
>    }
>
>    // deals with with the padding ...
>    if (nrest == 2) {
>      // 2 bytes left
>      buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
>      buf[1] = (byte) ( ( (bytes[k] & 0x03) << 4) |
>                       ( (bytes[k + 1] & 0xF0) >> 4));
>      buf[2] = (byte) ( (bytes[k + 1] & 0x0F) << 2);
>    }
>    else if (nrest == 1) {
>      // 1 byte left
>      buf[0] = (byte) ( (bytes[k] & 0xFC) >> 2);
>      buf[1] = (byte) ( (bytes[k] & 0x03) << 4);
>    }
>
>    if (nrest > 0) {
>      // send the padding
>      if ( (linelength += 4) >= 76)
>        output.append("\r\n");
>      output.append(BaseTable[buf[0]]).append(BaseTable[buf[1]]);
>      // Thanks to R. Claerman for the bug fix here!
>      if (nrest == 2) {
>        output.append(BaseTable[buf[2]]);
>      }
>      else {
>        output.append("=");
>      }
>      output.append("=");
>    }
>    return output.toString();
>  }
>}
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org
>
>
>  
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-httpclient-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-httpclient-dev-help@jakarta.apache.org