如何在Linux中解码xml文件中的base64文本?

如何在Linux中解码xml文件中的base64文本?

我是linux(shell)新手。我需要使用 Linux shell 脚本解码 xml 文件中的 base64 文本。你能帮我编写linux shell脚本来解码那些属性为encoding =“base64”的标签的值,我的文件结构是

    <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>

想要的输出是

    <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>

我正在使用 ldapsearch 从 Active Directory 生成 XML。我用来获取该文件的脚本是:

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

我不知道是否可以在生成 xml 文件时解码文本。先感谢您!

答案1

我就说说我平时做的事吧。请切勿使用正则表达式来解析 XML。这是个坏消息。 XML 具有多种格式,这意味着语义相同的 XML 将匹配或不匹配某些正则表达式。简单的事情,比如换行、一元标签等。

这意味着您创建了脆弱的代码,有一天可能会因为上游数据流的完全有效的更改而神秘地崩溃。

用于解析你的XML 我建议使用perl并且相当优秀XML::Twig模块。

#!/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;

这将给出:

<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>

您也可以$decoded_text像这样进行转换:

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

URI::Escape这里的模块也值得一看,因为它“百分比编码”文本 URL 样式。)

这会给出:

  <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>

但您可能还会发现 usingNet::LDAP可以满足您的需要。

#!/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";
        }
    }
}

答案2

紧凑的脚本

假设 xml 位于 中file.xml,只需执行以下操作:

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

这是一个紧凑的正则表达式,可以完成任务。让我分解并解释一下。

分解

首先,我使用 grep 选择 Base64 字符串并对其进行解码:

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

我可以将其保存在变量中:

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

然后使用sed保存在变量中的解码字符串替换 base64:

sed -r 's/("base64">)([[:graph:]]+)/\1'"$baseString"'/g' file.xml

答案3

这是使用 的正确答案xmlstarlet。这是一个用于xml解析和编辑的工具。首先,在您的系统上安装此软件包。如果您使用的是基于 Debian 的系统,请执行以下操作:

sudo apt-get install xmlstarlet

现在,

  1. 首先我们读取base64编码字符串的值
  2. 然后我们解码这个字符串
  3. 然后我们修改对应的标签值

这是完整的脚本:

#!/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

我已经对 3 个循环进行了此操作。您可以对任何数量的元素执行此操作。

答案4

使用xq来自https://kislyuk.github.io/yq/:

xq -x '( .. | select(type == "object" and ."@encoding" == "base64")."#text" )
    |= ( gsub("\n"; "") | @base64d )' file.xml

这会递归地遍历整个文档并找到具有encoding值为 的属性的任何节点base64。对于每个这样的节点,它获取节点的值,删除所有换行符(使用gsub()),并使用运算符对 base64 字符串进行解码@base64d。解码后的值替换原始的 Base64 数据。

给定问题中的文档,输出将是

<directory-entries>
  <entry dn="ads">
    <attr name="memberof">
      <value>CN=VPN-employee</value>
      <value encoding="base64">hello world</value>
      <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>
    </attr>
  </entry>
</directory-entries>

xq工具还有一个选项-i--in-place来进行“就地”编辑。

相关内容