File Coverage

blib/lib/LogicMonitor/REST/Signature.pm
Criterion Covered Total %
statement 52 58 89.6
branch 10 16 62.5
condition n/a
subroutine 9 9 100.0
pod 2 3 66.6
total 73 86 84.8


line stmt bran cond sub pod time code
1             package LogicMonitor::REST::Signature;
2              
3 2     2   143517 use 5.006;
  2         17  
4 2     2   18 use strict;
  2         4  
  2         53  
5 2     2   11 use warnings;
  2         4  
  2         77  
6 2     2   1179 use Time::HiRes qw( gettimeofday );
  2         2814  
  2         11  
7 2     2   1502 use Crypt::Mac::HMAC qw( hmac_hex );
  2         22717  
  2         129  
8 2     2   1062 use MIME::Base64;
  2         1457  
  2         1203  
9              
10             =head1 NAME
11              
12             LogicMonitor::REST::Signature - Generate signatures and authheader info for the Logicmonitor REST API.
13              
14             =head1 VERSION
15              
16             Version 0.0.1
17              
18             =cut
19              
20             our $VERSION = '0.0.1';
21              
22             =head1 SYNOPSIS
23              
24             use LogicMonitor::REST::Signature;
25            
26             my $company = 'someCompany';
27             my $accessKey = 'some key';
28             my $accessID = 'some id';
29            
30             my $lmsig_helper;
31             eval {
32             $lmsig_helper = LogicMonitor::REST::Signature->new(
33             {
34             company => $company,
35             accessID => $accessID,
36             accessKey => $accessKey,
37             }
38             );
39             } if ( !defined($lmsig_helper) ) {
40             die( "Failed to initial the module... " . $@ );
41             }
42            
43             my $sig;
44             eval{
45             $sig=$lmsig_helper->signature({
46             HTTPverb=>'GET',
47             path=>/foo/bar',
48             data=>'foo foo',
49             });
50             };
51             if (!defined($sig)){
52             die("Failed to generate the signature... ".$@);
53             }
54              
55             =head1 VARIABLES
56              
57             This is a basic explanation of various variables used in this doc.
58              
59             =head2 accessID
60              
61             This is the accessID for the key.
62              
63             =head2 accessKey
64              
65             This is the API key.
66              
67             =head2 company
68              
69             This is the company name as shown in the URL.
70              
71             =head2 HTTPverb
72              
73             This is the HTTP verb for the request in question... so either GET or PUT.
74              
75             =head2 path
76              
77             This is the path and any variables in the URL.
78              
79             'https://' . $company . '.logicmonitor.com/santaba/rest' . $path
80              
81             =head2 data
82              
83             The body of the HTTP request. Can be '', if doing like a GET.
84              
85             =head2 timestamp
86              
87             Milliseconds since epoc.
88              
89             use Time::HiRes qw( gettimeofday );
90             my $timestamp = gettimeofday * 1000;
91             $timestamp = int($timestamp);
92              
93             =head1 METHODS
94              
95             =head2 new
96              
97             This requires a hash ref with the following three variables.
98              
99             accessID
100             accessKey
101              
102             Example...
103              
104             my $lmsig_helper;
105             eval {
106             $lmsig_helper = LogicMonitor::REST::Signature->new(
107             {
108             accessID => $accessID,
109             accessKey => $accessKey,
110             }
111             );
112             } if ( !defined($lmsig_helper) ) {
113             die( "Failed to initial the module... " . $@ );
114             }
115              
116             =cut
117              
118             sub new {
119 2     2 1 633 my $args=$_[1];
120 2 50       8 if ( !defined( $_[1] ) ) {
121 0         0 die('No argument hash ref passed');
122             }
123              
124             # list of required keys
125 2         7 my $args_valid_keys = {
126             # company => 1,
127             accessID => 1,
128             accessKey => 1,
129             };
130              
131             #make sure all the keys required are present
132 2         5 foreach my $args_key ( keys( %{$args_valid_keys} ) ) {
  2         9  
133 3 100       9 if ( !defined( $args->{$args_key} ) ) {
134 1         12 die( 'The key "' . $args_key . '" is not present in the args hash ref' );
135             }
136             }
137              
138             my $self = {
139             # company => $args->{company},
140             accessID => $args->{accessID},
141             accessKey => $args->{accessKey},
142 1         5 };
143 1         3 bless $self;
144              
145 1         4 return $self;
146             }
147              
148             =head2 signature
149              
150             This generates the signature for a request.
151              
152             This requires variables below.
153              
154             HTTPverb
155             timestamp
156             path
157              
158             If data is not specified, it is assumed to be ''.
159              
160             data
161              
162             Example...
163              
164             my $sig;
165             eval{
166             $sig=$lmsig_helper->signature({
167             HTTPverb=>'GET',
168             path=>/foo/bar',
169             timestamp=>'1234',
170             });
171             };
172             if (!defined($sig)){
173             die("Failed to generate the signature... ".$@);
174             }
175              
176             =cut
177              
178             sub signature {
179 3     3 1 630 my $self = $_[0];
180 3         6 my $args=$_[1];
181 3 50       9 if ( !defined( $_[1] ) ) {
182 0         0 die('No argument hash ref passed');
183             }
184              
185             # a list of all required keys
186 3         10 my $args_valid_keys = {
187             HTTPverb => 1,
188             path => 1,
189             timestamp => 1,
190             };
191              
192             # make sure are the required variables are present
193 3         4 foreach my $args_key ( keys( %{$args_valid_keys} ) ) {
  3         12  
194 9 50       22 if ( !defined( $args->{$args_key} ) ) {
195 0         0 die( 'The key "' . $args_key . '" is not present in the args hash ref' );
196             }
197             }
198              
199             # If not specified, assume it is a request it is not needed for and set it to blank.
200 3 100       20 if ( !defined( $args->{data} ) ) {
201 1         4 $args->{data} = '';
202             }
203              
204             # put together the string that will be used for the signature
205             # https://www.logicmonitor.com/support/rest-api-developers-guide/overview/using-logicmonitors-rest-api#ss-header-24
206 3         11 my $string = $args->{HTTPverb} . $args->{timestamp} . $args->{data} . $args->{path};
207              
208             # create the signature and return it
209 3         6 my $sig;
210 3         6 eval {
211 3         68 $sig = encode_base64( hmac_hex( 'SHA256', $self->{accessKey}, $string ) );
212 3         19 $sig =~ s/\n//g;
213 3 50       10 if ( !defined($sig) ) {
214 0         0 die('hmac_b64 returned undef');
215             }
216             };
217 3 50       10 if ($@) {
218 0         0 die( 'Failed to generate the signature... ' . $@ );
219             }
220              
221 3         12 return $sig;
222             }
223              
224             =sub auth_header
225              
226             Generates the auth header. The usage is similiar to signature, but this does not
227             need a timestamp specified.
228              
229             This requires variables below.
230              
231             HTTPverb
232             path
233              
234             If data is not specified, it is assumed to be ''.
235              
236             data
237              
238             Example...
239              
240             my $auth_header;
241             eval{
242             $sig=$lmsig_helper->auth_header({
243             HTTPverb=>'GET',
244             path=>/foo/bar',
245             });
246             };
247             if (!defined($sig)){
248             die("Failed to generate the auth header... ".$@);
249             }
250              
251             =cut
252              
253             sub auth_header{
254 1     1 0 317 my $self = $_[0];
255 1         2 my $args=$_[1];
256 1 50       4 if ( !defined( $_[1] ) ) {
257 0         0 die('No argument hash ref passed');
258             }
259              
260 1         9 my $timestamp = gettimeofday * 1000;
261 1         4 $timestamp = int($timestamp);
262              
263 1         3 $args->{timestamp}=$timestamp;
264              
265 1         5 my $header='LMv1 '.$self->{accessID}.':'.$self->signature($args).':'.$timestamp;
266              
267 1         3 return $header;
268             }
269              
270             =head1 AUTHOR
271              
272             Zane C. Bowers-Hadley, C<< >>
273              
274             =head1 BUGS
275              
276             Please report any bugs or feature requests to C, or through
277             the web interface at L. I will be notified, and then you'll
278             automatically be notified of progress on your bug as I make changes.
279              
280              
281              
282              
283             =head1 SUPPORT
284              
285             You can find documentation for this module with the perldoc command.
286              
287             perldoc LogicMonitor::REST::Signature
288              
289              
290             You can also look for information at:
291              
292             =over 4
293              
294             =item * RT: CPAN's request tracker (report bugs here)
295              
296             L
297              
298             =item * CPAN Ratings
299              
300             L
301              
302             =item * Search CPAN
303              
304             L
305              
306             =item * GIT Repo
307              
308             L
309              
310             =back
311              
312              
313             =head1 ACKNOWLEDGEMENTS
314              
315              
316             =head1 LICENSE AND COPYRIGHT
317              
318             This software is Copyright (c) 2020 by Zane C. Bowers-Hadley.
319              
320             This is free software, licensed under:
321              
322             The Artistic License 2.0 (GPL Compatible)
323              
324              
325             =cut
326              
327             1; # End of LogicMonitor::REST::Signature