BEGIN {
require
't/test-lib.pm'
;
require
't/oidc-lib.pm'
;
}
my
(
$op
,
$rp
,
$res
);
LWP::Protocol::PSGI->register(
sub
{
my
$req
= Plack::Request->new(
@_
);
ok(
$req
->uri =~ m
my
$host
= $1;
my
$url
= $2;
my
(
$res
,
$client
);
count(1);
if
(
$host
eq
'op'
) {
pass(
" Request from RP to OP, endpoint $url"
);
$client
=
$op
;
}
elsif
(
$host
eq
'rp'
) {
pass(
' Request from OP to RP'
);
$client
=
$rp
;
}
else
{
fail(
' Aborting REST request (external)'
);
return
[ 500, [], [] ];
}
count(1);
if
(
$req
->method =~ /^post$/i ) {
my
$s
=
$req
->content;
ok(
$res
=
$client
->_post(
$url
, IO::String->new(
$s
),
length
=>
length
(
$s
),
type
=>
$req
->header(
'Content-Type'
),
),
' Execute request'
);
}
else
{
ok(
$res
=
$client
->_get(
$url
,
custom
=> {
HTTP_AUTHORIZATION
=>
$req
->header(
'Authorization'
),
}
),
' Execute request'
);
}
ok(
$res
->[0] == 200,
' Response is 200'
);
count(2);
if
(
$url
!~ /blogout/ ) {
ok( getHeader(
$res
,
'Content-Type'
) =~ m
' Content is JSON'
)
or explain(
$res
->[1],
'Content-Type => application/json'
);
count(1);
}
return
$res
;
}
);
$op
= register(
'op'
, \
&op
);
ok(
$res
=
$op
->_get(
'/oauth2/jwks'
),
'Get JWKS, endpoint /oauth2/jwks'
);
expectOK(
$res
);
my
$jwks
=
$res
->[2]->[0];
my
$obj
=
eval
{ JSON::from_json(
$jwks
) };
if
($@) {
fail $@;
exit
1;
}
ok(
ref
(
$obj
->{
keys
} ) eq
'ARRAY'
,
'JWKS->keys is an array'
);
ok( @{
$obj
->{
keys
} } == 2,
'Found 2 keys'
);
$jwks
= JSON::to_json( {
keys
=> [
$obj
->{
keys
}->[1],
$obj
->{
keys
}->[0] ] } );
count(3);
ok(
$res
=
$op
->_get(
'/.well-known/openid-configuration'
),
'Get metadata, endpoint /.well-known/openid-configuration'
);
expectOK(
$res
);
my
$metadata
=
$res
->[2]->[0];
count(1);
$rp
= register(
'rp'
,
sub
{ rp(
$jwks
,
$metadata
) } );
ok(
$res
=
$rp
->_get(
'/'
,
accept
=>
'text/html'
),
'Unauth RP request'
);
count(1);
my
(
$url
,
$query
) =
ok(
$res
=
$op
->_get(
$url
,
query
=>
$query
,
accept
=>
'text/html'
),
"Push request to OP, endpoint $url"
);
count(1);
expectOK(
$res
);
$query
=
"user=french&password=french&$query"
;
ok(
$res
=
$op
->_post(
$url
,
IO::String->new(
$query
),
accept
=>
'text/html'
,
length
=>
length
(
$query
),
),
"Post authentication, endpoint $url"
);
count(1);
my
$idpId
= expectCookie(
$res
);
my
(
$host
,
$tmp
);
(
$host
,
$tmp
,
$query
) = expectForm(
$res
,
'#'
,
undef
,
'confirm'
);
ok(
$res
=
$op
->_post(
$url
,
IO::String->new(
$query
),
accept
=>
'text/html'
,
cookie
=>
"lemonldap=$idpId"
,
length
=>
length
(
$query
),
),
"Post confirmation, endpoint $url"
);
count(1);
ok(
$res
=
$rp
->_get(
'/'
,
query
=>
$query
,
accept
=>
'text/html'
),
'Call openidconnectcallback on RP'
);
count(1);
my
$spId
= expectCookie(
$res
);
withHandler(
'op'
,
sub
{
$op
->p->HANDLER->checkConf(1) } );
ok(
$res
=
$op
->_get(
'/'
,
query
=>
'logout'
,
cookie
=>
"lemonldap=$idpId"
,
accept
=>
'text/html'
),
'Query OP for logout'
);
count(1);
expectOK(
$res
);
ok(
$res
=
$op
->_get(
'/'
,
cookie
=>
"lemonldap=$idpId"
,
),
'Test if user is reject on OP'
);
count(1);
expectReject(
$res
);
ok(
$res
=
$rp
->_get(
'/'
,
cookie
=>
"lemonldap=$spId"
,
accept
=>
'text/html'
),
'Test if user is reject on RP'
);
count(1);
clean_sessions();
done_testing( count() );
sub
op {
return
LLNG::Manager::Test->new( {
ini
=> {
domain
=>
'idp.com'
,
authentication
=>
'Demo'
,
userDB
=>
'Same'
,
issuerDBOpenIDConnectActivation
=>
"1"
,
oidcRPMetaDataExportedVars
=> {
rp
=> {
email
=>
"mail"
,
family_name
=>
"cn"
,
name
=>
"cn"
}
},
oidcServiceAllowHybridFlow
=> 1,
oidcServiceAllowImplicitFlow
=> 1,
oidcServiceAllowAuthorizationCodeFlow
=> 1,
oidcRPMetaDataOptions
=> {
rp
=> {
oidcRPMetaDataOptionsDisplayName
=>
"RP"
,
oidcRPMetaDataOptionsIDTokenExpiration
=> 3600,
oidcRPMetaDataOptionsClientID
=>
"rpid"
,
oidcRPMetaDataOptionsIDTokenSignAlg
=>
"RS256"
,
oidcRPMetaDataOptionsBypassConsent
=> 0,
oidcRPMetaDataOptionsClientSecret
=>
"rpsecret"
,
oidcRPMetaDataOptionsUserIDAttr
=>
""
,
oidcRPMetaDataOptionsAccessTokenExpiration
=> 3600,
oidcRPMetaDataOptionsLogoutUrl
=>
oidcRPMetaDataOptionsLogoutType
=>
'back'
,
oidcRPMetaDataOptionsLogoutSessionRequired
=> 1,
oidcRPMetaDataOptionsRedirectUris
=>
}
},
oidcOPMetaDataOptions
=> {},
oidcOPMetaDataJSON
=> {},
oidcOPMetaDataJWKS
=> {},
oidcServiceMetaDataAuthnContext
=> {
'loa-4'
=> 4,
'loa-1'
=> 1,
'loa-5'
=> 5,
'loa-2'
=> 2,
'loa-3'
=> 3
},
oidcServicePrivateKeySig
=> alt_oidc_key_op_private_sig,
oidcServicePublicKeySig
=> alt_oidc_cert_op_public_sig,
oidcServiceOldPrivateKeySig
=> oidc_key_op_private_sig,
oidcServiceOldPublicKeySig
=> oidc_cert_op_public_sig,
}
}
);
}
sub
rp {
my
(
$jwks
,
$metadata
) =
@_
;
return
LLNG::Manager::Test->new( {
ini
=> {
domain
=>
'rp.com'
,
authentication
=>
'OpenIDConnect'
,
userDB
=>
'Same'
,
restSessionServer
=> 1,
oidcOPMetaDataExportedVars
=> {
op
=> {
cn
=>
"name"
,
uid
=>
"sub"
,
sn
=>
"family_name"
,
mail
=>
"email"
}
},
oidcServiceMetaDataBackChannelURI
=>
'blogout'
,
oidcOPMetaDataOptions
=> {
op
=> {
oidcOPMetaDataOptionsCheckJWTSignature
=> 1,
oidcOPMetaDataOptionsJWKSTimeout
=> 0,
oidcOPMetaDataOptionsClientSecret
=>
"rpsecret"
,
oidcOPMetaDataOptionsScope
=>
"openid profile"
,
oidcOPMetaDataOptionsStoreIDToken
=> 0,
oidcOPMetaDataOptionsDisplay
=>
""
,
oidcOPMetaDataOptionsClientID
=>
"rpid"
,
oidcOPMetaDataOptionsConfigurationURI
=>
}
},
oidcOPMetaDataJWKS
=> {
op
=>
$jwks
,
},
oidcOPMetaDataJSON
=> {
op
=>
$metadata
,
}
}
}
);
}