diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt
index bf4d80e66..17ea74dd1 100644
--- a/docs/changelog/7.x.x.txt
+++ b/docs/changelog/7.x.x.txt
@@ -19,6 +19,11 @@
- fixed a small error in WebGUI::Group documentation.
- Added WebGUI::Text with some CSV functions.
- Added Karma RFE: Thumbnail size can be enterred in CS
+ - Added diskUsage.pl utility script to show space used by assets in a webgui
+ site, similar to the unix du utility.
+ - Added option to WebGUI Auth module to require strong passwords. Admins can
+ now require users to enter a specific combination of characters, etc.
+ - Added skeleton code for writing WebGUI utility scripts.
7.0.9
- Removed the need for DateTime::Cron::Simple, which also added the ability
diff --git a/docs/upgrades/upgrade_7.0.9-7.1.0.pl b/docs/upgrades/upgrade_7.0.9-7.1.0.pl
index 503bfa318..0a839d42c 100755
--- a/docs/upgrades/upgrade_7.0.9-7.1.0.pl
+++ b/docs/upgrades/upgrade_7.0.9-7.1.0.pl
@@ -25,9 +25,23 @@ updateProductsTable($session);
makeLdapRecursiveFiltersText($session);
addWikiAssets($session);
addImageStuffToCs($session);
+addNewAuthSettings($session);
finish($session); # this line required
+#-------------------------------------------------
+sub addNewAuthSettings {
+ my $session = shift;
+ print "\tAdding new WebGUI auth settings to support strong passwords.\n" unless $quiet;
+ my $newSettings = {
+ webguiRequiredDigits => 0,
+ webguiNonWordCharacters => 0,
+ webguiRequiredMixedCase => 0,
+ };
+ foreach my $setting (keys %{$newSettings}) {
+ $session->db->write("insert into settings (name,value) values (?,?)",[$setting,$newSettings->{$setting}]);
+ }
+}
#-------------------------------------------------
sub addImageStuffToCs {
diff --git a/lib/WebGUI/Auth/WebGUI.pm b/lib/WebGUI/Auth/WebGUI.pm
index 9b56d1e63..1d60eec46 100644
--- a/lib/WebGUI/Auth/WebGUI.pm
+++ b/lib/WebGUI/Auth/WebGUI.pm
@@ -24,12 +24,59 @@ use WebGUI::Utility;
our @ISA = qw(WebGUI::Auth);
+#-------------------------------------------------------------------
+
+sub _hasNonWordCharacters {
+ my $self = shift;
+ my $password = shift;
+ my $numberRequired = shift;
+ my @characters = split(//,$password);
+ my $counter = 0;
+ foreach my $character (@characters) {
+ $self->session->errorHandler->warn($character);
+ $counter++ if ($character =~ /\W/);
+ return 1 if ($counter == $numberRequired);
+ }
+
+ return 0;
+}
+
+#-------------------------------------------------------------------
+
+sub _hasNumberCharacters {
+ my $self = shift;
+ my $password = shift;
+ my $numberRequired = shift;
+ my @characters = split(//,$password);
+ my $counter = 0;
+ foreach my $character (@characters) {
+ $counter++ if ($character =~ /\d/);
+ return 1 if ($counter == $numberRequired);
+ }
+ return 0;
+}
+
+#-------------------------------------------------------------------
+
+sub _hasMixedCaseCharacters {
+ my $self = shift;
+ my $password = shift;
+ my $numberRequired = shift;
+ my @characters = split(//,$password);
+ my ($numberOfCaps, $hasLower, $counter);
+ foreach my $character (@characters) {
+ $hasLower = 1 if ($character =~ /[a-z]/);
+ $numberOfCaps++ if ($character =~ /[A-Z]/);
+ return 1 if ($hasLower && $numberOfCaps == $numberRequired);
+ }
+ return 0;
+}
#-------------------------------------------------------------------
=head2 _isValidPassword ( )
- Validates the password.
+ Validates the password9.
=cut
@@ -41,7 +88,8 @@ sub _isValidPassword {
WebGUI::Macro::negate(\$confirm);
my $error = "";
- my $i18n = WebGUI::International->new($self->session,'AuthWebGUI');
+ my $i18n = WebGUI::International->new($self->session,'AuthWebGUI');
+
if ($password ne $confirm) {
$error .= '
'.$i18n->get(3).'';
}
@@ -53,6 +101,18 @@ sub _isValidPassword {
$error .= ''.$i18n->get(7)." ".$self->getSetting("passwordLength").'';
}
+ if ($self->getSetting("requiredDigits") && !$self->_hasNumberCharacters($password, $self->getSetting("requiredDigits"))) {
+ $error .= ''.sprintf($i18n->echo("Password must conatain at least %s numeric characters."), $self->getSetting("requiredDigits")).'';
+ }
+
+ if ($self->getSetting("nonWordCharacters") && !$self->_hasNonWordCharacters($password, $self->getSetting("nonWordCharacters"))) {
+ $error .= ''.sprintf($i18n->echo("Password must contain at least %s non-word characters such as , ! @ etc."), $self->getSetting("nonWordCharacters")).'';
+ }
+
+ if ($self->getSetting("requiredMixedCase") && !$self->_hasMixedCaseCharacters($password, $self->getSetting("requiredMixedCase"))) {
+ $error .= ''.sprintf($i18n->echo("Password must contain at least %s upper case characters and at least one lowercase character (mixed case)."), $self->getSetting("requiredMixedCase")).'';
+ }
+
$self->error($error);
return $error eq "";
}
@@ -301,7 +361,7 @@ sub editUserFormSave {
my $userId = $self->session->form->get("uid");
my $properties;
my $userData = $self->getParams($userId);
- unless (!$self->session->form->process('authWebGUI.identifier') || $self->session->form->process('authWebGUI.identifier') eq "password") {
+ unless (!$self->session->form->process('authWebGUI.identifier') || $self->session->form->process('authWebGUI.identifier') eq "password" || !$self->_isValidPassword($self->session->form->get('authWebGUI.identifier'))) {
$properties->{identifier} = Digest::MD5::md5_base64($self->session->form->process('authWebGUI.identifier'));
if($userData->{identifier} ne $properties->{identifier}){
$properties->{passwordLastUpdated} =$self->session->datetime->time();
@@ -337,6 +397,21 @@ sub editUserSettingsForm {
-value=>$self->session->setting->get("webguiPasswordLength"),
-label=>$i18n->get(15),
);
+ $f->integer(
+ -name => "webguiRequiredDigits",
+ -label => $i18n->echo("Number of digits required in password"),
+ -value => $self->session->setting->get("webguiRequiredDigits")
+ );
+ $f->integer(
+ -name => "webguiNonWordCharacters",
+ -label => $i18n->echo("Number of non-word characters required in password"),
+ -value => $self->session->setting->get("webguiNonWordCharacters")
+ );
+ $f->integer(
+ -name => "webguiRequiredMixedCase",
+ -label => $i18n->echo("Number of upper case case characters required in password"),
+ -value => $self->session->setting->get("webguiRequiredMixedCase")
+ );
$f->interval(
-name=>"webguiPasswordTimeout",
-label=>$i18n->get(16),
@@ -426,6 +501,9 @@ sub editUserSettingsFormSave {
my $f = $self->session->form;
my $s = $self->session->setting;
$s->set("webguiPasswordLength", $f->process("webguiPasswordLength","integer"));
+ $s->set("webguiRequiredDigits", $f->process("webguiRequiredDigits","integer"));
+ $s->set("webguiNonWordCharacters", $f->process("webguiNonWordCharacters","integer"));
+ $s->set("webguiRequiredMixedCase", $f->process("webguiRequiredMixedCase","integer"));
$s->set("webguiPasswordTimeout", $f->process("webguiPasswordTimeout","interval"));
$s->set("webguiExpirePasswordOnCreation", $f->process("webguiExpirePasswordOnCreation","yesNo"));
$s->set("webguiSendWelcomeMessage", $f->process("webguiSendWelcomeMessage","yesNo"));
diff --git a/sbin/_utility.skeleton b/sbin/_utility.skeleton
new file mode 100644
index 000000000..c6b7a9c25
--- /dev/null
+++ b/sbin/_utility.skeleton
@@ -0,0 +1,47 @@
+use lib "../lib";
+use strict;
+use Getopt::Long;
+use WebGUI::Session;
+
+my $session = start();
+# Do your work here
+finish($session);
+
+#-------------------------------------------------
+# Your sub here
+
+#-------------------------------------------------
+sub start {
+ my $configFile;
+ $|=1; #disable output buffering
+ GetOptions(
+ 'configFile=s'=>\$configFile,
+ );
+ my $session = WebGUI::Session->open("..",$configFile);
+ $session->user({userId=>3});
+
+ ## If your script is adding or changing content you need these lines, otherwise leave them commented
+ #
+ # my $versionTag = WebGUI::VersionTag->getWorking($session);
+ # $versionTag->set({name=>'Name Your Tag'});
+ #
+ ##
+
+ return $session;
+}
+
+#-------------------------------------------------
+sub finish {
+ my $session = shift;
+ my $versionTag = WebGUI::VersionTag->getWorking($session);
+
+ ## If your script is adding or changing content you need these lines, otherwise leave them commented
+ #
+ # my $versionTag = WebGUI::VersionTag->getWorking($session);
+ # $versionTag->commit;
+ ##
+
+ $session->var->end;
+ $session->close();
+}
+
diff --git a/sbin/diskUsage.pl b/sbin/diskUsage.pl
new file mode 100644
index 000000000..719875328
--- /dev/null
+++ b/sbin/diskUsage.pl
@@ -0,0 +1,153 @@
+#!/data/wre/prereqs/perl/bin/perl
+
+use lib "../lib";
+use Getopt::Long;
+use strict;
+use WebGUI::Session;
+use WebGUI::Asset;
+
+my $configFile;
+my $quiet;
+my $assetId;
+my $assetUrl;
+my $summarize = 0;
+my $blockSize = 1;
+my $recurse = 1;
+my $help;
+
+$| = 1; # No buffering
+
+GetOptions(
+ 'configFile=s'=>\$configFile, # WebGUI Config file
+ 'assetId=s' =>\$assetId, # AssetId to start with (optional) uses default page if not specified.
+ 'assetUrl=s' =>\$assetUrl, # AssetUrl to start with (optional) uses default page if not specified
+ 'quiet' =>\$quiet, # No output except for numeric file size (default unit is bytes, will use blockSize if specified)
+ 'summary!' =>\$summarize, # Displays total space used for asset and descendants (unless recurse flag is set to false in which case only the asset specified will be used)
+ 'blockSize=i' =>\$blockSize, # Change units in which space used is specified, defaults to bytes.
+ 'recurse!' =>\$recurse, # Flag indicating whether the disk space usage should consider asset and all descendants (default) or just the asset specified.
+ 'help!' =>\$help,
+);
+
+if ($help || !$configFile) {
+
+ print <<__EOH;
+
+usage perl $0
+
+Description: This utility is modeled after the *nix 'du' utility.
+
+ It displays the amount of disk space used by an asset and
+ it's descendants.
+
+Options:
+
+ --assetId AssetId to use as starting point for calculating
+ disk usage. Defaults to the WebGUI default page
+ defined in the sites settings.
+
+ --assetUrl Relative asset URL to use as starting point for
+ calculating (i.e., /home) disk usage. Defaults to the
+ WebGUI default page defined in the sites settings.
+
+ --blockSize Numeric value to change the unit of measure for
+ the amount of disk space used. Defaults to 1
+ (bytes)
+
+ --help Display this help message
+
+ --norecurse Returns the disk space used by the starting asset only.
+
+ --quiet Display nothing but the amount of disk space used.
+ This value will respect the blockSize and recurse
+ parameters when calculating it's output.
+
+ --summary Display only the total amount of disk space used in a
+ human readable format.
+
+ --configFile WebGUI config file to use. This parameter is required.
+
+__EOH
+ exit;
+}
+
+my $session = start();
+du();
+finish($session);
+
+#-------------------------------------------------
+sub start {
+ my $session = WebGUI::Session->open("../",$configFile);
+ $session->user({userId=>3});
+ return $session;
+}
+
+#-------------------------------------------------
+sub finish {
+ my $session = shift;
+ $session->var->end();
+ $session->close();
+}
+
+#-------------------------------------------------------
+sub du {
+ my $asset;
+ my $totalSize; # disk space used
+
+ if ($assetId) { # They specified an assetId to start with
+ $asset = WebGUI::Asset->newByDynamicClass($session,$assetId);
+ die ("Unable to instanciate asset $assetId") unless defined $asset;
+ print "\nStarting with asset $assetId...\n" unless $quiet;
+ }
+ elsif ($assetUrl) { # They specified an assetUrl to start with
+ $asset = WebGUI::Asset->newByUrl($session,$assetUrl);
+ die ("Unable to instanciate asset with URL $assetUrl") unless defined $asset;
+ print "\nStarting with asset url $assetUrl...\n" unless $quiet;
+ }
+ else { # No id specified, assume they want to start with the site's home page
+ $asset = WebGUI::Asset->getDefault($session);
+ die ("Unable to instanciate the WebGUI Default Page. Something is seriously broken.") unless defined $asset;
+ print "\nStarting with the Default Page...\n" unless $quiet;
+ }
+
+ my $lineage = ["self"];
+ push (@$lineage, "descendants") if $recurse;
+
+ my $descendants = $asset->getLineage($lineage,{returnObjects=>1});
+ foreach my $currentAsset (@$descendants) {
+ my $size = $currentAsset->get("assetSize");
+ $size = $size / $blockSize; # convert to blockSize specified
+ $totalSize += $size;
+
+ $size = sprintf("%.2f", $size) unless ($blockSize == 1); # No point in printing .00 after everything
+ print "$size\t".$currentAsset->getUrl."\n" unless ($quiet || $summarize);
+ }
+
+ # Format to a whole number unless the total is less than 1. If it's less than 1 attempt to display 2 digits of precision to avoid displaying a zero size.
+ unless ($totalSize < 1) {
+ $totalSize = sprintf("%d", $totalSize);
+ }
+ else {
+ $totalSize = sprintf("%.2f", $totalSize);
+ }
+
+ unless ($quiet) { # Human readable
+ # try to come up with an intellegible label for the output
+ my $units;
+ if ($blockSize == 1) { # bytes
+ $units = "bytes";
+ } elsif ($blockSize == 1000 || $blockSize == 1024) { # kilobytes
+ $units = "Kb";
+ } elsif ($blockSize == 1000*1000 || $blockSize == 1024*1024) { # megabytes
+ $units = "Mb";
+ } else { # Unknown units
+ $units = "units";
+ }
+
+ print "\nTotal Space used: $totalSize $units \n\n";
+ }
+ else { # return script friendly output of the size only.
+ print $totalSize;
+ }
+}
+
+