coldfusion struct in function argument - facebook

I'm trying to do server side facebook connect, but the sdk (get it here) provided gives the following error:
Invalid CFML construct found on line 523 at column 78.
ColdFusion was looking at the following text:
{
And it doesn't explain why it's throwing this error. I'm not good at cfscript, so I don't know whether the sdk uses the correct syntax, but it throws the error on this function, at the braces of the struct in the function arguments:
private String function getUrl(String path = "", Struct parameters = {})
{
var key = "";
var resultUrl = "https://www.facebook.com/" & arguments.path;
if (structCount(arguments.parameters)) {
resultUrl = resultUrl & "?" & serializeQueryString(arguments.parameters);
}
return resultUrl;
}
I had thought that using an sdk would be a no brainer, but apparently I'm missing something.
What am I doing wrong?
Part 2:
The code now comes to a halt at:
for (var propertyName in arguments.properties) {
httpService.addParam(type="formField", name=propertyName, value=arguments.properties[propertyName]);
}
Are you not allowed to use a for loop in cfscript?

Try structNew() or "#structNew()#" instead of {}

This should work for connecting to Facebook and getting an access token:
<cfset appID = ""/>
<cfset secret_key = ""/>
<cfset app_url = ""/>
<cfparam name="URL.Code" default="0">
<cfparam name="URL.state" default="0">
<cfparam name="SESSION.Redirect" default="0">
<cfset code_ = URL.Code>
<cfif code_ EQ "" OR code_ EQ 0>
<cfset SESSION.State = Hash(CreateUUID(),"MD5")>
<cfset dialog_url = "http://www.facebook.com/dialog/oauth?client_id=" & appID & "&redirect_uri=" & app_url & "&scope=email,user_photos,publish_stream" & "&state=" & SESSION.State>
<cflocation url="#dialog_url#" addtoken="no">
</cfif>
<cfif SESSION.State EQ URL.State>
<cfset token_url = "https://graph.facebook.com/oauth/access_token?client_id=" & appID & "&redirect_uri=" & app_url & "&client_secret=" & secret_key & "&code=" & code_>
<cfhttp url="#token_url#" result="AccessToken" method="GET">
<cfelse>
<p>The state does not match. You may be a victim of CSRF.</p>
</cfif>

Related

Creating a credential for use with SAML in CFML

I am trying to create a SAML authentication request in CFML (Railo) with OpenSAML and have got stuck at the point of creating a certificate object to set the public key.
I found soem code that worked well with the private key butusing similar code with the public key certificate does not work. It fails on the call to keyFactory.generatePublic() with : "java.security.InvalidKeyException: IOException: algid parse error, not a sequence".
Does that mean I need a different format for my public key or that I have the keySpec set wrongly? I have tried using PKCS8EncodedKeySpec and RSAPublicKeySpec but neither of those work either. The certificate I'm using is a self signed certificate made with the OpenSSL utils and was created in .crt format.
My Code:
<cfset local.rawKey = replace( arguments.privateKey, "-----BEGIN PRIVATE KEY-----", "" )>
<cfset local.rawKey = replace( local.rawKey, "-----END PRIVATE KEY-----", "" )>
<cfset local.rawKey = trim(local.rawKey)>
<cfset local.keyBytes = binaryDecode(local.rawKey, "base64")>
<cfset local.keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec")>
<cfset local.keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA")>
<cfset local.privateKey = keyFactory.generatePrivate(local.keySpec.init(local.keyBytes))>
<cfset local.rawCert = replace( arguments.certificate, "-----BEGIN CERTIFICATE-----", "" )>
<cfset local.rawCert = replace( local.rawCert, "-----END CERTIFICATE-----", "" )>
<cfset local.rawCert = trim(local.rawCert)>
<cfset local.keyBytes = binaryDecode(local.rawCert, "base64")>
<cfset local.keySpec = createObject("java", "java.security.spec.PKCS8EncodedKeySpec")>
<cfset local.keyFactory = createObject("java", "java.security.KeyFactory").getInstance("RSA")>
<cfset local.certificate = keyFactory.generatePublic(local.keySpec.init(local.keyBytes))>
<cfset local.credential = _create( "org.opensaml.xml.security.x509.BasicX509Credential" )>
<cfset local.credential.setPrivateKey( local.privateKey )>
<cfset local.credential.setEntityCertificate( local.certificate )>
<cfreturn credential>
</cffunction>
Thanks in advance, Kevin
In case anyone else has to solve this issue. The following appears to do what I need:
<cfset local.certBytes = binaryDecode(local.rawCert, "base64")>
<cfset local.certStream = createObject("java", "java.io.ByteArrayInputStream").init(local.certBytes)>
<cfset local.certFactory = createObject("java", "java.security.cert.CertificateFactory").getInstance("X.509")>
<cfset local.certificate = local.certFactory.generateCertificate(local.certStream)>

How to check the signature of the request from Amazon Alexa using Coldfusion and OpenSSL

Amazon's documentation on how to verify is posted here: https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#checking-the-signature-of-the-request
I'm stuck trying to get this to work:
Once you have determined that the signing certificate is valid, extract the public key from it.
Base64-decode the Signature header value on the request to obtain the encrypted signature.
Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
Generate a SHA-1 hash value from the full HTTPS request body to produce the derived hash value
Compare the asserted hash value and derived hash values to ensure that they match.
Here's what I have so far. I have the verification done as far as the subject and valid pem file, the issue is I have no idea how to 'Compare the asserted hash value and derived hash values to ensure that they match.'
<!---get the request sent from amazon---->
<cfset local.request = deserializeJson(
toString(getHttpRequestData().content)
)>
<!---collect headers for authentication---->
<cfif this.isTesting is False>
<cftry>
<cfset local.request.headers.SignatureCertChainUrl = getHttpRequestData().headers.SignatureCertChainUrl>
<cfcatch type="any">
<cfset local.request.request.type = "SessionEndedRequest"><!---end session if SignatureCertChainUrl not passed--->
</cfcatch>
</cftry>
<cftry>
<cfset local.request.headers.Signature = getHttpRequestData().headers.Signature>
<cflog file="Alexa" text="URL Sig: #local.request.headers.Signature#" >
<cfcatch type="any">
<cfset local.request.request.type = "SessionEndedRequest"><!---end session if Signature not passed--->
<cflog file="Alexa" text="Signature is not defined" >
</cfcatch>
</cftry>
<cfif isDefined("local.request.headers.SignatureCertChainUrl") and
isDefined("local.request.headers.Signature")>
<cfif find('https://s3.amazonaws.com/echo.api/',local.request.headers.SignatureCertChainUrl)
or find('https://s3.amazonaws.com:443/echo.api/',local.request.headers.SignatureCertChainUrl)><!---not ssl so kill it--->
<cflog file="Alexa" text="URL Chain: #local.request.headers.SignatureCertChainUrl#" >
<cfset local.request.headers.SignatureCertChainUrlFormatted = replacenocase(local.request.headers.SignatureCertChainUrl,'echo.api/../echo.api','echo.api')>
<cfhttp url="#local.request.headers.SignatureCertChainUrlFormatted#" method="get"></cfhttp>
<cffile action="write"
file="C:\inetpub\alexa\cert\echo.pem"
output="#cfhttp.FileContent#">
<!---check date is valid---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -dates -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_dates"
timeout="10" >
</cfexecute>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.OpenSSL_dates,'notbefore','')>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.datesFormatted,'notafter','')>
<cfset local.cert.datesFormatted = replacenoCase(local.cert.datesFormatted,'=','')>
<cfset local.cert.notBefore = trim(listgetat(local.cert.datesFormatted,1,'='))>
<cfset local.cert.notAfter = trim(listgetat(local.cert.datesFormatted,2,'='))>
<cfif datecompare(convertCertTime(local.cert.notBefore),now()) is '-1' and
datecompare(convertCertTime(local.cert.notAfter),now()) is '1'>
<!---cert date is valid--->
<cfelse>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!---check 'echo-api.amazon.com' in subject---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -subject -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_Subject"
timeout="10" >
</cfexecute>
<cfif NOT findNOcase('echo-api.amazon.com',local.cert.OpenSSL_Subject)>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!---check 'CN=Symantec Class 3 Secure Server CA' in issuer---->
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -issuer -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_issuer"
timeout="10" >
</cfexecute>
<cfif NOT findNOcase('Symantec Class 3 Secure Server CA',local.cert.OpenSSL_issuer)>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<cfexecute name="C:\OpenSSL-Win32\bin\openssl.exe"
arguments="x509 -noout -pubkey -in C:\inetpub\alexa\cert\echo.pem"
variable="local.cert.OpenSSL_Pubkey"
timeout="120" >
</cfexecute>
<cffile action="write"
file="C:\inetpub\alexa\keys\#local.request.request.requestId#.key"
output="#local.cert.OpenSSL_Pubkey#">
<!---decyrpt header signature---->
<!----Base64-decode the Signature header---->
<cfset local.cert.encryptedSig = toString(ToBinary(local.request.headers.Signature)) />
<cffile action="write"
file="C:\inetpub\alexa\keys\#local.request.request.requestId#.sig"
output="#local.cert.encryptedSig#">
<cfelse>
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
<!----end of header decrypting----->
<cfelse>
<!---if either of these are not defined kill the session---->
<cfset local.request.request.type = "SessionEndedRequest">
</cfif>
</cfif>
Try charsetDecode to utf-8 before Base64 decode
Use this before Base64 decode
<CFSET local.request.headers.Signature = charsetDecode( local.request.headers.Signature, "utf-8" )>

