SAML: add Service Providers node

This commit is contained in:
Clément Oudot 2010-03-25 14:38:54 +00:00
parent dec9d562d8
commit 3cd3050e9e
7 changed files with 188 additions and 63 deletions

View File

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

View File

@ -281,7 +281,8 @@ function display(div,title) {
$('#content_'+div).addClass('content');
$('#content_title').html(title);
$('#newkb,#newrb,#delkb,#newkbr,#newrbr,#bdelvh,#bnewvh').hide();
$('#newsamlmetadatab,#delsamlmetadatab').hide();
$('#newidpsamlmetadatab,#delidpsamlmetadatab').hide();
$('#newspsamlmetadatab,#delspsamlmetadatab').hide();
$('#newsamlattributeb,#delsamlattributeb').hide();
$('#newsamlattributebr').hide();
var height_cur=$('#buttons').height()+$('#edition').height()+$('#help').height();
@ -308,7 +309,12 @@ function vhostRoot(id){
function samlIdpRoot(id){
currentId=id;
display('default','');
$('#newsamlmetadatab').show();
$('#newidpsamlmetadatab').show();
}
function samlSpRoot(id){
currentId=id;
display('default','');
$('#newspsamlmetadatab').show();
}
function authParams(id) {
currentId=id;
@ -418,8 +424,9 @@ function filearea(id) {
currentId=id;
$('#urlinput').hide();
$('#filearea').attr('value',lmdata(id));
/* Only samlIDPMetaDataXML element could be loaded from URL */
/* Only samlIDPMetaDataXML and samlSPMetaDataXML element could be loaded from URL */
if(lmtext(id)=='samlIDPMetaDataXML'){$('#urlinput').show();}
if(lmtext(id)=='samlSPMetaDataXML') {$('#urlinput').show();}
display('filearea',lmtext(id));
}
function samlAssertion(id) {
@ -459,16 +466,27 @@ function samlAttributeRoot(){
display('default','');
$('#newsamlattributebr').show();
}
function samlMetaData(id){
function samlIdpMetaData(id){
currentId=id;
$('#samlMetaData').attr('value',lmtext(id));
display('samlMetaData',lmtext(id));
$('#samlIdpMetaData').attr('value',lmtext(id));
display('samlIdpMetaData',lmtext(id));
if($('#li_'+myB64('/samlIDPMetaDataNode')).find('span').size()==1){
$('#delsamlmetadatab').hide();
$('#delidpsamlmetadatab').hide();
}else{
$('#delsamlmetadatab').show();
$('#delidpsamlmetadatab').show();
}
$('#newsamlmetadatab').show();
$('#newidpsamlmetadatab').show();
}
function samlSpMetaData(id){
currentId=id;
$('#samlSpMetaData').attr('value',lmtext(id));
display('samlSpMetaData',lmtext(id));
if($('#li_'+myB64('/samlSPMetaDataNode')).find('span').size()==1){
$('#delspsamlmetadatab').hide();
}else{
$('#delspsamlmetadatab').show();
}
$('#newspsamlmetadatab').show();
}
function samlService(id) {
currentId=id;
@ -524,11 +542,6 @@ function rulesRoot(id){
display('default','');
$('#newrbr').show();
}
function samlMetaDataRoot(id){
currentId=id;
display('default', '');
$('#newsamlmetadatab').show();
}
function reloadAuthParams() {
var value=$('#authText').attr('value');
if($('#authOptions').is(':visible')==true){
@ -631,13 +644,22 @@ function newSamlAttributeR(){
});
return false;
}
function newSamlMetaData(){
var name = prompt(text4newSamlMetaData,'authentic');
function newIdpSamlMetaData(){
var name = prompt(text4newSamlMetaData,'idp-example');
if(!name){return false;}
var idpId='li_'+myB64('/samlIDPMetaDataExportedAttributes/'+name);
simpleTreeCollection[0].newAjaxNodeIn($('#li_L3NhbWxJRFBNZXRhRGF0YU5vZGU1'),idpId,name,scriptname+'?type=new&node=/samlIDPMetaDataNode/'+name,function(d,s){
$('>span',s).attr('name',name).attr('help','default').attr('id','text_'+idpId).attr('onclick','samlMetaData(\''+idpId+'\')');
samlMetaData(idpId);
$('>span',s).attr('name',name).attr('help','default').attr('id','text_'+idpId).attr('onclick','samlIdpMetaData(\''+idpId+'\')');
samlIdpMetaData(idpId);
});
}
function newSpSamlMetaData(){
var name = prompt(text4newSamlMetaData,'sp-example');
if(!name){return false;}
var spId='li_'+myB64('/samlSPMetaDataExportedAttributes/'+name);
simpleTreeCollection[0].newAjaxNodeIn($('#li_L3NhbWxTUE1ldGFEYXRhTm9kZQ2'),spId,name,scriptname+'?type=new&node=/samlSPMetaDataNode/'+name,function(d,s){
$('>span',s).attr('name',name).attr('help','default').attr('id','text_'+spId).attr('onclick','samlSpMetaData(\''+spId+'\')');
samlSpMetaData(spId);
});
}
var cfgAttrDone=0;

View File

@ -104,12 +104,20 @@
<lang en="Delete key" fr="Effacer la clef" />
</button>
<button id="newsamlmetadatab" style="display:none;" onclick="newSamlMetaData();return false;" class="ui-state-default ui-corner-all">
<lang en="New metadatas" fr="Nouvelles métadatas" />
<button id="newidpsamlmetadatab" style="display:none;" onclick="newIdpSamlMetaData();return false;" class="ui-state-default ui-corner-all">
<lang en="New identity provider" fr="Nouveau fournisseur d'identité" />
</button>
<button id="delsamlmetadatab" style="display:none;" onclick="delSamlMetaData(currentId);" class="ui-state-default ui-corner-all">
<lang en="Delete metadatas" fr="Supprimer les métadatas" />
<button id="delidpsamlmetadatab" style="display:none;" onclick="delIdpSamlMetaData(currentId);" class="ui-state-default ui-corner-all">
<lang en="Delete identity provider" fr="Supprimer le fournisseur d'identité" />
</button>
<button id="newspsamlmetadatab" style="display:none;" onclick="newSpSamlMetaData();return false;" class="ui-state-default ui-corner-all">
<lang en="New service provider" fr="Nouveau fournisseur de service" />
</button>
<button id="delspsamlmetadatab" style="display:none;" onclick="delSpSamlMetaData(currentId);" class="ui-state-default ui-corner-all">
<lang en="Delete service provider" fr="Supprimer le fournisseur de service" />
</button>
<button id="newsamlattributeb" style="display:none;" onclick="newSamlAttribute();return false;" class="ui-state-default ui-corner-all">
@ -281,11 +289,20 @@
</button>
</div>
<!-- samlMetaData -->
<div id="content_samlMetaData" class="hidden">
<input type="text" id="samlMetaData" />
<!-- samlIdpMetaData -->
<div id="content_samlIdpMetaData" class="hidden">
<input type="text" id="samlIdpMetaData" />
<br />
<button onclick="setlminputtext(currentId,samlMetaData);return false;" class="ui-state-default ui-corner-all">
<button onclick="setlminputtext(currentId,samlIdpMetaData);return false;" class="ui-state-default ui-corner-all">
<lang en="Apply" fr="Appliquer" />
</button>
</div>
<!-- samlSpMetaData -->
<div id="content_samlSpMetaData" class="hidden">
<input type="text" id="samlSpMetaData" />
<br />
<button onclick="setlminputtext(currentId,samlSpMetaData);return false;" class="ui-state-default ui-corner-all">
<lang en="Apply" fr="Appliquer" />
</button>
</div>

View File

@ -190,6 +190,7 @@ sub confNode {
elsif ( $target =~ s/^samlmetadata:// ) {
my $h = $self->keyToH( $target, $self->conf );
$h = $h->{samlIDPMetaDataXML} if ( $h->{samlIDPMetaDataXML} );
$h = $h->{samlSPMetaDataXML} if ( $h->{samlSPMetaDataXML} );
my $metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
$metadata->initializeFromConfHash($h);
my $text = $target;
@ -204,7 +205,6 @@ sub confNode {
target => "samlmetadata",
) . "</li>";
}
else {
$target =~ s/^(\w+)://;
my $type = $1 || 'text';
@ -213,7 +213,17 @@ sub confNode {
$text =~ s/^.*\///;
my $h = $self->keyToH( $target, $self->conf );
# Try to get value from defaultConf
$h = $self->keyToH( $target, $self->defaultConf ) unless ( defined $h );
# If no value found, try to remove 2 first target components
# to manage complex hash like samlIDPMetaDataOptions
unless ( defined $h ) {
$target =~ /([^\/]*)$/;
$h = $self->keyToH( $1, $self->defaultConf );
}
# If still no value, set a default value depending on type
unless ( defined $h ) {
$self->lmLog( "$target does not exists in menu hash", "debug" );
$h = {

View File

@ -35,6 +35,7 @@ sub confUpload {
# Variables to store current vhost and IDP name
my $vhostname;
my $idpname;
my $spname;
# 1. ANALYSE DATAS
@ -88,11 +89,20 @@ sub confUpload {
$idpname = $name;
}
# Get SAML SP name
if ( $id =~ /samlSPMetaDataExportedAttributes\/([^\/]*)?$/ ) {
$self->lmLog( "Entering SP $name", 'debug' );
$spname = $name;
}
# Manage new keys
if ($NK) {
# Special case: avoid bug with node created from parent node
if ( $id =~ /^(virtualHosts|samlIDPMetaDataExportedAttributes)/ ) {
if ( $id =~
/^(virtualHosts|samlIDPMetaDataExportedAttributes|samlSPMetaDataExportedAttributes)/
)
{
$self->lmLog( "Special trigger for $id (attribute $name)",
'debug' );
@ -110,6 +120,11 @@ s/^virtualHosts\/([^\/]*)?\/header.*/exportedHeaders\/$1\/$name/;
# SAML IDP attribute
$id =~
s/^samlIDPMetaDataExportedAttributes\/([^\/]*)?.*/samlIDPMetaDataExportedAttributes\/$1\/$name/;
# SAML SP attribute
$id =~
s/^samlSPMetaDataExportedAttributes\/([^\/]*)?.*/samlSPMetaDataExportedAttributes\/$1\/$name/;
}
# Normal case
@ -126,11 +141,16 @@ s/^(exportedHeaders|locationRules)\/([^\/]*)?\/(.*)$/$1\/$vhostname\/$3/;
$id =~
s/^(samlIDPMetaDataXML|samlIDPMetaDataExportedAttributes|samlIDPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$idpname\/$3/;
# Set current SAML SP name
$id =~
s/^(samlSPMetaDataXML|samlSPMetaDataExportedAttributes|samlSPMetaDataOptions)\/([^\/]*)?\/(.*)$/$1\/$spname\/$3/;
$self->lmLog( "id transformed into $id", 'debug' );
next
if ( $id =~
/^(generalParameters|variables|virtualHosts|samlIDPMetaDataNode)/ );
/^(generalParameters|variables|virtualHosts|samlIDPMetaDataNode|samlSPMetaDataNode)/
);
my ( $confKey, $test ) = $self->getConfTests($id);
my ( $res, $m );
@ -467,7 +487,7 @@ sub findAllConfKeys {
sub formatValue {
my ( $self, $key, $value ) = @_;
my $newvalue = $value;
if ( $key =~ /^samlIDPMetaDataXML/ ) {
if ( $key =~ /^(samlIDPMetaDataXML|samlSPMetaDataXML)/ ) {
my $metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
if ( ref($value) ) {
$metadata->initializeFromConfHash($value);

View File

@ -83,6 +83,33 @@ sub cstruct {
}
);
}
elsif ( $k1 =~ /^samlSPMetaDataNode/i ) {
%$h = (
%$h,
samlSPMetaDataNode => {
$k2 => {
_nodes => [
qw(samlSPMetaDataXML samlSPMetaDataExportedAttributes samlSPMetaDataOptions)
],
samlSPMetaDataExportedAttributes => {
_nodes => [
"hash:/samlSPMetaDataExportedAttributes/$k2"
. ":samlSPMetaDataExportedAttributes:samlAttribute"
],
_js => 'samlAttributeRoot'
},
samlSPMetaDataXML => "samlmetadata:/samlSPMetaDataXML/$k2"
. ":samlSPMetaDataXML:filearea",
samlSPMetaDataOptions => {
_nodes =>
['samlSPMetaDataOptionsRequestedAuthnContext'],
samlSPMetaDataOptionsRequestedAuthnContext =>
"text:/samlSPMetaDataOptions/$k2/samlSPMetaDataOptionsRequestedAuthnContext",
},
}
}
);
}
return $h;
}
@ -93,7 +120,7 @@ sub struct {
my $self = shift;
return {
_nodes => [
qw(n:generalParameters n:variables n:virtualHosts n:samlServiceMetaData n:samlIDPMetaDataNode)
qw(n:generalParameters n:variables n:virtualHosts n:samlServiceMetaData n:samlIDPMetaDataNode n:samlSPMetaDataNode)
],
_help => 'default',
@ -503,13 +530,22 @@ sub struct {
# virtual keys should not begin like configuration keys.
samlIDPMetaDataNode => {
_nodes => [
'nhash:/samlIDPMetaDataExportedAttributes:samlIDPMetaDataNode:samlMetaData'
'nhash:/samlIDPMetaDataExportedAttributes:samlIDPMetaDataNode:samlIdpMetaData'
],
_upload => [ '/samlIDPMetaDataXML', '/samlIDPMetaDataOptions' ],
_help => 'default',
_js => 'samlIdpRoot',
},
samlSPMetaDataNode => {
_nodes => [
'nhash:/samlSPMetaDataExportedAttributes:samlSPMetaDataNode:samlSpMetaData'
],
_upload => [ '/samlSPMetaDataXML', '/samlSPMetaDataOptions' ],
_help => 'default',
_js => 'samlSpRoot',
},
samlServiceMetaData => {
_nodes => [
qw(samlEntityID
@ -958,6 +994,31 @@ sub testStruct {
keyTest => sub { return 1; },
},
},
samlSPMetaDataExportedAttributes => {
keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/,
keyMsgFail => 'Bad metadata name',
'*' => {
keyTest => qr/^\w([\w\-]*\w)?$/,
keyMsgFail => 'Bad attribute name',
test => sub { return 1; },
},
},
samlSPMetaDataXML => {
keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/,
keyMsgFail => 'Bad metadata name',
'*' => {
test => sub { return 1; },
keyTest => sub { return 1; },
},
},
samlSPMetaDataOptions => {
keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/,
keyMsgFail => 'Bad metadata name',
'*' => {
test => sub { return 1; },
keyTest => sub { return 1; },
},
},
samlServicePrivateKey => $testNotDefined,
samlEntityID => $testNotDefined,
samlOrganizationDisplayName => $testNotDefined,
@ -1096,26 +1157,20 @@ sub defaultConf {
########
# SAML #
########
samlIDPMetaDataXML => { 'authentic' => {} },
samlIDPMetaDataExportedAttributes =>
{ 'authentic' => { 'uid' => '0;uid;;' } },
samlIDPMetaDataOptions => {
'authentic' => {
'samlIDPMetaDataOptionsNameIDFormat' => '',
'samlIDPMetaDataOptionsForceAuthn' => '0',
'samlIDPMetaDataOptionsAllowProxiedAuthn' => '1',
'samlIDPMetaDataOptionsSSOBinding' => '',
'samlIDPMetaDataOptionsSLOBinding' => '',
'samlIDPMetaDataOptionsResolutionRule' => '',
'samlIDPMetaDataOptionsAllowLoginFromIDP' => '1',
'samlIDPMetaDataOptionsAdaptSessionUtime' => '1',
}
},
samlServicePrivateKey => '',
samlEntityID => $portal . '/saml/metadata',
samlOrganizationDisplayName => 'Example',
samlOrganizationName => 'Example',
samlOrganizationURL => 'http://www.example.com',
samlIDPMetaDataOptionsNameIDFormat => '',
samlIDPMetaDataOptionsForceAuthn => '0',
samlIDPMetaDataOptionsAllowProxiedAuthn => '1',
samlIDPMetaDataOptionsSSOBinding => '',
samlIDPMetaDataOptionsSLOBinding => '',
samlIDPMetaDataOptionsResolutionRule => '',
samlIDPMetaDataOptionsAllowLoginFromIDP => '1',
samlIDPMetaDataOptionsAdaptSessionUtime => '1',
samlSPMetaDataOptionsRequestedAuthnContext => '',
samlSPSSODescriptorAuthnRequestsSigned => '0',
samlSPSSODescriptorKeyDescriptorSigning => '',
samlSPSSODescriptorSingleLogoutServiceHTTP =>
@ -1191,18 +1246,8 @@ sub subDefaultConf {
'proxy' => 'https://remote/index.pl/sessions',
'ns' => 'https://remote/Lemonldap/NG/Common/CGI/SOAPService',
},
samlIDPMetaDataXML => { {} },
samlIDPMetaDataExportedAttributes => { 'uid' => '0;uid;;' },
samlIDPMetaDataOptions => {
'samlIDPMetaDataOptionsNameIDFormat' => '',
'samlIDPMetaDataOptionsForceAuthn' => '0',
'samlIDPMetaDataOptionsAllowProxiedAuthn' => '1',
'samlIDPMetaDataOptionsSSOBinding' => '',
'samlIDPMetaDataOptionsSLOBinding' => '',
'samlIDPMetaDataOptionsResolutionRule' => '',
'samlIDPMetaDataOptionsAllowLoginFromIDP' => '1',
'samlIDPMetaDataOptionsAdaptSessionUtime' => '1',
},
samlSPMetaDataExportedAttributes => { 'uid' => '0;uid;;' },
};
}

View File

@ -198,8 +198,8 @@ sub en {
saml => 'SAML',
samlServicePrivateKey => 'Private Key',
samlIDPMetaDataNode => 'Identity providers',
samlIDPMetaDataXML => 'Metadata XML',
samlIDPMetaDataNode => 'SAML identity providers',
samlIDPMetaDataXML => 'Metadata',
samlIDPMetaDataExportedAttributes => 'Exported attributes',
samlIDPMetaDataOptions => 'Options',
samlIDPMetaDataOptionsNameIDFormat => 'NameID format',
@ -211,6 +211,11 @@ sub en {
samlIDPMetaDataOptionsSSOBinding => 'SSO binding',
samlIDPMetaDataOptionsSLOBinding => 'SLO binding',
samlIDPMetaDataOptionsResolutionRule => 'Resolution rule',
samlSPMetaDataNode => 'SAML service providers',
samlSPMetaDataXML => 'Metadata',
samlSPMetaDataExportedAttributes => 'Exported attributes',
samlSPMetaDataOptions => 'Options',
samlSPMetaDataOptionsRequestedAuthnContext => 'Authentication context',
samlServiceMetaData => 'SAML 2 Service',
samlEntityID => 'Entity Identifier',
samlOrganization => 'Organization',
@ -413,8 +418,8 @@ sub fr {
saml => 'SAML',
samlServicePrivateKey => 'Clé privée',
samlIDPMetaDataNode => 'Fournisseurs d\'identités',
samlIDPMetaDataXML => 'XML Metadata',
samlIDPMetaDataNode => 'Fournisseurs d\'identité SAML',
samlIDPMetaDataXML => 'Metadonnées',
samlIDPMetaDataExportedAttributes => 'Attributs exportés',
samlIDPMetaDataOptions => 'Options',
samlIDPMetaDataOptionsNameIDFormat => 'Format NameID',
@ -428,6 +433,12 @@ sub fr {
samlIDPMetaDataOptionsSSOBinding => 'Méthode SSO',
samlIDPMetaDataOptionsSLOBinding => 'Méthode SLO',
samlIDPMetaDataOptionsResolutionRule => 'Règle de résolution',
samlSPMetaDataNode => 'Fournisseurs de service SAML',
samlSPMetaDataXML => 'Metadonnées',
samlSPMetaDataExportedAttributes => 'Attributs exportés',
samlSPMetaDataOptions => 'Options',
samlSPMetaDataOptionsRequestedAuthnContext =>
'Contexte d\'authentification',
samlServiceMetaData => 'Service SAML 2',
samlEntityID => 'Identifiant d\'entité',
samlOrganization => 'Organisation',