Merge branch 'v2.0'
This commit is contained in:
commit
8653dde5b5
|
@ -30,6 +30,7 @@ Applications
|
||||||
applications/limesurvey
|
applications/limesurvey
|
||||||
applications/mattermost
|
applications/mattermost
|
||||||
applications/mediawiki
|
applications/mediawiki
|
||||||
|
applications/mobilizon
|
||||||
applications/nextcloud
|
applications/nextcloud
|
||||||
applications/obm
|
applications/obm
|
||||||
applications/office365
|
applications/office365
|
||||||
|
@ -108,6 +109,7 @@ Application Configuration
|
||||||
.. image:: applications/limesurvey_logo.png :doc:`LimeSurvey<applications/limesurvey>` ✔
|
.. image:: applications/limesurvey_logo.png :doc:`LimeSurvey<applications/limesurvey>` ✔
|
||||||
.. image:: applications/mattermost_logo.png :doc:`Mattermost<applications/mattermost>` ✔
|
.. image:: applications/mattermost_logo.png :doc:`Mattermost<applications/mattermost>` ✔
|
||||||
.. image:: applications/mediawiki_logo.png :doc:`Mediawiki<applications/mediawiki>` ✔
|
.. image:: applications/mediawiki_logo.png :doc:`Mediawiki<applications/mediawiki>` ✔
|
||||||
|
.. image:: applications/mobilizon_logo.jpg :doc:`Mobilizon<applications/mobilizon>` ✔
|
||||||
.. image:: applications/nextcloud-logo.png :doc:`NextCloud<applications/nextcloud>` ✔
|
.. image:: applications/nextcloud-logo.png :doc:`NextCloud<applications/nextcloud>` ✔
|
||||||
.. image:: applications/obm_logo.png :doc:`OBM<applications/obm>` ✔
|
.. image:: applications/obm_logo.png :doc:`OBM<applications/obm>` ✔
|
||||||
.. image:: applications/logo_office_365.png :doc:`Office 365<applications/office365>` ✔
|
.. image:: applications/logo_office_365.png :doc:`Office 365<applications/office365>` ✔
|
||||||
|
|
51
doc/sources/admin/applications/mobilizon.rst
Normal file
51
doc/sources/admin/applications/mobilizon.rst
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
Mobilizon
|
||||||
|
=========
|
||||||
|
|
||||||
|
|mobilizon_logo.jpg|
|
||||||
|
|
||||||
|
Presentation
|
||||||
|
------------
|
||||||
|
|
||||||
|
`Mobilizon <https://joinmobilizon.org>`__ is an online tool to help manage your events, your profiles and your groups.
|
||||||
|
|
||||||
|
Mobilizon lets users `authenticate with OpenID Connect <https://docs.joinmobilizon.org/administration/configure/auth/#oauth>`__ through the same plugin used by Keycloak.
|
||||||
|
|
||||||
|
First, make sure you have set up LemonLDAP::NG 's
|
||||||
|
:doc:`OpenID Connect service<..//openidconnectservice>` and added
|
||||||
|
:doc:`a Relaying Party for your Mobilizon instance<..//idpopenidconnect>`
|
||||||
|
|
||||||
|
The only options you need to configure are:
|
||||||
|
|
||||||
|
* *Client ID*: choose one
|
||||||
|
* *Client Secret*: choose one
|
||||||
|
* *Allowed redirection addresses for login*: ``https://mobilizon.example.com/auth/keycloak/callback``
|
||||||
|
|
||||||
|
Mobilizon configuration
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Edit ``/etc/mobilizon/config.exs``, and adjust the Client ID, Client Secret and URLs to match your domain ::
|
||||||
|
|
||||||
|
config :ueberauth,
|
||||||
|
Ueberauth,
|
||||||
|
providers: [
|
||||||
|
keycloak: {Ueberauth.Strategy.Keycloak, [default_scope: "openid profile email"]}
|
||||||
|
]
|
||||||
|
|
||||||
|
config :mobilizon, :auth,
|
||||||
|
oauth_consumer_strategies: [
|
||||||
|
{:keycloak, "LemonLDAP::NG"}
|
||||||
|
]
|
||||||
|
|
||||||
|
config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth,
|
||||||
|
client_id: "CHANGEME",
|
||||||
|
client_secret: "CHANGEME",
|
||||||
|
site: "https://auth.example.com",
|
||||||
|
authorize_url: "https://auth.example.com/oauth2/authorize",
|
||||||
|
token_url: "https://auth.example.com/oauth2/token",
|
||||||
|
userinfo_url: "https://auth.example.com/oauth2/userinfo",
|
||||||
|
token_method: :post
|
||||||
|
|
||||||
|
|
||||||
|
.. |mobilizon_logo.jpg| image:: /applications/mobilizon_logo.jpg
|
||||||
|
:class: align-center
|
||||||
|
|
BIN
doc/sources/admin/applications/mobilizon_logo.jpg
Normal file
BIN
doc/sources/admin/applications/mobilizon_logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.5 KiB |
|
@ -13,7 +13,7 @@ our $VERSION = '2.1.0';
|
||||||
has modules => ( is => 'rw', default => sub { {} } );
|
has modules => ( is => 'rw', default => sub { {} } );
|
||||||
has rules => ( is => 'rw', default => sub { {} } );
|
has rules => ( is => 'rw', default => sub { {} } );
|
||||||
has type => ( is => 'rw' );
|
has type => ( is => 'rw' );
|
||||||
has catch => ( is => 'rw', default => sub { {} } );
|
has catch => ( is => 'rw', default => sub { {} } );
|
||||||
has sessionKey => ( is => 'ro', default => '_choice' );
|
has sessionKey => ( is => 'ro', default => '_choice' );
|
||||||
|
|
||||||
my $_choiceRules;
|
my $_choiceRules;
|
||||||
|
@ -117,8 +117,10 @@ sub checkChoice {
|
||||||
}
|
}
|
||||||
|
|
||||||
unless ($name) {
|
unless ($name) {
|
||||||
|
|
||||||
# Set by OAuth Resource Owner grant // RESTServer pwdCheck
|
# Set by OAuth Resource Owner grant // RESTServer pwdCheck
|
||||||
if ($req->data->{_pwdCheck} and $self->{conf}->{authChoiceAuthBasic}) {
|
if ( $req->data->{_pwdCheck} and $self->{conf}->{authChoiceAuthBasic} )
|
||||||
|
{
|
||||||
$name = $self->{conf}->{authChoiceAuthBasic};
|
$name = $self->{conf}->{authChoiceAuthBasic};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +212,7 @@ sub getForm {
|
||||||
if ( $auth and $userDB and $passwordDB ) {
|
if ( $auth and $userDB and $passwordDB ) {
|
||||||
|
|
||||||
# Default URL
|
# Default URL
|
||||||
$req->{cspFormAction} ||= '';
|
$req->data->{cspFormAction} ||= {};
|
||||||
if (
|
if (
|
||||||
defined $url
|
defined $url
|
||||||
and not $self->checkXSSAttack( 'URI',
|
and not $self->checkXSSAttack( 'URI',
|
||||||
|
@ -219,11 +221,9 @@ sub getForm {
|
||||||
q%^(https?://)?[^\s/.?#$].[^\s]+$% # URL must be well formatted
|
q%^(https?://)?[^\s/.?#$].[^\s]+$% # URL must be well formatted
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
#$url .= $req->env->{'REQUEST_URI'};
|
|
||||||
|
|
||||||
# Avoid append same URL
|
my $csp_uri = $self->cspGetHost($url);
|
||||||
$req->{cspFormAction} .= " $url"
|
$req->data->{cspFormAction}->{$csp_uri} = 1;
|
||||||
unless $req->{cspFormAction} =~ qr%\b$url\b%;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$url .= '#';
|
$url .= '#';
|
||||||
|
|
|
@ -2683,6 +2683,8 @@ sub sendLogoutRequestToProvider {
|
||||||
name => $providerName,
|
name => $providerName,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
$req->data->{cspChildSrc}->{ $self->p->cspGetHost( $logout->msg_url ) }
|
||||||
|
= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# HTTP-SOAP
|
# HTTP-SOAP
|
||||||
|
|
|
@ -15,6 +15,7 @@ package Lemonldap::NG::Portal::Main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use URI::Escape;
|
use URI::Escape;
|
||||||
|
use URI;
|
||||||
use JSON;
|
use JSON;
|
||||||
use Lemonldap::NG::Common::Util qw(getPSessionID);
|
use Lemonldap::NG::Common::Util qw(getPSessionID);
|
||||||
|
|
||||||
|
@ -895,10 +896,14 @@ sub sendHtml {
|
||||||
$csp .= " $url";
|
$csp .= " $url";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( defined $req->{cspFormAction} ) {
|
if ( defined $req->data->{cspFormAction}
|
||||||
$self->logger->debug(
|
and ref( $req->data->{cspFormAction} ) eq "HASH" )
|
||||||
"Set CSP form-action with request URL: " . $req->{cspFormAction} );
|
{
|
||||||
$csp .= " " . $req->{cspFormAction};
|
my $request_csp_form_action =
|
||||||
|
join( " ", keys %{ $req->data->{cspFormAction} } );
|
||||||
|
$self->logger->debug( "Set CSP form-action with request URL: "
|
||||||
|
. $request_csp_form_action );
|
||||||
|
$csp .= " " . $request_csp_form_action;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set SAML Discovery Protocol in form-action
|
# Set SAML Discovery Protocol in form-action
|
||||||
|
@ -928,11 +933,18 @@ sub sendHtml {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if frames need to be embedded
|
# Check if frames need to be embedded
|
||||||
|
# FIXME: we should use $req->data->{cspChildSrc} anywhere an iframe is
|
||||||
|
# created in the code, and remove this
|
||||||
my @url;
|
my @url;
|
||||||
if ( $req->info ) {
|
if ( $req->info ) {
|
||||||
@url = map { s#https?://([^/]+).*#$1#; $_ }
|
@url = map { s#https?://([^/]+).*#$1#; $_ }
|
||||||
( $req->info =~ /<iframe.*?src="(.*?)"/sg );
|
( $req->info =~ /<iframe.*?src="(.*?)"/sg );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Update child-src header from request data
|
||||||
|
if ( ref( $req->data->{cspChildSrc} ) eq "HASH" ) {
|
||||||
|
push @url, keys %{ $req->data->{cspChildSrc} };
|
||||||
|
}
|
||||||
if (@url) {
|
if (@url) {
|
||||||
$csp .= join( ' ', 'child-src', @url, "'self'" ) . ';';
|
$csp .= join( ' ', 'child-src', @url, "'self'" ) . ';';
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1085,7 @@ sub registerLogin {
|
||||||
}
|
}
|
||||||
|
|
||||||
my $history = $req->sessionInfo->{_loginHistory} ||= {};
|
my $history = $req->sessionInfo->{_loginHistory} ||= {};
|
||||||
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
|
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
|
||||||
$history->{$type} ||= [];
|
$history->{$type} ||= [];
|
||||||
$self->logger->debug("Current login saved into $type");
|
$self->logger->debug("Current login saved into $type");
|
||||||
|
|
||||||
|
@ -1196,4 +1208,16 @@ sub loadTemplate {
|
||||||
return $tpl->output;
|
return $tpl->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This method extracts the scheme://host:port part of a URL for use in
|
||||||
|
# Content-Security-Polity header
|
||||||
|
sub cspGetHost {
|
||||||
|
my ( $self, $url ) = @_;
|
||||||
|
my $uri = $url // "";
|
||||||
|
unless ( $uri->isa("URI") ) {
|
||||||
|
$uri = URI->new($uri);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
$uri->scheme . "://" . ( $uri->_port ? $uri->host_port : $uri->host ) );
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -176,7 +176,7 @@ sub checkPasswordQuality {
|
||||||
## Min special characters
|
## Min special characters
|
||||||
# Just number of special characters must be checked
|
# Just number of special characters must be checked
|
||||||
if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars eq '__ALL__' ) {
|
if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars eq '__ALL__' ) {
|
||||||
my $spe = $password =~ s/\w//g;
|
my $spe = $password =~ s/\W//g;
|
||||||
if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) {
|
if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) {
|
||||||
$self->logger->error("Password has not enough special characters");
|
$self->logger->error("Password has not enough special characters");
|
||||||
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
|
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
||||||
|
|
||||||
require 't/test-lib.pm';
|
require 't/test-lib.pm';
|
||||||
|
|
||||||
my $res;
|
my ($res, $json);
|
||||||
|
|
||||||
my $client = LLNG::Manager::Test->new( {
|
my $client = LLNG::Manager::Test->new( {
|
||||||
ini => {
|
ini => {
|
||||||
|
@ -56,7 +56,7 @@ ok(
|
||||||
'Password min size not respected'
|
'Password min size not respected'
|
||||||
);
|
);
|
||||||
expectBadRequest($res);
|
expectBadRequest($res);
|
||||||
my $json;
|
|
||||||
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
|
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
|
||||||
or print STDERR "$@\n" . Dumper($res);
|
or print STDERR "$@\n" . Dumper($res);
|
||||||
ok(
|
ok(
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
use Test::More;
|
||||||
|
use strict;
|
||||||
|
use IO::String;
|
||||||
|
use JSON;
|
||||||
|
use Lemonldap::NG::Portal::Main::Constants
|
||||||
|
'PE_PP_INSUFFICIENT_PASSWORD_QUALITY';
|
||||||
|
|
||||||
|
require 't/test-lib.pm';
|
||||||
|
|
||||||
|
my ( $res, $json );
|
||||||
|
|
||||||
|
my $client = LLNG::Manager::Test->new( {
|
||||||
|
ini => {
|
||||||
|
logLevel => 'error',
|
||||||
|
passwordDB => 'Demo',
|
||||||
|
portalRequireOldPassword => 1,
|
||||||
|
passwordPolicyMinSize => 0,
|
||||||
|
passwordPolicyMinLower => 0,
|
||||||
|
passwordPolicyMinUpper => 0,
|
||||||
|
passwordPolicyMinDigit => 0,
|
||||||
|
passwordPolicyMinSpeChar => 2,
|
||||||
|
passwordPolicySpecialChar => '__ALL__',
|
||||||
|
portalDisplayPasswordPolicy => 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
# Try to authenticate
|
||||||
|
# -------------------
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new('user=dwho&password=dwho'),
|
||||||
|
length => 23
|
||||||
|
),
|
||||||
|
'Auth query'
|
||||||
|
);
|
||||||
|
count(1);
|
||||||
|
expectOK($res);
|
||||||
|
my $id = expectCookie($res);
|
||||||
|
|
||||||
|
ok(
|
||||||
|
$res =
|
||||||
|
$client->_get( '/', cookie => "lemonldap=$id", accept => 'text/html' ),
|
||||||
|
'Get Menu'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<input id="oldpassword" name="oldpassword"%,
|
||||||
|
' Old password input' )
|
||||||
|
or print STDERR Dumper( $res->[2]->[0] );
|
||||||
|
ok(
|
||||||
|
$res->[2]->[0] =~
|
||||||
|
m%<span trspan="passwordPolicyMinSpeChar">Minimal special characters:</span> 2%,
|
||||||
|
' passwordPolicyMinSpeChar'
|
||||||
|
) or print STDERR Dumper( $res->[2]->[0] );
|
||||||
|
count(3);
|
||||||
|
|
||||||
|
my $query = 'oldpassword=dwho&newpassword=@test&confirmpassword=@test';
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new($query),
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'application/json',
|
||||||
|
length => length($query)
|
||||||
|
),
|
||||||
|
'Password min special char policy not respected'
|
||||||
|
);
|
||||||
|
expectBadRequest($res);
|
||||||
|
ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' )
|
||||||
|
or print STDERR "$@\n" . Dumper($res);
|
||||||
|
ok(
|
||||||
|
$json->{error} == PE_PP_INSUFFICIENT_PASSWORD_QUALITY,
|
||||||
|
'Response is PE_PP_INSUFFICIENT_PASSWORD_QUALITY'
|
||||||
|
) or explain( $json, "error => 28" );
|
||||||
|
count(3);
|
||||||
|
|
||||||
|
$query = 'oldpassword=dwho&newpassword=@%&confirmpassword=@%';
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new($query),
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'application/json',
|
||||||
|
length => length($query)
|
||||||
|
),
|
||||||
|
'Password min special char respected'
|
||||||
|
);
|
||||||
|
expectOK($res);
|
||||||
|
count(1);
|
||||||
|
|
||||||
|
# Test $client->logout
|
||||||
|
$client->logout($id);
|
||||||
|
|
||||||
|
clean_sessions();
|
||||||
|
|
||||||
|
done_testing( count() );
|
|
@ -19,8 +19,8 @@ my $client = LLNG::Manager::Test->new( {
|
||||||
passwordPolicyMinLower => 0,
|
passwordPolicyMinLower => 0,
|
||||||
passwordPolicyMinUpper => 0,
|
passwordPolicyMinUpper => 0,
|
||||||
passwordPolicyMinDigit => 0,
|
passwordPolicyMinDigit => 0,
|
||||||
passwordPolicyMinSpeChar => 2,
|
passwordPolicyMinSpeChar => 0,
|
||||||
passwordPolicySpecialChar => '',
|
passwordPolicySpecialChar => '__ALL__',
|
||||||
portalDisplayPasswordPolicy => 1
|
portalDisplayPasswordPolicy => 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,8 @@ ok(
|
||||||
ok( $res->[2]->[0] =~ m%<input id="oldpassword" name="oldpassword"%,
|
ok( $res->[2]->[0] =~ m%<input id="oldpassword" name="oldpassword"%,
|
||||||
' Old password input' )
|
' Old password input' )
|
||||||
or print STDERR Dumper( $res->[2]->[0] );
|
or print STDERR Dumper( $res->[2]->[0] );
|
||||||
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinSpeChar">Minimal special characters:</span> 2%,
|
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyNone">%,
|
||||||
' passwordPolicyMinSpeChar' )
|
' passwordPolicyNone' )
|
||||||
or print STDERR Dumper( $res->[2]->[0] );
|
or print STDERR Dumper( $res->[2]->[0] );
|
||||||
count(3);
|
count(3);
|
||||||
|
|
||||||
|
|
|
@ -114,9 +114,9 @@ m%<form id="lformKerberos" action="#" method="post" class="login Kerberos">%,
|
||||||
' Action # found'
|
' Action # found'
|
||||||
) or explain( $res->[2]->[0], '<form id="lformSSL"' );
|
) or explain( $res->[2]->[0], '<form id="lformSSL"' );
|
||||||
my $header = getHeader( $res, 'Content-Security-Policy' );
|
my $header = getHeader( $res, 'Content-Security-Policy' );
|
||||||
ok( $header =~ m%;form-action \* https://test.example.com;%,
|
ok( $header =~ m%;form-action \* https://test.example.com;%,
|
||||||
' CSP URL found' )
|
' CSP URL found' )
|
||||||
or explain( $res->[1], 'form-action * https://test.example.com;' );
|
or explain( $res->[1], 'form-action * https://test.example.com;' );
|
||||||
ok( $res->[2]->[0] !~ /4_demo/, '4_Demo not displayed' );
|
ok( $res->[2]->[0] !~ /4_demo/, '4_Demo not displayed' );
|
||||||
ok(
|
ok(
|
||||||
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
|
||||||
|
|
|
@ -11,7 +11,7 @@ BEGIN {
|
||||||
require 't/saml-lib.pm';
|
require 't/saml-lib.pm';
|
||||||
}
|
}
|
||||||
|
|
||||||
my $maintests = 19;
|
my $maintests = 18;
|
||||||
my $debug = 'error';
|
my $debug = 'error';
|
||||||
my ( $issuer, $sp, $res );
|
my ( $issuer, $sp, $res );
|
||||||
|
|
||||||
|
@ -144,13 +144,8 @@ m#iframe src="http://auth.idp.com(/saml/relaySingleLogoutPOST)\?(relay=.*?)"#s,
|
||||||
'Get iframe request'
|
'Get iframe request'
|
||||||
) or explain( $res, '' );
|
) or explain( $res, '' );
|
||||||
( $url, $query ) = ( $1, $2 );
|
( $url, $query ) = ( $1, $2 );
|
||||||
ok(
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
getHeader( $res, 'Content-Security-Policy' ) =~
|
expectCspChildOK($res, "http://auth.sp.com");
|
||||||
/child-src auth.idp.com/,
|
|
||||||
' Frame is authorized'
|
|
||||||
)
|
|
||||||
or explain( $res->[1],
|
|
||||||
'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
|
|
||||||
ok(
|
ok(
|
||||||
$res = $issuer->_get(
|
$res = $issuer->_get(
|
||||||
|
|
|
@ -11,7 +11,7 @@ BEGIN {
|
||||||
require 't/saml-lib.pm';
|
require 't/saml-lib.pm';
|
||||||
}
|
}
|
||||||
|
|
||||||
my $maintests = 18;
|
my $maintests = 17;
|
||||||
my $debug = 'error';
|
my $debug = 'error';
|
||||||
my ( $issuer, $sp, $res );
|
my ( $issuer, $sp, $res );
|
||||||
|
|
||||||
|
@ -117,12 +117,7 @@ m#iframe src="http://auth.sp.com(/saml/proxySingleLogout)\?(SAMLRequest=.*?)"#,
|
||||||
);
|
);
|
||||||
$url = $1;
|
$url = $1;
|
||||||
my $query = $2;
|
my $query = $2;
|
||||||
ok(
|
expectCspChildOK($res, "auth.sp.com");
|
||||||
getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.sp.com/,
|
|
||||||
'Frame is authorized'
|
|
||||||
)
|
|
||||||
or explain( $res->[1],
|
|
||||||
'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
|
|
||||||
my $removedCookie = expectCookie($res);
|
my $removedCookie = expectCookie($res);
|
||||||
is( $removedCookie, 0, "SSO cookie removed" );
|
is( $removedCookie, 0, "SSO cookie removed" );
|
||||||
|
|
|
@ -197,11 +197,7 @@ count(1);
|
||||||
# Query IdP with iframe src
|
# Query IdP with iframe src
|
||||||
my $url = $1;
|
my $url = $1;
|
||||||
$query = $2;
|
$query = $2;
|
||||||
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
'Frame is authorized' )
|
|
||||||
or
|
|
||||||
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
count(1);
|
|
||||||
|
|
||||||
switch ('issuer');
|
switch ('issuer');
|
||||||
ok(
|
ok(
|
||||||
|
|
|
@ -197,11 +197,7 @@ count(1);
|
||||||
# Query IdP with iframe src
|
# Query IdP with iframe src
|
||||||
my $url = $1;
|
my $url = $1;
|
||||||
$query = $2;
|
$query = $2;
|
||||||
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
'Frame is authorized' )
|
|
||||||
or
|
|
||||||
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
count(1);
|
|
||||||
|
|
||||||
switch ('issuer');
|
switch ('issuer');
|
||||||
ok(
|
ok(
|
||||||
|
|
|
@ -167,11 +167,7 @@ count(1);
|
||||||
# Query IdP with iframe src
|
# Query IdP with iframe src
|
||||||
my $url = $1;
|
my $url = $1;
|
||||||
$query = $2;
|
$query = $2;
|
||||||
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
'Frame is authorized' )
|
|
||||||
or
|
|
||||||
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
count(1);
|
|
||||||
|
|
||||||
switch ('issuer');
|
switch ('issuer');
|
||||||
ok(
|
ok(
|
||||||
|
|
|
@ -157,11 +157,7 @@ count(1);
|
||||||
# Query IdP with iframe src
|
# Query IdP with iframe src
|
||||||
my $url = $1;
|
my $url = $1;
|
||||||
$query = $2;
|
$query = $2;
|
||||||
ok( getHeader( $res, 'Content-Security-Policy' ) =~ /child-src auth.idp.com/,
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
'Frame is authorized' )
|
|
||||||
or
|
|
||||||
explain( $res->[1], 'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
count(1);
|
|
||||||
|
|
||||||
switch ('issuer');
|
switch ('issuer');
|
||||||
ok(
|
ok(
|
||||||
|
|
|
@ -11,7 +11,7 @@ BEGIN {
|
||||||
}
|
}
|
||||||
my $userdb = tempdb();
|
my $userdb = tempdb();
|
||||||
|
|
||||||
my $maintests = 21;
|
my $maintests = 20;
|
||||||
my $debug = 'error';
|
my $debug = 'error';
|
||||||
my ( $issuer, $sp, $res );
|
my ( $issuer, $sp, $res );
|
||||||
|
|
||||||
|
@ -251,13 +251,7 @@ SKIP: {
|
||||||
# Query IdP with iframe src
|
# Query IdP with iframe src
|
||||||
$url = $1;
|
$url = $1;
|
||||||
$query = $2;
|
$query = $2;
|
||||||
ok(
|
expectCspChildOK($res, "auth.idp.com");
|
||||||
getHeader( $res, 'Content-Security-Policy' ) =~
|
|
||||||
/child-src auth.idp.com/,
|
|
||||||
'Frame is authorized'
|
|
||||||
)
|
|
||||||
or explain( $res->[1],
|
|
||||||
'Content-Security-Policy => ...child-src auth.idp.com' );
|
|
||||||
|
|
||||||
# Get iframe from CAS server
|
# Get iframe from CAS server
|
||||||
switch ('issuer');
|
switch ('issuer');
|
||||||
|
|
|
@ -483,6 +483,16 @@ sub exceptCspFormOK {
|
||||||
count(1);
|
count(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub expectCspChildOK {
|
||||||
|
my ( $res, $host ) = @_;
|
||||||
|
return 1 unless ($host);
|
||||||
|
my $csp = getHeader( $res, 'Content-Security-Policy' );
|
||||||
|
ok($csp, "Content-Security-Policy header found");
|
||||||
|
count(1);
|
||||||
|
like($csp, qr/child-src[^;]*\Q$host\E/, "Found $host in CSP child-src");
|
||||||
|
count(1);
|
||||||
|
}
|
||||||
|
|
||||||
=head4 getCookies($res)
|
=head4 getCookies($res)
|
||||||
|
|
||||||
Returns an hash ref with names => values of cookies set by server.
|
Returns an hash ref with names => values of cookies set by server.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user