Configure POST form replay for each vhost in Manager (#174)

This commit is contained in:
Clément Oudot 2010-09-30 12:22:18 +00:00
parent eec03867da
commit 7601bc6415
7 changed files with 274 additions and 12 deletions

View File

@ -102,7 +102,7 @@ sub unserialize {
# Manage hashes # Manage hashes
if ( $k =~ if ( $k =~
/^(?:exportedVars|locationRules|groups|exportedHeaders|macros|globalStorageOptions|remoteGlobalStorageOptions|notificationStorageOptions|samlIDPMetaDataXML|samlIDPMetaDataExportedAttributes|samlIDPMetaDataOptions|samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions|samlStorageOptions|CAS_proxiedServices|logoutServices|authChoiceModules|applicationList)$/ /^(?:exportedVars|locationRules|groups|exportedHeaders|macros|globalStorageOptions|remoteGlobalStorageOptions|notificationStorageOptions|samlIDPMetaDataXML|samlIDPMetaDataExportedAttributes|samlIDPMetaDataOptions|samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions|samlStorageOptions|CAS_proxiedServices|logoutServices|authChoiceModules|applicationList|post)$/
and $v ||= {} and $v ||= {}
and not ref($v) ) and not ref($v) )
{ {

View File

@ -152,23 +152,25 @@ function lmdata(id){
function lmparent(id){ function lmparent(id){
return $('#'+id).parent().parent().attr('id'); return $('#'+id).parent().parent().attr('id');
} }
function setlmtext(id,v){ function setlmtext(id,v,prefixvalue){
if(!prefixvalue){prefixvalue="";}
if(v.length==0){ if(v.length==0){
alert("Null value"); alert("Null value");
} }
else { else {
$('#text_'+id).attr('name',v); $('#text_'+id).attr('name',prefixvalue+v);
$('#text_'+id).text(v); $('#text_'+id).text(v);
} }
} }
function setlminputtext(id,input){ function setlminputtext(id,input,prefixvalue){
var inputname=$(input).attr('id'); var inputname=$(input).attr('id');
var inputvalue=$(input).attr('value'); var inputvalue=$(input).attr('value');
if(!prefixvalue){prefixvalue="";}
if(inputvalue.length==0){ if(inputvalue.length==0){
alert('No '+inputname); alert('No '+inputname);
return false; return false;
} }
setlmtext(id,inputvalue); setlmtext(id,inputvalue,prefixvalue);
} }
function setlmdata(id,v){ function setlmdata(id,v){
$('#text_'+id).attr('value',escape(v)); $('#text_'+id).attr('value',escape(v));
@ -288,6 +290,8 @@ function display(div,title) {
$('#newchoicer,#newchoice,#delchoice').hide(); $('#newchoicer,#newchoice,#delchoice').hide();
$('#newcategoryr,#delcategory').hide(); $('#newcategoryr,#delcategory').hide();
$('#newapplicationr,#delapplication').hide(); $('#newapplicationr,#delapplication').hide();
$('#newpostr,#delpost').hide();
$('#newpostdatar,#delpostdata').hide();
var height_cur=$('#buttons').height()+$('#edition').height()+$('#help').height(); var height_cur=$('#buttons').height()+$('#edition').height()+$('#help').height();
var height_max=$('#menu').height(); var height_max=$('#menu').height();
if(height_cur > height_max || $('#help_content').is(':visible')==false){ if(height_cur > height_max || $('#help_content').is(':visible')==false){
@ -1084,3 +1088,55 @@ function applicationListApplication(id){
$('#delapplication').show(); $('#delapplication').show();
} }
/* Post */
function postRoot(id){
currentId=id;
display('default','');
$('#newpostr').show();
}
function newPostR(){
var newIdValue=newId(currentId);
var newPostKey = 'none';
simpleTreeCollection[0].addNode(newIdValue,newPostKey,function(d,s){
$('>span',s).attr('onClick','post("'+newIdValue+'")').attr('name',newPostKey).attr('value','').attr('id','text_'+newIdValue);
post(newIdValue);
});
return false;
}
function newPostDataR(){
var newIdValue=newId(currentId);
var newPostKey = 'login';
simpleTreeCollection[0].addNode(newIdValue,newPostKey,function(d,s){
$('>span',s).attr('onClick','postData("'+newIdValue+'")').attr('name','postdata:'+newPostKey).attr('value','$uid').attr('id','text_'+newIdValue);
postData(newIdValue);
});
return false;
}
function post(id){
currentId=id;
$('#postKey').attr('value',lmtext(id));
$('#postUrl').attr('value',lmdata(id));
display('post',lmtext(lmparent(id)));
$('#delpost,#newpostdatar').show();
}
function postData(id){
currentId=id;
var cleankey = lmtext(id).replace('postdata:','');
$('#postDataKey').attr('value',cleankey);
$('#postDataValue').attr('value',lmdata(id));
display('postdata',cleankey);
$('#delpostdata').show();
}
function delPost(){
delKey();
}
function delPostData(){
delKey();
}

View File

@ -165,6 +165,21 @@
<lang en="Delete application" fr="Supprimer l'application" /> <lang en="Delete application" fr="Supprimer l'application" />
</button> </button>
<button id="newpostr" style="display:none;" onclick="newPostR();return false;" class="ui-state-default ui-corner-all">
<lang en="New POST URL" fr="Nouvelle URL POST" />
</button>
<button id="delpost" style="display:none;" onclick="delPost();return false;" class="ui-state-default ui-corner-all">
<lang en="Delete POST URL" fr="Supprimer l'URL POST" />
</button>
<button id="newpostdatar" style="display:none;" onclick="newPostDataR();return false;" class="ui-state-default ui-corner-all">
<lang en="New POST data" fr="Nouvelle donnée POST" />
</button>
<button id="delpostdata" style="display:none;" onclick="delPostData();return false;" class="ui-state-default ui-corner-all">
<lang en="Delete POST data" fr="Supprimer la donnée POST" />
</button>
</div> </div>
@ -518,6 +533,32 @@
</button> </button>
</div> </div>
<!-- Post -->
<div id="content_post" class="hidden">
<table>
<tr>
<td><lang en="POST URL" fr="URL POST"/></td>
<td><input type="text" id="postKey" /></td>
</tr>
<tr>
<td><lang en="Target URL (optional)" fr="URL cible (optionnelle)"/></td>
<td><input type="text" id="postUrl" /></td>
</tr>
</table>
<br />
<button onclick="setlminputtext(currentId,postKey);setlminputdata(currentId,postUrl);return false;" class="ui-state-default ui-corner-all">
<lang en="Apply" fr="Appliquer" />
</button>
</div>
<div id="content_postdata" class="hidden">
<input type="text" id="postDataKey" /> <input type="text" id="postDataValue" />
<br />
<button onclick="setlminputtext(currentId,postDataKey,'postdata:');setlminputdata(currentId,postDataValue);return false;" class="ui-state-default ui-corner-all">
<lang en="Apply" fr="Appliquer" />
</button>
</div>
</div> </div>
</form> </form>

View File

@ -80,7 +80,7 @@ sub node {
} }
# subnode points to a configuration node # subnode points to a configuration node
elsif ( $flag =~ /^(n?hash|applicationlist)$/ ) { elsif ( $flag =~ /^(n?hash|applicationlist|post)$/ ) {
$res .= $res .=
$self->confNode( $node, "$flag:$target", $help, $_j ); $self->confNode( $node, "$flag:$target", $help, $_j );
} }
@ -261,8 +261,6 @@ sub confNode {
if ( %{ $h->{$catid} } ) { if ( %{ $h->{$catid} } ) {
$res .= '<ul>'; $res .= '<ul>';
# $res .= '<li class="line">&nbsp;</li>';
} }
foreach my $appid ( sort keys %{ $h->{$catid} } ) { foreach my $appid ( sort keys %{ $h->{$catid} } ) {
@ -301,6 +299,81 @@ sub confNode {
} }
} }
# POST
elsif ( $target =~ s/^post:// ) {
$self->lmLog( "Load POST data (target $target)", 'debug' );
my $h = $self->keyToH( $target, $self->conf );
# Try to get value from defaultConf
unless ($h) {
unless ( $h = $self->subDefaultConf()->{post} ) {
$self->lmLog( "Try to get default conf for post", 'debug' );
$self->lmLog( "$target hash is not defined in configuration",
'error' );
return;
}
}
# Loop on POST URI
foreach my $posturi ( sort keys %$h ) {
# Build ID
my $id = "$target/$posturi";
$id =~ s/=*$//;
# Display menu item
$self->lmLog( "Display menu item for POST URI $posturi", 'debug' );
# Here, "notranslate" is set to true : hashvalues must not be
# translated
$res .= $self->li($id)
. $self->span(
id => $id,
text => "$posturi",
data => $h->{$posturi}->{postUrl},
js => $js,
help => $help,
noT => 1
);
# Loop on post data (expr)
if ( %{ $h->{$posturi}->{expr} } ) {
$res .= '<ul>';
}
foreach my $postdata ( sort keys %{ $h->{$posturi}->{expr} } ) {
$id = "$target/$posturi/$postdata";
$id =~ s/=*$//;
# Display menu item
$self->lmLog( "Display menu item for POST data $postdata",
'debug' );
$res .= $self->li($id)
. $self->span(
id => $id,
text => "$postdata",
name => "postdata:$postdata",
data => $h->{$posturi}->{expr}->{$postdata},
js => "postData",
help => $help,
noT => 1
) . "</li>";
}
if ( %{ $h->{$posturi}->{expr} } ) {
$res .= '</ul>';
}
$res .= "</li>";
}
}
else { else {
$target =~ s/^(\w+)://; $target =~ s/^(\w+)://;
my $type = $1 || 'text'; my $type = $1 || 'text';
@ -568,7 +641,8 @@ sub span {
$args{js} .= "('$args{id}')" unless ( $args{js} =~ /\(/ ); $args{js} .= "('$args{id}')" unless ( $args{js} =~ /\(/ );
# Text # Text
my $tmp = $args{text}; $args{name} ||= $args{text};
my $tmp = $args{name};
$tmp =~ s/"/&#39;/g; $tmp =~ s/"/&#39;/g;
$args{text} = join ' ', map { $self->translate($_) } split /\s+/, $args{text} = join ' ', map { $self->translate($_) } split /\s+/,
$args{text} $args{text}

View File

@ -36,10 +36,12 @@ sub confUpload {
# - Virtual host name # - Virtual host name
# - SP and IDP name # - SP and IDP name
# - Menu category ID # - Menu category ID
# - POST URL name
my $vhostname; my $vhostname;
my $idpname; my $idpname;
my $spname; my $spname;
my $catid; my $catid;
my $postname;
# 1. ANALYSE DATAS # 1. ANALYSE DATAS
@ -71,6 +73,10 @@ sub confUpload {
my $catflag = 0; my $catflag = 0;
my $appflag = 0; my $appflag = 0;
# For POST URL keys
my $postflag = 0;
my $postdataflag = 0;
# Unescape value # Unescape value
$value = uri_unescape($value); $value = uri_unescape($value);
@ -118,6 +124,19 @@ sub confUpload {
} }
} }
# Get POST URL name
if ( $id =~ /post\/([^\/]*)?\/.*$/ ) {
if ( $name =~ s/^postdata:// ) {
$self->lmLog( "POST data $name", 'debug' );
$postdataflag = 1;
}
else {
$self->lmLog( "Entering POST URL $name", 'debug' );
$postflag = 1;
$postname = $name;
}
}
# Manage new keys # Manage new keys
if ($NK) { if ($NK) {
@ -141,6 +160,9 @@ s/^virtualHosts\/([^\/]*)?\/header.*/exportedHeaders\/$1\/$name/;
$id =~ $id =~
s/^virtualHosts\/([^\/]*)?\/rule.*/locationRules\/$1\/$name/; s/^virtualHosts\/([^\/]*)?\/rule.*/locationRules\/$1\/$name/;
# Virtual Host post
$id =~ s/^virtualHosts\/([^\/]*)?\/post.*/post\/$1\/$name/;
# SAML IDP attribute # SAML IDP attribute
$id =~ $id =~
s/^samlIDPMetaDataExportedAttributes\/([^\/]*)?.*/samlIDPMetaDataExportedAttributes\/$1\/$name/; s/^samlIDPMetaDataExportedAttributes\/([^\/]*)?.*/samlIDPMetaDataExportedAttributes\/$1\/$name/;
@ -166,7 +188,7 @@ s/^generalParameters\/authParams\/choiceParams\/([^\/]*)?.*/authChoiceModules\/$
# Set current Virtual Host name # Set current Virtual Host name
$id =~ $id =~
s/^(exportedHeaders|locationRules)\/([^\/]*)?\/(.*)$/$1\/$vhostname\/$3/; s/^(exportedHeaders|locationRules|post)\/([^\/]*)?\/(.*)$/$1\/$vhostname\/$3/;
# Set current SAML IDP name # Set current SAML IDP name
$id =~ $id =~
@ -176,6 +198,9 @@ s/^(samlIDPMetaDataXML|samlIDPMetaDataExportedAttributes|samlIDPMetaDataOptions)
$id =~ $id =~
s/^(samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$spname\/$3/; s/^(samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$spname\/$3/;
# Set current POST URL name
$id =~ s/^(post)\/([^\/]*)?\/(.*)$/$1\/$vhostname\/$postname/;
$self->lmLog( "id transformed into $id", 'debug' ); $self->lmLog( "id transformed into $id", 'debug' );
if ( $id =~ if ( $id =~
@ -279,6 +304,29 @@ s/^(samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions)\/(
"application" ); "application" );
} }
# Post URL
elsif ($postflag) {
$self->lmLog( "Register POST URL $name data", 'debug' );
# Set postUrl
$self->setKeyToH(
$newConf, "post/$vhostname",
"$postname", { postUrl => $value }
) if $value;
}
# Post data
elsif ($postdataflag) {
$self->lmLog( "Register POST data $name", 'debug' );
# Set post data in expr
$self->setKeyToH( $newConf, "post/$vhostname", "$postname",
{ expr => { $name => $value } } )
if $value;
}
# Default case
else { else {
$self->setKeyToH( $self->setKeyToH(
$newConf, $confKey, $newConf, $confKey,
@ -636,11 +684,42 @@ sub setKeyToH {
); );
$tmp->{$key} = {}; $tmp->{$key} = {};
} }
# Value can be an hashref
if ( ref($value) eq 'HASH' ) {
foreach my $vv ( keys %$value ) {
# vv can be an hashref
if ( ref( $value->{$vv} ) eq 'HASH' ) {
foreach my $vvv ( keys %{ $value->{$vv} } ) {
$self->lmLog(
"setKeyToH: set "
. $value->{$vv}->{$vvv}
. " in key $vvv in key $vv in key $k2 inside key $key",
'debug'
);
$tmp->{$key}->{$k2}->{$vv}->{$vvv} =
$value->{$vv}->{$vvv};
}
}
else {
$self->lmLog(
"setKeyToH: set "
. $value->{$vv}
. " in key $vv in key $k2 inside key $key",
'debug'
);
$tmp->{$key}->{$k2}->{$vv} = $value->{$vv};
}
}
}
else {
$self->lmLog( $self->lmLog(
"setKeyToH: set $value in key $k2 inside key $key", "setKeyToH: set $value in key $k2 inside key $key",
'debug' ); 'debug' );
$tmp->{$key}->{$k2} = $value; $tmp->{$key}->{$k2} = $value;
} }
}
else { else {
$self->lmLog( "setKeyToH: set $value in key $key", 'debug' ); $self->lmLog( "setKeyToH: set $value in key $key", 'debug' );
$tmp->{$key} = $value; $tmp->{$key} = $value;

View File

@ -29,7 +29,7 @@ sub cstruct {
%$h, %$h,
virtualHosts => { virtualHosts => {
$k2 => { $k2 => {
_nodes => [qw(rules:rules:rules headers)], _nodes => [qw(rules:rules:rules headers post:post:post)],
rules => { rules => {
_nodes => ["hash:/locationRules/$k2:rules:rules"], _nodes => ["hash:/locationRules/$k2:rules:rules"],
_js => 'rulesRoot' _js => 'rulesRoot'
@ -38,6 +38,10 @@ sub cstruct {
_nodes => ["hash:/exportedHeaders/$k2"], _nodes => ["hash:/exportedHeaders/$k2"],
_js => 'hashRoot' _js => 'hashRoot'
}, },
post => {
_nodes => ["post:/post/$k2:post:post"],
_js => 'postRoot'
},
} }
} }
); );
@ -759,7 +763,7 @@ sub struct {
################# #################
virtualHosts => { virtualHosts => {
_nodes => ['nhash:/locationRules:virtualHosts:vhost'], _nodes => ['nhash:/locationRules:virtualHosts:vhost'],
_upload => ['/exportedHeaders'], _upload => [ '/exportedHeaders', '/post' ],
_help => 'virtualHosts', _help => 'virtualHosts',
_js => 'vhostRoot', _js => 'vhostRoot',
}, },
@ -1305,6 +1309,11 @@ sub testStruct {
test => qr/\w+$/, test => qr/\w+$/,
msgFail => 'Unvalid session field', msgFail => 'Unvalid session field',
}, },
post => {
keyTest => Lemonldap::NG::Common::Regexp::HOSTNAME,
keyMsgFail => 'Bad virtual host name',
'*' => { keyTest => $pcre, },
},
protection => { protection => {
keyTest => qr/^(?:none|authentificate|manager|)$/, keyTest => qr/^(?:none|authentificate|manager|)$/,
msgFail => 'must be one of none authentificate manager', msgFail => 'must be one of none authentificate manager',
@ -1763,6 +1772,7 @@ sub subDefaultConf {
}, },
notificationStorageOptions => notificationStorageOptions =>
{ dirName => '/var/lib/lemonldap-ng/notifications', }, { dirName => '/var/lib/lemonldap-ng/notifications', },
post => { none => { expr => {}, }, },
remoteGlobalStorageOptions => { remoteGlobalStorageOptions => {
'proxy' => 'https://remote/index.pl/sessions', 'proxy' => 'https://remote/index.pl/sessions',
'ns' => 'https://remote/Lemonldap/NG/Common/CGI/SOAPService', 'ns' => 'https://remote/Lemonldap/NG/Common/CGI/SOAPService',

View File

@ -215,6 +215,7 @@ sub en {
portalRequireOldPassword => 'Require old password', portalRequireOldPassword => 'Require old password',
portalSkin => 'Skin', portalSkin => 'Skin',
portalUserAttr => 'User attribute', portalUserAttr => 'User attribute',
post => 'Form replay',
proxyParams => 'Proxy parameters', proxyParams => 'Proxy parameters',
randomPasswordRegexp => 'Regexp for password generation', randomPasswordRegexp => 'Regexp for password generation',
redirection => 'Handler redirections', redirection => 'Handler redirections',
@ -573,6 +574,7 @@ sub fr {
portalRequireOldPassword => 'Ancien mot de passe requis', portalRequireOldPassword => 'Ancien mot de passe requis',
portalSkin => 'Thème visuel', portalSkin => 'Thème visuel',
portalUserAttr => "Attribut de l'utilisateur", portalUserAttr => "Attribut de l'utilisateur",
post => 'Rejeu de formulaires',
proxyParams => 'Paramètres Proxy', proxyParams => 'Paramètres Proxy',
randomPasswordRegexp => randomPasswordRegexp =>
'Expression regulière pour la génération des mots de passe', 'Expression regulière pour la génération des mots de passe',