Using Coldfusion to create a REST request

Using Coldfusion I would like to create a REST service
I would like to post it to: https://www.test.co.za/ using the username "person1" and password "password1".
The data type would be: application/json
And I would like to pass the following parameters:
callbackURL (string)
amount (bigdecimal)
reference (string)
description (string)
This will then return:
reference (string)
redirectURL (string)
status (string)
This is what I have got so far:
index.cfm
<cfset restInitApplication("C:\ColdFusion10\cfusion\wwwroot\restApp","IIT")>
<cfhttp url="http://127.0.0.1:8500/rest/IIT/rest" method="get">
<cfoutput>#cfhttp.filecontent#</cfoutput>
rest.cfc
<cfcomponent rest="true" restpath="restService">
<cffunction name="sayHello" access="remote" returntype="String" httpmethod="GET">
<cfset callbackURL = "https://www.google.com">
<cfset amount = "100,50">
<cfset reference = "123456789">
<cfset description = "This is a description">
<cfreturn rest>
</cffunction>
</cfcomponent>
I would like to know if I am on the right track and how I would post my values to https://www.test.co.za/ with a username and password
I am not sure if it will look something like this:
<cfhttp
url="https://www.test.co.za/"
method="post"
port="8500"
result="res">
</cfhttp>
Thanks in advance

