cloudstack-users-cn mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yao hu <huyao...@gmail.com>
Subject Re: 使用apikey访问实例console失败
Date Wed, 16 Oct 2013 02:54:47 GMT
我这是内网开发环境,给你也不能用,你自己用你的secret key试一下,
我现在的疑问是,客户端生成签名的方法是一样的,为什么服务器端验证时
用的方法不一样,是bug还是有什么我们不知道的特殊作用。


在 2013年10月16日上午10:31,Gavin Lee <gavin.lxh@gmail.com>写道:

> 你能把你的SecretKey贴出来吗?这样我也试一下生产Signature。
> encodeBase64URLSafeString应该都会调到的。
>
>
> 2013/10/11 yao hu <huyao.ct@gmail.com>
>
> > 1.     问题现象
> >
> > 用apikey访问实例console时,浏览器提示无效的session或者api key,导致访问失败。
> >
> > 测试版本:win7+cygwin+xenserver 6.1.0+cloudstack 4.1.1
> >
> > 测试操作步骤:
> >
> > 1.       用api key和secret key构造一个访问实例console的url
> >
> >
> >
> http://localhost:8080/client/console?cmd=access&vm=b194369f-e0d4-45d8-a50f-09ec51095e68&apikey=fmS7oyThP6MGxN5X_CgeOCxQIqgTu5QFDz46r2Pv5kLp88EYYBquSu6_3s3d9MXdbUHPpxj5qDDy1jvhEpQWvQ&signature=y3dNHn580NJiCVRGwrBTR4JHImo%3D
> >
> > 2.       把上面构造的url粘贴到浏览器地址栏,并访问,提示如下信息
> >
> >        [image: 内嵌图片 1]
> >
> > 2.     问题分析
> >
> > 问题出现后,一开始是怀疑构造url的脚本有错,后面又尝试构造其它api的url来验证脚本是否正确。如构造调用listAccounts
> API的url
> > ,其url如下:
> >
> >
> >
> http://localhost:8080/client/api?command=listAccounts&apikey=fmS7oyThP6MGxN5X_CgeOCxQIqgTu5QFDz46r2Pv5kLp88EYYBquSu6_3s3d9MXdbUHPpxj5qDDy1jvhEpQWvQ&signature=ALhJtw%2Bzi7Rcmo%2Bkk3xH3cTJgp4%3D
> >
> > 在浏览器中访问该url后,能正确返回结果,这就说明构造url的脚本是没有错的。
> >
> >         接着,调试了访问实例console这部分的源代码,并定位到失败的地方是在ConsoleProxyServlet.java文件的
> > verifyRequest函数,其主要代码如下:
> >
> > private boolean verifyRequest(Map<String, Object[]> requestParameters) {
> >
> >        try {
> >
> >        ...省略部分代码
> >
> >         unsignedRequest = unsignedRequest.toLowerCase();
> >
> >
> >
> >        Mac mac = Mac.getInstance("HmacSHA1");
> >
> >        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(),
> > "HmacSHA1");
> >
> >        mac.init(keySpec);
> >
> >        mac.update(unsignedRequest.getBytes());
> >
> >        byte[] encryptedBytes = mac.doFinal();
> >
> >        String computedSignature =
> > Base64.encodeBase64URLSafeString(encryptedBytes);
> >
> >        boolean equalSig = signature.equals(computedSignature);
> >
> >        if (!equalSig) {
> >
> >               s_logger.debug("User signature: " + signature + " is not
> > equaled to computed signature: " + computedSignature);
> >
> >        }
> >
> >        ... 省略部分代码
> >
> >        return equalSig;
> >
> >        } catch (Exception ex) {
> >
> >        s_logger.error("unable to verifty request signature", ex);
> >
> >        }
> >
> >        return false;
> >
> > }
> >
> > 这个函数中红色字体部分在验证签名时失败。其中,signature是客户端url中传进来的参数,computedSignature是服务端根据api
> > key和secret key计算出来的。signature与computedSignature比较时不相同,导致函数返回false。
> >
> >  由于用api key调用其它api时是能正确得到结果的,故又调试了其它api的调用流程,并定位到其验证signature的代码,在文件
> > ApiServer.java的verifyRequest函数中,其主要代码如下:
> >
> > public boolean verifyRequest(Map<String, Object[]> requestParameters,
> Long
> > userId)  throws ServerApiException {
> >
> >        try {
> >
> >               ...省略部分代码
> >
> >               unsignedRequest = unsignedRequest.toLowerCase();
> >
> >
> >
> >               Mac mac = Mac.getInstance("HmacSHA1");
> >
> >               SecretKeySpec keySpec = new
> > SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
> >
> >               mac.init(keySpec);
> >
> >               mac.update(unsignedRequest.getBytes());
> >
> >               byte[] encryptedBytes = mac.doFinal();
> >
> >               String computedSignature =
> > Base64.encodeBase64String(encryptedBytes);
> >
> >               boolean equalSig = signature.equals(computedSignature);
> >
> >               if (!equalSig) {
> >
> >                      s_logger.debug("User signature: " + signature + " is
> > not equaled to computed signature: " + computedSignature);
> >
> >               }
> >
> >               ...省略部分代码
> >
> >               return equalSig;
> >
> >        } catch (Exception ex) {
> >
> >               s_logger.error("unable to verifty request signature", ex);
> >
> >        }
> >
> >        return false;
> >
> > }
> >
> > 这个函数的红色部分对signature进行了验证,signature与computedSignature进行比较时相同,故能通过验证,函数返回
> > true。
> >
> > 仔细比较这两个verifyRequest函数验证signature部分的代码,我们可以发现前面的verifyRequest函数在计算
> > computedSignature时,使用的是Base64.encodeBase64URLSafeString
> >
> > 函数,而后面那个使用的是Base64.encodeBase64String,就这说明,客户端生成的signature可以通过
> > Base64.encodeBase64String的验证。接着,把Base64.encodeBase64URLSafeString
> >
> > 替换为Base64.encodeBase64String,重新编译源代码并部署,再次通过api
> key来访问实例console,这次是能成功访问的。
> >
> >
> > 为何这两个verifyRequest函数中使用两个不同的encode方法?是bug?还是用
> > Base64.encodeBase64URLSafeString有特别的意义?
> >
> >
> >
> >
> >
>
>
> --
> Gavin
>
Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message