Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
ShifterFilms
Visitor

CloudFront Secure streaming

We've had a bit of an issue figuring out how to use CloudFront for a protected stream. We have preview episodes which are okay to use public, not https url's, but for all full catalog, we need to have security in place.

Can someone who uses Amazon CloudFront point us in the right direction as to what exactly we need to do to get our Roku channel to authenticate with our private CloudFront URLs? Where in the code do we deal with SSL certificates?
0 Kudos
14 REPLIES 14
ShifterFilms
Visitor

Re: CloudFront Secure streaming

I found somewhat of a solution for this with expiring URLs. I'd like a better solution.

It appears if you have a ? in the URL, the Roku will not read the URL correctly. So after I generate the expiring URL with authentication keys, I'm using a URL shortener hosted on my server to create a new URL. Then I'm having the XML file written dynamically and updated through a cron job.

Hope this helps someone. Or if somebody has a better solution, let me know.
0 Kudos
RokuJoel
Binge Watcher

Re: CloudFront Secure streaming

I don't believe there is any reason why a ? in a url would cause any problems whatsoever. What might cause problems is a failure to urlencode the parameters in the URL after the ?.

- Joel
0 Kudos
ShifterFilms
Visitor

Re: CloudFront Secure streaming

Joel -

Can you provide an example of how that would be structured?
0 Kudos
RokuMarkn
Visitor

Re: CloudFront Secure streaming

Just to be clear, the question mark in your URL is the marker that begins the URL parameters, correct? Not some other question mark embedded in the parameters or anything like that? Can you provide an example of the kind of URL you are using?

--Mark
0 Kudos
RokuJoel
Binge Watcher

Re: CloudFront Secure streaming

"ShifterFilms" wrote:
Joel -

Can you provide an example of how that would be structured?


you might create your url like this:

url="http://myserver.com/restAPI?getPopSongs="+urlencode("Justin Bieber")+"&grammyNominated=true"


with a urlencode function like this:

function urlencode(text as string) as string
xfer=createobject("roUrlTransfer")
return xfer.urlencode(text)
end function
0 Kudos
ShifterFilms
Visitor

Re: CloudFront Secure streaming

The URL would be something like this:

http://d34TCSSDs9r8qxa.cloudfront.net/VIDEONAME.mp4?Expires=4340056027&Signature=xxce456iLCc5phPnt8NrH~orflXZs34rljsgfnkjx5sntPXj7Ov~YQ50ZOHsdafeTTfawoiLG1ndNxB5C3uh8Zsv2qil6Z2QGradEA34M9y8y-kNZ2lSbiwaVOEYt0UYh3TIvpKIpS9Mz15TSrsksioDSS~rC-U_&Key-Pair-Id=A45RRTQASD456LDF
0 Kudos
RokuMarkn
Visitor

Re: CloudFront Secure streaming

Since there are tildes in the parameters, they need to be encoded as RokuJoel said. There are three parameters (Expires, Signature, and Key-Pair-Id), so each of the 3 values should be URL encoded.

--Mark
0 Kudos
belltown
Roku Guru

Re: CloudFront Secure streaming

"RokuMarkn" wrote:
Since there are tildes in the parameters, they need to be encoded as RokuJoel said. There are three parameters (Expires, Signature, and Key-Pair-Id), so each of the 3 values should be URL encoded.

--Mark

Yes, tildes ("~") should be encoded, according to RFC 1738. However, it appears that UrlEncode () does not encode tildes.

I ran the following code snippet:


ut = CreateObject ("roUrlTransfer")
For c = 0 To 127
ch = Chr (c)
urlEncode = ut.UrlEncode (ch)
If Len (urlEncode) = 1 And ch = urlEncode
Print "Did not encode: " + ch
EndIf
End For


and got the following result:


------ Running ------
Did not encode: -
Did not encode: .
Did not encode: 0
Did not encode: 1
Did not encode: 2
Did not encode: 3
Did not encode: 4
Did not encode: 5
Did not encode: 6
Did not encode: 7
Did not encode: 8
Did not encode: 9
Did not encode: A
Did not encode: B
Did not encode: C
Did not encode: D
Did not encode: E
Did not encode: F
Did not encode: G
Did not encode: H
Did not encode: I
Did not encode: J
Did not encode: K
Did not encode: L
Did not encode: M
Did not encode: N
Did not encode: O
Did not encode: P
Did not encode: Q
Did not encode: R
Did not encode: S
Did not encode: T
Did not encode: U
Did not encode: V
Did not encode: W
Did not encode: X
Did not encode: Y
Did not encode: Z
Did not encode: _
Did not encode: a
Did not encode: b
Did not encode: c
Did not encode: d
Did not encode: e
Did not encode: f
Did not encode: g
Did not encode: h
Did not encode: i
Did not encode: j
Did not encode: k
Did not encode: l
Did not encode: m
Did not encode: n
Did not encode: o
Did not encode: p
Did not encode: q
Did not encode: r
Did not encode: s
Did not encode: t
Did not encode: u
Did not encode: v
Did not encode: w
Did not encode: x
Did not encode: y
Did not encode: z
Did not encode: ~

So it looks like UrlEncode encodes all characters except: hyphen ("-"), underscore ("_"), period ("."), alphanumerics and tilde ("~").

I don't believe this is the correct behavior according to RFC 1738.

Also, when I run the above code using Escape () instead of UrlEncode () I get the exact same output even though they are supposed to encode differently.

Is this a bug, or am I missing something here?
0 Kudos
ShifterFilms
Visitor

Re: CloudFront Secure streaming

This is the partial solution to creating the CloudFront URLs needed. This PHP function will create valid expiring URL's CloudFront likes:



function getSignedURL($resource, $timeout)
{
//This comes from key pair you generated for cloudfront
$keyPairId = "YOURKEYPAIRIDHERE1";

$expires = time() + $timeout; //Time out in seconds
$json = '{"Statement":[{"Resource":"'.$resource.'","Condition":{"DateLessThan":{"AWS:EpochTime":'.$expires.'}}}]}';

//Read Cloudfront Private Key Pair
$fp=fopen("your-keyfile.pem","r");
$priv_key=fread($fp,8192);
fclose($fp);

//Create the private key
$key = openssl_get_privatekey($priv_key);
if(!$key)
{
echo "<p>Failed to load private key!</p>";
return;
}

//Sign the policy with the private key
if(!openssl_sign($json, $signed_policy, $key, OPENSSL_ALGO_SHA1))
{
echo '<p>Failed to sign policy: '.openssl_error_string().'</p>';
return;
}

//Create url safe signed policy
$base64_signed_policy = base64_encode($signed_policy);
$signature = str_replace(array('+','=','/'), array('-','_','~'), $base64_signed_policy);

//Construct the URL
$url = $resource.'?Expires='.$expires.'&Signature='.$signature.'&Key-Pair-Id='.$keyPairId;

return $url;
}


My solution was to take this function and use it in conjunction with a URL shorterning script. That way I didn't have to deal with any BrightScript to format the URL's properly. The other solutions presented are probably cleaner, but if you're a little BrightScript retarded like myself, this could be a solution for you.
0 Kudos