WWW-Suffit-API
view release on metacpan or search on metacpan
lib/WWW/Suffit/Server/API/Auth.pm view on Meta::CPAN
# Access (username is optional; b,m,url,p,i,r will be got from controller)
my $has_access = $authdb->access(
c => $self,
u => $username,
k => $cachekey,
);
unless ($has_access) {
$self->reply->json_error($authdb->code, $authdb->error || "E1004: Access denied by realm restrictions");
return;
}
# Ok
return 1;
}
sub authorize {
my $self = shift;
$self->timing->begin('suffit_authorize');
my $token_type = $self->stash('token_type') || '';
my $skip_authdb_connect = $self->stash('skip_authdb_connect') ? 1 : 0;
my $username = $self->param('username') // $self->req->json('/username') // '';
my $password = $self->param('password') // $self->req->json('/password') // '';
my $encrypted = is_true_flag($self->param('encrypted') // $self->req->json('/encrypted')) || 0;
my $remember = is_true_flag($self->param('remember') // $self->req->json('/remember')) || 0;
my $cachekey = $self->param('cachekey') // $self->req->json('/cachekey') // $self->app->gen_cachekey;
# md5(User-Agent . Remote-Address)
my $ip = $self->client_ip($self->app->trustedproxies);
my $clientid = $self->param('clientid') // $self->req->json('/clientid')
|| md5_sum(sprintf("%s%s", $self->req->headers->header('User-Agent') // 'unknown', $ip));
# Get Referer from flash or header
my $href = $self->req->headers->header("Referer") // '';
my $referer = $self->flash("referer") // ($href ? Mojo::URL->new($href)->path->to_string // '' : '');
$referer =~ s/\/authorize//;
$self->stash(referer => $referer);
# Get authdb instance
my $authdb = $self->authdb;
return $self->reply->json_error(500 => "E1005" => "The authorization database is not ready") unless $authdb;
# Connect to AuthDB (optional)
if (!$skip_authdb_connect) {
$authdb->connect;
if ($authdb->error) {
return $self->reply->json_error(500 => $authdb->error);
} elsif (!$authdb->initialized) {
return $self->reply->json_error(500 => "E1307" => "The authorization database is not initialized");
}
}
# Token type
return $self->reply->json_error(400 => "E1020" => "Incorrect token type. Allowed: session, access, refresh, api")
unless grep {$token_type eq $_} (qw/session access refresh api/);
# Please provide username and password for authorization
return $self->reply->json_error(401 => "E1021" => "No username specified") unless length($username);
return $self->reply->json_error(401 => "E1022" => "No password specified") unless length($password);
# Password decrypt
if ($encrypted && length($password)) {
my $rsa = WWW::Suffit::RSA->new(private_key => $self->app->private_key);
$password = $rsa->decrypt($password);
return $self->reply->json_error(500 => "E1023" => $rsa->error) if $rsa->error; # RSA decrypt error
}
# Authentication
$authdb->authn(
u => $username,
p => $password,
a => $ip, # For check by stats
k => $cachekey,
) or return $self->reply->json_error($authdb->code, $authdb->error); # Unauthenticated (incorrect username or password)
# Authorization
my $user = $authdb->authz(
u => $username,
's' => 0,
k => $cachekey,
);
return $self->reply->json_error($authdb->code, $authdb->error) unless $user; # Unauthorized (Access denied)
# Generate token: access, session, api, etc.
my $jwt = $self->jwt;
my $jws_algorithm = $authdb->meta("jws_algorithm") || $self->conf->latest("/jws_algorithm") || '';
$jwt->algorithm($jws_algorithm) if length $jws_algorithm;
# Expires
my $now = time(); # NOW
my $tokenexpires = $authdb->meta("tokenexpires") || parse_time_offset($self->conf->latest("/tokenexpires")) || TOKEN_EXPIRATION;
my $exp = $now + ($remember ? TOKEN_EXPIRE_MAX : $tokenexpires);
if ($token_type eq 'api') {
$exp = $user->forever ? undef : ($now + TOKEN_EXPIRATION * 365);
}
my $jti = sprintf("%s%s", randchars(8), $self->req->request_id);
$jwt->expires($exp);
$jwt->iat($now)->jti($jti)->payload({
ver => $self->app->VERSION,
typ => $token_type,
usr => $username,
ip => $ip,
cid => $clientid,
$cachekey ? (key => $cachekey) : (),
});
# Issue (generate)
my $token = $jwt->encode->token;
return $self->reply->json_error(500 => "E1024" => $jwt->error || "Can't JWT generate") unless $token; # Can't JWT generation
# Store token
$authdb->token_set(
type => $token_type,
jti => $jti,
username => $username,
clientid => $clientid,
iat => $now,
exp => $exp || 0,
address => $ip,
) or return $self->reply->json_error($authdb->code, $authdb->error || "E1025: Can't token store to database"); # Can't store token data
# Ok
return $self->reply->json_ok({
( run in 1.010 second using v1.01-cache-2.11-cpan-39bf76dae61 )