Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
ldap2sid.pl 13 KiB
Newer Older
vernada's avatar
vernada committed
#!/usr/bin/perl
#
use strict;
use warnings;

#
use Data::Dumper;
use Config::IniFiles;
use File::Basename;
use CGI qw/:standard/;
use Spreadsheet::WriteExcel;
use Getopt::Long;
use JSON;
use utf8;

# Remove non-breaking space char
binmode( STDOUT, ":utf8" );

use Net::LDAP;
use Cache::FileCache;

# unbuffered output:
$| = 1;

BEGIN {
    my $global_iniFile = new Config::IniFiles( -file => "/opt/etc/ini/global.ini" );
    push( @INC, $global_iniFile->val( 'APPLICATION', 'LIBRARY' ) );
}
use SNET::access;
use SNET::common;
use SNET::dumper;
use SNET::html;
use SNET::libdb;
use SNET::ActiveDirectory;

use vars qw($verbose $debug $help $env $script $force $cli_mode $stderr);
$debug   = 0;
$verbose = 0;
( $script ) = split( /\./, basename( $0 ) );
$stderr = 1;

my $title    = "LDAP Group User Check";
my $function = $title;
$function =~ s/\s/_/g;
my $href     = "";
my $header   = h1( a( { href => "/cgi-bin/nCheck/$script.pl" }, $title ) );
my $html_msg = "";

my $global_iniFile = new Config::IniFiles( -file => "/opt/etc/ini/global.ini" );

$env = "test";
( $html_msg ) = Access_snet_script_head( $script, $global_iniFile, $ENV, $env );

#
# Global Declarations
#
my $AiniFile = new Config::IniFiles( -file => $global_iniFile->val( 'INI', 'LDAP' ) );
$html_msg .= "error value of AiniFile is undefined" . "\n" if ( !defined( $AiniFile ) );
my $ldapserver = $AiniFile->val( 'LDAP_EC', 'SERVER' );
$html_msg .= "error value of ldapserver is undefined" . "\n" if ( !defined( $ldapserver ) );
my $basedn = $AiniFile->val( 'LDAP_EC', 'BASE' );
$html_msg .= "error value of basedn is undefined" . "\n" if ( !defined( $basedn ) );
my $ldapuser = $AiniFile->val( 'LDAP_EC', 'USER' );
$html_msg .= "error value of ldapuser is undefined" . "\n" if ( !defined( $ldapuser ) );
my $ldappasswd = $AiniFile->val( 'LDAP_EC', 'PASSWORD' );
$html_msg .= "error value of ldappasswd is undefined" . "\n" if ( !defined( $ldappasswd ) );

my $cfg_ldap_server = $AiniFile->val( 'LDAP_SNET_NG', 'SERVER' );
$html_msg .= "error value of cfg_ldap_server is undefined" . "\n" if ( !defined( $cfg_ldap_server ) );
my $cfg_ldap_user = $AiniFile->val( 'LDAP_SNET_NG', 'USER' );
$html_msg .= "error value of cfg_ldap_user is undefined" . "\n" if ( !defined( $cfg_ldap_user ) );
my $cfg_ldap_passwd = $AiniFile->val( 'LDAP_SNET_NG', 'PASSWORD' );
$html_msg .= "error value of cfg_ldap_passwd is undefined" . "\n" if ( !defined( $cfg_ldap_passwd ) );
my $cfg_ldap_group_search = $AiniFile->val( 'LDAP_SNET_NG', 'GRP_SEARCH' );
$html_msg .= "error value of cfg_ldap_group_search is undefined" . "\n" if ( !defined( $cfg_ldap_group_search ) );
my $cfg_ldap_group_search_filter = $AiniFile->val( 'LDAP_SNET_NG', 'FILTER_posix' );
$html_msg .= "error value of cfg_ldap_group_search_filter is undefined" . "\n" if ( !defined( $cfg_ldap_group_search_filter ) );
my $cfg_ldap_group_attribute = $AiniFile->val( 'LDAP_SNET_NG', 'GRP_ATTRIBUTE' );
$html_msg .= "error value of cfg_ldap_group_attribute is undefined" . "\n" if ( !defined( $cfg_ldap_group_attribute ) );
my $cfg_ldap_search_scope = $AiniFile->val( 'LDAP_SNET_NG', 'SEARCH_SCOPE' );
$html_msg .= "error value of cfg_ldap_search_scope is undefined" . "\n" if ( !defined( $cfg_ldap_search_scope ) );
my $cfg_ldap_cafile = $AiniFile->val( 'LDAP_SNET_NG', 'CA' );
$html_msg .= "error value of cfg_ldap_cafile is undefined" . "\n" if ( !defined( $cfg_ldap_cafile ) );

my $all_ldap_group = $AiniFile->val( 'LDAP_EC', 'SID_GROUP' );
$html_msg .= "error value of all_ldap_group is undefined" . "\n" if ( !defined( $all_ldap_group ) );

######

my $groups = ();
@$groups = split( ',', $all_ldap_group );

my $colnames = [ 'uid', 'cn', 'departmentNumber', 'physicalDeliveryOfficeName', 'building', 'dg', 'telephoneNumber' ];

# Get all the SNet member of NS.
my $snet_member = {};
my $off_member  = {};

my $group = '';

my $cache_report = new Cache::FileCache(
                                         {
                                           'namespace'           => 'nCheck_ldap_group_check',
                                           'cache_root'          => '/opt/resources_SNet/DGtools',
                                           'default_expires_in'  => '1h',
                                           'auto_purge_interval' => '1h'
                                         }
);

metaprint( 'info', "init_cache cache_report" ) if $verbose;

$force   = 0;
$force   = 1 if ( ( defined( param( 'force' ) ) ) && ( param( 'force' ) !~ /^$/ ) && ( param( 'force' ) =~ /^Reload$/ ) );
$verbose = 1 if ( ( defined( param( 'verbose' ) ) ) && ( param( 'verbose' ) !~ /^$/ ) && ( param( 'verbose' ) =~ /^[\d\w]+$/ ) && ( param( 'verbose' ) eq 'godmode1' ) );

