added data serialization, encryption, and ip subnet checking to spectre

This commit is contained in:
JT Smith 2006-02-08 20:18:00 +00:00
parent 6595290272
commit 75ecd4d7f4
9 changed files with 139 additions and 6 deletions

View file

@ -35,6 +35,8 @@ save you many hours of grief.
POE POE
POE::Component::IKC::Server POE::Component::IKC::Server
POE::Component::Client::UserAgent POE::Component::Client::UserAgent
Crypt::Blowfish
Net::Subnets
* The upgrade script is going to convert your WebGUI config files * The upgrade script is going to convert your WebGUI config files
from the current PlainConfig format to the new JSON format. from the current PlainConfig format to the new JSON format.

View file

@ -320,7 +320,19 @@
# the LDAP server. Note that this will only happen for users # the LDAP server. Note that this will only happen for users
# that have LDAP as their authentication. # that have LDAP as their authentication.
"SyncProfilesToLDAP_hour" : 2 "SyncProfilesToLDAP_hour" : 2,
# Define the subnets that WebGUI should expect Spectre communication
# to come from. All other subnets will be ignored. The subnet
# should be listed in CIDR notation.
"spectreSubnets" : [ "127.0.0.1/32" ],
# Define the key that will be used to encrypt communcation
# between Spectre and WebGUI. Note that this must match the
# cryptoKey in the Spectre config file.
"spectreCryptoKey" : "123qwe"
} }

View file

