Created
April 7, 2011 03:45
-
-
Save alchemycs/907000 to your computer and use it in GitHub Desktop.
Generates signed referrer links for auto-authentication into CompliSpace Fundamentals Sites
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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"; | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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); | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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); | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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