my $res = $cache_report->get( 'snet_member' );
if ( ( !defined $res ) || $force ) {

    undef( $res );

    # do action
    my $ldap = Net::LDAP->new(
        $cfg_ldap_server,
        async   => 0,
        onerror => (
            ( $debug == 0 ) ? sub { return $_[0] } : sub {
                my $message = shift;
                my $error = defined( $message->error_desc ) ? $message->error_desc : $message->error();
                print STDERR 'Ldap: Unable to process request: ' . $error . "\n";
                return $message;
            }
        ),
    );

    if ( !$ldap ) {
        metaprint 'error', "Could not connect to LDAP: $cfg_ldap_server!";
        exit 1;
    }

    metaprint( 'info', "LDAP connection completed successfully." ) if $verbose;

    my $message;
    eval {
        print STDERR 'Starting tls' . "\n" if ( $debug );
        $message = $ldap->start_tls( verify => 'require',
                                     cafile => $cfg_ldap_cafile, );
        if ( $message->is_error() ) {
            metaprint( 'error', "Could not encrypt LDAP connection." );
            exit 1;
        }
    };
    if ( $@ ) {
        metaprint( 'error', "Crash - Could not encrypt LDAP connection." );
        exit 1;
    }

    eval {
        print STDERR 'binding' . "\n" if ( $debug );
        $message = $ldap->bind(
                                $cfg_ldap_user,
                                password => $cfg_ldap_passwd,
                                version  => 3,
        );
        if ( $message->is_error() ) {
            metaprint( 'error', "LDAP bind error occurred." );
            exit 1;
        }
    };
    if ( $@ ) {
        metaprint( 'error', "Crash - LDAP bind error occurred" );
        exit 1;
    }

    metaprint( 'info', "LDAP bind operation completed successfully." ) if $verbose;

    my $snetcol = [ 'memberUid', 'cn' ];
    $cfg_ldap_group_attribute = [ 'memberUid', 'cn' ];
    $group = '|(cn=com)(cn=ss)(cn=sd)(cn=pm)(cn=net)(cn=sec)(cn=tda)(cn=mgt)(cn=pi)(cn=bcp)';

    my %searchargs;
    my $cfg_ldap_group_search_f = $cfg_ldap_group_search_filter;
    $cfg_ldap_group_search_f =~ s/cn=REPLACE/$group/;

    $searchargs{base}   = $cfg_ldap_group_search;
    $searchargs{scope}  = $cfg_ldap_search_scope;
    $searchargs{filter} = $cfg_ldap_group_search_f;
    $searchargs{attrs}  = $cfg_ldap_group_attribute;

    metaprint( 'info', Dumper( \%searchargs ) ) if $verbose;

    my $results;
    eval {
        print STDERR 'searching' . "\n" if ( $debug );
        $results = $ldap->search( %searchargs );
        if ( $results->is_error() ) {
            metaprint( 'error', "LDAP search error occurred:" . $results->code . " : " . $results->error );
            exit 1;
        }
    };
    if ( $@ ) {
        metaprint( 'error', "Crash - LDAP Users Search." );
        exit 1;
    }

    my $count = $results->count;
    if ( $count >= 1 ) {
        foreach my $entry ( $results->entries ) {
            foreach my $key ( $entry->get_value( $snetcol->[0] ) ) {
                push( @{ $snet_member->{"$key"} }, $entry->get_value( $snetcol->[1] ) );
            }
        }
    } else {
        $html_msg .= "$group is an empty group.\n" . br;
    }
    AD_disconnect( $ldap );
    print Dumper ( $snet_member ) if ( $debug );

    $cache_report->set( 'snet_member', $snet_member );
} else {
    $snet_member = $res;
}

# print html_rendering (Dumper ( $snet_member ) );

######

my $fromcache = 1;
my $data      = [];

foreach my $group ( @{$groups} ) {

    my $gdata = $cache_report->get( $group );
    if ( ( !defined $gdata ) || $force ) {

        undef( $gdata );

        # do action
        my $ldap = AD_connect( $ldapserver, $ldapuser, $ldappasswd );

        my $searchquery = "(&(objectclass=*)(cudgroup=$group))";

        my $filter = "cudgroup=$group";

        my $results = $ldap->search( base => $basedn, filter => $filter, attrs => $colnames );
        my $count = $results->count;
        $html_msg .= "Total entries returned for $group: $count." . "\n" if $main::debug;

        if ( $count >= 1 ) {
            foreach my $entry ( $results->entries ) {
                my $tmp = ();
                push( @{$tmp}, $group );
                foreach my $cln ( @{$colnames} ) {
                    push( @{$tmp}, ( $entry->get_value( $cln ) ? $entry->get_value( $cln ) : '' ) );
                }
                push( @{$gdata}, $tmp );
            }
        } else {
            $html_msg .= "$group is an empty group." . br;
        }

        AD_disconnect( $ldap );

        $cache_report->set( $group, $gdata );
    }

    foreach my $dd ( @{$gdata} ) {
        push( @{$data}, $dd );
    }
}

# taking LDAP group 'DIGIT_NS_TEAM' as reference, for the official list members.

$group = 'DIGIT_NS_TEAM';
foreach my $member (
    grep { !/^$/ } map {
        if ( $_->[0] eq $group ) { $_->[1] }
    } map {
        $_
    } @$data
  ) {
    $off_member->{$member} = 1;
}

######

# print Dumper ( $data );
my $data_users  = ();
my $data_groups = ();

my $cln = ();
for ( my $i = 0 ; $i <= $#{$colnames} ; $i++ ) {
    $cln->{ $colnames->[$i] } = ( $i + 1 );
}
print Dumper ( $cln );

for my $group ( @{$groups} ) {
    print( "Group is $group\n" );
    $data_groups->{$group} = ();
    foreach my $d ( @$data ) {
        next if ( $d->[0] ne $group );

        # if ( $d->[1] eq 'alogin' ) {
        #    print Dumper( $d );
        # }
vernada's avatar
vernada committed

        #$VAR1 = [
        #          'DIGIT_UNIX',       group
        #          'gabrigr',          uid
        #          'GABRIEL Gregory',  cn
        #          'DIGIT.C.3.004',    departement
        #          'DRB- D1/007E'      physical delivry Office
        #        ];
        #        colnames:  'uid', 'cn', 'departmentNumber', 'physicalDeliveryOfficeName', 'building', 'dg', 'telephoneNumber'
        my $member = $d->[ $cln->{'uid'} ];
        if ( $group eq 'DIGIT_SNET' ) {

            # Could not be part of official and SNet at the same time
            next if ( defined( $off_member->{$member} ) && ( $off_member->{$member} ) );

            # Should be declared in Snet LDAP system.
            next if ( !defined( $snet_member->{$member} ) );

            foreach my $g ( @{ $snet_member->{$member} } ) {
                next if ( $g eq 'bcp' );
                push( @{ $data_groups->{ $group . '_' . uc( $g ) }{'contains'} }, $member );
                push( @{ $data_users->{$member}{'is_members_of'} },               $group . '_' . uc( $g ) );
            }
        } elsif ( $group eq 'DIGIT_SNET_PROX' ) {
            if ( ( $member !~ /^j/ ) && ( $member !~ /^x/ ) ) {

                # TODO open a ticket to request removal....
                next;
            }
        }
        push( @{ $data_groups->{$group}{'contains'} },      $member );
        push( @{ $data_users->{$member}{'is_members_of'} }, $group );
        $data_users->{$member}{'departement'}     = $d->[ $cln->{'departmentNumber'} ];
        $data_users->{$member}{'office'}          = $d->[ $cln->{'physicalDeliveryOfficeName'} ];
        $data_users->{$member}{'cn'}              = $d->[ $cln->{'cn'} ];
        $data_users->{$member}{'building'}        = $d->[ $cln->{'building'} ];
        $data_users->{$member}{'dg'}              = $d->[ $cln->{'dg'} ];
        $data_users->{$member}{'telephoneNumber'} = $d->[ $cln->{'telephoneNumber'} ];

        # cleaning stuff
        $data_users->{$member}{'building'} =~ s/\-$//;
        $data_users->{$member}{'office'} =~ s/^.+\s//;

        #  'office' => 'D2/058',$
        if ( $data_users->{$member}{'office'} =~ /\// ) {
            $data_users->{$member}{'nop'} = $data_users->{$member}{'office'};
            if ( $data_users->{$member}{'office'} =~ /^([A-Za-z])/ ) {
                $data_users->{$member}{'aisle'} = $1;
            }
            if ( $data_users->{$member}{'office'} =~ /^[A-Za-z]?(\d+)\// ) {
                $data_users->{$member}{'floor'} = $1;
                $data_users->{$member}{'floor'} =~ s/^0//;
            }
            $data_users->{$member}{'office'} =~ s/^.*\///;
        }
    }
}
print Dumper( $data_users );

my $json;
my $cert_data;
print Dumper ( $data_groups );
$json      = JSON->new->allow_nonref;
$cert_data = $json->pretty->canonical->encode( $data_groups );
open( OUTFILE, ">/tmp/groups.json" );
print OUTFILE $cert_data;
close( OUTFILE );

print Dumper ( $data_users );
$json      = JSON->new->allow_nonref;
$cert_data = $json->pretty->canonical->encode( $data_users );
open( OUTFILE, ">/tmp/users.json" );
print OUTFILE $cert_data;
close( OUTFILE );

exit 0;