* IDP metadata are in metadata key
* Use IDP internal ID instead of entityID to keep choosen IDP information
* Use base64 encoding for RelayState value
This commit is contained in:
Clément Oudot 2010-02-12 10:53:43 +00:00
parent cb7f7f8bd1
commit 71f142316f
2 changed files with 79 additions and 19 deletions

View File

@ -60,7 +60,7 @@ sub authInit {
# Load identity provider metadata
# IDP are listed in $self->{samlIDPMetaData}
# Each key is the IDP name and value is the metadata
# Each key is the IDP name and value is the metadata key
# Build IDP list for later use in extractFormInfo
foreach ( keys %{ $self->{samlIDPMetaData} } ) {
@ -70,7 +70,7 @@ sub authInit {
my $idp_metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
unless (
$idp_metadata->initializeFromConfHash(
$self->{samlIDPMetaData}->{$_}
$self->{samlIDPMetaData}->{$_}->{metadata}
)
)
{
@ -173,7 +173,24 @@ sub extractFormInfo {
# TODO check conditions
# TODO get urldc in RelayState
# Extract RelayState information
if ( $self->extractRelayState($login) ) {
$self->lmLog( "RelayState found in authentication assertion",
'debug' );
}
# Check IDP
my $idp = $self->{_idp};
unless ($idp) {
$self->lmLog( "IDP was not found in RelayState", 'error' );
return PE_ERROR;
}
$self->lmLog( "IDP $idp found in RelayState", 'debug' );
# Force redirection to portal if no urldc found
# (avoid displaying the whole SAML URL in user browser URL field)
$self->{mustRedirect} = 1 unless ( $self->{urldc} );
# Get NameID
my $nameid = $login->nameIdentifier;
@ -226,8 +243,8 @@ sub extractFormInfo {
foreach ( keys %{ $self->{_idpList} } ) {
$html .=
'<tr><td><input type="radio" name="idp" value="'
. $self->{_idpList}->{$_}->{entityID}
'<tr><td><input type="radio" name="idp" value="'
. $_
. '" /></td><td>'
. $self->{_idpList}->{$_}->{name}
. '</td></tr>';
@ -266,7 +283,11 @@ sub extractFormInfo {
my $html = '<h3>'
. &Lemonldap::NG::Portal::_i18n::msg( PM_SAML_IDPCHOOSEN,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. "</h3>\n<h4>$idp</h4>\n<input type=\"hidden\" name=\"idp\" value=\"$idp\" />\n";
. "</h3>\n"
. "<h4>$idp</h4>\n" . "<h5>("
. $self->{_idpList}->{$idp}->{entityID}
. ")</h5>\n"
. "<input type=\"hidden\" name=\"idp\" value=\"$idp\" />\n";
$self->info($html);
@ -293,10 +314,12 @@ sub extractFormInfo {
}
# 3. Build authentication request
$login = $self->createAuthnRequest( $server, $idp );
$self->{_idp} = $idp;
my $IDPentityID = $self->{_idpList}->{$idp}->{entityID};
$login = $self->createAuthnRequest( $server, $IDPentityID );
unless ($login) {
$self->lmLog( "Could not create authentication request on $idp",
$self->lmLog( "Could not create authentication request on $IDPentityID",
'error' );
return PE_ERROR;
}
@ -319,7 +342,7 @@ sub extractFormInfo {
# Extract attributes sent in authentication statement
# @return Lemonldap::NG::Portal error code
sub setAuthSessionInfo {
my $self = shift;
my $self = shift;
my $server = $self->{_lassoServer};
my $login = $self->{_lassoLogin};
@ -327,7 +350,7 @@ sub setAuthSessionInfo {
# Store other informations in session
$self->{sessionInfo}->{_user} = $self->{user};
$self->{sessionInfo}->{_idp} = $login->remote_providerID;
$self->{sessionInfo}->{_idp} = $self->{_idp};
# TODO adapt _utime with SessionNotOnOrAfter
@ -338,7 +361,7 @@ sub setAuthSessionInfo {
# Accept SSO from IDP
# @return PE_OK
sub authenticate {
my $self = shift;
my $self = shift;
my $server = $self->{_lassoServer};
my $login = $self->{_lassoLogin};

View File

@ -8,12 +8,13 @@ package Lemonldap::NG::Portal::_SAML;
use strict;
use base qw(Exporter);
use XML::Simple;
use MIME::Base64;
our @EXPORT = qw(
loadLasso checkLassoError createServer addIDP addProvider getOrganizationName
createAuthnRequest createLogin getHttpMethod initAuthnRequest
buildAuthnRequestMsg processAuthnResponseMsg getNameIdentifier
createIdentity createSession acceptSSO
createIdentity createSession acceptSSO extractRelayState
);
our $VERSION = '0.01';
@ -208,6 +209,9 @@ sub getOrganizationName {
return;
}
# Return if node is empty
return unless $node;
# Extract organization name
my $xs = XML::Simple->new();
my $data = $xs->XMLin($node);
@ -242,12 +246,15 @@ sub createAuthnRequest {
return;
}
# Set urldc in RelayState
my $relaystate = $self->{urldc};
if ($relaystate) {
$login->msg_relayState($relaystate);
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
# Set RelayState as key1;value1;key2;value2;... encoded in base 64
my $relaystate;
foreach (qw /_idp urldc/) {
$relaystate .= $_ . ";" . $self->{$_} . ";" if $self->{$_};
}
$relaystate =~ s/;$//;
$relaystate = encode_base64( $relaystate, '' );
$login->msg_relayState($relaystate);
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
# Customize request
my $request = $login->request();
@ -276,7 +283,7 @@ sub createLogin {
eval { $login = Lasso::Login->new($server); };
if ($@) {
$self->checkLassoError($@);
$self->checkLassoError($@);
return;
}
@ -413,6 +420,33 @@ sub acceptSSO {
return $self->checkLassoError($@);
}
## @method boolean extractRelayState(Lasso::Login login)
# Extract RelayState information into $self
## @param login Lasso::Login object
## @return result
sub extractRelayState {
my ( $self, $login ) = splice @_;
# Get relayState in assertion
my $relaystate = $login->msg_relayState;
return 0 unless $relaystate;
# Decode base64
$relaystate = decode_base64($relaystate);
# Recover values
my @values = split( /;/, $relaystate );
# Push values in $self
my $i;
for ( $i = 0, $i < $#values, $i++ ) {
$self->{ $values[$i] } = $values[ $i++ ];
}
return 1;
}
1;
__END__
@ -498,6 +532,10 @@ Create Lasso::Session object
Accept SSO from IDP
=head2 extractRelayState
Extract RelayState information into $self
=head1 SEE ALSO
L<Lemonldap::NG::Portal::AuthSAML>, L<Lemonldap::NG::Portal::UserDBSAML>
@ -515,5 +553,4 @@ This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut