Skip to content

Instantly share code, notes, and snippets.

@alchemycs
Created April 7, 2011 03:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alchemycs/907000 to your computer and use it in GitHub Desktop.
Save alchemycs/907000 to your computer and use it in GitHub Desktop.
Generates signed referrer links for auto-authentication into CompliSpace Fundamentals Sites
<?php
/**
* Generates signatures for referred logins to CompliSpace Fundamentals sites.
*
* Example: CSFReferrer::generate('http://xyz.complispace.com.au', 'bob',
* 'sampleAccessKeyId', 'sampleSecretAccessKey', 1320969600);
*
* @see Development Blog <http://complispace.github.com/>
* @see GitHub Repository <https://github.com/CompliSpace>
* @see Corporate Website <http://www.complispace.com.au/>
*/
class CSFReferrer {
static function generate($url, $referredUserLogin, $referredAccessKeyId, $secretAccessKey, $referredExpires) {
//Pull out the parts of the url and make sure that it parses ok
if (($urlParts = parse_url($url)) === false) {
throw new InvalidArgumentException('The URL is malformed');
}
// @TODO : Should realy check that the other paramters are valid
//Separate out the query parameters
$urlParameters = array();
if (!isset($urlParts['query'])) {
$urlParts['query'] = '';
}
parse_str($urlParts['query'], $urlParameters);
//These are our parameters for the signature
$signatureParameters = array(
'referredUserLogin' => $referredUserLogin,
'referredExpires' => $referredExpires,
'referredAccessKeyId' => $referredAccessKeyId
);
//Create the string to sign
$stringToSign = implode(':', $signatureParameters);
//Calculate the signature
$signature = base64_encode(hash_hmac('sha256', $stringToSign, $secretAccessKey, false));
//Put the signature onto the list of parameters
$signatureParameters['referredSignature'] = $signature;
//Now we want to merge our parameters onto any original parameters
$urlParameters = array_merge($urlParameters, $signatureParameters);
$queryString = http_build_str($urlParameters);
$urlParts['query'] = $queryString;
$signedUrl = http_build_url($urlParts);
return $signedUrl;
}
}
$userLogin = "bob";
$expires = 1320969600;
$accessKeyId = "mySiteId";
$secretAccessKey = "connie";
$url = "http://xyz.complispace.com.au/Home";
$output = CSFReferrer::generate($url, $userLogin, $accessKeyId, $secretAccessKey, $expires);
/*
* http://xyz.complispace.com.au/Home
* ?referredUserLogin=bob
* &referredExpires=1320969600
* &referredAccessKeyId=mySiteId
* &referredSignature=NzQzNWI5MTI5ZjA3YTkzZjc5MDg3NWYwNjFjOTM5NmIyN2NmNWQ2YmI1YmU4Y2Y3YjM3YWZhY2QxMWRkMDBjYQ%3D%3D
*/
echo $output . "\n";
?>
/**
* Generates signatures for referred logins to CompliSpace Fundamentals sites.
*
* See example `MainClass` for usage example
*
* This file was written and tested using MonoDevelop <http://monodevelop.com/>
* therefore YMMV.
*
* @see Development Blog <http://complispace.github.com/ReferredSignIn.html>
* @see GitHub Repository <https://github.com/CompliSpace>
* @see Corporate Website <http://www.complispace.com.au/>
*/
using System;
using System.Security.Cryptography;
using System.Diagnostics; //This is only required for the Process.Start() used in the demo usage main class
namespace CompliSpace
{
public class CSFReferrer
{
protected string accessKeyId;
protected string secretAccessKey;
protected long defaultExpiryOffset = 60*60; //1 hour
public CSFReferrer (string anAccessKeyId, string aSecretAccessKey)
{
accessKeyId = anAccessKeyId;
secretAccessKey = aSecretAccessKey;
}
public CSFReferrer (string anAccessKeyId, string aSecretAccessKey, long aDefaultExpiryOffset)
: this(anAccessKeyId, aSecretAccessKey)
{
defaultExpiryOffset = aDefaultExpiryOffset;
}
public string GenerateForUser(string url, string referredUserLogin) {
return Generate(url, referredUserLogin, accessKeyId, secretAccessKey, GetCurrentUnixTimestamp()+defaultExpiryOffset);
}
public string GenerateForUser(string url, string referredUserLogin, long anExpiryOffset) {
return Generate(url, referredUserLogin, accessKeyId, secretAccessKey, GetCurrentUnixTimestamp()+anExpiryOffset);
}
public static long GetCurrentUnixTimestamp() {
//WTF? Microsoft wants us to use their 1 AD offset, despite the rest of the computing world!
return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
public static string SignString(string stringToSign, string signingKey) {
HMACSHA256 hash = new HMACSHA256(System.Text.Encoding.UTF8.GetBytes(signingKey));
byte[] signedBuffer = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringToSign));
string signedString = BitConverter.ToString(signedBuffer).Replace("-", "").ToLower();
return signedString;
}
public static string Generate(string url,
string referredUserLogin,
string referredAccessKeyId,
string referredSecretAccessKey,
long referredExpires) {
string stringToSign = referredUserLogin+":"+referredExpires+":"+referredAccessKeyId;
string signedString = CSFReferrer.SignString(stringToSign, referredSecretAccessKey);
byte[] encodingBuffer = System.Text.Encoding.UTF8.GetBytes(signedString);
signedString = System.Convert.ToBase64String(encodingBuffer);
string signedUrl = url+"?referredUserLogin="+referredUserLogin+"&referredExpires="+referredExpires+"&referredAccessKeyId="+referredAccessKeyId+"&referredSignature="+signedString;
return signedUrl;
}
}
//The following class is for demonstrating the use of of the CSFReferrer class above
class MainClass
{
public static void Main (string[] args)
{
string accessKeyId = "myAccessKeyId";
string secretAccessKey = "mySecretAccessKey";
string csfUrl = "https://sample.complispace.com.au";
string referredUser = "bob.dobbs";
long expiryOffset = 60*60*6; //Maximum of six hours
CSFReferrer csReference = new CSFReferrer(accessKeyId, secretAccessKey);
/* Optionaly change the default expiry offset - default is 1 hour
CSFReferrer csReference = new CSFReferrer(accessKeyId, secretAccessKey, expiryOffset);
*/
string url = csReference.GenerateForUser(csfUrl, referredUser);
/* Optionally overide the expiry offset per call
string url = csReference.GenerateForUser(csfUrl, referredUser, expiryOffset);
*/
Console.WriteLine("Got this generated:\n"+url);
Process.Start(url);
}
}
}
/*
see Development Blog <http://complispace.github.com/ReferredSignIn.html>
see GitHub Repository <https://github.com/CompliSpace>
see Corporate Website <http://www.complispace.com.au/>
*/
(function() {
var url = require('url');
var crypto = require('crypto');
var querystring = require('querystring');
var util = require('util');
exports.generate = function(aUrl, aReferredUserLogin, aReferredExpires, credentials) {
//parse the url into its components
var uriObject = url.parse(aUrl);
//Caluclate the string to sign
var stringToSign = util.format("%s:%s:%s", aReferredUserLogin, aReferredExpires, credentials.accessKeyId);
//Calculate the signature
var hmac = crypto.createHmac('sha256', credentials.secretAccessKey);
hmac.update(stringToSign);
var signature = Buffer(hmac.digest('hex')).toString('base64');
//Extract the query parameters that may already exist
var query = querystring.parse(uriObject.query);
//Update the query parameters with referred sign in parameters
query = {
referredUserLogin:aReferredUserLogin,
referredExpires:aReferredExpires,
referredAccessKeyId:credentials.accessKeyId,
referredSignature:signature
};
//Put the query back into our object ('search' parameter overides 'query' parameter: http://nodejs.org/api/url.html#url_url_format_urlobj)
uriObject.search = querystring.stringify(query);
//Recomompose the url and return it
return url.format(uriObject);
}
})();
/*
A credentials object looks like this:
var credentials = {
accessKeyId:'mySiteId',
secretAccessKey:'connie'
}
Date object can be tricky for newbies since the conversion to a timestamp uses millisecond precission where
most other OS systems use seconds.
Please see https://gist.github.com/2405969 for an dead easy way to easily
get a UNXI based timestamp from any JS Date object.
*/
/* Example usage
* http://xyz.complispace.com.au/Home
* ?referredUserLogin=bob
* &referredExpires=1320969600
* &referredAccessKeyId=mySiteId
* &referredSignature=NzQzNWI5MTI5ZjA3YTkzZjc5MDg3NWYwNjFjOTM5NmIyN2NmNWQ2YmI1YmU4Y2Y3YjM3YWZhY2QxMWRkMDBjYQ%3D%3D
var csf = require('./CSFReferrer.js');
var dst = "http://www.complispace.com.au/Home";
var login = "bob";
var expires = 1320969600;
var cred = { accessKeyId:'mySiteId', secretAccessKey:'connie'};
var redirectUrl = csf.generate(dst, login, expires, cred);
console.log(redirectUrl);
*/
"""
Generates signatures for referred logins to CompliSpace Fundamentals sites.
Example: CSFReferrer::generate('http://xyz.complispace.com.au', 'bob', 'sampleAccessKeyId', 'sampleSecretAccessKey', 1320969600);
see Development Blog <http://complispace.github.com/ReferredSignIn.html>
see GitHub Repository <https://github.com/CompliSpace>
see Corporate Website <http://www.complispace.com.au/>
"""
import time
import webbrowser
import urlparse
import hashlib
import hmac
from base64 import standard_b64encode
class CSFReferrer:
"""Class to create CompliSpace referred login signed urls."""
def __init__(self, accessKeyId, secretAccessKey):
"""Initialize a CSFReferrer object with an access key id and a secret access key."""
self.accessKeyId = accessKeyId
self.secretAccessKey = secretAccessKey
def generate(self, url, referredUserLogin, referredExpires):
"""Build a signed referred login url from the parameters.
Returns A url as a string."""
#Get the parts of the URL
urlParts = urlparse.urlparse(url)
#Separate out the query parameters
urlParameters = urlparse.parse_qsl(urlParts.query)
#These are the parameters for the signature
signatureParameters = [
("referredUserLogin", referredUserLogin),
("referredExpires", referredExpires),
("referredAccessKeyId", self.accessKeyId)
]
#Create the string to sign
stringToSign = "%s:%s:%s" % (referredUserLogin, referredExpires, self.accessKeyId)
#Calculate the signature
signature = standard_b64encode(hmac.HMAC(self.secretAccessKey, stringToSign, hashlib.sha256).hexdigest());
#Add the signature to our extended parameters
signatureParameters.extend([("referredSignature", signature)])
#Add the our extended parameters to any existing user supplied parameters
urlParameters.extend(signatureParameters)
#Need to get the url parts into a mutable list...
newParts = [part for part in urlParts]
#...and then update the parameters
newParts[4] = "&".join(["%s=%s" % (key, value) for (key, value) in urlParameters])
#Finally we put all the pieces back together again
newUrl = urlparse.urlunparse(newParts)
return newUrl
if __name__ == "__main__":
#When you generate the timestamp, make sure it is an integer
#aTimeStamp = int(time.time()+60*60)
aTimeStamp = 1320969600
anAccessKeyId = "mySiteId"
aSecretAccessKey = "connie"
aReferredUser = "bob"
ref = CSFReferrer(anAccessKeyId, aSecretAccessKey)
csfUrl = "https://xyz.complispace.com.au/Home"
#csfUrl += "?me=you&bob=good&connie=evil"
url = ref.generate(csfUrl, aReferredUser, aTimeStamp)
print url
#webbrowser.open(url)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment