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; + } +} + +