Current date / time to RFC 2822 date function with vb / classic asp - rest

I am trying to write a script to push data out to an amazon s3 bucket and I need to generate what I believe is an RFC 2822 date to send in the header request.
The date looks like this "Tue, 12 June 2012 23:41:58 +0000"
I just need a function to generate the correct time format as I am getting the following error.
RequestTimeTooSkewed The difference between the request time and the current time is too large.
This is what I have so far...
<%
sTimeStamp = "Tue, 12 June 2012 23:41:58 +00002012-06-12T22:45:47Z"
sAWSAccessKeyId = "AESDQWDQWD"
sSignature=Encrypt("SecretQWEQWEQWEQWEYAYAY")
AWSServiceUrl = "https://s3.amazonaws.com/"
Set oXMLHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP")
oXMLHTTP.open "GET", AWSServiceUrl, False
oXMLHTTP.setRequestHeader "Authorization", "AWS " & sAWSAccessKeyId & ":" & sSignature
oXMLHTTP.setRequestHeader "x-amz-date", sTimeStamp
on error resume next
oXMLHTTP.send sRequest
Response.Write oXMLHTTP.responseText
%>
Any ideas?

The simplest way to do it is to get JScript to help:
<script runat="server" language="javascript">
function JSNow() { return new Date(); }
</script>
Now you can get the string format for the time required with:
Dim sTimeStamp: sTimeStamp = JSNow().toString()

Related

Access Azure Storage Services REST API with Elixir and HTTPoison

I'm trying to use Elixir to access Azure Storage Services via their REST API but I'm having difficulty getting the Authentication Header to work. I am able to connect if I use the ex_azure package (wrapper for erlazure) but not when I try to build the request and use HTTPoison.
Most Recent Error Messages
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-02T21:46:08.6488342Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\nWed, 02 Aug 2017 21:46:08
GMT\nx-ms-date-h:Wed, 02 Aug 2017 21:46:08 GMT\nx-ms-version-h:2017-05-10\n/storage_name/container_name?comp=list'.</AuthenticationErrorDetail>
</Error>
After 1st Edit
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.\nRequestId:00000000-0000-0000-0000-000000000000\nTime:2017-08-03T03:03:57.1385277Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request '<signature>' is not the same as any computed signature. Server used following string to sign: 'GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 03 Aug
2017 03:03:57 GMT\nx-ms-version:2017-04-17\n/storage_name/container_name\ncomp:list\nrestype:container'.</AuthenticationErrorDetail>
</Error>
Dependencies
# mix.exs
defp deps do
{:httpoison, "~> 0.12"}
{:timex, "~> 3.1"}
end
Code
Am I formatting the Authentication Header (string_to_sign) right?
Am I using encode/decode right?
Am I adding headers correctly to HTTPoison?
Should I be using something else for REST actions instead of HTTPoison?
# account credentials
storage_name = "storage_name"
container_name = "container_name"
storage_key = "storage_key"
storage_service_version = "2017-04-17" # fixed version
request_date =
Timex.now
|> Timex.format!("{RFC1123}") # Wed, 02 Aug 2017 00:52:10 +0000
|> String.replace("+0000", "GMT") # Wed, 02 Aug 2017 00:52:10 GMT
# set canonicalized headers
x_ms_date = "x-ms-date:#{request_date}"
x_ms_version = "x-ms-version:#{storage_service_version}"
# assign values for string_to_sign
verb = "GET\n"
content_encoding = "\n"
content_language = "\n"
content_length = "\n"
content_md5 = "\n"
content_type = "\n"
date = "\n"
if_modified_since = "\n"
if_match = "\n"
if_none_match = "\n"
if_unmodified_since = "\n"
range = "\n"
canonicalized_headers = "#{x_ms_date}\n#{x_ms_version}\n"
canonicalized_resource = "/#{storage_name}/#{container_name}\ncomp:list\nrestype:container" # removed timeout. removed space
# concat string_to_sign
string_to_sign =
verb <>
content_encoding <>
content_language <>
content_length <>
content_md5 <>
content_type <>
date <>
if_modified_since <>
if_match <>
if_none_match <>
if_unmodified_since <>
range <>
canonicalized_headers <>
canonicalized_resource
# decode storage_key
{:ok, decoded_key} =
storage_key
|> Base.decode64
# sign and encode string_to_sign
signature =
:crypto.hmac(:sha256, decoded_key, string_to_sign)
|> Base.encode64
# build authorization header
authorization_header = "SharedKey #{storage_name}:#{signature}"
# build request and use HTTPoison
url = "https://storage_name.blob.core.windows.net/container_name?restype=container&comp=list"
headers = [ # "Date": request_date,
"x-ms-date": request_date, # fixed typo
"x-ms-version": storage_service_version, # fixed typo
# "Accept": "application/json",
"Authorization": authorization_header]
options = [ssl: [{:versions, [:'tlsv1.2']}], recv_timeout: 500]
HTTPoison.get(url, headers, options)
Notes
Some sources I used/tried...
Authentication for the Azure Storage Services
The MAC signature found in the HTTP request is not the same as any computed signature azure integration using php
How to access rest azure blob using cURL
Accessing Azure blob storage using bash, curl
A few issues I noticed:
You included Date request header in your request but it is not included in your string_to_sign. Either include this header in your string_to_sign or remove this header from request headers.
You included timeout:30 in your canonicalized_resource but it is not included in your request URL. Again, either add timeout=30 in your request querystring or remove timeout:30 from canonicalized_resource.
I have not used Elixir as such so I don't know how request headers work there, but you're naming your request headers as x-ms-date-h and x-ms-version-h. Shouldn't they be x-ms-date and x-ms-version respectively?

Check VAT Number at VIES with classic ASP + SOAP

I'm trying to check European VAT Number at VIES via Webservice:
with my poor knowledge I built the following routine:
<%
strEnvelope="<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:ec.europa.eu:taxud:vies:services:checkVat:types"">"
strEnvelope=strEnvelope&"<soapenv:Header/>"
strEnvelope=strEnvelope&"<soapenv:Body>"
strEnvelope=strEnvelope&"<urn:checkVat>"
strEnvelope=strEnvelope&"<urn:countryCode>DE</urn:countryCode>"
strEnvelope=strEnvelope&"<urn:vatNumber>247856515</urn:vatNumber>"
strEnvelope=strEnvelope&"</urn:checkVat>"
strEnvelope=strEnvelope&"</soapenv:Body>"
strEnvelope=strEnvelope&"</soapenv:Envelope>"
set objHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
objHTTP.open "post", "http://ec.europa.eu/taxation_customs/vies/services/checkVatService"
objHTTP.setRequestHeader "Content-Type", "text/xml"
objHTTP.setRequestHeader "SOAPMethodName", "checkVat"
objHTTP.send strEnvelope
strReturn = objHTTP.responseBody
response.write strReturn
%>
but I got this answer
猼慯㩰湅敶潬数ç æ±­ç®çŒºæ…¯ãµ°æ ¢ç‘´ã©°â¼¯æ³æ•¨æ…­â¹³æµ¸ç¬æ…¯â¹°ç‰¯â½§æ½³ç¡æ”¯ç™®æ±¥ç¯â½¥ã¸¢çŒ¼æ…¯ã©°æ½‚祤㰾档æ¥å™«ç‘¡æ•’ç³æ¹¯æ•³ç æ±­ç®âˆ½ç‰µã©®æ¥æ”®ç‰µç¯â¹¡ç•¥çºç¡¡æ‘µç˜ºæ•©ã©³æ•³ç™²æ©ç¥æŒºæ•¨æ­£æ…–㩴祴数≳㰾潣湵牴ä¹æ‘¯ã¹¥ä•„⼼潣湵牴ä¹æ‘¯ã¹¥ç˜¼ç‘¡ç•Žæ‰­ç‰¥ãˆ¾ãœ´ã”¸ã”¶ã”±â¼¼æ…¶ä¹´æµµæ•¢ã¹²çˆ¼ç…¥æ•µç‘³æ…„整㈾㄰ⴷ㜰ㄭ⬵㈰〺㰰爯煥敵瑳慄整㰾慶楬㹤牴敵⼼慶楬㹤渼浡㹥ⴭ㰭港浡㹥愼摤敲ç³â´¾â´­â¼¼æ‘¡ç‰¤ç¥ã¹³â¼¼æ¡£æ¥å™«ç‘¡æ•’ç³æ¹¯æ•³ã°¾çŒ¯æ…¯ã©°æ½‚祤㰾猯慯㩰湅敶潬数> 猼慯㩰湅敶潬数ç æ±­çÂ®çŒºæ…¯ãµ°æ ¢ç‘´ã©°â¼¯æ³敨慭⹳浸ç¬慯⹰牯⽧潳ç¡æâ€Â¯Ã§â„¢Â®Ã¦Â±Â¥Ã§Â¯â½¥ã¸¢çŒ¼æ…¯ã©°æ½‚祤㰾档æ¥噫瑡敒ç³湯敳ç æ±­ç®∽牵㩮æÂ¥æâ€Â®Ã§â€°ÂµÃ§Â¯â¹¡ç•¥çº硡摵瘺敩㩳敳癲æ©ç¥挺敨正慖㩴祴数≳㰾潣湵牴ä¹摯㹥䕄⼼潣湵牴ä¹摯㹥瘼瑡畎扭牥㈾㜴ãâ€Â¸Ã£â€Â¶Ã£â€Â±Ã¢Â¼Â¼Ã¦â€¦Â¶Ã¤Â¹Â´Ã¦ÂµÂµÃ¦â€¢Â¢Ã£Â¹Â²Ã§Ë†Â¼Ã§â€¦Â¥Ã¦â€¢ÂµÃ§â€˜Â³Ã¦â€¦â€žÃ¦â€¢Â´Ã£Ë†Â¾Ã£â€žÂ°Ã¢Â´Â·Ã£Å“°ã„­â¬µãˆ°ã€ºã°°çˆ¯ç…¥æ•µç‘³æ…„整㰾慶楬㹤牴敵⼼慶楬㹤渼浡㹥ⴭ㰭港浡㹥愼摤敲ç³ⴾⴭ⼼摡牤ç¥㹳⼼档æ¥噫瑡敒ç³湯敳㰾猯慯㩰潂祤㰾猯慯㩰湅敶潬数>
can give some hints?
Thanks
The text representation of the response is in the responseText property, so:
strReturn = objHTTP.responseText

