Save/restore state in OpenID Connect RP (#183)

This commit is contained in:
Clément Oudot 2014-11-17 13:55:26 +00:00
parent c64f69a852
commit 3cde211810
2 changed files with 133 additions and 3 deletions

View File

@ -50,8 +50,12 @@ sub extractFormInfo {
# AuthN Request
$self->lmLog( "Build OpenIDConnect AuthN Request", 'debug' );
# TODO Save state
my $state = "dummy";
# Save state
my $state = $self->storeState( qw/urldc checkLogins/ );
my $stateSession = $self->storeState();
# TODO Use AuthChoiceParam in redirect URL
# Authorization Code Flow
$self->{urldc} = $self->buildAuthorizationCodeAuthnRequest($state);
@ -72,7 +76,16 @@ sub extractFormInfo {
my $state = $self->param("state");
my $code = $self->param("code");
# TODO Restore state
# Restore state
if ($state) {
if ( $self->extractState($state) ) {
$self->lmLog( "State $state extracted", 'debug' );
}
else {
$self->lmLog( "Unable to extract state $state", 'error' );
return PE_ERROR;
}
}
# Get access_token and id_token
my $content = $self->getAuthorizationCodeAccessToken($code);

View File

@ -116,6 +116,111 @@ sub decodeJSON {
return $json_hash;
}
## @method hashref getOpenIDConnectSession(string id)
# Try to recover the OpenID Connect session corresponding to id and return session
# If id is set to undef, return a new session
# @param id session reference
# @return Lemonldap::NG::Common::Session object
sub getOpenIDConnectSession {
my ( $self, $id ) = splice @_;
my $oidcSession = Lemonldap::NG::Common::Session->new(
{
storageModule => $self->{globalStorage},
storageModuleOptions => $self->{globalStorageOptions},
cacheModule => $self->{localSessionStorage},
cacheModuleOptions => $self->{localSessionStorageOptions},
id => $id,
kind => "OpenIDConnect",
}
);
if ( $oidcSession->error ) {
if ($id) {
$self->_sub( 'userInfo',
"OpenIDConnect session $id isn't yet available" );
}
else {
$self->lmLog( "Unable to create new OpenIDConnect session",
'error' );
$self->lmLog( $oidcSession->error, 'error' );
}
return undef;
}
return $oidcSession;
}
## @method string storeState(array data)
# Store information in state database and return
# corresponding session_id
# @param data Array of information to store
# @return State Session ID
sub storeState {
my ( $self, @data ) = splice @_;
# check if there are data to store
my $infos;
foreach (@data) {
$infos->{$_} = $self->{$_} if $self->{$_};
}
return unless ($infos);
# Create state session
my $stateSession = $self->getOpenIDConnectSession();
return unless $stateSession;
# Session type
$infos->{_type} = "state";
# Set _utime for session autoremove
# Use default session timeout and relayState session timeout to compute it
my $time = time();
my $timeout = $self->{timeout};
my $stateTimeout = $self->{OIDCRPStateTimeout} || $timeout;
$infos->{_utime} = $time + ( $stateTimeout - $timeout );
# Store infos in state session
$stateSession->update($infos);
# Return session ID
return $stateSession->id;
}
## @method boolean extractState(string state)
# Extract state information into $self
# @param state state value
# @return result
sub extractState {
my ( $self, $state ) = splice @_;
return 0 unless $state;
# Open state session
my $stateSession = $self->getOpenIDConnectSession($state);
return 0 unless $stateSession;
# Push values in $self
foreach ( keys %{ $stateSession->data } ) {
next if $_ =~ /(type|_session_id|_utime)/;
$self->{$_} = $stateSession->data->{$_};
}
# Delete state session
if ( $stateSession->remove ) {
$self->lmLog( "State $state was deleted", 'debug' );
}
else {
$self->lmLog( "Unable to delete state $state", 'error' );
$self->lmLog( $stateSession->error, 'error' );
}
return 1;
}
1;
__END__
@ -153,6 +258,18 @@ Get Token response with autorization code
Convert JSON to HashRef
=head2 getOpenIDConnectSession
Try to recover the OpenID Connect session corresponding to id and return session
=head2 storeState
Store information in state database and return
=head2 extractState
Extract state information into $self
=head1 SEE ALSO
L<Lemonldap::NG::Portal::AuthOpenIDConnect>, L<Lemonldap::NG::Portal::UserDBOpenIDConnect>