cloudstack-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From heince kurniawan <hei...@gmail.com>
Subject Re: (SOLVED] Having trouble getting a CloudStack API URL with api_key and generated signature to work from the browser (Firefox).
Date Tue, 19 Jun 2012 14:28:09 GMT
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:Anantha.Kasetty@citrix.com] 
> Sent: Saturday, June 09, 2012 6:52 AM
> To: cloudstack-users@incubator.apache.org
> 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" <Alena.Prokharchyk@citrix.com>
> wrote:
> 
>> On 6/8/12 7:08 PM, "Evan Miller" <Evan.Miller@citrix.com> wrote:
>> 
>>> Hi Alena:
>>> 
>>> -----Original Message-----
>>> From: Alena Prokharchyk [mailto:Alena.Prokharchyk@citrix.com]
>>> Sent: Friday, June 08, 2012 3:56 PM
>>> To: cloudstack-users@incubator.apache.org
>>> 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" <Evan.Miller@citrix.com> 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:prasanna.santhanam@citrix.com]
>>>> Sent: Friday, June 08, 2012 1:20 AM
>>>> To: cloudstack-users@incubator.apache.org
>>>> 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.,
>>>> 
>>>> 
>>> 
>>> 
>>> 
>> 
>> 
> 


Mime
View raw message