Qlikview Macro VBScript to print pdf and email will not run consistently - Fails in email

I have been tearing my hair out over the last few days in trying to get this macro to work consistantly on the Windows scheduler.
Basically the workflow is as follows:
1) Windows Scheduler - Daily, uses Admin user credentials
2) Batch file - Reloads using /l
3) Reloads Qlikview application, which has triggers on post reload to save a pdf and email it using PDF Xchange and an html formatted e-mail to cover mobile.
I am getting such inconsistent behaviour that I cannot isolate the problem to any particular one thing. Sometimes it works, sometimes it doesn't. More often than not it fails on the Windows scheduler. There is no error since QV has just thrown up the VBScript window in the hidden process.
I've been changing permissions, which helped me reach a level of inconsistent performance as opposed to no performance.
In addition, it appears that you cannot pass variables to the PDF Xchange printer.
The code in the macro is as follows:
sub ExportPDF
printReportPDF "\\SGH-SRV-FPS1\S-Drive\eCommerce\Data Analyst\Reporting\Daily E-Commerce Report\E-Commerce Daily Report.pdf"
ActiveDocument.GetApplication.Sleep 2000
ActiveDocument.PrintReport "RP01", "PDF-XChange 3.0"
ActiveDocument.GetApplication.Sleep 8000
end sub
Function printReportPDF(pdfOutputFile)
Set WSHShell = CreateObject("WScript.Shell")
WSHShell.RegWrite "HKCU\Software\Tracker Software\PDF-XChange 3.0\OutputFile", pdfOutputFile, "REG_SZ"
WSHShell.RegWrite "HKCU\Software\Tracker Software\PDF-XChange 3.0\BypassSaveAs", "1", "REG_SZ"
Set WSHShell = nothing
End function
Sub ExportEmail
Dim strvDest 'as string
strvDest = ActiveDocument.Variables("vDestination").GetContent().String
msgbox(strvDestination)
Define report variables
get the date as a serial for the filename output
Export an Object
Set obj = ActiveDocument.ActiveSheet.SheetObjects("TX25")
Set obj1 = ActiveDocument.ActiveSheet.SheetObjects("TX17")
Set obj2 = ActiveDocument.ActiveSheet.SheetObjects("TX18")
Set obj3 = ActiveDocument.ActiveSheet.SheetObjects("TX15")
Set obj5 = ActiveDocument.ActiveSheet.SheetObjects("CH62")
Set obj6 = ActiveDocument.ActiveSheet.SheetObjects("TX16")
Set obj8 = ActiveDocument.ActiveSheet.SheetObjects("CH58")
Set obj9 = ActiveDocument.ActiveSheet.SheetObjects("TX31")
Set obj10 = ActiveDocument.ActiveSheet.SheetObjects("CH69")
msgbox("defined objects")
obj.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\MainLogo.jpg"
obj1.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\MainHeader.jpg"
obj2.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\DateRange.jpg"
obj3.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader.jpg"
obj5.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\DailySiteDetail.jpg"
obj6.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader2.jpg"
obj8.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\WeeklySiteDetail.jpg"
obj9.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader3.jpg"
obj10.ExportBitmapToFile "D:\QlikView\SGP-UDA\QVS_Source\UserApp\WeeklySiteDetailLW.jpg"
msgbox("created objects")
Dim objEmail
Const cdoSendUsingPort = 2 Send the message using SMTP
Const cdoAnonymous = 0 Do not authenticate
Const cdoBasic = 1 basic (clear-text) authentication
Const cdoNTLM = 2 NTLM
Const SMTPServer = "xxxx" ' changed for public consumption
Const SMTPPort = 25 ' Port number for SMTP
Const SMTPTimeout = 120 ' Timeout for SMTP in seconds
Set objEmail = CreateObject("CDO.Message")
Set objConf = objEmail.Configuration
Set objFlds = objConf.Fields
With objFlds
———————————————————————
SMTP server details
removed the html links down to this being my first post
.Update
———————————————————————
End With
allow the passing of a variable from the load script to define the distribution list
if len(strvDest) > 0 then
msgbox("variable exists "&strvDest)
objEmail.To = strvDest
else
msgbox("variable does not exist")
objEmail.To = "xxxx" 'changed for public consumption
end if
objEmail.From = "xxxx" 'changed for public consumption
objEmail.Subject = "Daily Reporting"
HTML = "<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML//EN"">" & chr(13) & chr(10)
HTML = HTML & "<html>"
HTML = HTML & "<head>"
HTML = HTML & "<meta http-equiv=""Content-Type"" content=""text/html; charset=iso-8859-1"">"
HTML = HTML & "<title>Automated Emails!</title>"
HTML = HTML & "</head>"
HTML = HTML & "<body bgcolor=""#FFFFFF"">"
HTML = HTML & "<br> <img src=""cid:MainLogo.jpg"" >"
HTML = HTML & "<br> <img src=""cid:MainHeader.jpg"" >"
HTML = HTML & "<br> <img src=""cid:DateRange.jpg"" >"
HTML = HTML & "<br> <img src=""cid:SecondaryHeader.jpg"" >"
HTML = HTML & "<br> <img src=""cid:DailySiteDetail.jpg"" >"
HTML = HTML & "<br> <img src=""cid:SecondaryHeader2.jpg"" >"
HTML = HTML & "<br> <img src=""cid:WeeklySiteDetail.jpg"" >"
HTML = HTML & "<br> <img src=""cid:SecondaryHeader3.jpg"" >"
HTML = HTML & "<br> <img src=""cid:WeeklySiteDetailLW.jpg"" >"
HTML = HTML & "<p>"
HTML = HTML & "</p>"
HTML = HTML & "</body>"
HTML = HTML & "</html>"
Set objBP = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\MainLogo.jpg", "MainLogo.jpg", CdoReferenceTypeName)
objBP.Fields.Item("urn:schemas:mailheader:Content-ID") = "<MainLogo.jpg>"
objBP.Fields.Update
Set objBP1 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\MainHeader.jpg", "MainHeader.jpg", CdoReferenceTypeName)
objBP1.Fields.Item("urn:schemas:mailheader:Content-ID") = "<MainHeader.jpg>"
objBP1.Fields.Update
Set objBP2 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\DateRange.jpg", "DateRange.jpg", CdoReferenceTypeName)
objBP2.Fields.Item("urn:schemas:mailheader:Content-ID") = "<DateRange.jpg>"
objBP2.Fields.Update
Set objBP3 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader.jpg", "SecondaryHeader.jpg", CdoReferenceTypeName)
objBP3.Fields.Item("urn:schemas:mailheader:Content-ID") = "<SecondaryHeader.jpg>"
objBP3.Fields.Update
Set objBP5 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\DailySiteDetail.jpg", "DailySiteDetail.jpg", CdoReferenceTypeName)
objBP5.Fields.Item("urn:schemas:mailheader:Content-ID") = "<DailySiteDetail.jpg>"
objBP5.Fields.Update
Set objBP6 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader2.jpg", "SecondaryHeader2.jpg", CdoReferenceTypeName)
objBP6.Fields.Item("urn:schemas:mailheader:Content-ID") = "<SecondaryHeader2.jpg>"
objBP6.Fields.Update
Set objBP8 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\WeeklySiteDetail.jpg", "WeeklySiteDetail.jpg", CdoReferenceTypeName)
objBP8.Fields.Item("urn:schemas:mailheader:Content-ID") = "<WeeklySiteDetail.jpg>"
objBP8.Fields.Update
Set objBP9 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\SecondaryHeader3.jpg", "SecondaryHeader3.jpg", CdoReferenceTypeName)
objBP9.Fields.Item("urn:schemas:mailheader:Content-ID") = "<SecondaryHeader3.jpg>"
objBP9.Fields.Update
Set objBP10 = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\WeeklySiteDetailLW.jpg", "WeeklySiteDetailLW.jpg", CdoReferenceTypeName)
objBP10.Fields.Item("urn:schemas:mailheader:Content-ID") = "<WeeklySiteDetailLW.jpg>"
objBP10.Fields.Update
Set objBPDoc = objEmail.AddRelatedBodyPart("D:\QlikView\SGP-UDA\QVS_Source\UserApp\Qlikview Printing.pdf", "Qlikview Printing.pdf", CdoReferenceTypeName)
objBPDoc.Fields.Item("urn:schemas:mailheader:Content-ID") = "<Qlikview Printing.pdf>"
objBPDoc.Fields.Update
objEmail.HTMLBody = HTML
msgbox("attached objects")
objEmail.Send
Set objFlds = Nothing
Set objConf = Nothing
Set objEmail = Nothing
ActiveDocument.Save
Application.Quit
End Sub
I cannot ask questions so I will try to give you an answer of the bat.
Firstly, does it reload manually from the QV Document? If yes then
Then you are most probably using 2 differant usernames to reload, please make sure that the username used to reload via scheduler has permissions on every single file the VB is accessing.
Did you set the permissions on the VB side to the following:
Requested Module Security = System Access
Current Local Security = Allow system access
Lastly, On the General screen of the scheduled task, under security options at the bottom. Make sure "Run with highest privileges" is unticked, this sometimes causes issues.

