Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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 = config[:ip]
- self.start_time = config[:start_time]
- self.acl = config[:acl]
- self.url = config[:url]
- self.hash_strategy = config[:hash_strategy] || :sha256
- self.key = config[:key] || "aabbccddeeff00112233445566778899"
- @window = config[:window] || 300
- @session_id = config[:session_id]
- @data = config[:data]
- @salt = config[:salt]
- @field_delimiter = config[:field_delimiter] || "~"
- @early_url_encoding = config[:early_url_encoding] || true
- 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
Add Comment
Please, Sign In to add comment