Nice, but since you split it by '&' , i expect a problem when specifying ldapConfig 'queryfilter' let say => (&(uid=%u))
Regards, Heince On 19-Jun-2012, at 12:09 PM, Evan Miller wrote: > Hi Anatha (and Alena and others): > > Thanks for your script. > I ended up finding this gem of a perl script: > https://github.com/snumano/CloudStack-API/blob/master/generate-url.pl > in this really excellent article about signed and (mostly) unsigned api calls: > > http://www.shapeblue.com/2012/05/10/using-the-api-for-advanced-network-management/ > I used that gem of a script for my own perl script below: > > #!/usr/bin/perl -w > > use strict; > use warnings; > > use Digest::SHA qw(hmac_sha1); > use Encode; > use Getopt::Std; > use File::Basename qw(basename); > use HTTP::Request; > use JSON::XS; > use LWP::UserAgent; > use MIME::Base64; > use URI::Encode; > > my ($content, $debug, $field, $value); > > my $my_filename = basename($0, ''); > > our ($opt_a, $opt_d, $opt_f, $opt_s, $opt_u); > > $MY_CS_IP_AND_PORT = 'Enter your CS Server Name or IP here followed by :8080'; > > my $site = "http://$MY_CS_IP_AND_PORT/client/api?"; > > getopt "adfsu"; > > if (!defined ($opt_u) || !defined ($opt_a) || !defined ($opt_s) || !defined > ($opt_f)){ > my $usage = "Usage:\n$my_filename -d <0|1> -f <flag: 1. URL "; > $usage = "$usage" . "only, OR 2. URL and Output> -u \"command=<cmd>\" "; > $usage = "$usage" . "-a <api_key> -s <secret_key>\n"; > die ("$usage"); > } > > ###################################################################### > # Process input parameters. > ###################################################################### > > my $api_key = $opt_a; > $debug = $opt_d; > my $secret_key = $opt_s; > my $command = $opt_u; > > # Flag for output: 1. URL only, 2. Both URL and Output > my $flag = $opt_f; > > # URL encoded for special characters. > my $uri = URI::Encode->new(); > > ###################################################################### > ### Step 1 > ### Combine parts to form initial URL. > ###################################################################### > > my $query = $command."&apiKey=".$api_key; > my @list = split (/&/, $query); > foreach (@list){ > if (/(.+)\=(.+)/) { > $field = $1; > # Encode_reserved option is set to 1. > $value = $uri->encode($2, 1); > $_ = $field."=".$value; > } > } > > ###################################################################### > ### Step 2 > ### Lower-case each parameter and parameter value. > ###################################################################### > > foreach (@list){ > $_ = lc ($_); > } > > ###################################################################### > ### Step 3 > # Sort parameter=parameter_values by parameter and join each > # with an ampersand. > ###################################################################### > > my $output = join ("&", sort @list); > > ###################################################################### > ### Step 4 > ### HMAC SHA1 encode the URL. > ###################################################################### > > my $digest = hmac_sha1($output, $secret_key); > my $base64_encoded = encode_base64 ($digest); > chomp($base64_encoded); > > # Encode_reserved option is set to 1. > my $url_encoded = $uri->encode($base64_encoded, 1); > > ###################################################################### > ### Step 5 > ### Combine parts for the Final URL. > ###################################################################### > > my $final_url = > $site."apikey=".$api_key."&".$command."&signature=".$url_encoded; > > ###################################################################### > ### Step 6 > ### Print out the Final URL and/or the output from > ### executing the Final URL. > ###################################################################### > > if ($flag == 1 || $flag == 2){ > if (defined $debug) { > if ($debug != 0) { > print "FINAL URL:\n"; > } > } > print "$final_url"; > if ($flag == 1){ > exit; > } > if ($flag == 2) { > my $agent = LWP::UserAgent->new(env_proxy => 1,keep_alive => 1, > timeout => 30); > my $header = HTTP::Request->new(GET => $final_url); > my $request = HTTP::Request->new('GET', $final_url, $header); > my $response = $agent->request($request); > > # Check the outcome of the response > if ($response->is_success){ > if (defined $debug) { > if ($debug != 0) { > print "\nHEADERS:\n"; > print $response->headers_as_string; > } > } > print "\nCONTENT:\n"; > $content = $response->as_string; > print $content; > exit 0; > } elsif ($response->is_error){ > print "\nError My Final URL: $final_url\n"; > print $response->error_as_HTML; > exit 1; > } > } > } > > Regards, > Evan > > > > -----Original Message----- > From: Anantha Kasetty [mailto:[email protected]] > Sent: Saturday, June 09, 2012 6:52 AM > To: [email protected] > Subject: Re: Having trouble getting a CloudStack API URL with api_key and > generated signature to work from the browser (Firefox). > > Had to dust up my long forgotten Perl skills, here is a sample program > > use URI::Escape; > use Digest::SHA qw(hmac_sha1_base64); > > sub hmac_digest { > my $uri = shift @_; > my $key = shift @_; > > $digest = hmac_sha1_base64($uri, $key); > > #@#$%! perl does not pad the output of base64 > > while (length($digest) % 4) { > $digest .= '='; > } > return $digest; > } > > sub escape_hash { > my %hash = @_; > my @pairs; > > for my $key (sort keys %hash) { > push @pairs, join "=", map { uri_escape($_) } lc($key), > lc($hash{$key}); > } > return join "&", @pairs; > } > > my $secret_key = > 'kNd2VxlXxCXwyJGlidr0ZcmcqXSH2refwxZTStD6If4vJu4QmJPOIui0rgr88mDI6DuGQTzP9e > QNOjlZBTReKg' ; > > > my $uri = escape_hash( > 'apikey'=>'8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seago > 1ycctnute1ot0v7npcus8q', > 'command'=>'listZones', > 'response'=>'json'); > > $signature = uri_escape(hmac_digest($uri, $secret_key)); > > $uri .= "&signature=$signature"; > print "$uri\n"; > > > > Let me know if this works for you. > > > > regards, > Anantha Kasetty > > > > > > > > > > > > On 6/8/12 8:40 PM, "Alena Prokharchyk" <[email protected]> > wrote: > >> On 6/8/12 7:08 PM, "Evan Miller" <[email protected]> wrote: >> >>> Hi Alena: >>> >>> -----Original Message----- >>> From: Alena Prokharchyk [mailto:[email protected]] >>> Sent: Friday, June 08, 2012 3:56 PM >>> To: [email protected] >>> Subject: Re: Having trouble getting a CloudStack API URL with api_key and >>> generated signature to work from the browser (Firefox). >>> >>> On 6/8/12 12:23 PM, "Evan Miller" <[email protected]> wrote: >>> >>>> Hi: >>>> >>>> I am not doing something quite right yet generating a good >>>> CloudStack API URL. >>>> >>>> I still get this same error from the browser when >>>> I try to execute the final url: >>>> >>>> { "listvirtualmachinesresponse" : {"errorcode" : 401, "errortext" : >>>> "unable to verify user credentials"} } >>>> >>>> Here is what my perl script is doing: >>>> >>>> Original Command String: >>>> >>>> apiKey=8v_GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1 >>>> y >>>> C >>>> CTnUtE1oT0v7npCuS8Q&command=listVirtualMachines&response=json >>>> >>>> Sorted (by field), lower-case Command String: >>>> >>>> apikey=8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seago1 >>>> y >>>> c >>>> ctnute1ot0v7npcus8q&command=listvirtualmachines&response=json >>>> >>>> Encoded, sorted, lower-case Command String: >>>> >>>> apikey%3D8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seag >>>> o >>>> 1 >>>> ycctnute1ot0v7npcus8q%26command%3Dlistvirtualmachines%26response%3Djson >>> >>> Here is the problem - you have to encode just parameter values, not the >>> parameters themselves and definitely not "=" and "&" special chars. >>> >>> You can look at the java code sample I wrote for the dev bootcamp, here >>> is >>> the link in the source tree: >>> >>> http://git.cloud.com/cgit/cloudstack-oss/tree/test/src/com/cloud/test/dem >>> o >>> /Demo.java?h=3.0.x >>> >>> >>> - Begin - >>> >>> I don't really know Java, but I did see your numbered steps >>> at the bottom. >>> >>> I still get an error for the final url: >>> >>> { "listvirtualmachinesresponse" : {"errorcode" : 401, "errortext" : >>> "unable to verify user credentials and/or request signature"} } >>> >>> Here is what I tried ... continuing in perl. >>> I encoded just the parameters (not the field values). >>> The parameters didn't really require any encoding. >>> No special characters, but I did it anyway. >>> So, after encoding, the parameters didn't change. >>> I did encode the signature before appending to the >>> final url. >>> >>> Here's the flow ... >>> >>> Original Command String: >>> >>> apiKey=8v_GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1y >>> C >>> CTnUtE1oT0v7npCuS8Q&command=listVirtualMachines&response=json >>> >>> Command String with Encoded Parameters: >>> >>> apiKey=8v_GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1y >>> C >>> CTnUtE1oT0v7npCuS8Q&command=listVirtualMachines&response=json >>> >>> Sorted (by field), lower-case, encoded Command String: >>> >>> apikey=8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seago1y >>> c >>> ctnute1ot0v7npcus8q&command=listvirtualmachines&response=json >>> >>> SHA1 HEX String: >>> f8d4d96dd59c3bd562dc32586539fa9162c5ed70 >>> >>> SHA1 Base64 Signature (using SHA1 HEX String): >>> 3wOrhy/SstxN+NbdoT8h/bkla2E >>> >>> Encoded Signature: >>> 3wOrhy%2FSstxN%2BNbdoT8h%2Fbkla2E >>> >>> Final URL: >>> >>> http://10.217.5.192:8080/client/api?command=listVirtualMachines&apiKey=8v >>> _ >>> GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1yCCTnUtE1oT >>> 0 >>> v7npCuS8Q&response=json&signature=3wOrhy%2FSstxN%2BNbdoT8h%2Fbkla2E >>> >>> Does the syntax of the final url, at least, look right? >>> >>> If so, then there must be something wrong with the signature. >>> >>> Regards, >>> Evan >> >> >> >> The syntax looks right to me. >> >> -Alena. >> >>> >>> - End - >>> >>> >>> -Alena. >>> >>>> >>>> SHA1 HEX String: >>>> 9066d795102c0cf8a12322507887122b6b4a6095 >>>> >>>> SHA1 Base64 Signature (using SHA1 HEX String and Secret Key): >>>> SvDq03i4Tql9qkXuZwUDi3HfbH4 >>>> >>>> Final URL: >>>> >>>> http://10.217.5.192:8080/client/api?command=listVirtualMachines&apiKey=8 >>>> v >>>> _ >>>> GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1yCCTnUtE1o >>>> T >>>> 0 >>>> v7npCuS8Q&response=json&signature=SvDq03i4Tql9qkXuZwUDi3HfbH4 >>>> >>>> I am generating the SHA1 HEX String like so: >>>> $digest = sha1_hex ($encode, $secret_key); >>>> using this module: >>>> use Digest::SHA qw(sha1 sha1_hex sha1_base64); >>>> >>>> I am generating the SHA1 Base64 Signature like so: >>>> $signature = sha1_base64 ($digest, $secret_key); >>>> >>>> >>>> Curious - Is SHA1 HEX different from HMAC SHA1? >>>> >>>> >>>> Regards, >>>> Evan >>>> >>>> -----Original Message----- >>>> From: Prasanna Santhanam [mailto:[email protected]] >>>> Sent: Friday, June 08, 2012 1:20 AM >>>> To: [email protected] >>>> Subject: Re: Having trouble getting a CloudStack API URL with api_key >>>> and >>>> generated signature to work from the browser (Firefox). >>>> >>>> On Thu, Jun 07, 2012 at 10:38:20PM -0400, Evan Miller wrote: >>>>> Hi: >>>>> >>>>> Right now, I am just testing a simple, final API-based url with >>>>> signature in a browser. >>>>> I am getting the following authentication related error in the >>>>> browser: >>>>> >>>>> { "listvirtualmachinesresponse" : {"errorcode" : 401, "errortext" : >>>>> "unable to verify user credentials and/or request signature"} } >>>>> >>>>> Here is the final API-based url: >>>>> >>>>> >>>>> http://10.217.5.192:8080/client/api?command=listVirtualMachines&apiKey >>>>> =8v_GEvJJgDjbbHIBmlle4yyHKseQhRefztnv4UP2fU3K9y12TH7lscsn6-7SEaGO1yCCT >>>>> nUtE1oT0v7npCuS8Q&response=json&signature=1ca7bc1bbc67b8f578c7d094c523 >>>>> 537571ee17b1 >>>>> >>>>> Here is how I built that final url: >>>>> >>>>> Using perl, it is based on the following pieces: >>>>> >>>>> my $cs_ip = '10.217.5.192'; >>>>> my $base_url = 'http://' . "$cs_ip" . ':8080'; my $api_path = >>>>> '/client/api?'; my $api_key = >>>>> '8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seago1ycct >>>>> nute1ot0v7npcus8q'; my $secret_key = >>>>> 'kNd2VxlXxCXwyJGlidr0ZcmcqXSH2refwxZTStD6If4vJu4QmJPOIui0rgr88mDI6DuGQ >>>>> TzP9eQNOjlZBTReKg'; >>>>> >>>>> The api_key and secret key come from my account (evan) in domain 1. >>>>> The keys were just generated in a new CloudStack GUI session. >>>>> The evan account has ROOT Domain privileges. >>>>> >>>>> Then, following directions in the Developer's Guide ... >>>>> >>>>> The sorted, lower-case command string ($sorted_lc_cmd) is: >>>>> >>>>> apikey=8v_gevjjgdjbbhibmlle4yyhkseqhrefztnv4up2fu3k9y12th7lscsn6-7seag >>>>> o1ycctnute1ot0v7npcus8q&command=listvirtualmachines&response=json >>>>> >>>>> >>>>> I obtained the hex signature in perl as follows: >>>>> >>>>> >>>>> $signature = hmac_sha1_hex ($sorted_lc_cmd, $secret_key); >>>>> >>>>> >>>>> And, then, put together the final url, as above, with the calculated >>>>> signature. >>>>> >>>>> >>>>> What am I doing wrong or missing? >>>> >>>> Before you obtain the hmac SHA-1 you need to url encode the request url >>>> stripping it off reserved characters like "+, !, $" etc. Then you >>>> perform >>>> the HMAC on the resultant string. This then is passed through a base64 >>>> encoder to obtain the signature. It looks like you missed this step. Can >>>> you base64 encode the hmac result and give it a shot? >>>> >>>> >>>> >>>> -- >>>> Prasanna., >>>> >>>> >>> >>> >>> >> >> >