@ -2,6 +2,12 @@
{ {
# Define a key that will be used between Spectre and WebGUI to encrypt
# communication. Note that this key must match the "spectreCryptoKey"
# directive in your WebGUI config files.
"cryptoKey" : "123qwe",
# Define a port for Spectre to run on between 1024 and 65000. # Define a port for Spectre to run on between 1024 and 65000.
"port" : 32133, "port" : 32133,

View file

@ -48,7 +48,7 @@ Gracefully shuts down the admin interface.
sub _stop { sub _stop {
my ($kernel, $self) = @_[KERNEL, OBJECT]; my ($kernel, $self) = @_[KERNEL, OBJECT];
print "Stopping WebGUI Admin..."; print "Stopping Spectre...";
undef $self; undef $self;
$kernel->stop; $kernel->stop;
print "OK\n"; print "OK\n";

View file

@ -210,7 +210,17 @@ sub runWorker {
my $url = $job->{sitename}.'/'.$job->{gateway}; my $url = $job->{sitename}.'/'.$job->{gateway};
$url =~ s/\/\//\//g; $url =~ s/\/\//\//g;
$url = "http://".$url."?op=spectre;instanceId=".$job->{instanceId}; $url = "http://".$url."?op=spectre;instanceId=".$job->{instanceId};
$kernel->post( useragent => 'request', { request => HTTP::Request->new(GET => $url), response => $session->postback('workerResponse') }); my $payload = {
'do'=>'runWorkflow',
instanceId=>$job->{instanceId},
};
my $cipher = Crypt::Blowfish->new($self->{_config}->get("cryptoKey"));
my $request = HTTP::Request->new(POST => $url, Content => { op=>"spectre", payload=>$cipher->encrypt(objToJson($payload)) });
my $cookie = $self->{_cookies}{$job->{sitename}};
$request->header("Cookie","wgSession=".$cookie) if (defined $cookie);
$request->header("User-Agent","Spectre");
$request->header("X-JobId",$job->{instanceId});
$kernel->post( useragent => 'request', { request => $request, response => $session->postback('workerResponse') });
} }
#------------------------------------------------------------------- #-------------------------------------------------------------------
@ -247,9 +257,16 @@ This method is called when the response from the runWorker() method is received.
sub workerResponse { sub workerResponse {
my $self = $_[OBJECT]; my $self = $_[OBJECT];
my ($request, $response, $entry) = @{$_[ARG1]}; my ($request, $response, $entry) = @{$_[ARG1]};
my $jobId = ""; # got to figure out how to get this from the request, cuz the response may die my $jobId = $request->header("X-JobId"); # got to figure out how to get this from the request, cuz the response may die
if ($response->is_success) { if ($response->is_success) {
my $state = ""; # get the response if ($response->header("Cookie") ne "") {
my $cookie = $response->header("Set-Cookie");
$cookie =~ s/wgSession=([a-zA-Z0-9\_\-]{22})/$1/;
$self->{_cookies}{$self->{_jobs}{$jobId}{sitename}} = $cookie;
}
my $cipher = Crypt::Blowfish->new($self->{_config}->get("cryptoKey"));
my $payload = jsonToObj($cipher->decrypt($response->content));
my $state = $payload->{state};
if ($state eq "continue") { if ($state eq "continue") {
$self->suspendJob($jobId); $self->suspendJob($jobId);
} elsif ($state eq "done") { } elsif ($state eq "done") {

View file

@ -77,6 +77,7 @@ Returns a hash reference containing operation and package names.
sub getOperations { sub getOperations {
return { return {
'spectre' => 'WebGUI::Operation::Spectre',
'adminConsole' => 'WebGUI::Operation::Admin', 'adminConsole' => 'WebGUI::Operation::Admin',
'switchOffAdmin' => 'WebGUI::Operation::Admin', 'switchOffAdmin' => 'WebGUI::Operation::Admin',
'switchOnAdmin' => 'WebGUI::Operation::Admin', 'switchOnAdmin' => 'WebGUI::Operation::Admin',

View file

@ -0,0 +1,49 @@
package WebGUI::Operation::Spectre;
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2006 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use strict;
use Crypt::Blowfish;
use JSON;
=head1 NAME
Package WebGUI::Operation::Spectre
=head1 DESCRIPTION
Operation handler for Spectre functions.
=cut
#-------------------------------------------------------------------
=head2 www_spectre ( )
Checks to ensure the requestor is who we think it is, and then executes a spectre function, and returns a data packet.
=cut
sub www_spectre {
my $session = shift;
return $session->privilege->insufficient unless(isInSubnet($session->env->get("REMOTE_ADDR"), $session->config->get("spectreSubnets"));
my $cipher = Crypt::Blowfish->new($session->config->get("spectreCryptoKey"));
my $payload = jsonToObj($cipher->decrypt($session->form->get("payload")));
my $out = {};
if ($payload->{do} eq "runWorkflow") {
# do workflow stuff
}
return $cipher->encrypt(objToJson($out));
}
1;

View file

@ -19,9 +19,10 @@ package WebGUI::Utility;
use Exporter; use Exporter;
use strict; use strict;
use Tie::IxHash; use Tie::IxHash;
use Net::Subnets;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw(&isBetween &makeTabSafe &makeArrayTabSafe &randomizeHash &commify &randomizeArray our @EXPORT = qw(&isBetween &makeTabSafe &makeArrayTabSafe &randomizeHash &commify &randomizeArray &isInSubnet
&formatBytes &sortHashDescending &sortHash &isIn &makeCommaSafe &makeArrayCommaSafe &randint &round &formatBytes &sortHashDescending &sortHash &isIn &makeCommaSafe &makeArrayCommaSafe &randint &round
); );
@ -40,6 +41,7 @@ This package provides miscellaneous but useful utilities to the WebGUI programme
$string = commify($integer); $string = commify($integer);
$size = formatBytes($integer); $size = formatBytes($integer);
$boolean = isIn($value, @array); $boolean = isIn($value, @array);
$boolean = isInSubnet($ip, \@subnets);
makeArrayCommaSafe(\@array); makeArrayCommaSafe(\@array);
makeArrayTabSafe(\@array); makeArrayTabSafe(\@array);
$string = makeCommaSafe($string); $string = makeCommaSafe($string);
@ -155,6 +157,48 @@ sub isIn {
return 0; return 0;
} }
#-------------------------------------------------------------------
=head2 isInSubnet ( ipAddress, subnets )
Verifies whether an IP address is in a given subnet. Returns a 1 if it is, undef if there's a formatting error, or 0 if the IP is not in the list of subnets.
=head3 ipAddress
A scalar containing an IP address.
=head3 subnets
An array reference containing subnets in CIDR format. Example: 127.0.0.1/32
=cut
sub isInSubnet {
my $ip = shift;
my $subnets = shift;
# some validation
for my $cidr ( @{ $subnets } ) {
my @parts = $cidr =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/;
unless ( 5 == @parts ) { # cidr has 5 parts
return undef;
}
unless ( 4 == grep { $_ <= 255 } @parts[0..3] ) { # each octet needs to be between 0 and 255
return undef;
}
unless ( $parts[4] <= 32 ) { # the subnet needs to be less than or equal to 32, as 32 represents only 1 ip address
return undef;
}
}
my $net = Net::Subnets->new;
$net->subnets($subnets);
if ($net->check($ip)) {
return 1;
} else {
return 0;
}
}
#------------------------------------------------------------------- #-------------------------------------------------------------------
=head2 makeArrayCommaSafe ( array ) =head2 makeArrayCommaSafe ( array )

View file

@ -78,6 +78,8 @@ checkModule("Template",2.14,2);
checkModule("Parse::PlainConfig",1.1); checkModule("Parse::PlainConfig",1.1);
checkModule("XML::RSSLite",0.11); checkModule("XML::RSSLite",0.11);
checkModule("JSON",0.991); checkModule("JSON",0.991);
checkModule("Net::Subnets",0.21);
checkModule("Crypt::Blowfish",2.10);
checkModule("Finance::Quote",1.08); checkModule("Finance::Quote",1.08);
checkModule("POE",0.3202); checkModule("POE",0.3202);
checkModule("POE::Component::IKC::Server",0.18); checkModule("POE::Component::IKC::Server",0.18);