Added prequery statements to SQLReport and per-dbLink allowed keywords.

This commit is contained in:
Martin Kamerbeek 2006-02-02 13:23:32 +00:00
parent 929df9cbf9
commit 72b999b0ea
10 changed files with 218 additions and 68 deletions

View file

@ -14,6 +14,8 @@
sending attachments, HTML messages, and more. This will introduce many new
options for developers.
- The group mail screen now allows sending of HTML messages.
- Added prequery statements to the SQLReport and configurable allowed statements
to the databas link properties. (Martin Kamerbeek / Procolix)
6.8.6
- Added logic to deal with case sensitivity and whitespace problems in LDAP

View file

@ -26,9 +26,22 @@ addSearchEngine();
addEMSTemplates();
addEMSTables();
updateTemplates();
updateDatabaseLinksAndSQLReport();
finish($session); # this line required
#-------------------------------------------------
sub updateDatabaseLinksAndSQLReport {
print "\tUpdating the Database link and SQLReport Tables.\n";
$session->db->write('alter table databaseLink add column allowedKeywords text');
$session->db->write('update databaseLink set allowedKeywords="select\ndecsribe\nshow"');
$session->db->write('alter table SQLReport add column prequeryStatements1 text');
$session->db->write('alter table SQLReport add column prequeryStatements2 text');
$session->db->write('alter table SQLReport add column prequeryStatements3 text');
$session->db->write('alter table SQLReport add column prequeryStatements4 text');
$session->db->write('alter table SQLReport add column prequeryStatements5 text');
}
#-------------------------------------------------
sub updateTemplates {
print "\tUpdating base templates for XHTML compliance, and a cleaner look.\n" unless ($quiet);

View file

@ -47,7 +47,11 @@ sub definition {
dbQuery1=>{
fieldType=>"codearea",
defaultValue=>undef
},
},
prequeryStatements1=>{
fieldType=>"codearea",
defaultValue=>undef
},
preprocessMacros1=>{
fieldType=>"yesNo",
defaultValue=>0
@ -64,6 +68,10 @@ sub definition {
fieldType=>"codearea",
defaultValue=>undef
},
prequeryStatements2=>{
fieldType=>"codearea",
defaultValue=>undef
},
preprocessMacros2=>{
fieldType=>"yesNo",
defaultValue=>0
@ -80,6 +88,10 @@ sub definition {
fieldType=>"codearea",
defaultValue=>undef
},
prequeryStatements3=>{
fieldType=>"codearea",
defaultValue=>undef
},
preprocessMacros3=>{
fieldType=>"yesNo",
defaultValue=>0
@ -96,6 +108,10 @@ sub definition {
fieldType=>"codearea",
defaultValue=>undef
},
prequeryStatements4=>{
fieldType=>"codearea",
defaultValue=>undef
},
preprocessMacros4=>{
fieldType=>"yesNo",
defaultValue=>0
@ -112,6 +128,10 @@ sub definition {
fieldType=>"codearea",
defaultValue=>undef
},
prequeryStatements5=>{
fieldType=>"codearea",
defaultValue=>undef
},
preprocessMacros5=>{
fieldType=>"yesNo",
defaultValue=>0
@ -172,55 +192,62 @@ sub getEditForm {
|);
for my $nr (1..5) {
# Set TR class for this query properties
$tabform->getTab("properties")->trClass("query".$nr);
# Set TR class for this query properties
$tabform->getTab("properties")->trClass("query".$nr);
$tabform->getTab("properties")->readOnly(
-value=>"<hr>",
-label=>join '', "<b>", $i18n->get('4'), $nr,":</b>",
);
$tabform->getTab("properties")->yesNo(
-name=>"preprocessMacros".$nr,
-label=>$i18n->get(15),
-hoverHelp=>$i18n->get('15 description'),
-value=>$self->getValue("preprocessMacros".$nr)
);
$tabform->getTab("properties")->textarea(
-name=>"placeholderParams".$nr,
-label=>$i18n->get('Placeholder Parameters'),
-hoverHelp=>$i18n->get('Placeholder Parameters description'),
-value=>$self->getValue("placeholderParams".$nr)
);
$tabform->getTab("properties")->codearea(
-name=>"dbQuery".$nr,
-label=>$i18n->get(4),
-hoverHelp=>$i18n->get('4 description'),
-value=>$self->getValue("dbQuery".$nr)
);
$tabform->getTab("properties")->databaseLink(
-name=>"databaseLinkId".$nr,
-value=>$self->getValue("databaseLinkId".$nr)
);
$tabform->getTab("properties")->readOnly(
-value=>"<hr>",
-label=>join '', "<b>", $i18n->get('4'), $nr,":</b>",
);
$tabform->getTab("properties")->yesNo(
-name=>"preprocessMacros".$nr,
-label=>$i18n->get(15),
-hoverHelp=>$i18n->get('15 description'),
-value=>$self->getValue("preprocessMacros".$nr)
);
$tabform->getTab("properties")->textarea(
-name=>"placeholderParams".$nr,
-label=>$i18n->get('Placeholder Parameters'),
-hoverHelp=>$i18n->get('Placeholder Parameters description'),
-value=>$self->getValue("placeholderParams".$nr)
);
$tabform->getTab("properties")->codearea(
-name => "prequeryStatements".$nr,
-label => $i18n->get('Prequery statements'),
-hoverHelp => $i18n->get('Prequery statements description'),
-value => $self->getValue("prequeryStatements".$nr),
);
$tabform->getTab("properties")->codearea(
-name=>"dbQuery".$nr,
-label=>$i18n->get(4),
-hoverHelp=>$i18n->get('4 description'),
-value=>$self->getValue("dbQuery".$nr)
);
$tabform->getTab("properties")->databaseLink(
-name=>"databaseLinkId".$nr,
-value=>$self->getValue("databaseLinkId".$nr)
);
# Add a "Add another query" button
if ($nr < 5 and ($self->get("dbQuery".($nr+1)) eq "" || ($self->get("dbQuery".($nr)) eq "" and $self->get("dbQuery".($nr+1)) ne ""))) {
$tabform->getTab("properties")->button(
-value=>$i18n->get('Add another query'),
-extras=>'onclick="toggleQuery(\''.($nr+1).'\'); this.style.display=\'none\';"',
-noWait=>1
);
}
# Add a "Add another query" button
if ($nr < 5 and ($self->get("dbQuery".($nr+1)) eq "" || ($self->get("dbQuery".($nr)) eq "" and $self->get("dbQuery".($nr+1)) ne ""))) {
$tabform->getTab("properties")->button(
-value=>$i18n->get('Add another query'),
-extras=>'onclick="toggleQuery(\''.($nr+1).'\'); this.style.display=\'none\';"',
-noWait=>1
);
}
# Make empty query blocks invisible
if ($nr > 1 && ($self->get("dbQuery".$nr) eq "" || $self->get("dbQuery".($nr-1)) eq "")) {
$tabform->getTab("properties")->raw(qq|
<script type="text/javascript">
toggleQuery('$nr');
</script>
|);
}
# Make empty query blocks invisible
if ($nr > 1 && ($self->get("dbQuery".$nr) eq "" || $self->get("dbQuery".($nr-1)) eq "")) {
$tabform->getTab("properties")->raw(qq|
<script type="text/javascript">
toggleQuery('$nr');
</script>
|);
}
}
# Undefine TR class
$tabform->getTab("properties")->trClass();
@ -229,7 +256,8 @@ sub getEditForm {
-label=>$i18n->get(14),
-hoverHelp=>$i18n->get('14 description'),
-value=>$self->getValue("paginateAfter")
);
);
return $tabform;
}
@ -308,7 +336,6 @@ sub _parsePlaceholderParams {
#-------------------------------------------------------------------
sub _processQuery {
my $self = shift;
my $nr = shift || 1;
@ -328,14 +355,38 @@ sub _processQuery {
} else {
$query = $self->{_query}{$nr}{dbQuery};
}
my $i18n = WebGUI::International->new($self->session,"Asset_SQLReport");
push(@{$self->{_debug_loop}},{'debug.output'=>$i18n->get(17).$query});
push(@{$self->{_debug_loop}},{'debug.output'=>$i18n->get('debug placeholder parameters').join(",",@$placeholderParams)});
my $dbLink = WebGUI::DatabaseLink->new($self->session,$self->{_query}{$nr}{databaseLinkId});
my $dbh = $dbLink->db;
my $dbh = $dbLink->db;
if (defined $dbh) {
if ($query =~ /^select/i || $query =~ /^show/i || $query =~ /^describe/i) {
if ($dbLink->queryIsAllowed($query)) {
# if ($query =~ /^select/i || $query =~ /^show/i || $query =~ /^describe/i) {
# Check and execute prequery statements first
foreach (split(/\n/, $self->getValue("prequeryStatements".$nr))) {
my $prequeryStatement = $_;
WebGUI::Macro::process($self->session, \$prequeryStatement) if ($self->{_query}{$nr}{preprocessMacros});
if ($dbLink->queryIsAllowed($prequeryStatement)) {
my $sth = $dbh->unconditionalRead($prequeryStatement);
if ($sth->errorCode > 0) {
push(@{$self->{_debug_loop}},{
'debug.output' => $i18n->get('Prequery error').' "'.$prequeryStatement.'": '.$sth->errorMessage
});
} else {
push(@{$self->{_debug_loop}},{
'debug.output' => "Prequery: $prequeryStatement"
});
}
$sth->finish;
} else {
push(@{$self->{_debug_loop}},{'debug.output'=>$i18n->get("Prequery not allowed").$prequeryStatement});
}
}
my $url = $self->getUrl('func=view');
foreach ($self->session->form->param) {
unless ($_ eq "pn" || $_ eq "func" || $_ =~ /identifier/i || $_ =~ /password/i) {

View file

@ -230,18 +230,43 @@ sub new {
DSN=>$session->config->get("dsn"),
username=>$session->config->get("dbuser"),
identifier=>$session->config->get("dbpass"),
title=>"WebGUI Database"
title=>"WebGUI Database",
allowedKeywords=>"select\ndescribe\ndesc\nshow",
);
} else {
%databaseLink = $session->db->quickHash("select * from databaseLink where databaseLinkId=".$session->db->quote($databaseLinkId));
}
}
return undef unless $databaseLink{databaseLinkId};
return undef unless defined($databaseLink{databaseLinkId});
bless {_session=>$session, _databaseLink => \%databaseLink }, $class;
}
#-------------------------------------------------------------------
=head2 queryIsAllowed ( query )
Returns a boolean indicating is the supplied query is allowed for this database link.
=head3 query
The SQL query which is to be investigated.
=cut
sub queryIsAllowed {
my $self = shift;
my $query = shift;
foreach (split(/\s+/, $self->{_databaseLink}{allowedKeywords})) {
return 1 if ($query =~ m/^$_/i);
}
return 0;
}
#-------------------------------------------------------------------
=head2 session
Returns a reference to the current session.

View file

@ -127,7 +127,8 @@ sub toHtmlWithWrapper {
$subtext = $self->session->icon->edit("op=editDatabaseLink;lid=".$self->get("value").";afterEdit=".$self->session->url->escape($self->get("afterEdit")));
}
$subtext .= $self->session->icon->manage("op=listDatabaseLinks");
$self->get("subtext") = $subtext . $self->get("subtext");
$self->set("subtext", $subtext . $self->get("subtext"));
# $self->get("subtext") = $subtext . $self->get("subtext");
}
return $self->SUPER::toHtmlWithWrapper;
}

View file

@ -25,6 +25,11 @@ our $HELP = {
description => '15 description',
namespace => 'Asset_SQLReport',
},
{
title => 'Prequery statements',
description => 'Prequery statements description',
namespace => 'Asset_SQLReport',
},
{
title => '4',
description => '4 description',
@ -44,7 +49,11 @@ our $HELP = {
{
tag => 'wobjects using',
namespace => 'Wobject'
}
},
{
tag => 'database links manage',
namespace => 'WebGUI',
},
]
},
'sql report template' => {

View file

@ -665,6 +665,11 @@ our $HELP = {
description => '995 description',
namespace => 'WebGUI',
},
{
title => 'allowed keywords',
description => 'allowed keywords description',
namespace => 'WebGUI',
},
],
related => [
{

View file

@ -65,8 +65,10 @@ sub www_deleteDatabaseLink {
sub www_deleteDatabaseLinkConfirm {
my $session = shift;
return $session->privilege->insufficient unless ($session->user->isInGroup(3));
return $session->privilege->vitalComponent if ($session->form->process("dlid") == 0);
WebGUI::DatabaseLink->new($session,$session->form->process("dlid"))->delete;
return www_listDatabaseLinks();
return www_listDatabaseLinks($session);
}
#-------------------------------------------------------------------
@ -76,7 +78,8 @@ sub www_editDatabaseLink {
my ($output, %db, $f);
tie %db, 'Tie::CPHash';
if ($session->form->process("dlid") eq "new") {
# Default values are SELECT, DESCRIBE and SHOW
$db{allowedKeywords} = "select\ndescribe\nshow";
} elsif ($session->form->process("dlid") eq "0") {
} else {
@ -123,6 +126,12 @@ sub www_editDatabaseLink {
-hoverHelp => $i18n->get('995 description'),
-value => $db{identifier},
);
$f->textarea(
-name => "allowedKeywords",
-label => $i18n->get('allowed keywords'),
-hoverHelp => $i18n->get('allowed keywords description'),
-value => $db{allowedKeywords},
);
$f->submit;
$output .= $f->print;
return _submenu($session,$output,"990","database link add/edit");
@ -130,20 +139,25 @@ sub www_editDatabaseLink {
#-------------------------------------------------------------------
sub www_editDatabaseLinkSave {
my ($allowedKeywords);
my $session = shift;
return $session->privilege->insufficient unless ($session->user->isInGroup(3));
# Convert enters to a single \n.
($allowedKeywords = $session->form->process("allowedKeywords")) =~ s/\s+/\n/g;
my $params = {
title=>$session->form->process("title"),
username=>$session->form->process("dbusername"),
identifier=>$session->form->process("dbidentifier"),
DSN=>$session->form->process("DSN")
DSN=>$session->form->process("DSN"),
allowedKeywords=>$allowedKeywords,
};
if ($session->form->process("dlid") eq "new") {
WebGUI::DatabaseLink->create($session,$params);
} else {
WebGUI::DatabaseLink->new($session,$session->form->process("dlid"))->set($params);
}
return www_listDatabaseLinks();
return www_listDatabaseLinks($session);
}
#-------------------------------------------------------------------
@ -154,12 +168,14 @@ sub www_listDatabaseLinks {
my $output = '<table border="1" cellpadding="3" cellspacing="0" align="center">';
my $i18n = WebGUI::International->new($session);
foreach my $id (keys %{$links}) {
$output .= '<tr><td valign="top" class="tableData"></td><td valign="top" class="tableData">'.$i18n->get(1076).'</td></tr>';
$output = '<tr><td valign="top" class="tableData">'
.$session->icon->delete('op=deleteDatabaseLink;dlid='.$id)
.$session->icon->edit('op=editDatabaseLink;dlid='.$id)
.$session->icon->copy('op=copyDatabaseLink;dlid='.$id)
.'</td>';
# $output .= '<tr><td valign="top" class="tableData"></td><td valign="top" class="tableData">'.$i18n->get(1076).'</td></tr>';
$output .= '<tr><td valign="top" class="tableData">';
if ($id ne '0') {
$output .= $session->icon->delete('op=deleteDatabaseLink;dlid='.$id)
.$session->icon->edit('op=editDatabaseLink;dlid='.$id)
.$session->icon->copy('op=copyDatabaseLink;dlid='.$id);
}
$output .= '</td>';
$output .= '<td valign="top" class="tableData">'.$links->{$id}.'</td></tr>';
}
$output .= '</table>';

View file

@ -54,9 +54,10 @@ while the second question mark will contain the form variable "field1".
},
'4 description' => {
message => q|This is a standard SQL query. If you are unfamiliar with SQL then you'll likely not want to use this wobject.<br>
A question mark ? in the query represents a placeholder. Note that the ? is not enclosed in quotation marks, even when the placeholder represents a string. |,
lastUpdated => 1119841649,
message => q|<p>This is a standard SQL query. If you are unfamiliar with SQL then you'll likely not want to use this wobject.</p>
<p>A question mark ? in the query represents a placeholder. Note that the ? is not enclosed in quotation marks, even when the placeholder represents a string.</p>
<p>The keywords that are allowed are defined in the database link properties. The allowed keywords for the WebGUI database are SELECT, DESCRIBE and SHOW.</p>|,
lastUpdated => 1119841650,
},
'14 description' => {
@ -277,7 +278,24 @@ will always be false for query5.
message => q|Add another query|,
lastUpdated => 1031514049
},
'Prequery not allowed' => {
message => q|<b>Debug:</b> Prequery statement is not allowed: |,
lastUpdated => 0,
},
'Prequery error' => {
message => q|<b>Debug:</b> An error occured in prequery|,
lastUpdated => 0,
},
'Prequery statements' => {
message => q|Prequery statements|,
lastUpdated => 0,
},
'Prequery statements description' => {
message => q|<p>Prequery statements are sql statements executed before the real query. You can use prequery statements for instance to set variables that you want to use in the real query. For example:</p>
<blockquote>set @myVariable := 1</blockquote>
<p>The prequery statements are seperated from each other by returns and cannot use placeholders. You can use macro's within the prequery statements, however. Please note that prequery statements are only visible in the query they belong to and that you can only use statements that are allowed by the database link.</p>|,
lastUpdated => 0,
},
};
1;

View file

@ -3849,6 +3849,16 @@ Message Boards hold forums for users. There are many different Wobjects in WebG
message => q|unknown user|,
lastUpdated => 1135205716,
},
'allowed keywords' => {
message => q|Allowed keywords|,
lastUpdated => 0,
},
'allowed keywords description' => {
message => q|You can enter the statements that are allowed for this databaselink. A safe (read-only) choice is SELECT, DESCRIBE and SHOW. The different keywords should be seperated from each other by whitespace.|,
lastUpdated => 0,
},
};