use strict;
use warnings;
use Mojolicious::Lite;
plugin 'ClientIP';
plugin 'basic_auth_plus';
# sample data for authentication
my %accepted_IPs = ( '8.8.8.8' => 1 );
my %users = ( usr1 => 'pwd1', usr2 => 'pwd2');
# sample data to send back to client
my $text_a = 'Né più mai toccherò le sacre sponde';
my $text_b = 'ove il mio corpo fanciulletto giacque,';
# I expect all non specified routes to answer 404, right?
# get text_a. Steps 2) and 3) of the above description
get '/get_first' => sub {
my $self = shift;
my $remote_IP = $self->client_ip;
# check username and password
my ($href, $auth_ok) = $self->basic_auth(
realm => sub {
# @_ contains username and password
if ( exists $users{$_[0]} and $users{$_[0]} eq $_[1]){
# log the correct login
$self->log->info( "$_[0] from $remote_IP login OK" );
return 1;
}
}
);
# reject unwanted remote IP
unless ( exists $accepted_IPs{ $remote_IP } ){
# log unwanted IP
$self->log->warn( "$href->{username} logged from unwanted IP: $remote_IP" );
# reject the request
return $self->render(
status => 401,
text => 'unauthorized',
)
}
# process the request..
if ( $auth_ok ) {
# set the session cookie valid for 2 minutes
$self->session( expiration => 120, is_my_user_authenticated => 1 );
# log the action
$self->log->info( "sent TEXT_A to $remote_IP" );
# render TEXT_A
return $self->render(
status => 200,
text => $text_a,
);
}
# .. or reject it
else {
# log a failed attempt
$self->log->warn( "bad login attempt from valid IP $remote_IP using user $href->{username}" );
# reject
return $self->render(
status => 401,
text => 'unauthorized',
);
}
};
# get text_b. Steps 6) and 7) of the above description
get '/get_second' => sub {
my $self = shift;
my $remote_IP = $self->client_ip;
# check the previously set cookie session
if ( $self->session( 'is_my_user_authenticated') == 1 ) {
# expire the session cookie
$self->session( expires => 1, is_my_user_authenticated => 0 );
# log the action
$self->log->info( "sent TEXT_B to $remote_IP" );
# render TEXT_B
return $self->render(
status => 200,
text => $text_b,
);
}
else {
# log the action
$self->log->warn( "unexpected request of TEXT_B from $remote_IP: rejected ".
"authenticated: $self->session( 'is_my_user_authenticated') ".
"expiration: $self->session( 'expiration')");
# reject
return $self->render(
status => 401,
text => 'unauthorized',
);
}
};
app->start;
####
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
my $ua = LWP::UserAgent->new();
$ua->cookie_jar( {} );
print "FIRST REQUEST\n\n";
my $request = GET 'http://10.0.0.1/get_first';
$request->authorization_basic('usr1', 'pwd1');
my $response = $ua->request($request);
print $response->as_string();
sleep 3;
print "SECOND REQUEST\n\n";
my $request2 = GET 'http://10.0.0.1/get_second';
my $response2 = $ua->request($request2);
print $response2->as_string();
sleep 3;
print "\nATTENTION: next should fail..\n\n";
my $request3 = GET 'http://10.0.0.1/get_second';
my $response3 = $ua->request($request3);
print $response3->as_string();
##
##
FIRST REQUEST
HTTP/1.0 200 OK
Date: Mon, 15 Jun 2020 11:26:18 GMT
Date: Mon, 15 Jun 2020 11:26:18 GMT
Server: HTTP::Server::PSGI
Content-Length: 38
Content-Type: text/html;charset=UTF-8
Client-Date: Mon, 15 Jun 2020 11:26:20 GMT
Client-Peer: 10.0.0.1:80
Client-Response-Num: 1
Set-Cookie: mojolicious=eyJleHBpcmF0aW9uIjoxMjAsImV4cGlyZXMiOjE1OTIyMjA0OTgsImlzX215X3VzZXJfYXV0aGVudGljYXRlZCI6MX0---d9029065f9456259d6cfdb50c3adee1d4a2f3b65; expires=Mon, 15 Jun 2020 11:28:18 GMT; path=/; HttpOnly; SameSite=Lax
N├® pi├╣ mai toccher├▓ le sacre sponde
SECOND REQUEST
HTTP/1.0 200 OK
Date: Mon, 15 Jun 2020 11:26:21 GMT
Date: Mon, 15 Jun 2020 11:26:21 GMT
Server: HTTP::Server::PSGI
Content-Length: 38
Content-Type: text/html;charset=UTF-8
Client-Date: Mon, 15 Jun 2020 11:26:24 GMT
Client-Peer: 10.0.0.1:80
Client-Response-Num: 1
Set-Cookie: mojolicious=eyJleHBpcmF0aW9uIjoxMjAsImV4cGlyZXMiOjEsImlzX215X3VzZXJfYXV0aGVudGljYXRlZCI6MH0---2f2a402a06de6b37f1eac53b7cbb79d5e08f04e7; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/; HttpOnly; SameSite=Lax
ove il mio corpo fanciulletto giacque,
ATTENTION: next should fail..
HTTP/1.0 401 Unauthorized
Date: Mon, 15 Jun 2020 11:26:24 GMT
Date: Mon, 15 Jun 2020 11:26:24 GMT
Server: HTTP::Server::PSGI
Content-Length: 12
Content-Type: text/html;charset=UTF-8
Client-Date: Mon, 15 Jun 2020 11:26:27 GMT
Client-Peer: 10.0.0.1:80
Client-Response-Num: 1
Client-Warning: Missing Authenticate header
unauthorized
##
##
HTTP::Server::PSGI: Accepting connections at http://0:80/
[2020-06-15 13:26:18.41707] [29291] [debug] [MfmL-Zeg] GET "/get_first"
[2020-06-15 13:26:18.41765] [29291] [debug] [MfmL-Zeg] Routing to a callback
[2020-06-15 13:26:18.41810] [29291] [info] [MfmL-Zeg] usr1 from 8.8.8.8 login OK
[2020-06-15 13:26:18.41820] [29291] [debug] Your secret passphrase needs to be changed
[2020-06-15 13:26:18.41832] [29291] [info] [MfmL-Zeg] sent TEXT_A to 8.8.8.8
[2020-06-15 13:26:18.41865] [29291] [debug] [MfmL-Zeg] 200 OK (0.001575s, 634.921/s)
8.8.8.8 - - [15/Jun/2020:13:26:18 +0200] "GET /get_first HTTP/1.1" 200 - "-" "libwww-perl/6.26"
[2020-06-15 13:26:21.60148] [29291] [debug] [cC2TWI3Q] GET "/get_second"
[2020-06-15 13:26:21.60208] [29291] [debug] [cC2TWI3Q] Routing to a callback
[2020-06-15 13:26:21.60249] [29291] [info] [cC2TWI3Q] sent TEXT_B to 8.8.8.8
[2020-06-15 13:26:21.60272] [29291] [debug] [cC2TWI3Q] 200 OK (0.001234s, 810.373/s)
8.8.8.8 - - [15/Jun/2020:13:26:21 +0200] "GET /get_second HTTP/1.1" 200 - "-" "libwww-perl/6.26"
[2020-06-15 13:26:24.68206] [29291] [debug] [jscLU00Y] GET "/get_second"
[2020-06-15 13:26:24.68244] [29291] [debug] [jscLU00Y] Routing to a callback
Use of uninitialized value in numeric eq (==) at /root/srv01/srv01.pl line 74, line 755.
[2020-06-15 13:26:24.68275] [29291] [warn] [jscLU00Y] unexpected request of TEXT_B from 8.8.8.8: rejected authenticated: Mojolicious::Controller=HASH(0x316b0a0)->session( 'is_my_user_authenticated') expiration: Mojolicious::Controller=HASH(0x316b0a0)->session( 'expiration')
[2020-06-15 13:26:24.68341] [29291] [debug] [jscLU00Y] 401 Unauthorized (0.001321s, 757.002/s)
8.8.8.8 - - [15/Jun/2020:13:26:24 +0200] "GET /get_second HTTP/1.1" 401 - "-" "libwww-perl/6.26"