Skip to content

Commit

Permalink
OpenID Connect (OAuth 2.0) authentication Handler for ACT (references b…
Browse files Browse the repository at this point in the history
  • Loading branch information
coudot committed Nov 28, 2014
1 parent 5a6dcb5 commit 4c76bab
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ requires(
'Apache::Request' => 0,
'AppConfig' => 0,
'Clone' => 0,
'Crypt::SSLeay' => 0,
'DBI' => 0,
'DBD::Pg' => 1.22,
'Data::ICal' => '0.16', # Data::ICal::Entry::Event
Expand Down
179 changes: 179 additions & 0 deletions lib/Act/AuthOAuth.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package Act::AuthOAuth;

use strict;
use Apache::Constants qw(OK REDIRECT);

use Act::Config;
use Act::User;
use Act::Util;

use JSON::XS;
use LWP::UserAgent;
use MIME::Base64;
use URI::Escape;

use base qw(Act::Auth);

sub oauth_login ($$)
{
my ( $self, $r ) = @_;

my %args = $r->args;
my $destination = $args{destination};

# Send AuthN Request
my $authorization_uri = $Config->oauth2_authorizationuri;
my $response_type = uri_escape("code");
my $scope = uri_escape("openid profile email");
my $client_id = uri_escape($Config->oauth2_clientid);
my $redirect_uri = uri_escape($Config->oauth2_redirecturi);
my $state = uri_escape($destination);

my $redirect_url = $authorization_uri."?response_type=$response_type&client_id=$client_id&scope=$scope&redirect_uri=$redirect_uri&state=$state";

$r->log_error("Redirect user to $redirect_url");

$r->header_out('Location' => $redirect_url);

return REDIRECT;
}

sub oauth_login_callback ($$)
{
my ( $self, $r ) = @_;

# AuthN Response
my %args = $r->args;
my $code = $args{code};
my $state = $args{state};

$r->log_error("Code received: $code");

my $grant_type = "authorization_code";

my %form;
$form{"code"} = $code;
$form{"client_id"} = $Config->oauth2_clientid;
$form{"client_secret"} = $Config->oauth2_clientsecret;
$form{"redirect_uri"} = $Config->oauth2_redirecturi;
$form{"grant_type"} = $grant_type;

$r->log_error("POST token request on ".$Config->oauth2_tokenuri);

my $ua = new LWP::UserAgent;
my $response = $ua->post( $Config->oauth2_tokenuri, \%form,
"Content-Type" => 'application/x-www-form-urlencoded' );

if ( $response->is_error ) {
$r->log_error("Bad authorization response: " . $response->message);
$r->log_error($response->content);
return undef;
}

# Get access_token and id_token
my $content = $response->decoded_content;

my $json;
eval { $json = decode_json $content; };

if ($@) {
$r->log_error("Wrong JSON content");
return undef;
}

if ( $json->{error} ) {
$r->log_error("Error in token response:" . $json->{error});
return undef;
}

my $access_token = $json->{access_token};
my $id_token = $json->{id_token};

# Get ID token content
my ( $id_token_header, $id_token_payload, $id_token_signature ) = split( /\./, $id_token );

# TODO check JWT signature

my $id_token_payload_hash = decode_json( decode_base64 ( $id_token_payload ) );

# Get user email
my $email = $id_token_payload_hash->{email};

# Match with ACT user
my $user = Act::User->new( email => lc $email );
$user or do { $r->log_error("Unknown user"); return $self->login_form; };

$r->log_error("User found with email $email");

# user is authenticated - create a session
my $sid = Act::Util::create_session($user);

$self->send_cookie($sid);

$self->handle_cache;

my $destination = $state || "/";

$r->header_out("Location" => $destination);

return REDIRECT;
}

1;

__END__
=head1 NAME
Act::AuthOAuth - OpenID Connect authentication backend for Act
=head1 SYNOPSIS
This module allows to log user on an OpenID Connect provider.
=head2 How it works
User click on a link on the login page and is redirected to OpenID Connect Provider. He must
accept to share his information with Act, and is then redirected back. If a user account with
the corresponding email is found in Act, the user is logged in.
=head2 Add the link
Edit templates/login file to add this link:
<p><a href="OAUTHLOGIN?destination=[% destination %]">Log with your Google account</a></p>
=head2 Configure endpoints in Apache
Edit Act Apache configuration to add these 2 endpoints:
<Files OAUTHLOGIN>
AuthType Act::AuthOAuth
AuthName Act
SetHandler "perl-script"
PerlHandler Act::AuthOAuth->oauth_login
</Files>
<Files OAUTHLOGINCB>
AuthType Act::AuthOAuth
AuthName Act
SetHandler "perl-script"
PerlHandler Act::AuthOAuth->oauth_login_callback
</Files>
Do not forget to add at the top of the file:
PerlModule Act::AuthOAuth
=head2 Configure act.ini
Add this section to your act.ini file:
[oauth2]
clientid = [CLIENT_ID]
clientsecret = [CLIENT_SECRET]
redirecturi = http://[ACT_HOST]/[CONF]/OAUTHLOGINCB
authorizationuri = [AUTHORIZATION_ENDPOINT]
tokenuri = [TOKEN_ENDPOINT]
You need to register your Act application inside the OpenID Connect Provider to gather the
required configuration parameters.
=cut

0 comments on commit 4c76bab

Please sign in to comment.