Invalid Signature with telesign call REST API

The API sends a verification code via a phone call that the user then enters into a website... basically verifying that there phone number is valid.
But I'm having trouble signing the request. No matter what I try it returns "Invalid Signature"
The API documentation:
http://docs.telesign.com/rest/content/verify-call.html
The authentication documentation:
http://docs.telesign.com/rest/content/rest-auth.html
The authentication examples:
http://docs.telesign.com/rest/content/auth-examples.html
The code:
<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#">
The headers need to be included in the signature with "new lines". And the docs also say that they need to be in the same order that the http tag is sending them in. I don't think I have the order correct... or even how I'm supposed to set an order in the cfhttp call.
Any help is appreciated. And yes the keys are real. I'll generate new ones soon.
Thanks,
Brian
Looking over their documentation on Constructing the CanonicalizedPOSTVariables Element it mentions that the POST body must match the string used when constructing the signature (emphasis mine):
... when you construct the signature string, you must use the body of
the POST request exactly as it is delivered to the service.
By default, cfhttpparam url encodes any formField values. Since you are not encoding those values when you construct the signature, the content submitted by cfhttp does not match. Hence the error.
Either disable automatic encoding for all of the form fields in the signature:
<cfhttpparam name="phone_number"
value="#phoneNumberToCall#"
type="formfield"
encoded="false">
... or use type="body" instead. Then you have complete control over the post content:
<cfhttpparam type="body"
value="phone_number=15554565555&ucid=OTHR">
Update:
Also, get rid of the final new line ie chr(10) in the "headerText". Otherwise your cfhttp content still will not match the signature. ie Use this:
headerText = arrayToList(headers, chr(10));
.. instead of:
headerText = arrayToList(headers, chr(10)) & chr(10);

How to Insert Record and Upload file using the FreeASPUpload Script

I want to Insert record and upload file at the same time, right now im using FreeASPUpload Script. When i submit the form it returns this error
Cannot use the generic Request collection after calling BinaryRead
Here is the Full Source Code of my page
<%
option explicit
Response.Expires = -1
Server.ScriptTimeout = 600
Session.CodePage = 65001
%>
<!-- #include file="UploadClass.asp" -->
<%
Dim uploadsDirVar
uploadsDirVar = server.MapPath("Files_Uploaded")
function OutputForm()
%>
<form name="frmSend" method="POST" enctype="multipart/form-data" accept-charset="utf-8" action="form.asp" onSubmit="return onSubmitForm();">
<input type="hidden" name="ApplicationForm" value="Insert" />
Name: <input type="text" name="name_insert" value="" size="30" />
<B>File names:</B><br>
File 1: <input name="attach1" type="file" size=35><br>
<br>
<input style="margin-top:4" type="submit" value="Submit">
</form>
<%
end function
function TestEnvironment()
Dim fso, fileName, testFile, streamTest
TestEnvironment = ""
Set fso = Server.CreateObject("Scripting.FileSystemObject")
if not fso.FolderExists(uploadsDirVar) then
TestEnvironment = "<B>Folder " & uploadsDirVar & " does not exist.</B><br>The value of your uploadsDirVar is incorrect. Open uploadTester.asp in an editor and change the value of uploadsDirVar to the pathname of a directory with write permissions."
exit function
end if
fileName = uploadsDirVar & "\test.txt"
on error resume next
Set testFile = fso.CreateTextFile(fileName, true)
If Err.Number<>0 then
TestEnvironment = "<B>Folder " & uploadsDirVar & " does not have write permissions.</B><br>The value of your uploadsDirVar is incorrect. Open uploadTester.asp in an editor and change the value of uploadsDirVar to the pathname of a directory with write permissions."
exit function
end if
Err.Clear
testFile.Close
fso.DeleteFile(fileName)
If Err.Number<>0 then
TestEnvironment = "<B>Folder " & uploadsDirVar & " does not have delete permissions</B>, although it does have write permissions.<br>Change the permissions for IUSR_<I>computername</I> on this folder."
exit function
end if
Err.Clear
Set streamTest = Server.CreateObject("ADODB.Stream")
If Err.Number<>0 then
TestEnvironment = "<B>The ADODB object <I>Stream</I> is not available in your server.</B><br>Check the Requirements page for information about upgrading your ADODB libraries."
exit function
end if
Set streamTest = Nothing
end function
function SaveFiles
Dim Upload, fileName, fileSize, ks, i, fileKey
Set Upload = New FreeASPUpload
Upload.Save(uploadsDirVar)
' If something fails inside the script, but the exception is handled
If Err.Number<>0 then Exit function
SaveFiles = ""
ks = Upload.UploadedFiles.keys
if (UBound(ks) <> -1) then
SaveFiles = "<B>Files uploaded:</B> "
for each fileKey in Upload.UploadedFiles.keys
SaveFiles = SaveFiles & Upload.UploadedFiles(fileKey).FileName & " (" & Upload.UploadedFiles(fileKey).Length & "B) "
next
else
SaveFiles = "No file selected for upload or the file name specified in the upload form does not correspond to a valid file in the system."
end if
SaveFiles = SaveFiles & "<br>Enter a number = " & Upload.Form("enter_a_number") & "<br>"
SaveFiles = SaveFiles & "Checkbox values = " & Upload.Form("checkbox_values") & "<br>"
SaveFiles = SaveFiles & "List values = " & Upload.Form("list_values") & "<br>"
SaveFiles = SaveFiles & "Text area = " & Upload.Form("t_area") & "<br>"
end function
%>
<HTML>
<HEAD>
<TITLE>Test Free ASP Upload 2.0</TITLE>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
BODY {background-color: white;font-family:arial; font-size:12}
</style>
<script>
function onSubmitForm() {
var formDOMObj = document.frmSend;
if (formDOMObj.attach1.value == "")
alert("Please press the Browse button and pick a file.")
else
return true;
return false;
}
</script>
</HEAD>
<BODY>
<br><br>
<div style="border-bottom: #A91905 2px solid;font-size:16">Upload files to your server</div>
<%
Dim diagnostics
if Request.ServerVariables("REQUEST_METHOD") <> "POST" then
diagnostics = TestEnvironment()
if diagnostics<>"" then
response.write "<div style=""margin-left:20; margin-top:30; margin-right:30; margin-bottom:30;"">"
response.write diagnostics
response.write "<p>After you correct this problem, reload the page."
response.write "</div>"
else
response.write "<div style=""margin-left:150"">"
OutputForm()
response.write "</div>"
end if
else
response.write "<div style=""margin-left:150"">"
OutputForm()
response.write SaveFiles()
response.write "<br><br></div>"
end if
%>
</BODY>
</HTML>
<!-- #include file="ADOVBS.inc" -->
<%
'=======================================================================================
' CONNECT DATABASE
'=======================================================================================
Dim objConn, objRs
Set objConn = CreateObject("ADODB.Connection")
Set objRs = CreateObject("ADODB.Recordset")
objConn.open"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="& server.MapPath("db/Job_database.mdb") &";Mode=ReadWrite|Share Deny None;Persist Security Info=False"
If Request("ApplicationForm") = "Insert" Then
Set InsCom=Server.CreateObject("ADODB.Command")
InsCom.ActiveConnection=objConn
InsName = Trim(request("name_insert"))
InsName = replace(InsName,"'","''")
InsCom.CommandText = "Insert into applications(aname)Values(?)"
InsCom.Parameters.Append InsCom.CreateParameter("#name_insert", adVarChar, adParamInput, 255, InsName)
InsCom.Execute
End If
%>
I have been searching for this problem, but couldn't make it work. although what i found is that i have to use the Form Collection provided by FreeASPUpload. therefore i change
If Request("ApplicationForm") = "Insert" Then
to this
If Upload.Form("ApplicationForm") = "Insert" Then
But it also returns an error, that says: Variable is undefined: 'Upload'
If i change the Request method, it only Uploads the file not inserts the record
If Request.QueryString("ApplicationForm") = "Insert" Then
What i understands is that my insert query is in wrong place or so...
Please help me solve this problem.. thanks
I haven't used AspFreeUpload much so I'm guessing a bit here.
It would appear that using the Request object isn't an option so you're stuck with having to use the Upload.Form. As your code stands, the Upload object is only defined and set within the context of your SaveFiles function.
Try moving your database insert code to within the SaveFiles function. This would mean cutting everything from the line
Dim objConn, objRs
to
InsCom.Execute
and pasting it just before 'End Function'
You may also need to move your include adovbs.inc directive to somewhere before the function was called. The most logical place would be on the line immediately below your other include directive = for uploadclass.asp