publikaccion @publikaccion
Mostrando entradas con la etiqueta utf-8. Mostrar todas las entradas
Mostrando entradas con la etiqueta utf-8. Mostrar todas las entradas

viernes, abril 25, 2008

.: Codificar y Decodificar en linux Base64 y UTF8 en Perl


El otro día volví a tener un problema de nuevo con el LDAP del proyecto en el que ando y con el famoso Base64 del OpenLDAP (para más información remitirse a un artículo anterior sobre el mismo tema), y bucenado un poco me encontré con unas instrucciones que a más de uno seguro que le van a sacar del paso en un momento cuando se cuentre con el mismo problema.

El problema viene siendo el mismo de siempre, y es que se pongan entradas en el DN de un LDAP con acentos o caracteres raros, de modo que cuando el LDAP hace un exportación de dicha entrada, nos la muestra como caracteres extraños y no comprensibles. Esto es la codificación en Base64.

Para decodificar dicho galimatías, basta con introducir la siguiente línea de texto en la línea de comandos:

echo | perl -MMIME::Base64 -ne 'print encode_base64($_) . "\n"'


que como ejemplo podría ser:

echo "Esto es un texto con eñes y acentos en las letras áéíóú" | perl -MMIME::Base64 -ne 'print encode_base64($_) . "\n"'


que nos devolvería la cadena de texto:

RXN0byBlcyB1biB0ZXh0byBjb24gZfFlcyB5IGFjZW50b3MgZW4gbGFzIGxldHJhcyDh6e3z+go=


y para volver a decodificar la cadena de Base64 a texto legible para nosotros tendríamos que poner en la línea de comandos Linux:

echo | perl -MMIME::Base64 -ne 'print decode_base64($_) . "\n"'


lo que para nuestro ejemplo sería:

echo "RXN0byBlcyB1biB0ZXh0byBjb24gZfFlcyB5IGFjZW50b3MgZW4gbGFzIGxldHJhcyDh6e3z+go=" | perl -MMIME::Base64 -ne 'print decode_base64($_) . "\n"'


lo que nos devolvería la cadena legible:

Esto es un texto con eñes y acentos en las letras áéíóú

Sin embargo tal y como comentaba en el anterior artículo, además de que OpenLDAP emplea Base64 para codificar los caracteres que no sean estándar (en nuestro caso los ISO Latin1 o ISO-8859-1), también codifica los acentos, eñes, cetillas, diéresis y demás "extraños" del ISO Latin1 en codificación UTF8.

Desde la línea de comandos de linux también tiene fácil solución empleando iconv.

De este modo si tenemos la siguiente cadena de caracteres que queremos codificar a UTF8:

El camión español chocó contra el pingüino en el término de Curação


y la introducimos en un archivo plano TXT que se llame isolatin1.txt empleamos desde la línea de comandos de linux:

iconv -f iso-8859-1 -t utf-8 isolatin1.txt > utfplano.txt


nos meterá en el utfplano.txt como salida la siguiente entrada:

El camión español chocó contra el pingüino en el término de Curação


que es nuestro texto codificado a UTF8.

Para decodificar el UTF8 del archivo utfplano.txt se emplearía sobre la línea de comandos linux:

iconv -f utf-8 -t iso-8859-1 utfplano.txt > isoplano.txt


lo que nos devolvería en nuestro isoplano.txt lo siguiente:

El camión español chocó contra el pingüino en el término de Curação


verificando de este modo que tenemos codificado correctamente el UTF8.

Ahora el texto codificado en UTF8, para transformarlo a Base64 desde línea de comandos sería del tipo:

echo "El camión español chocó contra el pingüino en el término de Curação" | perl -MMIME::Base64 -ne 'print encode_base64($_) . "\n"'


lo que nos devolvería:

RWwgY2FtacOzbiBlc3Bhw7FvbCBjaG9jw7MgY29udHJhIGVsIHBpbmfDvGlubyBlbiBlbCB0w6ly
bWlubyBkZSBDdXJhw6fDo28K


y para verificar que todo ha ido bien, decodificando Base64 a UTF8 sería:

echo "RWwgY2FtacOzbiBlc3Bhw7FvbCBjaG9jw7MgY29udHJhIGVsIHBpbmfDvGlubyBlbiBlbCB0w6lybWlubyBkZSBDdXJhw6fDo28K" | perl -MMIME::Base64 -ne 'print decode_base64($_) . "\n"'


lo que nos devolvería el texto en UTF8:

El camión español chocó contra el pingüino en el término de Curação


De este modo tenemos la transformación ISO Latin1 -> UTF8 -> Base64 que es el texto que finalmente estará en el OpenLDAP si el texto contiene acentos o cedillas o similares.

Para realizar la codificación desde archivos en Base64 (y la decodificación), tendríamos:

perl -MMIME::Base64 -ne 'print encode_base64($_) . "\n"' < utfplano.txt > encodedBase64.txt
perl -MMIME::Base64 -ne 'print decode_base64($_) . "\n"' < encodedBase64.txt > decodedBase64.txt


lo que nos daría como archivos:

utfplano.txt: Nuestro texto castellano formateado en UTF8 con los acentos y demás codificado en UTF8
encodedBase64.txt: Nuestro texto UTF8 codificado a Base64
decodedBase64.txt: Nuestro texto decodificado de Base64 en formato YTF8

Para volver a ver el texto de UTF8 en ISO Latin1 tendríamos:

iconv -f utf-8 -t iso-8859-1 decodedBase64.txt > isoplano.txt


Espero a que a alguien le sirva como me ha servido a mí...

martes, mayo 29, 2007

.: LDAP tilde/s, eñe/s Latin-1 (ISO-8859-1), UTF-8 y Base 64

Estos días el LDAP me ha estado dando la lata con el tema de las tildes, las eñes y otras hierbas del Latin-1 (ISO-8859-1) que es el estándar que reconoce nuestros caracteres acentuados, eñes y cedillas, y demás símbolos latinos escritos.

Necesitaremos:

- OpenLDAP
- OpenSSL

No entro en detalle de cómo se instala ninguno de estos 2 productos, ya que considero que hay suficiente información en sus respectivas webs para que cada uno sea el que se encargue de dichas instalaciones en sus máquinas y sistemas operativos correspondientes.

El caso es que intentando introducir una nueva entrada o NODO en un OpenLDAP, me encontraba con que cada vez que introducía un CN (Common Name) con acento através del formato LDIF de datos paa LDAP, el slapd me devolvía un error indicando que el DN estaba mañ formato (DN que por supuesto tenía tilde), sin embargo cuando daba de alta el mismo de DN mediante una herramienta visual como es JXplorer, el campeón se tragaba los acentos sin ningún tipo de queja, y eso me llevó a mosquearme, ya que el formato texto de LDIF no me dejaba.

En el ejemplo (ficticio para más información), tenía un caso del tipo:

dn: cn=Javier Gómez García,ou=people,dc=dominio,dc=es
objectClass: top
objectClass: usuario
cn: Javier Gómez García
uid: jgomezg
userName: jgomezg


al final encontré el por qué no podemos hacer una exportación en limpio desde línea de comandos con un LDIF que generemos nosootros.

La explicación viene por el siguiente motivo, principalmente el LDAP funciona con codificación de caracteres UTF-8, no en Latin-1 que es la iso-8859-1 que reconoce los caracteres españoles como tildes, diéresis, eñes o cedillas, de modo que intentar meter desde un LDIF un acento en un campo que tenga reconocimiento específico de caracteres (algunos atributos permiten introducir acentos sin problemas), causa que nos dé un error de sintaxis en el DN, en el CN, o en donde se encuentre las tildes codificados en Latin-1 o ISO-8859-1 (en español-castellano para entendernos).

Ahora surge la duda de cómo es que sí que nos deja el JXplorer hacerlo sin ningún tipo de problema. La explicación es que JXplorer así como otros muchos navegadores/administradores de LDAP, implementa el codificado automático del ISO correspondiente al idioma a codificación UTF-8, de modo que lo que está haciendo el cliente de administración de LDAP es codificar automáticamente a UTF-8, independientemente de que nosotros queramos o no.

Además de codificar en formato UTF-8, todas las entradas que contengan caracteres raros para LDAP (aquellos que no sean los caracteres estándar exployendo caracteres del tipo áéíóúäëïöüñç), deben además ir codificadas en Base64 (otro algoritmo de codificación), de modo que lo que son caracteres extraños para el LDAP que son los que genera UTF-8 (áéíóúäëïöüñç) cuando empleamos ISO 8859-1, deben ser transformados a Base64 de modo que JXplorer hace este tipo de transformación de Latin-1 (ISO-8859-1 -> UTF-8 -> Base64 por nosotros, y así, cuando exportamos una entrada que vemos que tiene acentos o eñes en el LDAP del MAP, vemos que las entradas son del tipo de un churro de caracteres raros... del tipo:

dn:: ZG46IGNuPUphdmllciBHw7NtZXogR2FyY8OtYSxvdT1wZW9wbGUsZGM9ZG9taW5p
 byxkYz1lcw==


que es el formato Base64 de un DN (los :: nos indican que está codificado en Base64) para la entrada:

dn: cn=Javier Gómez García,ou=people,dc=dominio,dc=es

que es a su vez el formato UTF-8 de un DN que corresponde con:

dn: cn=Javier Gómez García,ou=people,dc=dominio,dc=es

en formato ISO 8859-1 o Latin-1 (que tal y como comento es la ISO que identifica a nuestro idioma, el español).

Las codificaciones de Latin-1 a UTF-8 se pueden hacer o bien mirando unas tablas de UTF-8 o bien como hice yo con un sencillo javascript que traduce todo tipo de carácter raro para LDAP de modo que nos da la codificación sin mayor problema.


<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>

<script>
function encode_utf8(s){
return unescape(encodeURIComponent(s));
}

function decode_utf8(s){
return decodeURIComponent(escape(s));
}
</script>

</head>
<body>

<form name="formulario">
Texto a codificar en en formato<br />Latin-1 (ISO-8859-1) -> UTF-8<br />
<input type="text" name="entrada" value=""><br />
<input type="button" value="codificar"
onclick="document.formulario.resultado.value=(
encode_utf8(document.formulario.entrada.value));
document.formulario.salida.value=document.formulario.resultado.value"> <br /><br />

