Como decodificar o texto base64 no arquivo xml no Linux?

1

Sou novo no linux (shell). Eu preciso decodificar o texto base64 no arquivo xml usando o shell script linux. Poderia, por favor, me ajudar a escrever um script de shell linux para decodificar os valores dessas tags onde o atributo é encoding="base64" a estrutura do meu arquivo é

    <directory-entries>
        <entry dn="ads">
        <attr name="memberof">
        <value>CN=VPN-employee</value>
        <value encoding="base64">aGVsbG8gd29ybGQ=   </value>
<value encoding="base64">
Q049RmxvcHB5IC0g0LTQvtGB0YLRg9C/INC30LDQutGA0YvRgixPVT1EZXZpY2UgQ29udHJv
bCxPVT1Hcm91cHMsT1U90JHQkNCd0JosREM9aHEsREM9YmM=
    </value>
    <value encoding="base64">
Q049VVNCLdC00LjRgdC60LggLSDRgtC+0LvRjNC60L4g0YfRgtC10L3QuNC1LE9VPURldmlj
ZSBDb250cm9sLE9VPUdyb3VwcyxPVT3QkdCQ0J3QmixEQz1ocSxEQz1iYw==
    </value>
    </attr>
    </entry>
    </directory-entries>

A saída desejada é

    <directory-entries>
        <entry dn="ads">
        <attr name="memberof">
        <value>CN=VPN-employee</value>
        <value encoding="base64">Hello world  </value>
       <value encoding="base64"> decoded         </value>
       <value encoding="base64">    decoded         </value>
    </attr>
    </entry>
    </directory-entries>

Estou gerando XML do Active Directory usando o ldapsearch. O script que usei para obter este arquivo é:

ldapsearch -h host -p 389 -D "CN=informatica,OU=Accounts for System Purposes,OU=System Accounts,DC=hq,DC=bc" -w password -s sub -B -E UTF-8 -X "(&(objectClass=organizationalPerson)(CN=*))" employeeID memberof > ldap_logins.xml

Não sei se é possível decodificar o texto ao gerar o arquivo xml. Obrigado antecipadamente!

    
por Meruyert 20.05.2015 / 07:28

3 respostas

1

Eu direi o que sempre faço. Por favor, NUNCA use expressões regulares para analisar XML. São más notícias. O XML tem várias formatações diferentes, o que significa que o XML semanticamente idêntico corresponderá ou não a determinadas expressões regulares. Coisas simples, como quebra automática de linha, tags unários, etc.

Isso significa que você cria um código frágil, que um dia pode ser misteriosamente interrompido devido a uma alteração válida e ascendente do fluxo de dados.

Para analisar seu XML, sugiro usar perl e o excelente XML::Twig módulo.

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;
use MIME::Base64;

#we take a "value" element, check it for an "encoding=base64" and if it is
#we rewrite the content and delete that attribute in the XML. 
sub decode_value {
    my ( $twig, $value ) = @_;
    if (    $value->att('encoding')
        and $value->att('encoding') eq "base64" )
    {
        my $decoded_text = decode_base64( $value->text );
        if ( $decoded_text =~ m/[^\s\d\w\=\-\,\.]/ ) {
            $decoded_text = "decoded";
        }
        $value->set_text($decoded_text);
        $value -> del_att('encoding');

    }
}


#twig handlers 'fires' a piece of code each time you hit a 'value' element. 
#it passes this piece of code that chunk of XML to handle, which means
#you can do things like dynamic XML rewrites 
#pretty print controls output XML rendering - there's a variety of options
#check the manpage. 
my $twig = XML::Twig->new(
    pretty_print  => "indented",
    twig_handlers => { 'value' => \&decode_value, }
);
$twig->parsefile('your_xml_file');
$twig->print;

Isso vai dar:

