Implement GitHub logins
Requires the following configuration options enable_github_login = 1 github_client_id github_client_secret Or github_client_secret_file which points to a file with the secret
This commit is contained in:
parent
bde8d81876
commit
bbd4891133
|
@ -30,6 +30,8 @@ sub noLoginNeeded {
|
|||
return $whitelisted ||
|
||||
$c->request->path eq "api/push-github" ||
|
||||
$c->request->path eq "google-login" ||
|
||||
$c->request->path eq "github-redirect" ||
|
||||
$c->request->path eq "github-login" ||
|
||||
$c->request->path eq "login" ||
|
||||
$c->request->path eq "logo" ||
|
||||
$c->request->path =~ /^static\//;
|
||||
|
|
|
@ -4,6 +4,7 @@ use utf8;
|
|||
use strict;
|
||||
use warnings;
|
||||
use base 'Hydra::Base::Controller::REST';
|
||||
use File::Slurp;
|
||||
use Crypt::RandPasswd;
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use Hydra::Helper::Nix;
|
||||
|
@ -154,6 +155,57 @@ sub google_login :Path('/google-login') Args(0) {
|
|||
doEmailLogin($self, $c, "google", $data->{email}, $data->{name} // undef);
|
||||
}
|
||||
|
||||
sub github_login :Path('/github-login') Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
error($c, "Logging in via GitHub is not enabled.") unless $c->config->{enable_github_login};
|
||||
my $client_id = $c->config->{github_client_id} or die "github_client_id not configured.";
|
||||
my $client_secret = $c->config->{github_client_secret} // do {
|
||||
my $client_secret_file = $c->config->{github_client_secret_file} or die "github_client_secret nor github_client_secret_file is configured.";
|
||||
my $client_secret = read_file($client_secret_file);
|
||||
$client_secret =~ s/\s+//;
|
||||
$client_secret;
|
||||
};
|
||||
die "No github secret configured" unless $client_secret;
|
||||
|
||||
my $ua = new LWP::UserAgent;
|
||||
my $response = $ua->post(
|
||||
'https://github.com/login/oauth/access_token',
|
||||
{
|
||||
client_id => $client_id,
|
||||
client_secret => $client_secret,
|
||||
code => ($c->req->params->{code} // die "No token."),
|
||||
}, Accept => 'application/json');
|
||||
error($c, "Did not get a response from GitHub.") unless $response->is_success;
|
||||
|
||||
my $data = decode_json($response->decoded_content) or die;
|
||||
my $access_token = $data->{access_token} // die "No access_token in response from GitHub.";
|
||||
|
||||
$response = $ua->get('https://api.github.com/user', Authorization => "token $access_token");
|
||||
error($c, "Did not get a response from GitHub for user info.") unless $response->is_success;
|
||||
|
||||
$data = decode_json($response->decoded_content) or die;
|
||||
doEmailLogin($self, $c, "github", $data->{email}, $data->{name} // undef);
|
||||
|
||||
$c->res->redirect($c->uri_for($c->res->cookies->{'after_github'}));
|
||||
}
|
||||
|
||||
sub github_redirect :Path('/github-redirect') Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
||||
error($c, "Logging in via GitHub is not enabled.") unless $c->config->{enable_github_login};
|
||||
my $client_id = $c->config->{github_client_id} or die "github_client_id not configured.";
|
||||
|
||||
my $after = "/" . $c->req->params->{after};
|
||||
|
||||
$c->res->cookies->{'after_github'} = {
|
||||
name => 'after_github',
|
||||
value => $after,
|
||||
};
|
||||
|
||||
$c->res->redirect("https://github.com/login/oauth/authorize?client_id=$client_id");
|
||||
}
|
||||
|
||||
|
||||
sub captcha :Local Args(0) {
|
||||
my ($self, $c) = @_;
|
||||
|
|
|
@ -136,6 +136,10 @@
|
|||
<li><a href="#" id="google-signin">Sign in with Google</a></li>
|
||||
<li class="divider"></li>
|
||||
[% END %]
|
||||
[% IF c.config.enable_github_login %]
|
||||
<li><a href="/github-redirect?after=[% c.req.path %]">Sign in with GitHub</a></li>
|
||||
<li class="divider"></li>
|
||||
[% END %]
|
||||
<li>
|
||||
<a href="#hydra-signin" data-toggle="modal">Sign in with a Hydra account</a>
|
||||
</li>
|
||||
|
|
|
@ -11,7 +11,7 @@ sub showHelp {
|
|||
print <<EOF;
|
||||
Usage: $0 NAME
|
||||
[--rename-from NAME]
|
||||
[--type hydra|google]
|
||||
[--type hydra|google|github]
|
||||
[--full-name FULLNAME]
|
||||
[--email-address EMAIL-ADDRESS]
|
||||
[--password PASSWORD]
|
||||
|
@ -49,8 +49,8 @@ GetOptions("rename-from=s" => \$renameFrom,
|
|||
die "$0: one user name required\n" if scalar @ARGV != 1;
|
||||
my $userName = $ARGV[0];
|
||||
|
||||
die "$0: type must be `hydra' or `google'\n"
|
||||
if defined $type && $type ne "hydra" && $type ne "google";
|
||||
die "$0: type must be `hydra', `google' or `github'\n"
|
||||
if defined $type && $type ne "hydra" && $type ne "google" && $type ne "github";
|
||||
|
||||
my $db = Hydra::Model::DB->new();
|
||||
|
||||
|
@ -67,19 +67,19 @@ $db->txn_do(sub {
|
|||
{ username => $userName, type => "hydra", emailaddress => "", password => "!" });
|
||||
}
|
||||
|
||||
die "$0: Google user names must be email addresses\n"
|
||||
if $user->type eq "google" && $userName !~ /\@/;
|
||||
die "$0: Google or GitHub user names must be email addresses\n"
|
||||
if ($user->type eq "google" || $user->type eq "github") && $userName !~ /\@/;
|
||||
|
||||
$user->update({ type => $type }) if defined $type;
|
||||
|
||||
$user->update({ fullname => $fullName eq "" ? undef : $fullName }) if defined $fullName;
|
||||
|
||||
if ($user->type eq "google") {
|
||||
die "$0: Google accounts do not have an explicitly set email address.\n"
|
||||
if ($user->type eq "google" || $user->type eq "github") {
|
||||
die "$0: Google and GitHub accounts do not have an explicitly set email address.\n"
|
||||
if defined $emailAddress;
|
||||
die "$0: Google accounts do not have a password.\n"
|
||||
die "$0: Google and GitHub accounts do not have a password.\n"
|
||||
if defined $password;
|
||||
die "$0: Google accounts do not have a password.\n"
|
||||
die "$0: Google and GitHub accounts do not have a password.\n"
|
||||
if defined $passwordHash;
|
||||
$user->update({ emailaddress => $userName, password => "!" });
|
||||
} else {
|
||||
|
|
|
@ -10,7 +10,7 @@ create table Users (
|
|||
emailAddress text not null,
|
||||
password text not null, -- sha256 hash
|
||||
emailOnError integer not null default 0,
|
||||
type text not null default 'hydra', -- either "hydra" or "google"
|
||||
type text not null default 'hydra', -- either "hydra", "google" or "github"
|
||||
publicDashboard boolean not null default false
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue