Last active
September 25, 2018 18:34
-
-
Save kraih/a1f793dfd1aeafcf7f9fd86d8416f7dd to your computer and use it in GitHub Desktop.
Bits and pieces that will hopefully some day become an OpenID plugin for Mojolicious (with alternative dummy backend for testing and token backend for API users)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp::Controller::Auth; | |
use Mojo::Base 'Mojolicious::Controller'; | |
sub check { | |
my $self = shift; | |
my $role = $self->stash('role'); | |
my $user = $self->current_user; | |
# User needs to log in or a different role | |
$self->render('permissions', status => 403) and return undef | |
unless $user && $self->users->has_role($user, $role); | |
return 1; | |
} | |
sub logout { | |
my $self = shift; | |
delete $self->session->{user}; | |
$self->redirect_to('dashboard'); | |
} | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp::Controller::Auth::Dummy; | |
use Mojo::Base 'Mojolicious::Controller'; | |
sub login { | |
my $self = shift; | |
my $user = $self->users->find_or_create( | |
login => 'tester', | |
email => '[email protected]', | |
fullname => 'Dummy Test User', | |
roles => ['manager', 'admin'] | |
); | |
$self->session(user => $user->{login}); | |
$self->redirect_to('dashboard'); | |
} | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp; | |
use Mojo::Base 'Mojolicious'; | |
... | |
sub startup { | |
my $self = shift; | |
... | |
# Authentication | |
my $public = $self->routes; | |
my $bot = $public->under('/')->to('Auth::Token#check'); | |
my $manager = $public->under('/' => {role => 'manager'})->to('Auth#check'); | |
my $admin = $public->under('/' => {role => 'admin'})->to('Auth#check'); | |
if ($config->{openid}) { | |
$public->get('/login')->to('Auth::OpenID#login')->name('login'); | |
$public->get('/openid')->to('Auth::OpenID#openid')->name('openid'); | |
$public->get('/response')->to('Auth::OpenID#response')->name('response'); | |
} | |
else { $public->get('/login')->to('Auth::Dummy#login')->name('login') } | |
$public->get('/logout')->to('Auth#logout')->name('logout'); | |
... | |
# Bot API | |
$bot->get(...)->...; | |
# Manager API | |
$manager->post(...)->...; | |
# Admin API | |
$admin->patch(...)->...; | |
... | |
} | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp::Controller::Auth::OpenID; | |
use Mojo::Base 'Mojolicious::Controller'; | |
use LWP::UserAgent; | |
use Net::OpenID::Consumer; | |
sub login { | |
my $self = shift; | |
$self->csrf_token; | |
$self->redirect_to('openid'); | |
} | |
sub openid { | |
my $self = shift; | |
my $base = $self->req->url->base->to_string; | |
my $csr = Net::OpenID::Consumer->new( | |
ua => LWP::UserAgent->new, | |
required_root => $base, | |
consumer_secret => $self->csrf_token | |
); | |
my $claimed_id | |
= $csr->claimed_identity($self->app->config->{openid}{provider}); | |
return $self->render(text => $csr->err, status => 403) unless $claimed_id; | |
$claimed_id->set_extension_args('http://openid.net/extensions/sreg/1.1', | |
{required => 'email', optional => 'fullname,nickname'}); | |
$claimed_id->set_extension_args( | |
'http://openid.net/srv/ax/1.0', | |
{ | |
mode => 'fetch_request', | |
required => 'email,fullname,nickname,firstname,lastname', | |
'type.email' => "http://schema.openid.net/contact/email", | |
'type.fullname' => "http://axschema.org/namePerson", | |
'type.nickname' => "http://axschema.org/namePerson/friendly", | |
'type.firstname' => 'http://axschema.org/namePerson/first', | |
'type.lastname' => 'http://axschema.org/namePerson/last' | |
} | |
); | |
my $check_url = $claimed_id->check_url( | |
delayed_return => 1, | |
return_to => $self->url_for('response')->to_abs->to_string, | |
trust_root => $base | |
); | |
return $self->redirect_to($check_url) if $check_url; | |
$self->render(text => $csr->err, status => 403); | |
} | |
sub response { | |
my $self = shift; | |
my $params = $self->req->url->query->to_hash; | |
my $base = $self->req->url->base->to_string; | |
my $csr = Net::OpenID::Consumer->new( | |
ua => LWP::UserAgent->new, | |
required_root => $base, | |
consumer_secret => $self->csrf_token, | |
args => $params | |
); | |
my ($error, $login, $email, $fullname); | |
$csr->handle_server_response( | |
not_openid => sub { $error = 'Not an OpenID message' }, | |
setup_needed => sub { $error = 'Setup not supported' }, | |
cancelled => sub { $error = 'Authentication cancelled' }, | |
verified => sub { | |
my $vident = shift; | |
my $sreg = $vident->signed_extension_fields( | |
'http://openid.net/extensions/sreg/1.1'); | |
my $ax = $vident->signed_extension_fields('http://openid.net/srv/ax/1.0'); | |
$error = 'Missing username' | |
unless $login = $sreg->{nickname} || $ax->{'value.nickname'}; | |
$email = $sreg->{email} || $ax->{'value.email'}; | |
$fullname = $sreg->{fullname} || $ax->{'value.fullname'}; | |
}, | |
error => sub { | |
my ($err, $txt) = @_; | |
$error = "$err: $txt"; | |
}, | |
); | |
return $self->render(text => $error, status => 403) if $error; | |
# Create in DB | |
my $user = $self->users->find_or_create( | |
login => $login, | |
email => $email, | |
fullname => $fullname | |
); | |
$self->session(user => $user->{login}); | |
$self->redirect_to('dashboard'); | |
} | |
1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package MyApp::Controller::Auth::Token; | |
use Mojo::Base 'Mojolicious::Controller'; | |
sub check { | |
my $self = shift; | |
my $tokens = $self->app->config('tokens'); | |
return 1 unless @$tokens; | |
$self->_denied and return undef | |
unless my $auth = $self->req->headers->authorization; | |
$self->_denied and return undef unless $auth =~ /^Token\ (\S+)$/; | |
my $token = $1; | |
$self->_denied and return undef unless grep { $token eq $_ } @$tokens; | |
return 1; | |
} | |
sub _denied { | |
my $self = shift; | |
$self->render('permissions', status => 403); | |
} | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment