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 )