File Coverage

blib/lib/Chef/Header.pm
Criterion Covered Total %
statement 65 137 47.4
branch 13 50 26.0
condition 0 12 0.0
subroutine 17 31 54.8
pod 1 1 100.0
total 96 231 41.5


line stmt bran cond sub pod time code
1             package Chef::Header;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Chef::Header - Class that will generate Chef::Headers
8              
9             =head1 VERSION
10              
11             1.0
12              
13             =cut
14              
15             $Chef::Header::VERSION = 1.0;
16              
17             my @base;
18             BEGIN {
19 4     4   5839 use File::Basename qw { dirname };
  4         10  
  4         17068  
20 4     4   54 use File::Spec::Functions qw { splitdir rel2abs };
  4         9  
  4         467  
21 4     4   262 @base = ( splitdir ( rel2abs ( dirname(__FILE__) ) ) );
22 4         115 pop @base; #Chef
23 4         92 push @INC, '/', @base;
24             };
25              
26 4     4   34 use parent qw { Chef };
  4         8  
  4         41  
27 4     4   1750 use Chef::Encoder;
  4         13  
  4         338  
28              
29             =pod
30              
31             =head1 DESCRIPTION
32              
33             This class inherites from Chef. This class will generate encrypted headers as described in the
34             L
35              
36             Once you call L
method it will load L class . Which will generate and fill up
37             User Agent with appropriate Chef Headrs as specified in the above documentation.
38              
39             =begin html
40              
41             +---------------+
42             | Chef::Header |
43             +-----------------------+
44             | Chef::Header::header |
45             +-----------------------------------+
46             | Chef::Header::header::chefheader |
47             +-----------------------------------+
48              
49             =end html
50              
51             =head2 header
52              
53             loads L class and returns an object.
54              
55             =head2 Methods of B> class
56              
57             =over
58              
59             =item Method( $Method )
60              
61             set internally to either 'GET' or 'POST'
62              
63             =item HashedPath ( $path )
64              
65             calcualtes hash of end point for chef
66              
67             =item XOpsContentHash ( $content )
68              
69             calculdates hash of the content
70              
71             =item XOpsUserId ( $class->name )
72              
73             initialized user-id field sets to the user_id or client-name.
74              
75             =item Host( $server )
76              
77             initialized Host parameter of UA to chef server
78              
79             =item XChefVersion ( $chef_server_version )
80              
81             initialized Chef server Version to use
82              
83             =item XOpsSign( $XOpsSign )
84              
85             initializes to 'version=1.0' as specified in the chef API documentation.
86              
87             =item XOpsTimestamp
88              
89             initialized the request timestamp for http request to now
90              
91             =item header
92              
93             returns all the headers
94              
95             =item hash
96              
97             returns hash of all the headers , initialized so far.
98              
99             =item header_to_string
100              
101             return a comma seperated list of keys and values of the header
102              
103             =back
104              
105             =cut
106            
107             sub header {
108 2     2 1 2534 my $class = shift;
109 2         8 my $param = {@_};
110            
111             package Chef::Header::header;
112              
113 4     4   182 use parent -norequire,qw { Chef::Header };
  4         7  
  4         33  
114            
115 2         1166 my $self = new Chef::Header::header();
116              
117 2         25 $self->_chef_encoder( new Chef::Encoder( 'private_key_file' => $class->private_key ) );
118            
119 2         13 $self->Method ($param->{'Method' });
120 2         13 $self->HashedPath ($param->{'Path' });
121 2         13 $self->XOpsContentHash ($param->{'Content' });
122             #$self->XOpsTimestamp ($param->{'X-Ops-Timestamp' });
123 2         318 $self->XOpsUserId ($class->name );
124            
125             #default_values
126             #$self->Accept ($param->{'Accept' });
127 1         29 $self->Host ($class->server );
128 1         19 $self->XChefVersion ($class->chef_version );
129 1         14 $self->XOpsSign ($param->{'XOpsSign' });
130 1         12 $self->Accept ($param->{'Accept' });
131              
132 1         30 return $self;
133            
134             sub _chef_encoder {
135 4     4   7 my $self = shift;
136 4         8 my $obj = shift;
137 4 100       35 $self->{'header_chef_encoder'} = $obj if defined $obj;
138 4         9 return $self->{'header_chef_encoder'};
139             }
140            
141             sub XOpsSign
142             {
143 1     1   3 my ($self, $x_ops_sign) = (@_);
144 1 50       9 $self->header->{'X-Ops-Sign'} = $x_ops_sign if defined $x_ops_sign;
145 1 50       6 $self->header->{'X-Ops-Sign'} = 'version=1.0;' unless
146             defined $self->header->{'X-Ops-Sign'};
147 1         7 return $self->header->{'X-Ops-Sign'};
148             }
149              
150             sub XChefVersion
151             {
152 1     1   2 my ($self, $x_chef_version) = (@_);
153 1 50       5 $self->header->{'X-Chef-Version'} = $x_chef_version if defined $x_chef_version;
154 1         54 return $self->header->{'X-Chef-Version'};
155             }
156              
157             sub Host
158             {
159 1     1   2 my ($self, $host) = (@_);
160 1 50       8 if( defined ($host) ){
161 0         0 $host =~ s/^(http|https):\/\/(.*)/$2/;
162 0         0 $self->header->{'Host'} = $host;
163             }
164 1         5 return $self->header->{'Host'};
165             }
166              
167             sub Accept
168             {
169 1     1   4 my ($self, $accept) = (@_);
170 1 50       17 $self->header->{'Accept'} = $method if defined $accept;
171 1 50       3 $self->header->{'Accept'} = 'application/json' unless
172             defined $self->header->{'Accept'};
173 1         8 return $self->header->{'Accept'};
174             }
175              
176             sub Method
177             {
178 2     2   8 my ($self, $method) = (@_);
179 2 50       9 $self->header->{'Method'} = $method if defined $method;
180 2         11 return $self->header->{'Method'};
181             }
182              
183             sub HashedPath
184             {
185 2     2   6 my ($self,$path) = (@_);
186            
187 2 50       9 if (defined ($path) )
188             {
189 0 0       0 my $end_point = ($path =~ m/^\//) ? $path : "/$path";
190 0         0 my $chef_encoder = $self->_chef_encoder();
191 0         0 $self->header->{'Hashed Path'} = $chef_encoder->sha1
192             ->digest( 'data' => $end_point );
193             }
194            
195 2         7 return $self->header->{'Hashed Path'};
196             }
197              
198             sub XOpsContentHash
199             {
200 2     2   6 my ($self,$content) = (@_);
201 2         8 my $chef_encoder = $self->_chef_encoder();
202            
203 2         13 $self->header->{'X-Ops-Content-Hash'} = $chef_encoder->sha1
204             ->digest( 'data' => $content );
205 2         101 return $self->header->{'X-Ops-Content-Hash'};
206             }
207            
208             sub XOpsTimestamp
209             {
210 0     0   0 my ($self,$x_ops_timestamp) = (@_);
211 0 0       0 $self->header->{'X-Ops-Timestamp'} = $x_ops_timestamp
212             if defined $x_ops_timestamp;
213            
214 0 0       0 if (!$self->header->{'X-Ops-Timestamp'}){
215 0         0 $self->header->{'X-Ops-Timestamp'} = `date -u "+%Y-%m-%dT%H:%M:%SZ"`;
216             }
217 0         0 chomp( $self->header->{'X-Ops-Timestamp'} );
218 0         0 return $self->header->{'X-Ops-Timestamp'};
219            
220             }
221              
222             sub XOpsUserId
223             {
224 1     1   9 my ($self,$x_ops_user_id) = (@_);
225 1 50       11 $self->header->{'X-Ops-UserId'} = $x_ops_user_id
226             if defined $x_ops_user_id;
227 1         6 return $self->header->{'X-Ops-UserId'};
228             }
229              
230             sub header
231             {
232 17     17   41 my $self = shift;
233 17 100       51 $self->{'header'} = {} unless defined $self->{'header'};
234 17         72 return $self->{'header'};
235             }
236              
237             sub hash{
238 0     0     my $self = shift;
239            
240             return {
241 0           'Accept' => $self->Accept ,
242             'Host' => $self->Host ,
243             'X-Chef-Version' => $self->XChefVersion ,
244             'X-Ops-Userid' => $self->XOpsUserId ,
245             'X-Ops-Timestamp' => $self->XOpsTimestamp,
246             'X-Ops-Sign' => $self->XOpsSign ,
247             'X-Ops-Content-Hash' => $self->XOpsContentHash,
248 0           %{$self->chef_header->XOpsAuthorization}
249             } ;
250             }
251              
252             sub header_to_string
253             {
254 0     0     my $self = shift;
255 0           return ( $self->{'header'} );
256             }
257            
258             =pod
259            
260             =head2 Methods of B>
261              
262             =over
263              
264             =item Method ( $method )
265              
266             initialized chefheader with $method . either 'GET' or 'POST'
267              
268             =item HashedPath ( $hashed_path )
269              
270             initializes hashed path and 'Hashed Path' heder value.
271              
272             =item XOpsContentHash ( $content_hash )
273              
274             initializes content hash and 'X-Ops-Content-Hash' header.
275              
276             =item XOpsTimestamp
277              
278             initializes X-Ops-Timestamp values
279              
280             =item XOpsUserId
281              
282             initialized X-Ops-UserId value
283              
284             =item XOpsAuthorization
285              
286             initializes X-Ops-Authorization-xxxx values . for more details refere to chef header API
287              
288             =item split_60
289              
290             split the heder in chuncks of 60 characters
291              
292             =item hash
293              
294             return chef_header in hash format
295              
296             =item to_string
297              
298             returns chef_header in string format . directly insertable to UserAgent headers.
299              
300             =back
301              
302             =cut
303            
304             #-----------------------------------------#
305             # class Chef::Header::header::chefheader #
306             #-----------------------------------------#
307              
308             sub chef_header {
309 0     0     my $class = shift;
310              
311             package Chef::Header::header::chefheader;
312            
313 0           my $self = {};
314 0           bless $self, qw { Chef::Header::header::chefheader };
315            
316 0           $self->_chef_encoder( $class->_chef_encoder );
317 0           $self->Method ( $class->Method );
318 0           $self->HashedPath ( $class->HashedPath );
319 0           $self->XOpsContentHash ( $class->XOpsContentHash );
320 0           $self->XOpsTimestamp ( $class->XOpsTimestamp );
321 0           $self->XOpsUserId ( $class->XOpsUserId );
322            
323 0           return $self;
324             sub _chef_encoder {
325 0     0     my $self = shift;
326 0           my $obj = shift;
327 0 0         $self->{'header_chef_encoder'} = $obj if defined $obj;
328 0           return $self->{'header_chef_encoder'};
329             }
330            
331             sub Method {
332 0     0     my ($self,$method) = (@_);
333 0 0         $self->{'chef_header'}->{'Method'} = $method if
334             defined $method;
335 0           return $self->{'chef_header'}->{'Method'};
336             }
337              
338             sub HashedPath {
339 0     0     my ($self,$hashed_path) = (@_);
340 0 0         $self->{'chef_header'}->{'Hashed Path'} = $hashed_path if
341             defined $hashed_path;
342 0           return $self->{'chef_header'}->{'Hashed Path'};
343             }
344              
345             sub XOpsContentHash {
346 0     0     my ($self,$x_ops_content_hash) = (@_);
347 0 0         $self->{'chef_header'}->{'X-Ops-Content-Hash'} = $x_ops_content_hash if
348             defined $x_ops_content_hash;
349 0           return $self->{'chef_header'}->{'X-Ops-Content-Hash'};
350             }
351              
352             sub XOpsTimestamp {
353 0     0     my ($self,$x_ops_Timestamp) = (@_);
354 0 0         $self->{'chef_header'}->{'X-Ops-Timestamp'} = $x_ops_Timestamp if
355             defined $x_ops_Timestamp;
356 0           return $self->{'chef_header'}->{'X-Ops-Timestamp'};
357             }
358              
359             sub XOpsUserId {
360 0     0     my ($self,$x_ops_user_id) = (@_);
361 0 0         $self->{'chef_header'}->{'X-Ops-UserId'} = $x_ops_user_id if
362             defined $x_ops_user_id;
363 0           return $self->{'chef_header'}->{'X-Ops-UserId'};
364             }
365              
366             sub hash {
367 0     0     my $self = shift;
368 0           return $self->{'chef_header'};
369             }
370            
371             sub to_string{
372 0     0     my $self = shift;
373 0 0 0       return undef unless defined $self->Method
      0        
      0        
      0        
374             && defined $self->HashedPath
375             && defined $self->XOpsContentHash
376             && defined $self->XOpsTimestamp
377             && defined $self->XOpsUserId;
378            
379 0           return join "\n", ( 'Method:' . $self->Method ,
380             'Hashed Path:' . $self->HashedPath ,
381             'X-Ops-Content-Hash:' . $self->XOpsContentHash ,
382             'X-Ops-Timestamp:' . $self->XOpsTimestamp ,
383             'X-Ops-UserId:' . $self->XOpsUserId ,
384             );
385             }
386              
387             sub XOpsAuthorization {
388 0     0     my $self = shift;
389 0           my $chef_encoder = $self->_chef_encoder();
390 0           my $canonical_headers = $self->to_string;
391 0           my $raw_header = $chef_encoder->pki->sign( 'data' => $canonical_headers );
392              
393 0           chomp($raw_header);
394            
395 0           my $authorization_header = {};
396 0           my $authorization_header_count = 1;
397            
398 0           foreach my $line (@{$self->split_60($raw_header,[])}){
  0            
399 0           chomp($line);
400 0           $authorization_header->{ "X-Ops-Authorization-$authorization_header_count"}
401             = $line;
402 0           $authorization_header_count++;
403             }
404            
405 0           return $authorization_header;
406             }
407              
408             sub split_60 {
409 0     0     my ($self,$string,$result) = (@_);
410              
411 0 0         return $result unless defined $string;
412 0 0         $string =~ s/\n//g if defined $string;
413            
414 0           my $fp = substr $string , 0 , 60;
415 0           my $sp = substr $string , 60;
416 0 0         push @{$result} , $fp if defined $fp;
  0            
417 0 0         $self->split_60( $sp,$result) if defined $sp;
418              
419 0           return $result;
420             }
421            
422             }#chef_header ends.
423            
424             }#header
425            
426             #}# new
427              
428             1;
429              
430             =pod
431              
432             =head1 KNOWN BUGS
433              
434             =head1 SUPPORT
435              
436             open a github ticket or email comments to Bhavin Patel
437              
438             =head1 COPYRIGHT AND LICENSE
439              
440             This Software is free to use , licensed under : The Artisic License 2.0 (GPL Compatible)
441              
442             =cut