Texto a decodificar en formato<br />UTF-8 -> Latin-1 (ISO-8859-1)<br />
<input type="text" name="salida" value=""><br />
<input type="button" value="decodificar"
onclick="document.formulario.resultado.value=(
decode_utf8(document.formulario.salida.value));"><br /><br /><br />

Resultado<br />
<input type="text" name="resultado" value=""><br />

</form>

</body>
</html>


Una vez realizada la codificación a UTF-8 el mismo OpenSSL tiene una utilidad de línea de comandos que permite codificar y decodificar en Base64, con lo que quedaría el chorro de caracteres raros listos para introducir dentro del LDIF en el DN correspondiente.

Yo creo 3 archivos:

- plain.txt es el archivo con el texto plano en formato UTF-8
- coded.txt es el archivo con el texto UTF-8 codificado en Base64
- decoded.txt es el archivo con el texto en UTF-8 decodificado de Base64 (por motivo de comprobación más que nada)

de modo que tecleando desde consola

type plain.txt|openssl base64 -e > coded.txt

Codifica plain.txt en UTF-8 a coded.txt en Base64, y

type coded.txt|openssl base64 -d > decoded.txt

Codifica coded.txt en base64 a decoded.txt en UTF-8 comprobando que el plain.txt y el decoded.txt deben coincidir.

Probando de esta manera no hay problema en dar de alta desde línea de comandos preparando el archivo LDIF a las entradas que queramos asignar al nuevo árbol, siendo lo más engorroso quizás el tema de codificado con los diferentes algoritmos, pero que a fin de cuentas es la explicación que se tiene a por qué el JXplorer sí que daba de alta con acentos y eñes sin despeinarse...

De este modo tendríamos:

Latin-1 o ISO-8859-1 (1)


dn: cn=Begoña Gómez García,ou=people,dc=dominio,dc=es
objectClass: top
objectClass: usuario
cn: Begoña Gómez García
uid: bgomezg
userName: bgomezg


UTF-8 (2)


dn: cn=Begoña Gómez García,ou=people,dc=dominio,dc=es
objectClass: top
objectClass: usuario
cn: Begoña Gómez García
uid: bgomezg
userName: bgomezg


Base64 (3)


dn:: Y249QmVnb8OxYSBHw7NtZXogR2FyY8OtYSxvdT1wZW9wbGUsZGM9ZG9taW5pbyxk
 Yz1lcw==
objectClass: top
objectClass: usuario
cn:: QmVnb8OxYSBHw7NtZXogR2FyY8OtYQ==
uid: bgomezg
userName: bgomezg


Algunas notas a este tipo de codificaciones.

Cuando en el punto (2) tenemos el DN (dn: cn=Begoña Gómez García,ou=people,dc=dominio,dc=es), es el conjunto de DN el que tenemos que poner en el archivo plaint.txt para codificarlo en Base64, que si nos fijamos en (3), se codifica la entrada al completo (incluyendo los OU y DC de la entrada, pero NO dn:), de modo que estamos codificando realmente el texto:

cn=Begoña Gómez García,ou=people,dc=dominio,dc=es

Otro dato más es que cuando codificamos dicho DN completo a Base64, el texto plano que nos queda en el coded.txt es un texto del tipo:

Y249QmVnb8OxYSBHw7NtZXogR2FyY8OtYSxvdT1wZW9wbGUsZGM9ZG9taW5pbyxk
Yz1lcw==


Es decir, en 2 líneas, y tal y como sabemos (o deberíamos de saber), cuando tenemos 2 líneas y queremos introducirlas en un archivo LDIF, se comienza la segunda línea con un sólo espacio en blanco y a continuación el texto correspondiente a la segunda línea, de modo que esto indica al LDIF, que la línea con un sólo espacio en blanco es continuación de la línea anterior.

De modo que quedaría del modo:

Y249QmVnb8OxYSBHw7NtZXogR2FyY8OtYSxvdT1wZW9wbGUsZGM9ZG9taW5pbyxk
 Yz1lcw==


Importante recordar que la codificación en Base64 debe ir con :: para indicar este tipo de codificación al archivo LDIF.

Asimismo en la entrada correspondiente al CN de (2) (es decir, la línea cn: Begoña Gómez García), codificaríamos sólo en texto correspondiente al nombre de la persona (Begoña Gómez García) si el cn:, y del mismo modo podríamos los :: para indicar que es una entrada en Base64.

Confío en que más de uno solucione sus problemas con la codificación en ISO-8859-1 (Latin-1) para LDAP con esta pequeña entrada ;o)

technoratiquetas | | | |