Skip to content

Commit baf6838

Browse files
committed
Create two Catalyst auth realms (::UsernamePassword and ::APIKey)
1 parent a9ce86d commit baf6838

File tree

8 files changed

+115
-43
lines changed

8 files changed

+115
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package Catalyst::Authentication::Credential::MediaWords::APIKey;
2+
3+
#
4+
# Authenticate users with API key.
5+
#
6+
7+
use strict;
8+
use warnings;
9+
10+
use Moose;
11+
use namespace::autoclean;
12+
13+
with 'MooseX::Emulate::Class::Accessor::Fast';
14+
15+
use Catalyst::Exception ();
16+
use Readonly;
17+
18+
__PACKAGE__->mk_accessors( qw/realm/ );
19+
20+
use MediaWords::DBI::Auth::Login;
21+
22+
# API key parameter
23+
Readonly our $API_KEY_FIELD => 'key';
24+
25+
sub new
26+
{
27+
my ( $class, $config, $app, $realm ) = @_;
28+
29+
my $self = {};
30+
bless $self, $class;
31+
32+
$self->realm( $realm );
33+
34+
return $self;
35+
}
36+
37+
sub authenticate
38+
{
39+
my ( $self, $c, $realm, $authinfo ) = @_;
40+
41+
my $db = $c->dbis;
42+
43+
my $api_key = $authinfo->{ $API_KEY_FIELD };
44+
my $ip_address = $c->request_ip_address();
45+
46+
if ( $api_key and $ip_address )
47+
{
48+
49+
my $user;
50+
eval { $user = MediaWords::DBI::Auth::Login::login_with_api_key( $db, $api_key, $ip_address ); };
51+
unless ( $@ or ( !$user ) )
52+
{
53+
my $user_obj = $realm->find_user( { username => $user->email() }, $c );
54+
if ( ref( $user_obj ) )
55+
{
56+
return $user_obj;
57+
}
58+
}
59+
}
60+
61+
if ( $c->debug )
62+
{
63+
$c->log->debug( 'Unable to locate user matching user info provided in realm: ' . $realm->name );
64+
}
65+
66+
return undef;
67+
}
68+
69+
__PACKAGE__;

lib/Catalyst/Authentication/Credential/MediaWords.pm lib/Catalyst/Authentication/Credential/MediaWords/UsernamePassword.pm

+10-15
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
package Catalyst::Authentication::Credential::MediaWords;
1+
package Catalyst::Authentication::Credential::MediaWords::UsernamePassword;
22

33
#
4-
# Media Cloud Catalyst credentials package, uses ::DBI::Auth to do the authentication.
5-
#
6-
# Adapted from Catalyst::Authentication::Credential::Password.
4+
# Authenticate users with username and password.
75
#
86

97
use strict;
@@ -42,23 +40,20 @@ sub authenticate
4240

4341
my $db = $c->dbis;
4442

45-
## because passwords may be in a hashed format, we have to make sure that we remove the
46-
## password_field before we pass it to the user routine, as some auth modules use
47-
## all data passed to them to find a matching user...
48-
my $userfindauthinfo = { %{ $authinfo } };
49-
delete( $userfindauthinfo->{ $PASSWORD_FIELD } );
43+
my $username = $authinfo->{ $USERNAME_FIELD };
44+
my $password = $authinfo->{ $PASSWORD_FIELD };
5045

