Created
April 29, 2013 17:50
-
-
Save repocers/5483370 to your computer and use it in GitHub Desktop.
Akamai token generation for ruby applications.
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
require "cgi" | |
class AkamaiTokenConfig | |
attr_accessor :window, :session_id, :data, :salt, :field_delimiter, :early_url_encoding, :ip | |
attr_reader :start_time, :hash_strategy, :acl, :url | |
def initialize(config={}) | |
@ip = '' | |
self.start_time = Time.now.to_i | |
self.acl = '/*' | |
self.url = '' | |
self.hash_strategy = :sha256 | |
self.key = '47187B5BA02AC633DC26A87B24927435' | |
@window = 140 | |
@session_id = '' | |
@data = '' | |
@salt = '' | |
@field_delimiter = "~" | |
@early_url_encoding = false | |
end | |
def encode(value) | |
@early_url_encoding ? CGI.escape(value) : value | |
end | |
def start_time=(value) | |
return if value.nil? | |
raise "start_time out of range" if value < 0 || value > 4294967295 | |
@start_time = value | |
end | |
# hexlify and unhexlify, respectively | |
def key=(value) | |
@key = AkamaiToken.hexlify(value) | |
end | |
def key | |
AkamaiToken.unhexlify(@key) | |
end | |
def hash_strategy=(value) | |
raise "Invalid hash strategy" if ![:md5, :sha1, :sha256].include?(value) | |
@hash_strategy = value | |
end | |
def acl=(value) | |
return if value.nil? | |
raise "ACL and URL cannot both be set at the same time" if !@url.nil? | |
@acl = value | |
end | |
def url=(value) | |
return if value.nil? | |
raise "ACL and URL cannot both be set at the same time" if !@acl.nil? | |
@url = value | |
end | |
def start_time_field | |
fieldify("st", @start_time) | |
end | |
def expiration_field | |
time = @start_time || Time.now.to_i | |
expiration = time + @window | |
fieldify("exp", expiration) | |
end | |
def acl_field | |
@url.nil? ? fieldify("acl", encode(@acl || "/*")) : "" | |
end | |
def url_field | |
@acl.nil? ? fieldify("url", encode(@url)) : "" | |
end | |
def ip_field | |
@ip ? fieldify("ip", encode(@ip)) : "" | |
end | |
def session_field | |
@session_id ? fieldify("id", encode(@session_id)) : "" | |
end | |
def data_field | |
@data ? fieldify("data", encode(@data)) : "" | |
end | |
def salt_field | |
@salt ? fieldify("salt", encode(@salt)) : "" | |
end | |
def fieldify(key, value) | |
"#{key}=#{value}" | |
end | |
end | |
class AkamaiToken | |
HASH_STRATEGY = { :sha1 => OpenSSL::Digest::SHA1, :sha256 => OpenSSL::Digest::SHA256, | |
:md5 => OpenSSL::Digest::MD5 } | |
def initialize(debug=false) | |
@debug = debug | |
end | |
def self.hexlify(value) | |
value.unpack("C*").map { |byte| "%02X" % byte }.join("") | |
end | |
def self.unhexlify(value) | |
[value].pack("H*") | |
end | |
def join_fields(fields, delimiter) | |
fields.reject { |field| field == "" }.join(delimiter) | |
end | |
def generate_token(token_config) | |
# sanity check | |
if (!token_config.acl && !token_config.url) || (token_config.acl && token_config.url) | |
raise "Must specify either an ACL or a URL but not both" | |
end | |
# determine values for hashing | |
t = token_config | |
mtoken = join_fields([t.ip_field, t.start_time_field, t.expiration_field, t.acl_field, t.session_field, | |
t.data_field], t.field_delimiter) | |
mtoken_digest = join_fields([mtoken, t.url_field, t.salt_field], t.field_delimiter) | |
encoded_key = AkamaiToken.hexlify(token_config.key) | |
hmac = OpenSSL::HMAC::digest(HASH_STRATEGY[token_config.hash_strategy].new, encoded_key, mtoken_digest) | |
encoded_hmac = AkamaiToken.hexlify(hmac) | |
if @debug | |
puts "SIGNING VALUE: #{mtoken_digest}" | |
puts "PRODUCES: #{encoded_hmac}" | |
end | |
"#{join_fields([mtoken, "hmac"], token_config.field_delimiter)}=#{encoded_hmac}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the gist!
But I'm continuously getting
RuntimeError: ACL and URL cannot both be set at the same time
error.How to use this classes properly?