diff --git a/info.textgrid.middleware.tgauth.pdp2posix/00Readme.txt b/info.textgrid.middleware.tgauth.pdp2posix/00Readme.txt deleted file mode 100644 index 95ce22c9c4af4f52b2379800371df4d216cd6f2c..0000000000000000000000000000000000000000 --- a/info.textgrid.middleware.tgauth.pdp2posix/00Readme.txt +++ /dev/null @@ -1 +0,0 @@ -synchronizes Access Policy from openRBAC into POSIX ACL entries on a Grid Host. To be called by CRON with root access regularly. diff --git a/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.conf-dist b/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.conf-dist deleted file mode 100644 index 531b46ecf589bb3f4536e71d554d65a82b2219ab..0000000000000000000000000000000000000000 --- a/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.conf-dist +++ /dev/null @@ -1,15 +0,0 @@ -ldap_conf_host = ldap.example.org -ldap_conf_port = 389 -ldap_conf_binddn = "cn=manager,dc=example,dc=org" -ldap_conf_bindpw = secret -ldap_conf_is_tls = 1 -ldap_conf_tls_cafile = /path/to/cacert/directory/chain.pem -ldap_conf_tls_verify = require -ldap_conf_tls_cypher = AES256-SHA -ldap_conf_basedn = dc=example,dc=org -ldap_conf_scope = sub - -gridmapfilepath = /etc/grid-security/grid-mapfile -groupfilepath = /etc/group - -slcs_dn_prefix = /C=DE/O=DFN-Verein/OU=DFN-PKI/OU=SLCS/ diff --git a/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.sys b/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.sys deleted file mode 100644 index cb5fc251d3e5f705cccdfa1492eb0788bd8d20fb..0000000000000000000000000000000000000000 --- a/info.textgrid.middleware.tgauth.pdp2posix/etc/syncFromRBAC.sys +++ /dev/null @@ -1,118 +0,0 @@ -progname = "syncFromRBAC" - -version = 0.2 - -date = "2010-12-06" -<author> - name = "Martin Haase" - org= "DAASI International GmbH" - mail = "martin.haase@daasi.de" -</author> - -<copyright> -text1 = Copyright (c) 2010 DAASI International GmbH -text2 = This library is free software; you can redistribute it and/or \ -modify it under the same terms as Perl itself. -</copyright> - -progshortdescr = "Synchronize RBAC rules into POSIX ACLs" - -<progdescription> -text01 = Syncs an external PDP's policy into extendeded Access Control entries -text02 = in the resource's file system. The PDP for this proof-of-concept system -text03 = is an RBAC implementation (openRBAC), which is part of TextGrid's -text04 = TG-auth* infrastructure. -</progdescription> - -<bugs> -text = Please report bugs to martin.haase@daasi.de -</bugs> - -<additions example> -text1 = "For getting this manpage: " -text2 = " syncFromRBAC.pl -h" -</additions> - -<additions requirements> -text1 = "Following modules are required: " -text2 = Data::Dump -text3 = Net::LDAP -text4 = Set::Scalar -text5 = DAASIlib::CONF -text5 = DAASIlib::DATA -</additions> - -<options loglevel> - key = "l" - must = 0 - description = "Loglevel for controlling logmessages. Currently unused, use -d." - arg = 1 - argtype = "skalar" - values = "debug, info" - default = "info" -</options> - -<options logfile> - key = "f" - must = 0 - description = "Name of the logfile with absolute or relative path. " - arg = 1 - argtype = "filename_add_subdir_log" - default = "./log/syncFromRBAC.log" -</options> - -<options debugmode> - key = "d" - must = 0 - description = "sets debug mode to on" - arg = 0 - default = 0 -</options> - -<options write_to_system> - key = "w" - must = 0 - description = "does not make a dry run. Unless -w is specified, nothing is really written into the system" - arg = 0 - default = 0 -</options> - -<options printhelp> - key = "h" - must = 0 - description = "prints out the manpage" - arg = 0 -</options> - -<options helpfeature> - key = "H" - must = 0 - description = "prints out description of the feature referenced by \ - commandline flag or config file token. " - arg = 1 -</options> - -<options alternative_last_modify_timestamp> - key = "t" - must = 0 - description = "Instead of reading from a file (see option -m), use this option to specify a timestamp directly on the command line in the same format." - arg = 1 -</options> - -<options last_modifyTimestamp_path> - key = "m" - must = 0 - description = "File to read timestamp from when to start synchronizing. Format: YYYYMMDDhhmmssZ on first line of file. Needs to be Z time, aka GMT." - arg = 1 - argtype = "filename_exist_subdir_etc" - default = "./last_LDAP_sync_timestamp.txt" -</options> - -<options configfile> - key = "c" - must = 0 - description = Name of the user config file with absolute or relative path. - arg = 1 - argtype = "filename_exist_subdir_etc" - default = "./etc/syncFromRBAC.conf" -</options> diff --git a/info.textgrid.middleware.tgauth.pdp2posix/last_LDAP_sync_timestamp.txt b/info.textgrid.middleware.tgauth.pdp2posix/last_LDAP_sync_timestamp.txt deleted file mode 100644 index cd25fb315f66126de45158f88ac693af19d5a70b..0000000000000000000000000000000000000000 --- a/info.textgrid.middleware.tgauth.pdp2posix/last_LDAP_sync_timestamp.txt +++ /dev/null @@ -1 +0,0 @@ -20101231235959Z diff --git a/info.textgrid.middleware.tgauth.pdp2posix/syncFromRBAC b/info.textgrid.middleware.tgauth.pdp2posix/syncFromRBAC deleted file mode 100755 index 68b486689b1e08f0aba09068b7162f00767e05cc..0000000000000000000000000000000000000000 --- a/info.textgrid.middleware.tgauth.pdp2posix/syncFromRBAC +++ /dev/null @@ -1,459 +0,0 @@ -#!/usr/bin/perl -w -############################################ -# Syncs an external PDP's policy (here: the contents of the LDAP Database -# of a TextGrid TG-auth* openRBAC instance) into group and extendeded Access -# Control entries in the Grid resource's file system. -# -# Author: Martin Haase / DAASI International GmbH / Gap-SLC -# -### Detailed function: -# * Every role in a TextGrid project will be mapped to a system group entry. -# * Every performer of this role will be added as a member to this group. -# * A TextGrid project is mapped to a directory under <project creator's home>/.textgrid/ -# * A TextGrid object is mapped to a file in a project directory -# * Extended POSIX ACLs will be used to ensure each resource can be accessed by the right project members. -# -### Some remarks: - -### A user's account must exist in the system's grid-mapfile. You can -#use the companion gap-SLC script, Pseudo_dgridmap.perl, to accomplish -#this. - -### Currently only a subset of the accounts in the gri-mapfile is -#honored, i.e. only those which are issued by the Short-Lived -#Certificate Service (SLCS). Why? We need a mapping from the PDP. A -#user's identity in TG-auth* is by reference to his -#eduPersonPrincipalName, and the SLCS DNs contain exactly the -#ePPN. This way the mapping can be established. - -### Permissions for roles are still hard-wired, as they are in -#TG-auth* as well - -### we contact the LDAP database of TG-auth*/openRBAC -#directly. Re-implementors might wish to create dedicated accessor -#functions in the PDP they wish to contact. - -### see syncFromRBAC -h for the man page -# -# -# History: -# version 0.1 2010-07-13 first proof-of-concept -# version 0.2 2010-12-06 separated configuration and code, documentation -# version 0.2b 2010-12-23 error handling, configuration with DAASIlib, first check-in to SVN -# version 0.2c 2010-12-27 further documentation - -### imports =========================================== -use Data::Dump qw(dump); -use Net::LDAP qw(LDAP_SUCCESS LDAP_TIMELIMIT_EXCEEDED LDAP_SIZELIMIT_EXCEEDED LDAP_NO_SUCH_OBJECT LDAP_ALREADY_EXISTS ); -use Set::Scalar; - -use DAASIlib::CONF qw (is_debug); -use DAASIlib::Data; -# these two need: IO::Prompt, Log::Log4perl, DBI, DAASIlib::Gettext, Config::General - - -### configuration management =========================== -my $data = new DAASIlib::Data; -my ($progname, $progpath, $etcdir, $sysconfig) = $data->getProgramFiles($0); - -my $conf = new DAASIlib::CONF; -$conf->loadConfig($sysconfig, $progpath, $etcdir); - - - -# GLOBAL CONSTANTS ====================================== -$DEBUG = 0; -$DRY_RUN = 1; -if (defined $conf->{data}->{debugmode} && $conf->{data}->{debugmode}) { $DEBUG = 1 } -if (defined $conf->{data}->{write_to_system} && $conf->{data}->{write_to_system}) { $DRY_RUN = 0 } - -$gridmapfilepath = $conf->{data}->{gridmapfilepath}; -$groupfilepath = $conf->{data}->{groupfilepath}; -$logfilepath = $conf->{data}->{logfile}; - -$last_modifyTimestamp_path = $conf->{data}->{last_modifyTimestamp_path}; -$alternative_last_modify_timestamp = $conf->{data}->{alternative_last_modify_timestamp}; - -# these roles are currently hard-wired in TG-auth* -@standardroles = ( - {rolename => "Projektleiter", projectperms => "", resourceperms => ""}, - {rolename => "Administrator", projectperms => "wx", resourceperms => ""}, - {rolename => "Bearbeiter", projectperms => "rwx", resourceperms => "rw"}, - {rolename => "Beobachter", projectperms => "rx", resourceperms => "r"}, - ); - -my %ldap_config; -foreach $k (keys %{$conf->{data}}) { - if ($k =~ /^ldap_conf_(\S+)/) { - $ldap_config{$1} = $conf->{data}{$k}; - } -} -$ldap_config{attribs} = ['*', 'modifyTimestamp']; - -if (defined $alternative_last_modify_timestamp ) { - $last_modifyTimestamp = $alternative_last_modify_timestamp; -} else { - open LMTS, $last_modifyTimestamp_path; - $last_modifyTimestamp = <LMTS>; - chomp $last_modifyTimestamp; - close LMTS; -} - -open LOG, ">>$logfilepath"; # used by logg(); - -if ($last_modifyTimestamp !~/^\d{4}[01]\d[0123]\d[012]\d[0-5]\d[0-5]\dZ$/) { - logg ("invalid timestamp ($last_modifyTimestamp) specified, should be YYYYMMDDhhmmssZ."); - exit 0; -} -logg ("Start synchronizing LDAP from timestamp ($last_modifyTimestamp)"); - - -############## MAIN =========================================== - -# user must exist in grid-mapfile, and we only take those DNs into account that are issued by DFN's SLCS -$userhash = parse_gridmap ( $gridmapfilepath, $conf->{data}->{slcs_dn_prefix}); -$grouphash = parse_groupfile ($groupfilepath); - -debugg( dump $userhash); -debugg ( "Log file is $logfilepath"); - - -# query BEFORE ldapsearch, to ldap write operations in this second are accounted for -# doesnt matter if one entry gets processed twice -$now_timestamp = construct_timestamp (gmtime()); - -$result = getNewEntriesFromLDAP ( $last_modifyTimestamp, \%ldap_config); - -foreach $e ($result->entries) { - - if (is_role($e)) { - logg ("found role, ". $e->dn()); - handle_role($e); - } elsif (is_resource($e)) { - logg ("found resource, ". $e->get_value("TGResourceURI")); - handle_resource($e); - } else { - # do nothing - } -} - - -if (not $DRY_RUN) { - logg ("write system timestamp of last ldapsearch ($now_timestamp) to file for next run"); - open LMTS, ">$last_modifyTimestamp_path"; - print LMTS $now_timestamp; - close LMTS; -} else { - logg ("This has been a DRY RUN, did NOT alter anything on the system nor write timestamp of last ldapsearch ($now_timestamp) to file. After verifying from the logs that everything is correct, you can force this with -w."); -} - -close LOG; -exit 0; - -# FUNCTIONS ====================================== - -# this function handles ordinary TextGridObjects. As CRUD has written -# them already, including the project directory they live in, no mkdir -# has to be issued. -sub handle_resource { - my $e = shift; - my ($tgpr, $dir, $uuid) = parse_uuid ($e->get_value("TGResourceUUID")); - - - logg ("Now setting ACLs of $dir and ./$uuid such that the right ones can access them."); - - if (not exists $grouphash->{$tgpr."_Projektleiter"}) { - logg ( "WARNING: It seems that project $tgpr has not been created although you try to add resources! I will create it for you now..."); - create_project ($tgpr); - } - - sssys ("chgrp ${tgpr}_Projektleiter $dir $dir/$uuid $dir/${uuid}.meta"); - sssys ("setfacl -m m::rwx $dir; setfacl -m m::rw $dir/$uuid $dir/${uuid}.meta"); - sssys ("chmod 700 $dir; chmod 600 $dir/$uuid $dir/${uuid}.meta"); - - # TODO: query actual permissions instead of using the standard roles. However, this has no use as long as there is no Lab frontend for it... - foreach $r (@standardroles) { - - if ($r->{projectperms}) { - sssys ( "setfacl -m g:${tgpr}_".$r->{rolename}.":".$r->{projectperms} ." $dir"); - } - if ($r->{resourceperms}) { - sssys ( "setfacl -m g:${tgpr}_".$r->{rolename}.":".$r->{resourceperms} ." $dir/$uuid $dir/${uuid}.meta"); - } - } -} - -sub parse_uuid { - my $u = shift; - # format: - # gsiftp://ingrid.sub.uni-goettingen.de//home/ttest/.textgrid/TGPR29/a084e9c0-e7d4-3802-b16d-37a223414c82 - if ($u =~ /gsiftp:\/\/ingrid.sub.uni-goettingen.de\/(\/home\/[^\/]+\/.textgrid)\/([^\/]+)\/(\S+)/) { - return ($2, "$1/$2", $3); # i.e. TGPR29, /home/ttest/.textgrid/TGPR29, a084e9c0-e7d4-3802-b16d-37a223414c82 - } else { - return (0,0,0) - } -} - -# this functions handles any change in a project role entry, either -# the project itself (it is a role as well in TG-auth*) or sub-roles. -# takes existing group entries into account and only makes a diff - -sub handle_role { - my $e = shift; - my ($tgpr, $role) = parse_role_dn ($e->dn()); - return if not $tgpr; - if (not $role) { - create_project($tgpr); - return; - } - my @eppnperformers = $e->get_value("rbacPerformer"); - my @uidperformers = (); - foreach $eppn (@eppnperformers) { - if (exists $userhash->{$eppn} ) { - push @uidperformers, $userhash->{$eppn}; - } else { - logg ("Warning: User $eppn not yet in Gridmap File"); - } - } - my $newperformers = new Set::Scalar(@uidperformers); - - if (not exists $grouphash->{$tgpr."_".$role}) { - logg ( "WARNING: It seems that project $tgpr has not been created although you try to add members to its $role role! I will create it for you now..."); - create_project ($tgpr); - } - my $oldperformers = $grouphash->{$tgpr."_".$role}; - debugg ("Old members in $tgpr: ". join ",", $oldperformers->members); - - foreach $out ($oldperformers->difference($newperformers)->members) { - logg ("Throwing out $out of $role in $tgpr"); - sssys ("/usr/sbin/groupmod -R $out ${tgpr}_".$role); - } - foreach $in ($newperformers->difference($oldperformers)->members) { - logg ("Adding $in to $role in $tgpr"); - sssys ("/usr/sbin/groupmod -A $in ${tgpr}_".$role); - } - $grouphash->{$tgpr."_".$role} = $newperformers; -} - - -sub create_project { - $p = shift; - logg ("Creating role groups in $p IF they didnt exist before..."); - foreach $r (@standardroles) { - if (not exists $grouphash->{$p."_".$r->{rolename}}) { - sssys("/usr/sbin/groupadd ${p}_".$r->{rolename}); - $grouphash->{$p."_".$r->{rolename}} = new Set::Scalar(()); - } - } -} - -sub parse_role_dn { - my $dn = shift; - # format: - # rbacName=Bearbeiter,rbacName=TGPR29,rbacName=Projekt-Teilnehmer,ou=roles,dc=rbac,dc=textgrid,dc=de - if ($dn =~ m/rbacName=([^,]+),rbacName=([^,]+),rbacName=Projekt-Teilnehmer,ou=roles,dc=rbac,dc=textgrid,dc=de/) { - return ($2, $1); - } elsif ($dn =~ m/rbacName=([^,]+),rbacName=Projekt-Teilnehmer,ou=roles,dc=rbac,dc=textgrid,dc=de/) { - return ($1,0); - } else { - return (0,0); - } -} - -sub is_role { - my $e = shift; - my @oc = $e->get_value("objectClass"); - return in_array("rbacRole",@oc); -} - -sub is_resource { - my $e = shift; - my @oc = $e->get_value("objectClass"); - return in_array("TextGridResource",@oc) -} - -sub in_array { - my $x = shift; - foreach $e (@_) { - return 1 if ($x eq $e); - } - return 0; -} - -sub logg { - if ($DRY_RUN) { - print "\n".scalar localtime(). " LOG: "; - print shift; - print "\n"; - } else { - print LOG "\n".scalar localtime(). " LOG: "; - print LOG shift; - print LOG "\n"; - } -} - -sub debugg { - return unless $DEBUG; - print "\n".scalar localtime(). " DEBUG: "; - print shift; - print "\n"; -} - -sub errorExit { - my $msg = shift; - logg ($msg); - exit 0; -} - -sub sssys { - my $cmd = shift; - if ($DRY_RUN) { - print "\nSYSTEM CALL: >>>"; - print $cmd; - print "<<<\n"; - } else { - logg ($cmd); - system ($cmd); - } -} - -sub parse_gridmap { - my ($path, $only) = @_; - - my %h = (); - open F, $path; - while (<F>) { - # Format: - # "/C=DE/O=DFN-Verein/OU=DFN-PKI/OU=SLCS/OU=DAASI International GmbH/CN=Tanja Test - tanja.test@idp01.nds.daasi.de" ttest - if (m/$only/) { - m/ - (\S+)\" (\S+)/; - $h{$1} = $2; # eppn => uid - } - } - close F; - return \%h; -} - -sub parse_groupfile { - my ($path) = shift; - - my %h = (); - open F, $path; - while (<F>) { - # TGPR29_Bearbeiter:!:1008:aausprobier,bbenutzer - if (/(TGPR[^:]+):[^:]+:\d+:(.*)/) { - debugg ("found group $1, with members $2"); - $h{$1} = new Set::Scalar(split ",", $2); - } - } - close F; - return \%h; -} - -sub getNewEntriesFromLDAP { - my ($since, $rh_ldap_config) = @_; - - my $ldap = ldapConnect($rh_ldap_config); - - my $filter = "(modifyTimestamp>=$since)"; - - my $mesg = ldapSearch($ldap, $filter, $rh_ldap_config); - # ingrid:~ # ldapsearch -x -H ldap://:5389 -b dc=rbac,dc=textgrid,dc=de -D cn=manager,dc=rbac,dc=textgrid,dc=de -w XhNtmqigeXz61pI9jfwmLyqUOTeJ "*" "+" | less - - foreach $entry ($mesg->entries) { -# $entry->dump; - debugg (dump $entry); - } - - logg "Found ". $mesg->count() . " new entries since last call."; - - return $mesg; -} - -sub ldapConnect { - my ($rh_ldapdef) = @_; - - my $uri = 'ldap://'.$rh_ldapdef->{host}.':'.$rh_ldapdef->{port}; - - my $ldap = Net::LDAP->new( $uri); - - - if ( !$ldap ) { - logg ("ERROR while creating connection to ldap server ". - "$$rh_ldapdef{host}:$$rh_ldapdef{port}"); - errorExit ( " ERROR while creating connection to ldap server ". - "$$rh_ldapdef{host}:$$rh_ldapdef{port} \n"); - return(undef); - } - - if ( $rh_ldapdef->{is_tls} ) { - debugg("starting TLS "); - debugg("verify: $rh_ldapdef->{tls_verify}, cafile: $rh_ldapdef->{tls_cafile} cypher: $rh_ldapdef->{tls_cypher}"); - my $tlsmesg = $ldap->start_tls ( verify => $rh_ldapdef->{tls_verify}, - cafile => $rh_ldapdef->{tls_cafile}, - ciphers => $rh_ldapdef->{tls_cypher}); - - if ( $tlsmesg->code != Net::LDAP::LDAP_SUCCESS ) { - logg ( "ERROR in ldap->start_tls: " . $tlsmesg->error ); - errorExit( "ERROR in ldap->start_tls: " . $tlsmesg->error) ; - } - else { - debugg ( "Start_TLS operation succeeded"); - debugg ( "tls cipher: " . $ldap->cipher . "\n" ); - debugg ( "tls certificate: " . $ldap->certificate . "\n" ); - } - } - - my $mesg = $ldap->bind( $rh_ldapdef->{binddn}, - password => $rh_ldapdef->{bindpw} ); - - unless ( $mesg->code == Net::LDAP::LDAP_SUCCESS ) { - logg ("Returning undef instead of ldap connection"); - $ldap = undef; - errorExit( "Error in LDAP-Bind: ".$mesg->error); - } - - return $ldap; -} - - - -sub ldapSearch { - my ( $ldap, $filter, $rh_ldapdef ) = @_; - - if ( ! $$rh_ldapdef{filter}) { - $$rh_ldapdef{filter}="(objectclass=*)"; - } - - my $mesg = $ldap->search( - base => $$rh_ldapdef{basedn}, - scope => $$rh_ldapdef{scope}, - filter => $filter, - attrs => $$rh_ldapdef{attribs}, -# deref => $$rh_ldapdef{deref}, -# sizelimit => $$rh_ldapdef{sizelimit}, -# timelimit => $$rh_ldapdef{timelimit}, -# typesonly => $$rh_ldapdef{is_typesonly}, -# callback => $$rh_ldapdef{callback}, - ); - - if ( $mesg->code == Net::LDAP::LDAP_SUCCESS ) { - debugg("search performed without error" ); - } else { - errorExit ( "Error in search: ". $mesg->error); - } - - return ($mesg); -} - -### takes time as from localtime() -### returns ldap timstamp as in attribute modifyTimestamp -sub construct_timestamp { - my ($nsec,$nmin,$nhours,$nmday,$nmon,$nyear) = @_; - my $ntime = sprintf("%04d%02d%02d%02d%02d%02dZ", - ($nyear+1900),($nmon+1), - $nmday,$nhours,$nmin,$nsec); - return $ntime; -} - -