Skip to content

Instantly share code, notes, and snippets.

@repocers
Created April 29, 2013 17:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save repocers/5483370 to your computer and use it in GitHub Desktop.
Save repocers/5483370 to your computer and use it in GitHub Desktop.
Akamai token generation for ruby applications.
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
@scaryguy
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment