package Lemonldap::NG::Portal::Issuer::OpenID; use strict; use JSON; use Mouse; use Lemonldap::NG::Common::Regexp; use Lemonldap::NG::Portal::Main::Constants qw( PE_BADPARTNER PE_CONFIRM PE_ERROR PE_OK PE_OPENID_BADID PE_OPENID_EMPTY PE_REDIRECT PE_SENDRESPONSE ); our $VERSION = '2.0.0'; extends 'Lemonldap::NG::Portal::Main::Issuer'; # INTERFACE sub beforeAuth { 'forUnauthUser' } # PROPERTIES has secret => ( is => 'rw', default => sub { return $_[0]->conf->{openIdIssuerSecret} || $_[0]->conf->{cipher}->encrypt(0); } ); has listIsWhite => ( is => 'rw', default => sub { ( $_[0]->conf->{openIdSPList} =~ /^(\d);/ )[0] + 0; } ); has spList => ( is => 'rw', default => sub { Lemonldap::NG::Common::Regexp::reDomainsToHost( ( $_[0]->conf->{openIdSPList} =~ /^\d;(.*)$/ )[0] ); } ); has openidPortal => ( is => 'rw' ); # INITIALIZATION sub init { my ($self) = @_; eval { require Lemonldap::NG::Portal::Lib::OpenID::Server }; if ($@) { $self->error("Unable to load Net::OpenID::Server: $@"); return 0; } return 0 unless ( $self->SUPER::init() ); $self->openidPortal( $self->conf->{portal} . '/' . $self->path . '/' ); #$openidPortal =~ s#(?param('openid.mode'); unless ($mode) { $self->logger->debug('OpenID SP test'); return PE_OPENID_EMPTY; } if ( $mode eq 'associate' ) { return $self->_openIDResponse( $req, $self->openIDServer($req)->_mode_associate() ); } elsif ( $mode eq 'check_authentication' ) { return $self->_openIDResponse( $req, $self->openIDServer($req)->_mode_check_authentication() ); } return PE_OK; } sub run { my ( $self, $req ) = @_; my $mode = $req->param('openid.mode'); unless ($mode) { $self->logger->debug('OpenID SP test'); return PE_OPENID_EMPTY; } unless ( $mode =~ /^checkid_(?:immediate|setup)/ ) { $self->logger->error( "OpenID error : $mode is not known at this step (issuerForAuthUser)" ); return PE_ERROR; } my @r = $self->openIDServer($req)->_mode_checkid($mode); return $self->_openIDResponse( $req, @r ); } sub logout { PE_OK; } # INTERNAL METHODS # Create if not done a new Lemonldap::NG::Portal::Lib::OpenID::Server objet sub openIDServer { my ( $self, $req ) = @_; return $req->datas->{_openidserver} if ( $req->datas->{_openidserver} ); $req->datas->{_openidserver} = Lemonldap::NG::Portal::Lib::OpenID::Server->new( server_secret => sub { return $self->secret }, args => sub { $req->param(@_) }, endpoint_url => $self->openidPortal, setup_url => $self->openidPortal, get_user => sub { return $req->{sessionInfo} ->{ $self->conf->{openIdAttr} || $self->conf->{whatToTrace} }; }, get_identity => sub { my ( $u, $identity ) = @_; return $identity unless $u; return $self->openidPortal . $u; }, is_identity => sub { my ( $u, $identity ) = @_; return 0 unless ( $u and $identity ); if ( $u eq ( split '/', $identity )[-1] ) { return 1; } else { $self->{_badOpenIdentity} = 1; return 0; } }, is_trusted => sub { my ( $u, $trust_root, $is_identity ) = @_; return 0 unless ( $u and $is_identity ); my $tmp = $trust_root; $tmp =~ s#^http://(.*?)/#$1#; if ( $tmp =~ $self->spList xor $self->listIsWhite ) { $self->userLogger->warn( "$trust_root is forbidden for openID exchange"); $req->datas->{_openIdForbidden} = 1; return 0; } elsif ( $req->{sessionInfo}->{"_openidTrust$trust_root"} ) { $self->logger->debug('OpenID request already trusted'); return 1; } elsif ( $req->param("confirm") and $req->param("confirm") == 1 ) { $self->p->updatePersistentSession( { "_openidTrust$trust_root" => 1 } ); return 1; } elsif ( $req->param("confirm") and $req->param("confirm") == -1 ) { $self->p->updatePersistentSession( { "_openidTrust$trust_root" => 0 } ); return 0; } else { $self->logger->debug('OpenID request not trusted'); $req->datas->{_openIdTrustRequired} = 1; return 0; } }, extensions => { sreg => sub { return ( 1, {} ) unless (@_); require Lemonldap::NG::Portal::Lib::OpenID::SREG; return $self->Lemonldap::NG::Portal::Lib::OpenID::SREG::sregHook( $req, @_ ); }, }, ); return $req->datas->{_openidserver}; } # Manage Lemonldap::NG::Portal::OpenID::Server responses # @return Lemonldap::NG::Portal error code sub _openIDResponse { my ( $self, $req, $type, $data ) = @_; # Redirect if ( $type eq 'redirect' ) { $self->logger->debug("OpenID redirection to $data"); $req->{urldc} = $data; return PE_REDIRECT; } # Setup elsif ( $type eq 'setup' ) { if ( $req->datas->{_openIdTrustRequired} or $req->datas->{_openIdTrustExtMsg} ) { # TODO $req->info('

'); $req->info( $req->datas->{_openIdTrustExtMsg} ) if ( $req->datas->{_openIdTrustExtMsg} ); $self->logger->debug('OpenID confirmation'); return PE_CONFIRM; } elsif ( $req->datas->{_badOpenIdentity} ) { $self->userLogger->warn( "The user $req->{sessionInfo}->{_user} tries to use the id \"$data->{identity}\" on $data->{trust_root}" ); return PE_OPENID_BADID; } elsif ( $req->datas->{_openIdForbidden} ) { return PE_BADPARTNER; } # User has refused sharing its datas else { $self->userLogger->notice( $req->{sessionInfo}->{ $self->conf->{whatToTrace} } . ' refused to share its OpenIdentity' ); return PE_OK; } } elsif ($type) { $self->logger->debug("OpenID generated page ($type)"); $req->response( [ 200, [ 'Content-Type' => $type ], [$data] ] ); } else { $req->response( $self->p->sendError( $req, 'OpenID error ' . $self->openIDServer($req)->err() ) ); } return PE_SENDRESPONSE; } 1;