File Coverage

blib/lib/Azure/AD/ClientCredentialsV2.pm
Criterion Covered Total %
statement 15 33 45.4
branch 0 8 0.0
condition n/a
subroutine 5 9 55.5
pod 1 1 100.0
total 21 51 41.1


line stmt bran cond sub pod time code
1             package Azure::AD::ClientCredentialsV2;
2 1     1   1073 use Moo;
  1         2  
  1         6  
3 1     1   273 use Azure::AD::Errors;
  1         1  
  1         33  
4 1     1   5 use Types::Standard qw/Str Int InstanceOf/;
  1         1  
  1         9  
5 1     1   689 use JSON::MaybeXS;
  1         2  
  1         56  
6 1     1   6 use HTTP::Tiny;
  1         1  
  1         558  
7              
8             our $VERSION = '0.01';
9              
10             has ua_agent => (
11             is => 'ro',
12             isa => Str,
13             default => sub {
14             'Azure::AD::ClientCredentialsV2 ' . $Azure::AD::ClientCredentialsV2::VERSION
15             }
16             );
17              
18             has ua => (
19             is => 'rw',
20             required => 1,
21             lazy => 1,
22             default => sub {
23             my $self = shift;
24             HTTP::Tiny->new(
25             agent => $self->ua_agent,
26             timeout => 60,
27             );
28             }
29             );
30              
31             has scope => (
32             is => 'ro',
33             isa => Str,
34             required => 1,
35             );
36              
37             has tenant_id => (
38             is => 'ro',
39             isa => Str,
40             required => 1,
41             default => sub {
42             $ENV{AZURE_TENANT_ID}
43             }
44             );
45              
46             has client_id => (
47             is => 'ro',
48             isa => Str,
49             required => 1,
50             default => sub {
51             $ENV{AZURE_CLIENT_ID}
52             }
53             );
54              
55             has secret_id => (
56             is => 'ro',
57             isa => Str,
58             required => 1,
59             default => sub {
60             $ENV{AZURE_SECRET_ID}
61             }
62             );
63              
64             has ad_url => (
65             is => 'ro',
66             isa => Str,
67             default => sub {
68             'https://login.microsoftonline.com'
69             },
70             );
71              
72             has token_endpoint => (
73             is => 'ro',
74             isa => Str,
75             lazy => 1,
76             default => sub {
77             my $self = shift;
78             sprintf "%s/%s/oauth2/v2.0/token", $self->ad_url, $self->tenant_id;
79             }
80             );
81              
82             sub access_token {
83 0     0 1   my $self = shift;
84 0           $self->_refresh;
85 0           $self->current_creds->{ access_token };
86             }
87              
88             has current_creds => (is => 'rw');
89              
90             has expiration => (
91             is => 'rw',
92             isa => Int,
93             lazy => 1,
94             default => sub { 0 }
95             );
96              
97             sub _refresh_from_cache {
98 0     0     my $self = shift;
99             #TODO: implement caching strategy
100 0           return undef;
101             }
102              
103             sub _save_to_cache {
104 0     0     my $self = shift;
105             #TODO: implement caching strategy
106             }
107              
108             sub _refresh {
109 0     0     my $self = shift;
110              
111 0 0         if (not defined $self->current_creds) {
112 0           $self->_refresh_from_cache;
113 0 0         return $self->current_creds if (defined $self->current_creds);
114             }
115              
116 0 0         return if $self->expiration >= time;
117              
118 0           my $auth_response = $self->ua->post_form(
119             $self->token_endpoint,
120             {
121             grant_type => 'client_credentials',
122             client_id => $self->client_id,
123             client_secret => $self->secret_id,
124             scope => $self->scope,
125             }
126             );
127              
128 0 0         if (not $auth_response->{success}) {
129             Azure::AD::RemoteError->throw(
130             message => $auth_response->{content},
131             code => 'GetClientCredentialsFailed',
132             status => $auth_response->{status}
133 0           );
134             }
135              
136 0           my $auth = decode_json($auth_response->{content});
137 0           $self->current_creds($auth);
138 0           $self->expiration($auth->{expires_in} + time);
139 0           $self->_save_to_cache;
140             }
141              
142             1;
143              
144             =encoding UTF-8
145              
146             =head1 NAME
147              
148             Azure::AD::ClientCredentialsV2 - Azure AD Client Credentials authentication flow
149              
150             =head1 SYNOPSIS
151              
152             use Azure::AD::ClientCredentialsV2;
153             my $creds = Azure::AD::ClientCredentialsV2->new(
154             resource_id => 'https://management.core.windows.net/',
155             client_id => '',
156             secret_id => '',
157             tenant_id => '',
158             );
159             say $creds->access_token;
160              
161             =head1 DESCRIPTION
162              
163             Implements the Azure AD Client Credentials flow using the V2 Oauth endpoint. See L for more
164             information and alternative flows.
165              
166             =head1 ATTRIBUTES
167              
168             =head2 scope
169              
170             Defines the set of permissions being requested by the application. Scopes can be either static (using .default) or dynamic. This set can include the OpenID Connect scopes (openid, profile, email). If you need application permissions, you must use .default to request the statically configured list of permissions.
171              
172             =head2 tenant_id
173              
174             The ID of the Azure Active Directory Tenant that you want to request permission from. It can be provided in a GUID or friendly name format.
175              
176             =head2 client_id
177              
178             The Client ID (also referred to as the Application ID) of an application
179              
180             =head2 secret_id
181              
182             A Key assigned to the Client Id.
183              
184             =head2 ad_url
185              
186             This defaults to C, and generally doesn't need to
187             be specified. Azure AD has more endpoints for some clouds:
188              
189             C China Cloud
190              
191             C US Gov Cloud
192              
193             C German Cloud
194              
195             =head1 METHODS
196              
197             =head2 access_token
198              
199             Returns the access token that has to be sent to the APIs you want to access. This
200             is normally sent in the Authentication header of HTTPS requests as a Bearer token.
201              
202             The access_token is cached in the object as long as it's valid, so subsequent calls
203             to access_token will return the appropiate token without reauthenticating to Azure AD.
204             If the token has expired, access_token will call Azure AD to obtain a new token transparently.
205              
206             Example usage:
207              
208             my $auth = Azure::AD::ClientCredentialsV2->new(...);
209              
210             use HTTP::Tiny;
211             my $ua = HTTP::Tiny->new;
212             my $response = $ua->get(
213             'http://aservice.com/orders/list',
214             {
215             headers => { Authorization => 'Bearer ' . $auth->access_token }
216             }
217             );
218              
219             =head1 SEE ALSO
220              
221             L
222              
223             =head1 COPYRIGHT and LICENSE
224              
225             Copyright (c) 2020 by Jose Luis Martinez
226              
227             This code is distributed under the Apache 2 License. The full text of the
228             license can be found in the LICENSE file included with this module.
229              
230             =cut