File Coverage

blib/lib/Net/OAuth2/AuthorizationServer/PasswordGrant.pm
Criterion Covered Total %
statement 28 29 96.5
branch 5 6 83.3
condition 12 16 75.0
subroutine 10 11 90.9
pod 0 2 0.0
total 55 64 85.9


line stmt bran cond sub pod time code
1             package Net::OAuth2::AuthorizationServer::PasswordGrant;
2              
3             =head1 NAME
4              
5             Net::OAuth2::AuthorizationServer::PasswordGrant - OAuth2 Resource Owner Password Credentials Grant
6              
7             You "MUST NOT" use this grant type (see L)
8              
9             =head1 SYNOPSIS
10              
11             my $Grant = Net::OAuth2::AuthorizationServer::PasswordGrant->new(
12             clients => {
13             TrendyNewService => {
14             client_secret => 'TopSecretClientSecret',
15             scopes => {
16             post_images => 1,
17             annoy_friends => 1,
18             },
19             },
20             },
21             users => {
22             bob => 'j$s03R#!\fs',
23             tom => 'dE0@@s^tWg1',
24             },
25             );
26              
27             # verify a client and username against known clients/users
28             my ( $client_id,$error,$scopes,$username ) = $Grant->verify_user_password(
29             client_id => $client_id,
30             client_secret => $client_secret,
31             username => $username,
32             password => $password,
33             scopes => [ qw/ list of scopes / ],
34             );
35              
36             if ( ! $Grant->login_resource_owner ) {
37             # resource owner needs to login
38             ...
39             }
40              
41             # have resource owner confirm (and perhaps modify) scopes
42             my ( $confirmed,$error,$scopes_ref ) = $Grant->confirm_by_resource_owner(
43             client_id => $client_id,
44             scopes => [ qw/ list of scopes / ],
45             );
46              
47             # generate a token
48             my $token = $Grant->token(
49             client_id => $client_id,
50             scopes => $scopes_ref,
51             type => 'access', # one of: access, refresh
52             redirect_uri => $redirect_uri,
53             user_id => $user_id, # optional
54             jwt_claims_cb => sub { ... }, # optional, see jwt_claims_cb in Manual
55             );
56              
57             # store access token
58             $Grant->store_access_token(
59             client_id => $client,
60             access_token => $access_token,
61             refresh_token => $refresh_token,
62             scopes => $scopes_ref,
63             old_refresh_token => $old_refresh_token,
64             );
65              
66             # verify an access token
67             my ( $is_valid,$error ) = $Grant->verify_access_token(
68             access_token => $access_token,
69             scopes => $scopes_ref,
70             is_refresh_token => 0,
71             );
72              
73             # or:
74             my ( $oauth_details,$error ) = $Grant->verify_token_and_scope(
75             refresh_token => $refresh_token,
76             auth_header => $http_authorization_header,
77             );
78              
79             =head1 DESCRIPTION
80              
81             This module implements the OAuth2 "Resource Owner Password Credentials Grant" flow as described
82             at L.
83              
84             =head1 CONSTRUCTOR ARGUMENTS
85              
86             Along with those detailed at L
87             the following are supported by this grant type:
88              
89             =head2 users
90              
91             A hashref of client details keyed like so:
92              
93             $username => $password
94              
95             =head1 CALLBACK FUNCTIONS
96              
97             The following callbacks are supported by this grant type:
98              
99             login_resource_owner_cb
100             confirm_by_resource_owner_cb
101             verify_client_cb
102             verify_user_password_cb
103             store_access_token_cb
104             verify_access_token_cb
105              
106             Please see L for
107             documentation on each callback function.
108              
109             =cut
110              
111 3     3   1554 use strict;
  3         8  
  3         93  
112 3     3   18 use warnings;
  3         6  
  3         78  
113              
114 3     3   1064 use Moo;
  3         22982  
  3         19  
115             with 'Net::OAuth2::AuthorizationServer::Defaults';
116              
117 3     3   3469 use Carp qw/ croak /;
  3         7  
  3         172  
118 3     3   1120 use Types::Standard qw/ :all /;
  3         154907  
  3         35  
119              
120             has 'verify_user_password_cb' => (
121             is => 'ro',
122             isa => Maybe [CodeRef],
123             required => 0,
124             );
125              
126             has 'users' => (
127             is => 'ro',
128             isa => Maybe [HashRef],
129             required => 0,
130             default => sub { {} },
131             );
132              
133              
134 12     12   77 sub _uses_auth_codes { 0 };
135 0     0   0 sub _uses_user_passwords { 1 };
136              
137 1 50 50 1   3 sub _has_users { return keys %{ shift->users // {} } ? 1 : 0 }
  1         21  
138              
139             sub BUILD {
140 6     6 0 349 my ( $self, $args ) = @_;
141              
142 6 100 33     30 if (
143             # if we don't have a list of clients
144             !$self->_has_clients
145              
146             # and we don't have a list of users
147             and !$self->_has_users
148              
149             # we must know how to verify clients and tokens
150             and ( !$args->{ verify_client_cb }
151             and !$args->{ verify_user_password_cb }
152             and !$args->{ store_access_token_cb }
153             and !$args->{ verify_access_token_cb } )
154             )
155             {
156 1         18 croak __PACKAGE__ . " requires either clients or overrides";
157             }
158             }
159              
160             sub verify_user_password {
161 20     20 0 42720 _delegate_to_cb_or_private( 'verify_user_password', @_ );
162             }
163              
164             sub _verify_user_password {
165 20     20   73 my ( $self, %args ) = @_;
166              
167             my ( $client_id, $client_secret, $username, $password, $scopes ) =
168 20         65 @args{ qw/ client_id client_secret username password scopes / };
169              
170 20   100     107 my $client = $self->clients->{ $client_id }
171             || return ( 0, 'unauthorized_client' );
172              
173 16 100 66     179 if ( !exists( $self->clients->{ $client_id } )
      100        
      100        
174             or !exists( $self->users->{ $username } )
175             or ( $client_secret ne $self->clients->{ $client_id }{ client_secret } )
176             or ( $password ne $self->users->{ $username } )
177             ) {
178 12         81 return ( 0, 'invalid_grant' );
179             }
180             else {
181             return (
182             {
183 4         40 client_id => $client_id,
184             scopes => $scopes,
185             username => $username
186             },
187             undef,
188             $scopes, # here for back compat
189             $username, # here for back compat
190             );
191             }
192              
193             }
194              
195             =head1 AUTHOR
196              
197             Lee Johnson - C
198              
199             =head1 LICENSE
200              
201             This library is free software; you can redistribute it and/or modify it under
202             the same terms as Perl itself. If you would like to contribute documentation
203             or file a bug report then please raise an issue / pull request:
204              
205             https://github.com/Humanstate/net-oauth2-authorizationserver
206              
207             =cut
208              
209             __PACKAGE__->meta->make_immutable;