UTC_TIMESTAMP() to user defined timezone?

I am storing timestamps in my db using UTC_TIMESTAMP().
I want to output them based on user selected timezone. I tried writing a small function to do this, however, it does not output correctly.
// Date/time converter
function convertTZ($date, $tz, $tzFormat)
{
$date = new DateTime($date);
$date->setTimezone(new DateTimeZone($tz));
return $date->format($tzFormat);
}
echo $_SESSION['dtCurrLogin'].'<br />';
echo convertTZ($_SESSION['dtCurrLogin'], 'UTC', 'F j, Y # g:i:s a e');
dtCurrLogin from db = 2013-09-12 01:23:45
the above outputs :
2013-09-12 01:23:45
September 12, 2013 # 5:23:45 am UTC
Obviously this is not correct as I went from UTC to UTC so they should be equal. If I change to output EST then it shows 1:23:45 am, but of course that would not be right either.
Didn't realize I needed to specify incoming timezone... using the following worked for me...
function convertTZ($date_time, $from_tz, $to_tz, $format_tz)
{
$time_object = new DateTime($date_time, new DateTimeZone($from_tz));
$time_object->setTimezone(new DateTimeZone($to_tz));
return $time_object->format($format_tz);
}

Classic ASP amazon s3 rest authorisation

