Merge branch 'fix-oauth2-handler-2167' into 'v2.0'
Change OAuth2 handler behavior to conform to RFC See merge request lemonldap-ng/lemonldap-ng!139
This commit is contained in:
commit
00a0aac46a
|
@ -64,7 +64,7 @@ server {
|
|||
# If CDA is used, uncomment this
|
||||
#auth_request_set $cookie_value $upstream_http_set_cookie;
|
||||
#add_header Set-Cookie $cookie_value;
|
||||
# Remove this for AuthBasic handler
|
||||
# Remove this for AuthBasic and OAuth2 handlers
|
||||
error_page 401 $lmlocation;
|
||||
|
||||
##################################
|
||||
|
|
|
@ -2,7 +2,7 @@ package Lemonldap::NG::Handler::Lib::OAuth2;
|
|||
|
||||
use strict;
|
||||
|
||||
our $VERSION = '2.0.4';
|
||||
our $VERSION = '2.0.8';
|
||||
|
||||
sub retrieveSession {
|
||||
my ( $class, $req, $id ) = @_;
|
||||
|
@ -88,7 +88,11 @@ sub fetchId {
|
|||
return "O-$_session_id";
|
||||
}
|
||||
|
||||
return $class->Lemonldap::NG::Handler::Main::fetchId($req);
|
||||
my $value = $class->Lemonldap::NG::Handler::Main::fetchId($req);
|
||||
unless ($value) {
|
||||
$req->data->{oauth2_error} = 'invalid_token';
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
## @rmethod protected hash getOIDCInfos(id)
|
||||
|
@ -123,4 +127,18 @@ sub getOIDCInfos {
|
|||
return $infos;
|
||||
}
|
||||
|
||||
## The OAuth2 handler does not redirect, we simply return a 401 with relevant
|
||||
# information as described in https://tools.ietf.org/html/rfc6750#section-3
|
||||
sub goToPortal {
|
||||
my ( $class, $req, $url, $arg, $path ) = @_;
|
||||
|
||||
my $oauth2_error = '';
|
||||
if ( $req->data->{oauth2_error} ) {
|
||||
$oauth2_error = ' error="' . $req->data->{oauth2_error} . '"';
|
||||
}
|
||||
$class->set_header_out( $req,
|
||||
'WWW-Authenticate' => "Bearer" . $oauth2_error );
|
||||
return $class->HTTP_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
use Test::More;
|
||||
|
||||
BEGIN {
|
||||
require 't/test-psgi-lib.pm';
|
||||
}
|
||||
|
||||
my $maintests = 10;
|
||||
|
||||
init(
|
||||
'Lemonldap::NG::Handler::Server',
|
||||
{
|
||||
logLevel => 'error',
|
||||
vhostOptions => {
|
||||
'test1.example.com' => {
|
||||
vhostHttps => 0,
|
||||
vhostPort => 80,
|
||||
vhostMaintenance => 0,
|
||||
vhostServiceTokenTTL => -1,
|
||||
},
|
||||
},
|
||||
exportedHeaders => {
|
||||
'test1.example.com' => {
|
||||
'Auth-User' => '$uid',
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Inject an on-line access token session
|
||||
Lemonldap::NG::Common::Session->new( {
|
||||
storageModule => 'Apache::Session::File',
|
||||
storageModuleOptions => { Directory => 't/sessions' },
|
||||
id =>
|
||||
'f0fd4e85000ce35d062f97f5b466fc00abc2fad0406e03e086605f929ec4a249',
|
||||
force => 1,
|
||||
kind => 'OIDCI',
|
||||
info => {
|
||||
"user_session_id" => $sessionId,
|
||||
"_type" => "access_token",
|
||||
"_utime" => time,
|
||||
"rp" => "rp-example2",
|
||||
"scope" => "openid email"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Inject an offline access token session
|
||||
Lemonldap::NG::Common::Session->new( {
|
||||
storageModule => 'Apache::Session::File',
|
||||
storageModuleOptions => { Directory => 't/sessions' },
|
||||
id => '999888777',
|
||||
force => 1,
|
||||
kind => 'OIDCI',
|
||||
info => {
|
||||
"offline_session_id" => '000999000',
|
||||
"_type" => "refresh_token",
|
||||
"_utime" => time,
|
||||
"rp" => "rp-example",
|
||||
"scope" => "openid email"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Inject the refresh token containing user attributes
|
||||
Lemonldap::NG::Common::Session->new( {
|
||||
storageModule => 'Apache::Session::File',
|
||||
storageModuleOptions => { Directory => 't/sessions' },
|
||||
id => '000999000',
|
||||
force => 1,
|
||||
kind => 'OIDCI',
|
||||
info => {
|
||||
"_type" => "refresh_token",
|
||||
"_utime" => time,
|
||||
"rp" => "rp-example2",
|
||||
"scope" => "openid email",
|
||||
'groups' => 'users; timelords',
|
||||
'uid' => 'dwho',
|
||||
'cn' => 'Doctor Who',
|
||||
'hGroups' => {
|
||||
'users' => {},
|
||||
'timelords' => {}
|
||||
},
|
||||
'ipAddr' => '127.0.0.1',
|
||||
'mail' => 'dwho@badwolf.org',
|
||||
'authenticationLevel' => 1,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Request without Access Token
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test', undef, 'test1.example.com', '', VHOSTTYPE => 'OAuth2',
|
||||
),
|
||||
'Unauthenticated request to OAuth2 URL'
|
||||
);
|
||||
|
||||
# Check headers
|
||||
%h = @{ $res->[1] };
|
||||
is( $h{'WWW-Authenticate'}, 'Bearer', 'Got WWW-Authenticate: Bearer' );
|
||||
|
||||
# Request with invalid Access Token
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test', undef,
|
||||
'test1.example.com', '',
|
||||
VHOSTTYPE => 'OAuth2',
|
||||
HTTP_AUTHORIZATION => 'Bearer 123',
|
||||
),
|
||||
'Invalid access token'
|
||||
);
|
||||
|
||||
# Check headers
|
||||
%h = @{ $res->[1] };
|
||||
like(
|
||||
$h{'WWW-Authenticate'},
|
||||
qr#Bearer.*error="invalid_token"#,
|
||||
'Got invalid token error'
|
||||
);
|
||||
|
||||
# Request with valid Access Token
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test', undef,
|
||||
'test1.example.com', '',
|
||||
VHOSTTYPE => 'OAuth2',
|
||||
HTTP_AUTHORIZATION =>
|
||||
'Bearer f0fd4e85000ce35d062f97f5b466fc00abc2fad0406e03e086605f929ec4a249',
|
||||
),
|
||||
'Invalid access token'
|
||||
);
|
||||
|
||||
# Check headers
|
||||
%h = @{ $res->[1] };
|
||||
is( $res->[0], 200, "Request accepted" );
|
||||
ok( $h{'Auth-User'} eq 'dwho', 'Header Auth-User is set to "dwho"' )
|
||||
or explain( \%h, 'Auth-User => "dwho"' );
|
||||
|
||||
# Request with Access token from offline session
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test', undef,
|
||||
'test1.example.com', '',
|
||||
VHOSTTYPE => 'OAuth2',
|
||||
HTTP_AUTHORIZATION => 'Bearer 999888777',
|
||||
),
|
||||
'Invalid access token'
|
||||
);
|
||||
|
||||
# Check headers
|
||||
%h = @{ $res->[1] };
|
||||
is( $res->[0], 200, "Request accepted" );
|
||||
ok( $h{'Auth-User'} eq 'dwho', 'Header Auth-User is set to "dwho"' )
|
||||
or explain( \%h, 'Auth-User => "dwho"' );
|
||||
|
||||
count($maintests);
|
||||
done_testing( count() );
|
||||
clean();
|
|
@ -41,48 +41,53 @@ sub init {
|
|||
);
|
||||
ok( $client->app, 'App object' ) or explain( $client, '->app...' );
|
||||
count(3);
|
||||
open F, ">$file"
|
||||
or die $!;
|
||||
|
||||
my $now = time;
|
||||
my $ts = strftime "%Y%m%d%H%M%S", localtime;
|
||||
|
||||
print F <<EOF;
|
||||
{
|
||||
"_startTime" : "$ts",
|
||||
"_session_kind" : "SSO",
|
||||
"UA" : "Mozilla/5.0 (X11; VAX4000; rv:43.0) Gecko/20100101 Firefox/143.0 Iceweasel/143.0.1",
|
||||
"cn" : "Doctor Who",
|
||||
"_utime" : $now,
|
||||
"_whatToTrace" : "dwho",
|
||||
"mail" : "dwho\@badwolf.org",
|
||||
"_passwordDB" : "Demo",
|
||||
"_lastAuthnUTime" : $now,
|
||||
"uid" : "dwho",
|
||||
"_issuerDB" : "Null",
|
||||
"_userDB" : "Demo",
|
||||
"_user" : "dwho",
|
||||
"_session_id" : "f5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545",
|
||||
"authenticationLevel" : 1,
|
||||
"_auth" : "Demo",
|
||||
"_updateTime" : "$ts",
|
||||
"_loginHistory" : {
|
||||
"successLogin" : [
|
||||
{
|
||||
"ipAddr" : "127.0.0.1",
|
||||
"_utime" : $now
|
||||
}
|
||||
]
|
||||
},
|
||||
"ipAddr" : "127.0.0.1",
|
||||
"_timezone" : "1",
|
||||
"groups" : "users; timelords",
|
||||
"hGroups" : {
|
||||
"users" : {},
|
||||
"timelords" : {}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
close F;
|
||||
my $sessionData = {
|
||||
'_timezone' => '1',
|
||||
'groups' => 'users; timelords',
|
||||
'uid' => 'dwho',
|
||||
'_loginHistory' => {
|
||||
'successLogin' => [ {
|
||||
'_utime' => $now,
|
||||
'ipAddr' => '127.0.0.1'
|
||||
}
|
||||
]
|
||||
},
|
||||
'cn' => 'Doctor Who',
|
||||
'_lastAuthnUTime' => $now,
|
||||
'_whatToTrace' => 'dwho',
|
||||
'_issuerDB' => 'Null',
|
||||
'_startTime' => "$ts",
|
||||
'_user' => 'dwho',
|
||||
'_updateTime' => "$ts",
|
||||
'_userDB' => 'Demo',
|
||||
'hGroups' => {
|
||||
'users' => {},
|
||||
'timelords' => {}
|
||||
},
|
||||
'ipAddr' => '127.0.0.1',
|
||||
'mail' => 'dwho@badwolf.org',
|
||||
'authenticationLevel' => 1,
|
||||
'_utime' => $now,
|
||||
'_passwordDB' => 'Demo',
|
||||
'_auth' => 'Demo',
|
||||
'UA' =>
|
||||
'Mozilla/5.0 (X11; VAX4000; rv:43.0) Gecko/20100101 Firefox/143.0 Iceweasel/143.0.1'
|
||||
};
|
||||
|
||||
my $as = Lemonldap::NG::Common::Session->new( {
|
||||
storageModule => 'Apache::Session::File',
|
||||
storageModuleOptions => { Directory => 't/sessions' },
|
||||
id => $sessionId,
|
||||
force => 1,
|
||||
kind => 'SSO',
|
||||
info => $sessionData,
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
sub client {
|
||||
|
@ -109,7 +114,8 @@ sub explain {
|
|||
}
|
||||
|
||||
sub clean {
|
||||
unlink $file;
|
||||
unlink glob 't/sessions/*';
|
||||
unlink glob 't/sessions/lock/*';
|
||||
}
|
||||
|
||||
package Lemonldap::NG::Handler::PSGI::Cli::Lib;
|
||||
|
|
Loading…
Reference in New Issue