Ado

 view release on metacpan or  search on metacpan

lib/Ado/Plugin/Auth.pm  view on Meta::CPAN

    if ($val->csrf_protect->has_error('csrf_token')) {
        delete $c->session->{csrf_token};
        $c->render(error_login => 'Bad CSRF token!', status => 403, template => 'login');
        return '';
    }
    my $_checks = Ado::Model::Users->CHECKS;
    $val->required('login_name')->like($_checks->{login_name}{allow});
    $val->required('digest')->like(qr/^[0-9a-f]{40}$/);
    if ($val->has_error) {
        delete $c->session->{csrf_token};
        return '';
    }

    #2. find the user and do logical checks
    my $login_name = $val->param('login_name');
    my $user       = Ado::Model::Users->by_login_name($login_name);
    if ((not $user->id) or $user->disabled) {
        delete $c->session->{csrf_token};
        $c->stash(error_login_name => "No such user '$login_name'!");
        return '';
    }

    #3. really authnticate the user
    my $checksum = Mojo::Util::sha1_hex($c->session->{csrf_token} . $user->login_password);
    if ($checksum eq $val->param('digest')) {
        $c->session(login_name => $user->login_name);
        $c->user($user);
        $c->app->log->info('$user ' . $user->login_name . ' logged in!');
        delete $c->session->{csrf_token};
        return 1;
    }

    $c->debug('We should not be here! - wrong password') if $Ado::Control::DEV_MODE;
    delete $c->session->{csrf_token};
    return '';
}

#used as helper within login()
# this method is called as return_url after the user
# agrees or denies access for the application
sub _login_google {
    my ($c) = @_;
    state $app = $c->app;
    my $provider  = $c->param('auth_method');
    my $providers = $app->config('Ado::Plugin::Auth')->{providers};

    #second call should get the token it self
    my $response = $c->oauth2->get_token($provider, $providers->{$provider});
    do {
        $c->debug("in _login_google \$response: " . $c->dumper($response));
        $c->debug("in _login_google error from provider: " . ($c->param('error') || 'no error'));
    } if $Ado::Control::DEV_MODE;
    if ($response->{access_token}) {    #Athenticate, create and login the user.
        return _create_or_authenticate_google_user(
            $c,
            $response->{access_token},
            $providers->{$provider}
        );
    }
    else {
        #Redirect to front-page and say sorry
        # We are very sorry but we need to know you are a reasonable human being.
        $c->flash(error_login => $c->l('oauth2_sorry[_1]', ucfirst($provider))
              . ($c->param('error') || ''));
        $c->app->log->error('error_response:' . $c->dumper($response));
        $c->res->code(307);    #307 Temporary Redirect
        $c->redirect_to('/');
    }
    return;
}

#used as helper within login()
# this method is called as return_url after the user
# agrees or denies access for the application
sub _login_facebook {
    my ($c) = @_;
    state $app = $c->app;
    my $provider  = $c->param('auth_method');
    my $providers = $app->config('Ado::Plugin::Auth')->{providers};

    #second call should get the token it self
    my $response = $c->oauth2->get_token($provider, $providers->{$provider});
    do {
        $c->debug("in _login_facebook \$response: " . $c->dumper($response));
        $c->debug(
            "in _login_facebook error from provider: " . ($c->param('error') || 'no error'));
    } if $Ado::Control::DEV_MODE;
    if ($response->{access_token}) {    #Athenticate, create and login the user.
        return _create_or_authenticate_facebook_user(
            $c,
            $response->{access_token},
            $providers->{$provider}
        );
    }
    else {
        #Redirect to front-page and say sorry
        # We are very sorry but we need to know you are a reasonable human being.
        $c->flash(error_login => $c->l('oauth2_sorry[_1]', ucfirst($provider))
              . ($c->param('error') || ''));
        $c->app->log->error('error_response:' . $c->dumper($response));
        $c->res->code(307);    #307 Temporary Redirect
        $c->redirect_to('/');
    }
    return;

}

sub _authenticate_oauth2_user {
    my ($c, $user, $time) = @_;
    if (   $user->disabled
        || ($user->stop_date != 0 && $user->stop_date < $time)
        || $user->start_date > $time)
    {
        $c->flash(login_message => $c->l('oauth2_disabled'));
        $c->redirect_to('/');
        return;
    }
    $c->session(login_name => $user->login_name);
    $c->user($user);
    $c->app->log->info('$user ' . $user->login_name . ' logged in!');
    return 1;
}

#Creates a user using given info from provider
sub _create_oauth2_user {
    my ($c, $user_info, $provider) = @_;
    state $app = $c->app;
    if (my $user = Ado::Model::Users->add(_user_info_to_args($user_info, $provider))) {
        $app->plugins->emit_hook(after_user_add => $c, $user, $user_info);
        $c->user($user);
        $c->session(login_name => $user->login_name);
        $app->log->info($user->description . ' New $user ' . $user->login_name . ' logged in!');
        $c->flash(login_message => $c->l('oauth2_wellcome[_1]', $user->name));
        $c->redirect_to('/');
        return 1;
    }
    $app->log->error($@);
    return;
}

#next two methods
#(_create_or_authenticate_facebook_user and _create_or_authenticate_google_user)
# exist only because we pass different parameters in the form
# which are specific to the provider.
# TODO: think of a way to map the generation of the form arguments to the
# specific provider so we can dramatically reduce the number of provider
# specific subroutines
sub _create_or_authenticate_facebook_user {
    my ($c, $access_token, $provider) = @_;
    my $ua = Mojo::UserAgent->new;
    my $appsecret_proof = Digest::SHA::hmac_sha256_hex($access_token, $provider->{secret});
    $c->debug('$appsecret_proof:' . $appsecret_proof);
    my $user_info =
      $ua->get($provider->{info_url},
        form => {access_token => $access_token, appsecret_proof => $appsecret_proof})->res->json;
    $c->debug('Response from info_url:' . $c->dumper($user_info)) if $Ado::Control::DEV_MODE;



( run in 0.670 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )