使用telesign调用REST API的签名无效

时间:2014-11-17 18:15:08

标签: rest coldfusion coldfusion-10

API通过电话发送验证码,然后用户进入网站...基本上验证电话号码是否有效。

但我在签署请求时遇到问题。无论我尝试什么,它都会返回“无效签名”

API文档: http://docs.telesign.com/rest/content/verify-call.html

身份验证文档: http://docs.telesign.com/rest/content/rest-auth.html

身份验证示例: http://docs.telesign.com/rest/content/auth-examples.html

代码:

<cffunction name="encryptHmacSHA1" returntype="binary" access="public" output="false">
    <cfargument name="base64Key" type="string" required="true">
    <cfargument name="signMessage" type="string" required="true">
    <cfargument name="encoding" type="string" default="UTF-8">

    <cfset var messageBytes = JavaCast("string",arguments.signMessage).getBytes(arguments.encoding)>
    <cfset var keyBytes = binaryDecode(arguments.base64Key, "base64")>
    <cfset var key  = createObject("java","javax.crypto.spec.SecretKeySpec")>
    <cfset var mac  = createObject("java","javax.crypto.Mac")>
    <cfset key  = key.init(keyBytes,"HmacSHA1")>
    <cfset mac  = mac.getInstance(key.getAlgorithm())>
    <cfset mac.init(key)>
    <cfset mac.update(messageBytes)>

    <cfreturn mac.doFinal()>
</cffunction>


<cfscript>
    // PHONE NUMBER TO CALL
    phoneNumberToCall = "15554565555"; 

    // KEYS
    keys = structNew();
    keys.customerID = "D561FCF4-BA8D-4DFC-86D1-1A46DF47A308";
    keys.apiKey = "mDzGHsMOc2g/ivkuINEFVh6fn/v4kdjvlTvtgFVOShu7hVWXS0eV2nLSw1FXgEzDSuOjhlKLXvneiq+YFG1/Vg==";

    // DATES
    dates = structNew();
    dates.timeZoneInfo = GetTimeZoneInfo();
    dates.dateToUse = DateAdd("h",dates.timeZoneInfo.utcHourOffset,now());
    dates.signingDate = DateFormat(dates.dateToUse,"ddd, dd mmm yyyy") & " " & TimeFormat(dates.dateToUse,"HH:mm:ss") & " +0000";


    // HEADERS
    headers = [ 
           "POST",
           "application/x-www-form-urlencoded", 
           "#dates.signingDate#",
           "phone_number=#phoneNumberToCall#&ucid=OTHR", 
           "/v1/verify/call"
          ];

    headerText = arrayToList(headers, chr(10)) & chr(10);

    // CREATE SIGNATURE
    stringToSign = binaryEncode( encryptHmacSHA1(keys.apiKey, headerText), "base64");

    // AUTHORIZE HEADER
    Authorization = "TSA" & " " & keys.customerID & ":" & stringToSign;
</cfscript>

<cfhttp method="POST" url="https://rest.telesign.com/v1/verify/call" port="443" charset="UTF-8" result="verifyPhoneCall"> 
    <cfhttpparam type="header" name="authorization" value="#Authorization#">
    <cfhttpparam type="header" name="content-type" value="application/x-www-form-urlencoded">
    <cfhttpparam type="header" name="date" value="#dates.signingDate#">
    <cfhttpparam name="phone_number" value="#phoneNumberToCall#" type="formfield">
    <cfhttpparam name="ucid" value="OTHR" type="formfield">
</cfhttp>
<cfdump var="#verifyPhoneCall#"> 

标题需要包含在“新行”的签名中。文档还说它们需要与http标签发送它们的顺序相同。我不认为我的顺序正确...或者甚至我应该如何在cfhttp中设置顺序调用

感谢任何帮助。是的,钥匙是真实的。我很快就会生成新的。

谢谢,

布赖恩

1 个答案:

答案 0 :(得分:0)

查看他们在Constructing the CanonicalizedPOSTVariables Element上的文档,它提到POST主体必须与构造签名时使用的字符串匹配(强调我的):

  

...构造签名字符串时,必须使用正文   POST请求完全,因为它已发送到服务。

默认情况下,cfhttpparam url会对任何formField值进行编码。由于在构造签名时对这些值进行编码,因此cfhttp提交的内容不匹配。因此错误。

禁用签名中所有表单字段的自动编码:

   <cfhttpparam name="phone_number" 
         value="#phoneNumberToCall#"
         type="formfield"  
         encoded="false">

...或者使用type =“body”代替。然后您可以完全控制帖子内容:

   <cfhttpparam type="body" 
       value="phone_number=15554565555&ucid=OTHR">

<强>更新

另外,摆脱最后的新行,即“headerText”中的chr(10)。否则,您的cfhttp内容仍将与签名不匹配。即使用此:

headerText = arrayToList(headers, chr(10));

..而不是:

headerText = arrayToList(headers, chr(10)) & chr(10);