I am confused on what I am doing wrong here...
<script language="javascript" runat="server">
function GMTNow(){return new Date().toGMTString()}
</script>
<%
Const AWS_BUCKETNAME = "uk-bucketname"
Const AWS_ACCESSKEY = "GOES HERE"
Const AWS_SECRETKEY = "SECRET"
LocalFile = Server.Mappath("/test.jpg")
Dim sRemoteFilePath
sRemoteFilePath = "/files/test.jpg" 'Remote Path, note that AWS paths (in fact they aren't real paths) are strictly case sensitive
Dim strNow
strNow = GMTNow() ' GMT Date String
Dim StringToSign
StringToSign = Replace("PUT\n\nimage/jpeg\n\nx-amz-date:" & strNow & "\n/"& AWS_BUCKETNAME & sRemoteFilePath, "\n", vbLf)
Dim Signature
Signature = BytesToBase64(HMACSHA1(AWS_SECRETKEY, StringToSign))
Dim Authorization
Authorization = "AWS " & AWS_ACCESSKEY & ":" & Signature
Dim AWSBucketUrl
AWSBucketUrl = "http://s3.amazonaws.com/" & AWS_BUCKETNAME
With Server.CreateObject("Microsoft.XMLHTTP")
.open "PUT", AWSBucketUrl & sRemoteFilePath, False
.setRequestHeader "Authorization", Authorization
.setRequestHeader "Content-Type", "image/jpeg"
.setRequestHeader "Host", AWS_BUCKETNAME & ".s3.amazonaws.com"
.setRequestHeader "x-amz-date", strNow
.send GetBytes(LocalFile) 'Get bytes of local file and send
If .status = 200 Then ' successful
Response.Write "<a href="& AWSBucketUrl & sRemoteFilePath &" target=_blank>Uploaded File</a>"
Else ' an error ocurred, consider xml string of error details
Response.ContentType = "text/xml"
Response.Write .responseText
End If
End With
Function GetBytes(sPath)
dim fs,f
set fs=Server.CreateObject("Scripting.FileSystemObject")
set f=fs.GetFile(sPath)
GetBytes = f.Size
set f=nothing
set fs=nothing
End Function
Function BytesToBase64(varBytes)
With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64 = .Text
End With
End Function
Function HMACSHA1(varKey, varValue)
With Server.CreateObject("System.Security.Cryptography.HMACSHA1")
.Key = UTF8Bytes(varKey)
HMACSHA1 = .ComputeHash_2(UTF8Bytes(varValue))
End With
End Function
Function UTF8Bytes(varStr)
With Server.CreateObject("System.Text.UTF8Encoding")
UTF8Bytes = .GetBytes_4(varStr)
End With
End Function
%>
Now getting the error.
msxml3.dll error '800c0008'
The download of the specified resource has failed.
/s3.asp, line 39
I'd like to explain how S3 Rest Api works as far as I know.First, you need to learn what should be the string to sign Amazon accepts.
Format :
StringToSign = HTTP-Verb + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedAmzHeaders +
CanonicalizedResource;
Generating signed string :
Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );
Passing authorization header:
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;
Unfortunately you'll play byte to byte since there is no any SDK released for classic asp. So, should understand by reading the entire page http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html
For string to sign as you can see above in format, there are three native headers are reserved by the API. Content-Type, Content-MD5 and Date. These headers must be exists in the string to sign even your request hasn't them as empty without header name, just its value. There is an exception, Date header must be empty in string to sign if x-amz-date header is already exists in the request. Then, If request has canonical amazon headers, you should add them as key-value pairs like x-amz-headername:value. But, there is another exception need to be considered for multiple headers. Multiple headers should combine to one header with values comma separated.
Correct
x-amz-headername:value1,value2
Wrong
x-amz-headername:value1\n
x-amz-headername:value2
Most importantly, headers must be ascending order by its group in the string to sign. First, reserved headers with ascending order, then canonical headers with ascending order.
I'd recommend using DomDocument functionality to generate Base64 encoded strings.
Additionally instead of a Windows Scripting Component (.wsc files), you could use .Net's interops such as System.Security.Cryptography to generating keyed hashes more effectively with power of System.Text. All of these interoperabilities are available in today's IIS web servers.
So, as an example I wrote the below script just sends a file to bucket you specified. Consider and test it.
Assumed local file name is myimage.jpg and will be uploaded with same name to root of the bucket.
<script language="javascript" runat="server">
function GMTNow(){return new Date().toGMTString()}
</script>
<%
Const AWS_BUCKETNAME = "uk-bucketname"
Const AWS_ACCESSKEY = "GOES HERE"
Const AWS_SECRETKEY = "SECRET"
LocalFile = Server.Mappath("/test.jpg")
Dim sRemoteFilePath
sRemoteFilePath = "/files/test.jpg" 'Remote Path, note that AWS paths (in fact they aren't real paths) are strictly case sensitive
Dim strNow
strNow = GMTNow() ' GMT Date String
Dim StringToSign
StringToSign = Replace("PUT\n\nimage/jpeg\n\nx-amz-date:" & strNow & "\n/"& AWS_BUCKETNAME & sRemoteFilePath, "\n", vbLf)
Dim Signature
Signature = BytesToBase64(HMACSHA1(AWS_SECRETKEY, StringToSign))
Dim Authorization
Authorization = "AWS " & AWS_ACCESSKEY & ":" & Signature
Dim AWSBucketUrl
AWSBucketUrl = "https://" & AWS_BUCKETNAME & ".s3.amazonaws.com"
With Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
.open "PUT", AWSBucketUrl & sRemoteFilePath, False
.setRequestHeader "Authorization", Authorization
.setRequestHeader "Content-Type", "image/jpeg"
.setRequestHeader "Host", AWS_BUCKETNAME & ".s3.amazonaws.com"
.setRequestHeader "x-amz-date", strNow
.send GetBytes(LocalFile) 'Get bytes of local file and send
If .status = 200 Then ' successful
Response.Write "<a href="& AWSBucketUrl & sRemoteFilePath &" target=_blank>Uploaded File</a>"
Else ' an error ocurred, consider xml string of error details
Response.ContentType = "text/xml"
Response.Write .responseText
End If
End With
Function GetBytes(sPath)
With Server.CreateObject("Adodb.Stream")
.Type = 1 ' adTypeBinary
.Open
.LoadFromFile sPath
.Position = 0
GetBytes = .Read
.Close
End With
End Function
Function BytesToBase64(varBytes)
With Server.CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64 = .Text
End With
End Function
Function HMACSHA1(varKey, varValue)
With Server.CreateObject("System.Security.Cryptography.HMACSHA1")
.Key = UTF8Bytes(varKey)
HMACSHA1 = .ComputeHash_2(UTF8Bytes(varValue))
End With
End Function
Function UTF8Bytes(varStr)
With Server.CreateObject("System.Text.UTF8Encoding")
UTF8Bytes = .GetBytes_4(varStr)
End With
End Function
%>
The Amazon Signature must be url encoded in a slightly different way to what VBSCript encodes. The following function will encode the result correctly:
JScript Version:
function amazonEncode(s)
{
return Server.UrlEncode(s).replace(/\+/g,"%20").replace(/\%2E/g,".").replace(/\%2D/g,"-").replace(/\%7E/g,"~").replace(/\%5F/g,"_");
}
VBScript Version:
function amazonEncode(s)
dim retval
retval = Server.UrlEncode(s)
retval = replace(retval,"+","%20")
retval = replace(retval,"%2E",".")
retval = replace(retval,"%2D","-")
retval = replace(retval,"%7E","~")
retval = replace(retval,"%5F","_")
amazonEncode = retval
end function
As for base64, I used .NET's already built functionality for it. I had to create a DLL to wrap it, so that I could use it from JScript (or VBScript).
Here's how to create that dll:
Download the free C# 2010 Express and install it.
You also need to use two other tools that you won’t have a path to, so you will need to add the path to your PATH environment variable, so at a cmd prompt search for regasm.exe, guidgen.exe and sn.exe (you might find several versions – select the one with the latest date).
• cd\
• dir/s regasm.exe
• dir/s sn.exe
• dir/s guidgen.exe
So as an example, a COM object that has just one method which just returns “Hello”:
Our eventual aim is to use it like this:
<%#Language=JScript%>
<%
var x = Server.CreateObject("blah.whatever");
Response.Write(x.someMethod());
%>
or
<%#Language=VBScript%>
<%
dim x
set x = Server.CreateObject("blah.whatever")
Response.Write x.someMethod()
%>
• Start C# and create a new project
• Select “Empty Project”
• Give it a name – this becomes the namespace by default (the blah in the sample above)
• Next save the project (so you know where to go for the next bit). This will create a folder structure like so:
o blah this contains your solution files that the editor needs (blah.sln etc)
 blah this contains your source code and project files
• bin
o Debug the compiled output ends up here
• Next, using the cmd console, navigate to the root blah folder and create a key pair file:
sn –k key.snk
• Next you need a unique guid (enter guidgen at the cmd prompt)
o Select registry format
o Click “New Guid”
o Click “Copy”
• Back to C# editor – from the menu, select Project – Add Class
• Give it a name – this is the whatever in the sample above
• After the opening brace just after the namespace line type:
[GuidAttribute(“paste your guid here”)]
remove the curly brackets from your pasted guid
• You will need to add another “using” at the top
using System.Runtime.InteropServices;
• Finally you need to create someMethod
The final C# code looks like this (the bits in red may be different in your version):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace blah
{
[GuidAttribute("AEF4F27F-9E97-4189-9AD5-64386A1699A7")]
public class whatever
{
public string someMethod()
{
return "Hello";
}
}
}
• Next, from the menu, select Project – Properties
o On the left, select Application and, for the Output type dropdown, select “Class Library”
o On the left, select Signing and tick the “Sign the assembly” box, then browse to the key.snk file you made earlier
o Save the properties (CTRL-S)
• Next build the dll (Press F6) – This will create a dll in the Debug folder
• Open a cmd window as administrator (right click cmd.exe and select “Run as Administrator”)
• Navigate to the Debug folder and enter the following to register the assembly:
regasm blah.dll /tlb:blah.tlb /codebase blah
That’s it – the above is a genuine COM component and will work in other applications, the example below allows for event handling and only really works in ASP due to the default property mechanism of ASP:
The code for the base64 stuff would be:
// returns a base 64 encoded string that has been encrypted with SHA256
// parameters:
// s string to encrypt
// k key to use during encryption
public string getBase64SHA256(string s, string k)
{
HMACSHA256 sha = new HMACSHA256();
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
sha.Key = encoding.GetBytes(k);
byte[] hashBytes = sha.ComputeHash(encoding.GetBytes(s));
return System.Convert.ToBase64String(hashBytes);
}
// returns a base 64 encoded string that has been encrypted with SHA1
// parameters:
// s string to encrypt
// k key to use during encryption
public string getBase64SHA1(string s, string k)
{
HMACSHA1 sha = new HMACSHA1();
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
sha.Key = encoding.GetBytes(k);
byte[] hashBytes = sha.ComputeHash(encoding.GetBytes(s));
return System.Convert.ToBase64String(hashBytes);
}
You would need the relevant usings:
using System.Security.Cryptography;
The signature in full must have all the query string name-value pairs in alphabetical order before computing the SHA and base64. Here is my version of the signature creator function:
function buildAmazonSignature(host,req,qstring)
{
var str="", i, arr = String(qstring).split("&");
for (i=0; i<arr.length; i++)
arr[i] = arr[i].split("=");
arr.sort(amazonSortFunc);
for (i=0; i<arr.length; i++)
{
if (str != "")
str += "&";
str += arr[i][0] + "=" + arr[i][1];
}
str = "GET\n"+host+"\n"+req+"\n"+str;
var utils = Server.CreateObject("FMAG.Utils");
var b64 = utils.getBase64SHA256(str, "xxxxxxxxxx");
utils = null;
return amazonEncode(b64);
}
function amazonSortFunc(a,b)
{
return (a[0]<b[0])?-1:((a[0]>b[0])?1:0);
}
VBScript doesn't have a very good array sort facility, so you'll have to work that one out yourself - sorry
Also I have the timestamp in this format:
YYYY-MM-DDTHH:MM:SSZ
Also the stuff in the query string included the following:
AWSAccessKeyId
SignatureMethod
SignatureVersion
Version
Expires
Action
Hope that helps
Thank you so much for this question, it has been such a great help to start my WSH/VBScript for my S3 backup service ;-)
I do not have much time, so I will not go through the details of the things I have changed from Chris' code, but please find below my little prototype script which works perfectly ;-)
This is just a WSH/VBScript, so you do not need IIS to run it, you just need to paste the content in a file with the ".vbs" extension, and you can then directly execute it ;-)
Option Explicit
'-- Amazon Web Services > My Account > Access Credentials > Access Keys --'
Dim strAccessKeyID: strAccessKeyID = "..."
Dim strSecretAccessKey: strSecretAccessKey = "..."
'-- Parameters: --'
Dim strLocalFile: strLocalFile = "..."
Dim strRemoteFile: strRemoteFile = "..."
Dim strBucket: strBucket = "..."
'-- Authentication: --'
Dim strNowInGMT: strNowInGMT = NowInGMT()
Dim strStringToSign: strStringToSign = _
"PUT" & vbLf & _
"" & vbLf & _
"text/xml" & vbLf & _
strNowInGMT & vbLf & _
"/" & strBucket + "/" & strRemoteFile
Dim strSignature: strSignature = ConvertBytesToBase64(HMACSHA1(strSecretAccessKey, strStringToSign))
Dim strAuthorization: strAuthorization = "AWS " & strAccessKeyID & ":" & strSignature
'-- Upload: --'
Dim xhttp: Set xhttp = CreateObject("MSXML2.ServerXMLHTTP")
xhttp.open "PUT", "http://" & strBucket & ".s3.amazonaws.com/" & strRemoteFile, False
xhttp.setRequestHeader "Content-Type", "text/xml"
xhttp.setRequestHeader "Date", strNowInGMT 'Yes, this line is mandatory ;-) --'
xhttp.setRequestHeader "Authorization", strAuthorization
xhttp.send GetBytesFromFile(strLocalFile)
If xhttp.status = "200" Then
WScript.Echo "The file has been successfully uploaded ;-)"
Else
WScript.Echo "There was an error :-(" & vbCrLf & vbCrLf & _
xhttp.responseText
End If
Set xhttp = Nothing
'-- NowInGMT ------------------------------------------------------------------'
Function NowInGMT()
'This is probably not the best implementation, but it works ;-) --'
Dim sh: Set sh = WScript.CreateObject("WScript.Shell")
Dim iOffset: iOffset = sh.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias")
Dim dtNowGMT: dtNowGMT = DateAdd("n", iOffset, Now())
Dim strDay: strDay = "NA"
Select Case Weekday(dtNowGMT)
Case 1 strDay = "Sun"
Case 2 strDay = "Mon"
Case 3 strDay = "Tue"
Case 4 strDay = "Wed"
Case 5 strDay = "Thu"
Case 6 strDay = "Fri"
Case 7 strDay = "Sat"
Case Else strDay = "Error"
End Select
Dim strMonth: strMonth = "NA"
Select Case Month(dtNowGMT)
Case 1 strMonth = "Jan"
Case 2 strMonth = "Feb"
Case 3 strMonth = "Mar"
Case 4 strMonth = "Apr"
Case 5 strMonth = "May"
Case 6 strMonth = "Jun"
Case 7 strMonth = "Jul"
Case 8 strMonth = "Aug"
Case 9 strMonth = "Sep"
Case 10 strMonth = "Oct"
Case 11 strMonth = "Nov"
Case 12 strMonth = "Dec"
Case Else strMonth = "Error"
End Select
Dim strHour: strHour = CStr(Hour(dtNowGMT))
If Len(strHour) = 1 Then strHour = "0" & strHour End If
Dim strMinute: strMinute = CStr(Minute(dtNowGMT))
If Len(strMinute) = 1 Then strMinute = "0" & strMinute End If
Dim strSecond: strSecond = CStr(Second(dtNowGMT))
If Len(strSecond) = 1 Then strSecond = "0" & strSecond End If
Dim strNowInGMT: strNowInGMT = _
strDay & _
", " & _
Day(dtNowGMT) & _
" " & _
strMonth & _
" " & _
Year(dtNowGMT) & _
" " & _
strHour & _
":" & _
strMinute & _
":" & _
strSecond & _
" +0000"
NowInGMT = strNowInGMT
End Function
'-- GetBytesFromString --------------------------------------------------------'
Function GetBytesFromString(strValue)
Dim stm: Set stm = CreateObject("ADODB.Stream")
stm.Open
stm.Type = 2
stm.Charset = "ascii"
stm.WriteText strValue
stm.Position = 0
stm.Type = 1
GetBytesFromString = stm.Read
Set stm = Nothing
End Function
'-- HMACSHA1 ------------------------------------------------------------------'
Function HMACSHA1(strKey, strValue)
Dim sha1: Set sha1 = CreateObject("System.Security.Cryptography.HMACSHA1")
sha1.key = GetBytesFromString(strKey)
HMACSHA1 = sha1.ComputeHash_2(GetBytesFromString(strValue))
Set sha1 = Nothing
End Function
'-- ConvertBytesToBase64 ------------------------------------------------------'
Function ConvertBytesToBase64(byteValue)
Dim dom: Set dom = CreateObject("MSXML2.DomDocument")
Dim elm: Set elm = dom.CreateElement("b64")
elm.dataType = "bin.base64"
elm.nodeTypedValue = byteValue
ConvertBytesToBase64 = elm.Text
Set elm = Nothing
Set dom = Nothing
End Function
'-- GetBytesFromFile ----------------------------------------------------------'
Function GetBytesFromFile(strFileName)
Dim stm: Set stm = CreateObject("ADODB.Stream")
stm.Type = 1 'adTypeBinary --'
stm.Open
stm.LoadFromFile strFileName
stm.Position = 0
GetBytesFromFile = stm.Read
stm.Close
Set stm = Nothing
End Function
Dear stone-edge-technology-VBScript-mates (*), let me know if it is working for you as well ;-)
(*) This is a reference to the comment from Spudley, see above ;-)