<directory-entries>
  <entry dn="ads">
    <attr name="memberof">
      <value>CN=VPN-employee</value>
      <value encoding="base64">hello world</value>
      <value encoding="base64">decoded</value>
      <value encoding="base64">decoded</value>
    </attr>
  </entry>
</directory-entries>

Você pode, alternativamente, transformar $decoded_text assim:

$decoded_text =~ s/[^\s\d\w=,-. ]+/_/g;

( URI::Escape module vale a pena dar uma olhada aqui também, já que 'porcentagem codifica' o estilo de URL de texto.)

O que daria em vez disso:

  <value encoding="base64">CN=Floppy - _ _,OU=Device Control,OU=Groups,OU=_,DC=hq,DC=bc</value>
  <value encoding="base64">CN=USB-_ - _ _,OU=Device Control,OU=Groups,OU=_,DC=hq,DC=bc</value>

Mas você também pode descobrir que usar Net::LDAP faz o que você precisa.

#!/usr/bin/perl
use strict;
use warnings;

use Net::LDAP;

my $ldap   = Net::LDAP->new('host');
my $result = $ldap->bind(
    'CN=informatica,OU=Accounts for System Purposes,OU=System Accounts,DC=hq,DC=bc',
    'password'
);
if ( $result->code ) { die "Error connecting to LDAP server"; }

my $ldap_search = $ldap->search(
    base   => 'DC=hq,DC=bc',
    scope  => 'subtree',
    filter => '(&(objectClass=organizationalPerson)(CN=*))',
    attrs  => [ 'employeeID', 'memberOf' ],
);

foreach my $entry ( $ldap_search->entries ) {
    print "dn:\t", $entry->dn(), "\n";
    foreach my $attr ( $entry->attributes ) {
        print "$attr:";
        foreach my $value ( $entry->get_value($attr) ) {
            next unless defined $value;
            if ( $value =~ m/[^\s\d\w,-=+@\'.()]/ ) { $value = "binary_data" }
            chomp($value);
            print "\t$value\n";
        }
    }
}
    
por 20.05.2015 / 15:27
1

Script Compacto

Supondo que o xml esteja em file.xml , faça:

sed -r 's/("base64">)([[:graph:]]+)/'"'grep -oP '"base64">\K[[:graph:]]+' file.xml | base64 -d'"'/g' file.xml 

Este é um regex compacto, que fará a tarefa. Deixe-me dividir e explicar.

Break Down

Primeiro eu seleciono a string base64 usando grep e decodifico:

grep -oP '"base64">\K[[:graph:]]+' file.xml | base64 -d

Eu poderia salvar isso em uma variável:

baseString='grep -oP '"base64">\K[[:graph:]]+' file.xml | base64 -d'

Em seguida, use sed para substituir o base64 pela string decodificada salva na variável:

sed -r 's/("base64">)([[:graph:]]+)/'"$baseString"'/g' file.xml
    
por 20.05.2015 / 11:52
0

Aqui está uma resposta apropriada usando xmlstarlet . Esta é uma ferramenta usada para análise e edição xml. Primeiro de tudo, instale este pacote no seu sistema. Se você está em um sistema baseado em Debian, faça:

sudo apt-get install xmlstarlet

Agora,

  1. primeiro lemos o valor da string codificada base64
  2. então nós decodificamos essa string
  3. então modificamos o valor da tag correspondente

Aqui está o script completo para isso:

#!/bin/bash

for i in $(seq 3)
do
    #Find the string and decoded it and save it in a variable
    decodedString='xmlstarlet sel -t -v "/directory-entries/entry/attr/value[@encoding='base64'][$i]" file.xml | tr -d \r\n[:space:] | base64 -d'

    #Now modify the xml document
    xmlstarlet ed -L -u "/directory-entries/entry/attr/value[@encoding='base64'][$i]" -v "$decodedString" file.xml
done

Eu fiz isso por um loop de 3. Você faz isso por qualquer número de elementos que você tenha.

    
por 22.05.2015 / 04:56