51-
my $user_obj = $realm->find_user( $userfindauthinfo, $c );
52-
if ( ref( $user_obj ) )
53-
{
54-
my $username = $authinfo->{ $USERNAME_FIELD };
55-
my $password = $authinfo->{ $PASSWORD_FIELD };
46+
if ( $username and $password ) {
5647

5748
my $user;
5849
eval { $user = MediaWords::DBI::Auth::Login::login_with_email_password( $c->dbis, $username, $password ); };
5950
unless ( $@ or ( !$user ) )
6051
{
61-
return $user_obj;
52+
my $user_obj = $realm->find_user( { username => $user->email() }, $c );
53+
if ( ref( $user_obj ) )
54+
{
55+
return $user_obj;
56+
}
6257
}
6358
}
6459

lib/MediaWords.pm

+13-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use MediaWords::Util::Config;
1414
use MediaWords::DBI::Auth::Roles;
1515

1616
use Net::IP;
17+
use Readonly;
1718
use URI;
1819

1920
# Set flags and add plugins for the application
@@ -54,15 +55,23 @@ use HTML::FormFu::Unicode;
5455

5556
my $config = __PACKAGE__->config( -name => 'MediaWords' );
5657

58+
# Authentication realms
59+
Readonly our $AUTH_REALM_USERNAME_PASSWORD => 'mc_auth_realm_username_password';
60+
Readonly our $AUTH_REALM_API_KEY => 'mc_auth_realm_api_key';
61+
5762
# Configure authentication scheme
5863
__PACKAGE__->config( 'Plugin::Static::Simple' => { dirs => [ 'gexf', 'nv' ] } );
5964
__PACKAGE__->config(
6065
'Plugin::Authentication' => {
61-
'default_realm' => 'users',
62-
'users' => {
63-
'credential' => { 'class' => 'MediaWords' },
66+
'default_realm' => $AUTH_REALM_USERNAME_PASSWORD,
67+
$AUTH_REALM_USERNAME_PASSWORD => {
68+
'credential' => { 'class' => 'MediaWords::UsernamePassword' },
6469
'store' => { 'class' => 'MediaWords' }
65-
}
70+
},
71+
$AUTH_REALM_API_KEY => {
72+
'credential' => { 'class' => 'MediaWords::APIKey' },
73+
'store' => { 'class' => 'MediaWords' }
74+
},
6675
}
6776
);
6877

lib/MediaWords/ActionRole/AbstractAuthenticatedActionRole.pm

+11-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use namespace::autoclean;
1616
use Data::Dumper;
1717
use HTTP::Status qw(:constants);
1818

19+
use Catalyst::Authentication::Credential::MediaWords::APIKey;
1920
use MediaWords::DBI::Auth;
2021

2122
# test whether the authenticated user has $permission_type access to the topic in the path of the currently requested
@@ -94,12 +95,16 @@ sub _user_email_and_roles($$)
9495
{
9596
my ( $self, $c ) = @_;
9697

98+
my $db = $c->dbis;
99+
97100
my $user_email = undef;
98101
my @user_roles;
99102

100-
# 1. If the request has the "key" parameter, force authenticating via API
103+
my $api_key_param = $Catalyst::Authentication::Credential::MediaWords::APIKey::API_KEY_FIELD;
104+
105+
# 1. If the request has the API key parameter, force authenticating via API
101106
# key (even if the user is logged in)
102-
if ( $c->request->param( 'key' ) )
107+
if ( $c->request->param( $api_key_param ) )
103108
{
104109

105110
my $api_auth = undef;
@@ -109,7 +114,10 @@ sub _user_email_and_roles($$)
109114
}
110115
else
111116
{
112-
$api_auth = MediaWords::DBI::Auth::Login::login_with_api_key_catalyst( $c );
117+
if ( $c->authenticate( { key => $c->request->param( $api_key_param ) }, $MediaWords::AUTH_REALM_API_KEY ) )
118+
{
119+
$api_auth = MediaWords::DBI::Auth::Profile::user_info( $db, $c->user->username );
120+
}
113121
}
114122

115123
if ( $api_auth )

lib/MediaWords/Controller/Api/V2/Auth.pm

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ sub profile : Local
9797
my $db = $c->dbis;
9898

9999
my $userinfo;
100-
eval { $userinfo = MediaWords::DBI::Auth::Login::login_with_api_key_catalyst( $c ); };
100+
eval { $userinfo = MediaWords::DBI::Auth::Profile::user_info( $db, $c->user->username ); };
101101
if ( $@ or ( !$userinfo ) )
102102
{
103103
die "Unable to find user for given API key.";

lib/MediaWords/Controller/Api/V2/Media.pm

+2-2
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ sub submit_suggestion_GET
494494
my $feed_url = $data->{ feed_url } || 'none';
495495
my $reason = $data->{ reason } || 'none';
496496

497-
my $user = MediaWords::DBI::Auth::Login::login_with_api_key_catalyst( $c );
497+
my $user = MediaWords::DBI::Auth::Profile::user_info( $db, $c->user->username );
498498
my $auth_users_id = $user->id();
499499

500500
$db->begin;
@@ -586,7 +586,7 @@ sub mark_suggestion_PUT
586586

587587
my $db = $c->dbis;
588588

589-
my $user = MediaWords::DBI::Auth::Login::login_with_api_key_catalyst( $c );
589+
my $user = MediaWords::DBI::Auth::Profile::user_info( $db, $c->user->username );
590590
my $auth_users_id = $user->id();
591591

592592
die( "status must be pending, approved, or rejected" )

lib/MediaWords/Controller/Login.pm

+9-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,15 @@ sub index : Path : Args(0)
8585
}
8686

8787
# Attempt to log the user in
88-
if ( $c->authenticate( { username => $email, password => $password } ) )
88+
if (
89+
$c->authenticate(
90+
{
91+
username => $email,
92+
password => $password,
93+
},
94+
$MediaWords::AUTH_REALM_USERNAME_PASSWORD
95+
)
96+
)
8997
{
9098
if ( $form->params->{ referer } )
9199
{

lib/MediaWords/DBI/Auth/Login.pm

-17
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ use Readonly;
1414

1515
use MediaWords::DBI::Auth::Profile;
1616

17-
# API key HTTP GET parameter
18-
Readonly my $API_KEY_PARAMETER => 'key';
19-
2017
# Post-unsuccessful login delay (in seconds)
2118
Readonly my $POST_UNSUCCESSFUL_LOGIN_DELAY => 1;
2219

@@ -244,18 +241,4 @@ SQL
244241
return $user;
245242
}
246243

247-
# Fetch user object for the API key, using Catalyst's object.
248-
# Only active users are fetched.
249-
# die()s on error
250-
sub login_with_api_key_catalyst($)
251-
{
252-
my $c = shift;
253-
254-
my $db = $c->dbis;
255-
my $api_key = $c->request->param( $API_KEY_PARAMETER . '' );
256-
my $ip_address = $c->request_ip_address();
257-
258-
return login_with_api_key( $db, $api_key, $ip_address );
259-
}
260-
261244
1;

0 commit comments

Comments
 (0)