Skip to content
Snippets Groups Projects
Commit e23136e5 authored by Martin Haase's avatar Martin Haase
Browse files

further merging

git-svn-id: https://textgridlab.org/svn/textgrid/trunk/middleware/tgauth@7749 7c539038-3410-0410-b1ec-0f2a7bf1c452
parent 2775522b
No related branches found
No related tags found
No related merge requests found
progname = "mapSIDtoPassPhrase"
version = 0.1
date = "2010-07-13"
<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 = "Provides lookup to PKCS\#12 passphrases based on a TextGrid SessionID"
<progdescription>
text01 = This Daemon has 3 Methods:
text02 = getCSR (sid)
text03 = - creates a new Certificate Signing Request together with a
text04 = - secret key which can be looked up via the Session ID (sid)
text05 = - the key will be held in memory
text06 = - returns the CSR
text07 = putCRT (sid, CRT)
text08 = - receives a signed certificate
text09 = - creates a PKCStext =12 key pair from the cert and the in-memory key
text10 = - encrypts the p12 with a random passphrase
text11 = - the random passphrase is held in memory, can be looked up via the sid
text12 = - the p12 is stored in LDAP under the users entry (found using the sid)
text13 = - returns true or false
text14 = getPassphrase (sid)
text15 = - returns the Passphrase to the p12 key pair using the sid.
</progdescription>
<bugs>
text = Please report bugs to martin.haase@daasi.de
</bugs>
<additions example>
text1 = "For getting this manpage: "
text2 = " mapSIDtoPassPhrase.pl -h"
</additions>
<additions requirements>
text1 = "Following modules are required: "
text2 = "*IO::Socket"
text3 = "*POSIX"
text4 = "*IPC::Shareable"
text5 = "*Math::Random"
text6 = "*Time::HiRes"
text7 = "*Data::Dump"
text8 = "*Net::LDAP"
text9 = "*Crypt::OpenSSL::PKCS10"
text10 = "*Crypt::OpenSSL::RSA"
text11 = "*Crypt::OpenSSL::X509"
text12 = "*Crypt::OpenSSL::PKCS12"
text13 = "*File::Temp"
</additions>
<options loglevel>
key = "l"
must = 0
description = "Loglevel for controlling logmessages."
# Possible values \
# are: no, all, debug, private, info, warn, error, fatal. Default: error."
arg = 1
argtype = "skalar"
values = "no, all, debug, info, warn, error, fatal"
default = "error"
</options>
<options logfile>
key = "L"
must = 0
description = "Name of the logfile with absolute or relative path. "
arg = 1
argtype = "filename_add_subdir_log"
default = "mapSIDtoPassPhrase.log"
</options>
<options debugmode>
key = "d"
must = 0
description = "sets debug mode to on"
arg = 0
</options>
<options verbose>
key = "v"
must = 0
description = "Sets verbose mode which makes the program quite chatty"
arg = 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 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/mapSIDtoPassPhrase.conf"
</options>
#!/usr/bin/perl -W
###################################################
# This Daemon has 3 Methods:
# getCSR (sid)
# - creates a new Certificate Signing Request together with a
# - secret key which can be looked up via the Session ID (sid)
# - the key will be held in memory
# - returns the CSR
# putCRT (sid, CRT)
# - receives a signed certificate
# - creates a PKCS#12 key pair from the cert and the in-memory key
# - encrypts the p12 with a random passphrase
# - the random passphrase is held in memory, can be looked up via the sid
# - the p12 is stored in LDAP under the user's entry (found using the sid)
# - returns true or false
# getPassphrase (sid)
# - returns the Passphrase to the p12 key pair using the sid.
#
# ... and possibly a credential negotiation function for CRUD to follow
#
# The daemon forks with each request and uses System V IPC to access
# the passphrase hash from each child process
#
# The socket is only accessible by RBAC (i.e. on the same machine)
# using proxy functions. RBAC speaks only HttpS and the separate RBAC function
# getPassphrase uses Client Auth from CRUD
#
# author Martin Haase / DAASI International GmbH / Project SLC-Gap
# inspired by gridshib-ca-demo-portal.cgi and the Perl Cookbook
#
# creation date: 2010-03-22
#
# 2010-03-23: rapid prototyping stubs for every function
# 2010-03-23: getCRT,
# 2010-03-24: putCRT,
# 2010-05-06: getPassphrase;
# 2010-05-19: debugged/fixed, ported to perl 5.10
# 2010-07-13: introduce configuration file using DAASIlib::CONF
# 2010-07-15: changed from INET to local UNIX socket
#
use IO::Socket;
use POSIX qw(:sys_wait_h);
use IPC::Shareable;
use Math::Random;
use Time::HiRes;
use warnings "all";
use Data::Dump qw(dump);
use Net::LDAP qw(LDAP_SUCCESS LDAP_TIMELIMIT_EXCEEDED LDAP_SIZELIMIT_EXCEEDED
LDAP_NO_SUCH_OBJECT LDAP_ALREADY_EXISTS );
# this one needs IO::Socket::SSL
use Crypt::OpenSSL::PKCS10 qw( :const );
use Crypt::OpenSSL::RSA;
use Crypt::OpenSSL::X509;
use Crypt::OpenSSL::PKCS12;
use File::Temp;
use DAASIlib::CONF qw (is_debug);
use DAASIlib::Data;
# these two need: IO::Prompt, Log::Log4perl, DBI, DAASIlib::Gettext, Config::General
my $data = new DAASIlib::Data;
my ($progname, $progpath, $etcdir, $sysconfig) = $data->getProgramFiles($0);
my $conf = new DAASIlib::CONF;
$conf->loadConfig($sysconfig, $progpath, $etcdir);
my %ldap_config;
foreach $k (keys %{$conf->{data}}) {
if ($k =~ /^ldap_conf_(\S+)/) {
$ldap_config{$1} = $conf->{data}{$k};
}
}
my $socketfile = $conf->{data}{socketfile};
my $RBACuser = $conf->{data}{rbacuser};
my $passphraselength = $conf->{data}{passphraselength};
# dead child process reaper
sub REAPER {
1 until (-1 == waitpid(-1, WNOHANG));
$SIG{CHLD} = \&REAPER;
}
$SIG{CHLD} = \&REAPER;
# child sigint definition
$SIG{INT} = sub { die "$$ dying...\n" };
# shared hash in-memory for passphrases
$handle = tie %passphrases, 'IPC::Shareable', undef, {destroy => 1};
random_set_seed_from_phrase(Time::HiRes::time);
unlink $socketfile;
$server = IO::Socket::UNIX->new(Local => $socketfile,
Type => SOCK_STREAM,
Reuse => 1,
Blocking => 1,
Listen => SOMAXCONN )
or die "Cannot be a UNIX Socket Server with file $socketfile: $@\n";
use vars qw($login $pass);
($login,$pass,$uid,$gid) = getpwnam($RBACuser) or die "$RBACuser not in passwd file";
chown $uid, $gid, $socketfile;
while (1) {
$client = $server->accept();
next unless defined( $client);
next if $pid = fork; # Parent macht weiter im while
die "fork: $!" unless defined $pid; # das kommt nicht vor
# ab hier kindprozess
close $server; # server nicht mehr gebraucht im Kindprozess
doJob ($client);
exit; # das Kind stirbt und macht keine neue accept-Prüfung
} continue {
close $client if defined( $client );; # im Elternprozess nicht mehr gebraucht
}
sub doJob {
print scalar ( localtime()) . " doing Job ...\n";
my $client = shift;
my $routine = <$client>;
chomp $routine;
print "Routine is $routine ...\n";
if ($routine eq "getCSR") {
my $sid = <$client>;
chomp $sid;
my ($csr, $key) = &getCSR();
$handle->shlock();
$passphrases{$sid} = $key; # store temporarily the RSA key here, will be replaced by a $passphraselength long pkcs12 passphrase when putCRT is called
$handle->shunlock();
print $client "getCSRresult\n";
print $client $csr;
} elsif ($routine eq "putCRT") {
my $sid = <$client>;
chomp $sid;
my $crt = "";
while ($next = <$client>) {
last if $next =~ />>>EOF<<</;
$crt .= $next;
}
$result = &putCRT ( $sid, $crt);
print $client "putCRTresult\n";
print $client $result;
} elsif ($routine eq "getPassphrase") {
my $sid = <$client>;
chomp $sid;
my $passphrase = &getPassphrase($sid);
print $client "getPassphraseresult\n";
print $client $passphrase;
} else {
die "Unknown command: $routine";
}
# print "returned $routine result to socket client\n...\n";
print $client "\n".'>>>EOF<<<'."\n";
# jetzt sagt der server nix mehr (s. exit im while)
}
########################################################
# specific functions
################
sub getCSR {
# print "getCSR doing something...\n";
# create dummy CSR with key
my $req = Crypt::OpenSSL::PKCS10->new();
# Use dummy DN, GridShib-CA will override with correct value
$req->set_subject("/C=US/O=Dummy/CN=Dummy");
$req->sign();
return ($req->get_pem_req(), $req->get_pem_pk());
}
sub putCRT {
# print "putCRT doing something...\n";
my ($sid, $crt) = @_;
my $key = $passphrases{$sid};
# check whether key and crt match
if ( !defined $key || !matchKeys($key,$crt)) { return "false";}
# create random passphrase for p12
my $randompassphrase = createRandomPhrase();
# create p12 from key and crt
my $p12 = buildP12 ($crt, $key, $randompassphrase);
# send p12 to LDAP, first looking up which user entry the $sid belongs to
my $transferToLDAPsuccess = sendPKCS12toLDAP ( $sid, $p12, $crt, \%ldap_config );
if (!$transferToLDAPsuccess) { return "false"; }
# finally, given all other operations succeeded,
# register passphrase now for daemon's lifetime, replacing the key
$handle->shlock();
$passphrases{$sid} = $randompassphrase;
$handle->shunlock();
return "true";
}
sub getPassphrase {
# print "getPassphrase doing something...\n";
my $sid = shift;
if (length $passphrases{$sid} > $passphraselength) {
die "Certificate for SID $sid not yet signed!";
}
return $passphrases{$sid};
}
#########################################################################
# helper subs
#############
sub createRandomPhrase {
$ps ="";
while(length ($ps) < $passphraselength ) {
$r = chr ( random_uniform_integer (1, 48, 122 ));
$ps .= $r if ($r =~ m/[a-zA-Z0-9]/);
}
return $ps;
}
sub matchKeys {
my ($key_string, $crt_string) = @_;
if (length ($key_string) <= $passphraselength) {
# is already passphrase set and no RSA key anymore
return 0;
}
my $key = Crypt::OpenSSL::RSA->new_private_key($key_string);
my $public_key_string = $key->get_public_key_string;
my $crt = Crypt::OpenSSL::X509->new_from_string ( $crt_string );
my $public_crt_string = $crt->pubkey();
return ( $public_key_string eq $public_crt_string);
}
sub buildP12 {
my ($crt, $key, $pass) = @_;
my ($fh, $filename) = File::Temp::tempfile(UNLINK => 0,
DIR => "/tmp");
# close $fh;
$p12obj = Crypt::OpenSSL::PKCS12->new();
$p12obj->create( $crt, $key, $pass, $filename );
open (P12, "<$filename");
read P12, $p12contents, 99999;
close P12;
unlink ( $filename );
return $p12contents;
}
sub sendPKCS12toLDAP {
my ($sid,$pkcs12,$crt_string,$rh_ldap_config) = @_;
my $gridX509subjectDn = Crypt::OpenSSL::X509->new_from_string ( $crt_string )->subject();
# make the Grid format: ", " -> "/"
$gridX509subjectDn =~ s(^)[/];
$gridX509subjectDn =~ s(, )[/]g;
my $ldap = ldapConnect($rh_ldap_config);
if (not defined $ldap) {
return 0;
}
### first search for the session entry
my $filter = "(rbacname=$sid)";
my $rbacbase = $rh_ldap_config->{basedn};
$rh_ldap_config->{basedn} = "ou=sessions," . $rbacbase;
my $mesg = ldapSearch($ldap, $filter, $rh_ldap_config);
my $entry;
my $eppn;
if ( $mesg) {
$entry = $mesg->pop_entry();
if (!defined ($entry)) {
### Kein Eintrag gefunden
return 0;
}
$eppn = $entry->get_value( 'rbacSessionUser' );
} else {
### Kein Eintrag gefunden
return 0;
}
### then search for the ePPN and put the p12 there
$filter = "(uid=$eppn)";
$rh_ldap_config->{basedn} = "ou=people," . $rbacbase;
$mesg = ldapSearch($ldap, $filter, $rh_ldap_config);
if ( $mesg) {
$entry = $mesg->pop_entry();
if (!defined ($entry)) {
### Kein Eintrag gefunden
return 0;
}
$entry->changetype( "modify" );
$entry->replace( "userpkcs12" => $pkcs12 );
if (! grep( /^gridCertificateUser$/, $entry->get_value('objectclass') ) ) {
$entry->add( "objectclass" => "gridCertificateUser" );
}
$entry->replace( "gridX509subject" => $gridX509subjectDn );
my $updatemesg = $entry->update($ldap);
if ( $updatemesg->code != Net::LDAP::LDAP_SUCCESS ) {
## Fehler;
return 0;
}
} else {
### Kein Eintrag gefunden
return 0;
}
return 1;
}
sub ldapConnect {
my ($rh_ldapdef) = @_;
my $uri = 'ldap://'.$rh_ldapdef->{'host'}.':'.$rh_ldapdef->{'port'};
my $ldap = Net::LDAP->new( $uri);
if ( !$ldap ) {
return(undef);
}
if ( $rh_ldapdef->{is_tls} ) {
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 ) {
# we can do without tls, the server is here.
# return undef;
}
}
my $mesg = $ldap->bind( $rh_ldapdef->{binddn},
password => $rh_ldapdef->{bindpw} );
unless ( $mesg->code == Net::LDAP::LDAP_SUCCESS ) {
return undef;
}
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,
);
if ( $mesg->code == Net::LDAP::LDAP_SUCCESS ) {
} else {
return undef;
}
return ($mesg);
}
......@@ -14,7 +14,7 @@ require_once( "../xacmlTypes.inc.php" );
// -----------------------------------------------------
// You'll need these services
// -----------------------------------------------------
$soapXACML = new SoapClient( "http://rbac.textgrid.daasi.de/wsdl/xacml.wsdl.local", Array( "trace" => 1 ) );
$soapXACML = new SoapClient( "../wsdl/xacml.wsdl", Array( "trace" => 1 ) );
echo "<BODY><HTML>";
......
<?php
// #######################################################
// Author: Markus Widmer
// Creation date: 18.07.2007
// Modification date: 18.07.2007
// Version: 0.1.0
// #######################################################
require_once( "../xacmlTypes.inc.php" );
// -----------------------------------------------------
// You'll need these services
// -----------------------------------------------------
$soapXACML = new SoapClient( "../wsdl/xacmlGrid.wsdl", Array( "trace" => 1 ) );
echo "<BODY><HTML>";
if( isset( $_POST['session'] ) ) {
// -----------------------------------------------------
// If this was successfull you can add a the user you
// wish to create
// -----------------------------------------------------
$regReq = new stdClass();
$regReq->Version = "2.0";
$regReq->ID = "abcde1234";
$regReq->ReturnContext = true;
$regReq->Request = new stdClass();
$regReq->Request->Subject = new stdClass();
$regReq->Request->Resource = new stdClass();
$regReq->Request->Action = new stdClass();
$regReq->Request->Environment = new stdClass();
$regReq->Request->Subject->Attribute = new stdClass();
$regReq->Request->Subject->Attribute->AttributeId = "urn:oasis:names:tc:xacml:1.0:subject:subject-id";
$regReq->Request->Subject->Attribute->DataType = "http://www.w3.org/2001/XMLSchema#string";
$regReq->Request->Subject->Attribute->AttributeValue = new stdClass();
$regReq->Request->Subject->Attribute->AttributeValue->any = $_POST['session'];
$regReq->Request->Resource->Attribute = new stdClass();
$regReq->Request->Resource->Attribute->AttributeId = "urn:oasis:names:tc:xacml:1.0:resource:resource-id";
$regReq->Request->Resource->Attribute->DataType = "http://www.w3.org/2001/XMLSchema#anyURI";
$regReq->Request->Resource->Attribute->AttributeValue = new stdClass();
$regReq->Request->Resource->Attribute->AttributeValue->any = $_POST['resource'];
$regReq->Request->Action->Attribute = new stdClass();
$regReq->Request->Action->Attribute->AttributeId = "urn:oasis:names:tc:xacml:1.0:action:action-id";
$regReq->Request->Action->Attribute->DataType = "http://www.w3.org/2001/XMLSchema#string";
$regReq->Request->Action->Attribute->AttributeValue = new stdClass();
$regReq->Request->Action->Attribute->AttributeValue->any = $_POST['operation'];
echo "<HR/>";
echo "checking access...<BR/>";
echo "Look at the code to see what happens!<BR/>";
try {
$caResponse = $soapXACML->checkXACMLaccess( $regReq );
echo "\n\n" . $soapXACML->__getLastRequest() . "<br><br>\n\n";
echo "\n\n" . $soapXACML->__getLastResponse() . "<br><br>\n\n";
if( preg_match( "/^permit$/i", $caResponse->Response->Result->Decision ) ) {
echo "<BR><HR><BR>Granted: YES.<BR><HR><BR>";
}
else {
echo "<BR><HR><BR>Granted: NO.<BR><HR><BR>";
}
}
catch( SoapFault $f ) {
echo "\n\n" . $soapXACML->__getLastRequest();
echo "\n\n" . $soapXACML->__getLastResponse() . "\n\n";
echo "SOAP FAULT!: " . $f->faultcode . " / " . $f->faultstring . " / " . $f->detail;
}
}
echo "<FORM action=\"xacmlGridCheckAccess.php\" method=\"post\" enctype=\"multipart/form-data\">\n";
echo "Subject-DN: <INPUT type=\"text\" name=\"session\" value=\"\"><BR>\n";
echo "Resource: <INPUT type=\"text\" name=\"resource\" value=\"\"><BR>\n";
echo "Operation: <INPUT type=\"text\" name=\"operation\" value=\"\"><BR>\n";
echo "<INPUT type=\"submit\" value=\"Commit...\">\n";
echo "</FORM>\n";
echo "</BODY></HTML>";
?>
......@@ -92,6 +92,21 @@ class getOwnerResponse {
}
class getUUIDRequest {
public $auth;
public $log;
public $resource;
}
class getUUIDResponse {
public $uuid;
}
class getMembersRequest {
public $auth;
......@@ -713,4 +728,21 @@ class checkXACMLaccessRequest {
public $request;
}
class getSLCRequest {
public $auth;
public $log;
public $secret;
}
class getSLCResponse {
public $slc;
}
?>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment