Unit tests for #2602
This commit is contained in:
parent
d3c27ed6fb
commit
7dabb0b896
197
lemonldap-ng-portal/t/32-OIDC-Grant-Type-OAuth2-Handler-Rules.t
Normal file
197
lemonldap-ng-portal/t/32-OIDC-Grant-Type-OAuth2-Handler-Rules.t
Normal file
|
@ -0,0 +1,197 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(
|
||||
PE_FIRSTACCESS
|
||||
);
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
require 't/oidc-lib.pm';
|
||||
}
|
||||
|
||||
my $res;
|
||||
my $debug = "error";
|
||||
|
||||
# Handler part
|
||||
use_ok('Lemonldap::NG::Handler::Server');
|
||||
use_ok('Lemonldap::NG::Common::PSGI::Cli::Lib');
|
||||
count(2);
|
||||
|
||||
my ( $handler, $portal );
|
||||
$portal = portal();
|
||||
$handler = Lemonldap::NG::Handler::Server->run( $portal->ini );
|
||||
|
||||
my $access_token;
|
||||
|
||||
$access_token = get_access_token_client($portal);
|
||||
|
||||
expectOK( handler_req( $handler, '/clientonly', $access_token ) );
|
||||
expectForbidden( handler_req( $handler, '/passwordonly', $access_token ), 403 );
|
||||
expectForbidden( handler_req( $handler, '/codeonly', $access_token ), 403 );
|
||||
|
||||
$access_token = get_access_token_password($portal);
|
||||
|
||||
expectForbidden( handler_req( $handler, '/clientonly', $access_token ) );
|
||||
expectOK( handler_req( $handler, '/passwordonly', $access_token ), 403 );
|
||||
expectForbidden( handler_req( $handler, '/codeonly', $access_token ), 403 );
|
||||
|
||||
$access_token = get_access_token_code($portal);
|
||||
|
||||
expectForbidden( handler_req( $handler, '/clientonly', $access_token ) );
|
||||
expectForbidden( handler_req( $handler, '/passwordonly', $access_token ), 403 );
|
||||
expectOK( handler_req( $handler, '/codeonly', $access_token ), 403 );
|
||||
|
||||
clean_sessions();
|
||||
|
||||
done_testing( count() );
|
||||
|
||||
sub handler_req {
|
||||
my ( $handler, $url, $access_token ) = @_;
|
||||
return $handler->( {
|
||||
'HTTP_ACCEPT' => 'text/html',
|
||||
'SCRIPT_NAME' => $url,
|
||||
'SERVER_NAME' => '127.0.0.1',
|
||||
'HTTP_CACHE_CONTROL' => 'max-age=0',
|
||||
'HTTP_ACCEPT_LANGUAGE' => 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3',
|
||||
'PATH_INFO' => $url,
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
'REQUEST_URI' => $url,
|
||||
'X_ORIGINAL_URI' => $url,
|
||||
'SERVER_PORT' => '80',
|
||||
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
||||
'HTTP_USER_AGENT' =>
|
||||
'Mozilla/5.0 (VAX-4000; rv:36.0) Gecko/20350101 Firefox',
|
||||
'REMOTE_ADDR' => '127.0.0.1',
|
||||
'HTTP_HOST' => 'oauth.example.com',
|
||||
'HTTP_AUTHORIZATION' => "Bearer $access_token",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sub get_access_token_client {
|
||||
my ($portal) = @_;
|
||||
my $query = buildForm( {
|
||||
client_id => 'rpid',
|
||||
client_secret => 'rpid',
|
||||
grant_type => 'client_credentials',
|
||||
scope => 'profile',
|
||||
}
|
||||
);
|
||||
|
||||
## Get Access Token with Client Credentials
|
||||
my $res = $portal->_post(
|
||||
"/oauth2/token",
|
||||
IO::String->new($query),
|
||||
accept => 'application/json',
|
||||
length => length($query),
|
||||
);
|
||||
|
||||
$res = expectJSON($res);
|
||||
return $res->{access_token};
|
||||
}
|
||||
|
||||
sub get_access_token_password {
|
||||
my ($portal) = @_;
|
||||
## Get Access Token with Password Grant
|
||||
my $query = buildForm( {
|
||||
client_id => 'rpid',
|
||||
client_secret => 'rpid',
|
||||
grant_type => 'password',
|
||||
username => 'dwho',
|
||||
password => 'dwho',
|
||||
scope => 'profile',
|
||||
}
|
||||
);
|
||||
my $res = $portal->_post(
|
||||
"/oauth2/token",
|
||||
IO::String->new($query),
|
||||
accept => 'application/json',
|
||||
length => length($query),
|
||||
);
|
||||
|
||||
$res = expectJSON($res);
|
||||
my $access_token = $res->{access_token};
|
||||
}
|
||||
|
||||
sub get_access_token_code {
|
||||
my ($portal) = @_;
|
||||
|
||||
my $id = login( $portal, 'dwho' );
|
||||
|
||||
my $code = authorize(
|
||||
$portal, $id,
|
||||
{
|
||||
response_type => "code",
|
||||
|
||||
# Include a weird scope name, to make sure they work (#2168)
|
||||
scope => "openid profile",
|
||||
client_id => "rpid",
|
||||
state => "af0ifjsldkj",
|
||||
redirect_uri => "http://test"
|
||||
}
|
||||
);
|
||||
|
||||
my $res = codeGrant( $portal, 'rpid', $code, 'http://test' );
|
||||
$res = expectJSON($res);
|
||||
return $res->{access_token};
|
||||
}
|
||||
|
||||
sub portal {
|
||||
return LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => $debug,
|
||||
domain => 'op.com',
|
||||
portal => 'http://auth.op.com',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
issuerDBOpenIDConnectActivation => 1,
|
||||
oidcServiceAllowOnlyDeclaredScopes => 1,
|
||||
vhostOptions => {
|
||||
'oauth.example.com' => {
|
||||
'vhostType' => 'OAuth2'
|
||||
},
|
||||
},
|
||||
locationRules => {
|
||||
'auth.example.com' => {
|
||||
default => 'accept',
|
||||
},
|
||||
'oauth.example.com' => {
|
||||
'(?#Client Only)^/clientonly' =>
|
||||
'$_oidc_grant_type eq "clientcredentials"',
|
||||
'(?#Code Only)^/codeonly' =>
|
||||
'$_oidc_grant_type eq "authorizationcode"',
|
||||
'(?#Password Only)^/passwordonly' =>
|
||||
'$_oidc_grant_type eq "password"',
|
||||
'default' => 'deny',
|
||||
},
|
||||
},
|
||||
oidcRPMetaDataExportedVars => {
|
||||
rp => {
|
||||
email => "mail",
|
||||
family_name => "cn",
|
||||
name => "cn"
|
||||
},
|
||||
},
|
||||
oidcRPMetaDataOptions => {
|
||||
rp => {
|
||||
oidcRPMetaDataOptionsDisplayName => "RP",
|
||||
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsClientID => "rpid",
|
||||
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
|
||||
oidcRPMetaDataOptionsClientSecret => "rpid",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
oidcRPMetaDataOptionsAccessTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsBypassConsent => 1,
|
||||
oidcRPMetaDataOptionsAllowClientCredentialsGrant => 1,
|
||||
oidcRPMetaDataOptionsAllowPasswordGrant => 1,
|
||||
oidcRPMetaDataOptionsRedirectUris => "http://test",
|
||||
},
|
||||
},
|
||||
oidcServicePrivateKeySig => oidc_key_op_private_sig,
|
||||
oidcServicePublicKeySig => oidc_key_op_public_sig,
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
169
lemonldap-ng-portal/t/32-OIDC-Grant-Type-Rules.t
Normal file
169
lemonldap-ng-portal/t/32-OIDC-Grant-Type-Rules.t
Normal file
|
@ -0,0 +1,169 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(
|
||||
PE_FIRSTACCESS
|
||||
);
|
||||
|
||||
BEGIN {
|
||||
require 't/test-lib.pm';
|
||||
require 't/oidc-lib.pm';
|
||||
}
|
||||
|
||||
my $res;
|
||||
my $debug = "error";
|
||||
|
||||
my ($portal);
|
||||
$portal = portal();
|
||||
|
||||
my $access_token;
|
||||
|
||||
# RP1, should only allow Auth code grant
|
||||
expectReject( try_access_token_client( $portal, 'rpcode' ), 400 );
|
||||
expectReject( try_access_token_password( $portal, 'rpcode' ), 400 );
|
||||
expectRedirection( try_access_token_code( $portal, 'rpcode' ),
|
||||
qr#http://.*code=([^\&]*)# );
|
||||
|
||||
# RP2, should only allow Client Credentials grant
|
||||
expectJSON( try_access_token_client( $portal, 'rpclient' ) );
|
||||
expectReject( try_access_token_password( $portal, 'rpclient' ), 400 );
|
||||
expectPortalError( try_access_token_code( $portal, 'rpclient' ), 84 );
|
||||
|
||||
# RP3, should only allow Password grant
|
||||
expectReject( try_access_token_client( $portal, 'rppassword' ), 400 );
|
||||
expectJSON( try_access_token_password( $portal, 'rppassword' ) );
|
||||
expectPortalError( try_access_token_code( $portal, 'rppassword' ), 84 );
|
||||
|
||||
clean_sessions();
|
||||
|
||||
done_testing( count() );
|
||||
|
||||
sub try_access_token_client {
|
||||
my ( $portal, $rp ) = @_;
|
||||
my $query = buildForm( {
|
||||
client_id => $rp,
|
||||
client_secret => $rp,
|
||||
grant_type => 'client_credentials',
|
||||
scope => 'profile',
|
||||
}
|
||||
);
|
||||
|
||||
## Get Access Token with Client Credentials
|
||||
my $res = $portal->_post(
|
||||
"/oauth2/token",
|
||||
IO::String->new($query),
|
||||
accept => 'application/json',
|
||||
length => length($query),
|
||||
);
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub try_access_token_password {
|
||||
my ( $portal, $rp ) = @_;
|
||||
## Get Access Token with Password Grant
|
||||
my $query = buildForm( {
|
||||
client_id => $rp,
|
||||
client_secret => $rp,
|
||||
grant_type => 'password',
|
||||
username => 'dwho',
|
||||
password => 'dwho',
|
||||
scope => 'profile',
|
||||
}
|
||||
);
|
||||
my $res = $portal->_post(
|
||||
"/oauth2/token",
|
||||
IO::String->new($query),
|
||||
accept => 'application/json',
|
||||
length => length($query),
|
||||
);
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub try_access_token_code {
|
||||
my ( $portal, $rp ) = @_;
|
||||
|
||||
my $id = login( $portal, 'dwho' );
|
||||
|
||||
my $params = {
|
||||
response_type => "code",
|
||||
|
||||
# Include a weird scope name, to make sure they work (#2168)
|
||||
scope => "openid profile",
|
||||
client_id => $rp,
|
||||
state => "af0ifjsldkj",
|
||||
redirect_uri => "http://test"
|
||||
};
|
||||
my $query = buildForm($params);
|
||||
my $res = $portal->_get(
|
||||
"/oauth2/authorize",
|
||||
query => "$query",
|
||||
accept => 'text/html',
|
||||
cookie => "lemonldap=$id",
|
||||
);
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub portal {
|
||||
return LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => $debug,
|
||||
domain => 'op.com',
|
||||
portal => 'http://auth.op.com',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
issuerDBOpenIDConnectActivation => 1,
|
||||
oidcServiceAllowOnlyDeclaredScopes => 1,
|
||||
oidcRPMetaDataOptions => {
|
||||
rpcode => {
|
||||
oidcRPMetaDataOptionsDisplayName => "RP",
|
||||
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsClientID => "rpcode",
|
||||
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
|
||||
oidcRPMetaDataOptionsClientSecret => "rpcode",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
oidcRPMetaDataOptionsAccessTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsBypassConsent => 1,
|
||||
oidcRPMetaDataOptionsAllowClientCredentialsGrant => 1,
|
||||
oidcRPMetaDataOptionsAllowPasswordGrant => 1,
|
||||
oidcRPMetaDataOptionsRedirectUris => "http://test",
|
||||
oidcRPMetaDataOptionsRule =>
|
||||
'$_oidc_grant_type eq "authorizationcode"',
|
||||
},
|
||||
rppassword => {
|
||||
oidcRPMetaDataOptionsDisplayName => "RP",
|
||||
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsClientID => "rppassword",
|
||||
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
|
||||
oidcRPMetaDataOptionsClientSecret => "rppassword",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
oidcRPMetaDataOptionsAccessTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsBypassConsent => 1,
|
||||
oidcRPMetaDataOptionsAllowClientCredentialsGrant => 1,
|
||||
oidcRPMetaDataOptionsAllowPasswordGrant => 1,
|
||||
oidcRPMetaDataOptionsRedirectUris => "http://test",
|
||||
oidcRPMetaDataOptionsRule =>
|
||||
'$_oidc_grant_type eq "password"',
|
||||
},
|
||||
rpclient => {
|
||||
oidcRPMetaDataOptionsDisplayName => "RP",
|
||||
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsClientID => "rpclient",
|
||||
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
|
||||
oidcRPMetaDataOptionsClientSecret => "rpclient",
|
||||
oidcRPMetaDataOptionsUserIDAttr => "",
|
||||
oidcRPMetaDataOptionsAccessTokenExpiration => 3600,
|
||||
oidcRPMetaDataOptionsBypassConsent => 1,
|
||||
oidcRPMetaDataOptionsAllowClientCredentialsGrant => 1,
|
||||
oidcRPMetaDataOptionsAllowPasswordGrant => 1,
|
||||
oidcRPMetaDataOptionsRedirectUris => "http://test",
|
||||
oidcRPMetaDataOptionsRule =>
|
||||
'$_oidc_grant_type eq "clientcredentials"',
|
||||
},
|
||||
},
|
||||
oidcServicePrivateKeySig => oidc_key_op_private_sig,
|
||||
oidcServicePublicKeySig => oidc_key_op_public_sig,
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user