Class: Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/AuthenticationSDK/util/Cache.rb

Overview

P12 file certificate Cache

Constant Summary collapse

@@cache_obj =
ActiveSupport::Cache::MemoryStore.new
@@mutex =
Mutex.new

Instance Method Summary collapse

Instance Method Details

#addPublicKeyToCache(runEnvironment, keyId, publicKey) ⇒ Object



290
291
292
293
294
295
# File 'lib/AuthenticationSDK/util/Cache.rb', line 290

def addPublicKeyToCache(runEnvironment, keyId, publicKey)
  cacheKey = "#{Constants::PUBLIC_KEY_CACHE_IDENTIFIER}_#{runEnvironment}_#{keyId}"
  @@mutex.synchronize do
    @@cache_obj.write(cacheKey, publicKey)
  end
end

#fetchCachedP12Certificate(merchantConfig) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/AuthenticationSDK/util/Cache.rb', line 20

def fetchCachedP12Certificate(merchantConfig)
  merchantId = merchantConfig.merchantId
  certificateFilePath = merchantConfig.p12KeyFilePath

  cacheKey = merchantConfig.keyFilename + "_JWT"

  @@mutex.synchronize do
    cachedCertificateInfo = @@cache_obj.read(cacheKey)
    fileModifiedTime = File.mtime(certificateFilePath)

    if !cachedCertificateInfo || cachedCertificateInfo.empty? || fileModifiedTime != cachedCertificateInfo.file_modified_time
      setupCache(cacheKey, certificateFilePath, merchantConfig)
      cachedCertificateInfo = @@cache_obj.read(cacheKey)
    end

    return cachedCertificateInfo
  end
end

#fetchPEMFileForNetworkTokenization(filePath) ⇒ Object

DEPRECATED: This method has been marked as Deprecated and will be removed in coming releases.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/AuthenticationSDK/util/Cache.rb', line 269

def fetchPEMFileForNetworkTokenization(filePath)
  warn("[DEPRECATED] 'fetchPEMFileForNetworkTokenization' method is deprecated and will be removed in coming releases.")

  # Thread-safe cache access for deprecated method

  @@mutex.synchronize do
    pem_file_cache = @@cache_obj.read('privateKeyFromPEMFile')
    cached_pem_file_last_updated_time = @@cache_obj.read('cachedLastModifiedTimeOfPEMFile')

    if File.exist?(filePath)
      current_last_modified_time_of_PEM_file = File.mtime(filePath)
      if pem_file_cache.nil? || pem_file_cache.to_s.empty? || current_last_modified_time_of_PEM_file > cached_pem_file_last_updated_time
        private_key = JOSE::JWK.from_pem_file filePath
        @@cache_obj.write('privateKeyFromPEMFile', private_key)
        @@cache_obj.write('cachedLastModifiedTimeOfPEMFile', current_last_modified_time_of_PEM_file)
      end
    end

    return @@cache_obj.read('privateKeyFromPEMFile')
  end
end

#get_mle_kid_data_from_cache(merchant_config) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/AuthenticationSDK/util/Cache.rb', line 181

def get_mle_kid_data_from_cache(merchant_config)
  cache_key = merchant_config.responseMlePrivateKeyFilePath + Constants::RESPONSE_MLE_P12_PFX_CACHE_IDENTIFIER
  file_path = merchant_config.responseMlePrivateKeyFilePath

  @@mutex.synchronize do
    if !@@cache_obj.exist?(cache_key)
      setup_mle_kid_cache(merchant_config)
    else
      cached_mle_kid = @@cache_obj.read(cache_key)
      file_modified_time = File.mtime(file_path).to_i

      if cached_mle_kid.nil? || cached_mle_kid.last_modified_timestamp != file_modified_time
        if !Cache.class_variable_defined?(:@@logger) || @@logger.nil?
          @@logger = Log.new merchant_config.log_config, "Cache"
        end
        logger = @@logger.logger
        logger.info("MLE KID cache outdated or file modified. Refreshing cache for: #{file_path}")
        setup_mle_kid_cache(merchant_config)
      end
    end

    return @@cache_obj.read(cache_key)
  end
end

#getMLECertificateBasedOnCacheKey(merchantConfig, cacheKey, certificateFilePath) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/AuthenticationSDK/util/Cache.rb', line 147

def getMLECertificateBasedOnCacheKey(merchantConfig, cacheKey, certificateFilePath)
  cachedCertificateInfo = nil
  @@mutex.synchronize do
    cachedCertificateInfo = @@cache_obj.read(cacheKey)
    fileTimestamp = File.mtime(certificateFilePath)

    if cachedCertificateInfo.nil? || cachedCertificateInfo.file_modified_time != fileTimestamp
      setupCache(cacheKey, certificateFilePath, merchantConfig)
      cachedCertificateInfo = @@cache_obj.read(cacheKey)
    end
  end

  cachedCertificateInfo ? cachedCertificateInfo.cert : nil
end

#getMLEResponsePrivateKeyFromFilePath(merchantConfig) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/AuthenticationSDK/util/Cache.rb', line 162

def getMLEResponsePrivateKeyFromFilePath(merchantConfig)
  merchantId = merchantConfig.merchantId
  keyIdentifier = Constants::MLE_CACHE_KEY_IDENTIFIER_FOR_RESPONSE_PRIVATE_KEY
  cacheIdentifier = "#{merchantId}_#{keyIdentifier}"
  mleResponsePrivateKeyFilePath = merchantConfig.responseMlePrivateKeyFilePath
  cachedCertificateInfo = nil

  @@mutex.synchronize do
    cachedCertificateInfo = @@cache_obj.read(cacheIdentifier)

    if cachedCertificateInfo.nil? || cachedCertificateInfo.file_modified_time != File.mtime(mleResponsePrivateKeyFilePath)
      setupCache(cacheIdentifier, mleResponsePrivateKeyFilePath, merchantConfig)
      cachedCertificateInfo = @@cache_obj.read(cacheIdentifier)
    end
  end

  cachedCertificateInfo ? cachedCertificateInfo.private_key : nil
end

#getPublicKeyFromCache(runEnvironment, keyId) ⇒ Object



297
298
299
300
301
302
# File 'lib/AuthenticationSDK/util/Cache.rb', line 297

def getPublicKeyFromCache(runEnvironment, keyId)
  cacheKey = "#{Constants::PUBLIC_KEY_CACHE_IDENTIFIER}_#{runEnvironment}_#{keyId}"
  @@mutex.synchronize do
    return @@cache_obj.read(cacheKey)
  end
end

#getRequestMLECertificateFromCache(merchantConfig) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/AuthenticationSDK/util/Cache.rb', line 115

def getRequestMLECertificateFromCache(merchantConfig)
  if !Cache.class_variable_defined?(:@@logger) || @@logger.nil?
    @@logger = Log.new merchantConfig.log_config, "Cache"
  end

  logger = @@logger.logger
  merchantId = merchantConfig.merchantId
  certificate_identifier = nil
  certificate_file_path = nil

  # Priority #1: Get cert from merchantConfig.mleForRequestPublicCertPath if certPath is provided

  if merchantConfig.mleForRequestPublicCertPath && !merchantConfig.mleForRequestPublicCertPath.strip.empty?
    certificate_identifier = Constants::MLE_CACHE_IDENTIFIER_FOR_CONFIG_CERT
    certificate_file_path = merchantConfig.mleForRequestPublicCertPath
  # Priority #2: If mleForRequestPublicCertPath not provided, get mlecert from p12 if provided and jwt auth type

  elsif Constants::AUTH_TYPE_JWT.downcase == merchantConfig.authenticationType.downcase && merchantConfig.p12KeyFilePath
    certificate_identifier = Constants::MLE_CACHE_IDENTIFIER_FOR_P12_CERT
    certificate_file_path = merchantConfig.p12KeyFilePath
  # Priority #3: Get mlecert from default cert in SDK as per CAS or PROD env.

  else
    logger.debug("The certificate to use for MLE for requests is not provided in the merchant configuration. Please ensure that the certificate path is provided.")
    return nil
  end

  cache_key = "#{merchantId}_#{certificate_identifier}"
  mle_certificate = getMLECertificateBasedOnCacheKey(merchantConfig, cache_key, certificate_file_path)

  CertificateUtility.validateCertificateExpiry(mle_certificate, merchantConfig.keyAlias, certificate_identifier, merchantConfig.log_config)

  mle_certificate
end

#setupCache(cacheKey, certificateFilePath, merchantConfig) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/AuthenticationSDK/util/Cache.rb', line 39

def setupCache(cacheKey, certificateFilePath, merchantConfig)
  if !Cache.class_variable_defined?(:@@logger) || @@logger.nil?
    @@logger = Log.new merchantConfig.log_config, "Cache"
  end
  logger = @@logger.logger
  fileModifiedTime = File.mtime(certificateFilePath)

  if cacheKey.end_with?(Constants::MLE_CACHE_KEY_IDENTIFIER_FOR_RESPONSE_PRIVATE_KEY)
    password = merchantConfig.responseMlePrivateKeyFilePassword
    mlePrivateKey = nil

    begin
      fileExtension = File.extname(certificateFilePath).delete_prefix('.').downcase

      if fileExtension == 'p12' || fileExtension == 'pfx'
        mlePrivateKey = CertificateUtility.read_private_key_from_p12(certificateFilePath, password)
      elsif fileExtension == 'pem' || fileExtension == 'key' || fileExtension == 'p8'
        mlePrivateKey = CertificateUtility.load_private_key_from_pem_file(certificateFilePath, password)
      else
        err = StandardError.new(Constants::ERROR_PREFIX + "Unsupported Response MLE Private Key file format: `" + fileExtension + "`. Supported formats are: .p12, .pfx, .pem, .key, .p8")
        logger.error(ExceptionHandler.new.new_api_exception err)
        raise err
      end

      cacheValue = CacheValue.new(mlePrivateKey, nil, fileModifiedTime)

      @@cache_obj.write(cacheKey, cacheValue)
    rescue StandardError => e
      err = StandardError.new(Constants::ERROR_PREFIX + "Error loading MLE response private key from: " + certificateFilePath + ". Error: " + e.message)
      logger.error(ExceptionHandler.new.new_api_exception err)
      raise err
    end
    return
  end

  if (cacheKey.end_with?("_JWT"))
    privateKey, certificateList = Utility.getCertificateCollectionAndPrivateKeyFromP12(certificateFilePath, merchantConfig.keyPass)
    jwtCertificate = Utility.getCertificateBasedOnKeyAlias(certificateList, merchantConfig.keyAlias)

    cacheValue = CacheValue.new(privateKey, jwtCertificate, fileModifiedTime)

    @@cache_obj.write(cacheKey, cacheValue)
    return
  end

  if (cacheKey.end_with?(Constants::MLE_CACHE_IDENTIFIER_FOR_CONFIG_CERT))
    certificateList = CertificateUtility.getCertificatesFromPemFile(certificateFilePath)
    mleCertificate = Utility.getCertificateBasedOnKeyAlias(certificateList, merchantConfig.requestMleKeyAlias)
    if (!mleCertificate)
      fileName = File.basename(certificateFilePath)
      logger.warn("No certificate found for the specified mle_key_alias '#{merchantConfig.requestMleKeyAlias}'. Using the first certificate from file #{fileName} as the MLE request certificate.")
      mleCertificate = certificateList[0]
    end

    cacheValue = CacheValue.new(nil, mleCertificate, fileModifiedTime)

    @@cache_obj.write(cacheKey, cacheValue)
    return
  end

  if (cacheKey.end_with?(Constants::MLE_CACHE_IDENTIFIER_FOR_P12_CERT))
    privateKey, certificateList = Utility.getCertificateCollectionAndPrivateKeyFromP12(certificateFilePath, merchantConfig.keyPass)
    mleCertificate = Utility.getCertificateBasedOnKeyAlias(certificateList, merchantConfig.requestMleKeyAlias)
    if (!mleCertificate)
      fileName = File.basename(certificateFilePath)
      logger.error("No certificate found for the specified mle_key_alias '#{merchantConfig.requestMleKeyAlias}' in file #{fileName}.")
      raise ArgumentError, "No certificate found for the specified mle_key_alias '#{merchantConfig.requestMleKeyAlias}' in file #{fileName}."
    end

    cacheValue = CacheValue.new(privateKey, mleCertificate, fileModifiedTime)

    @@cache_obj.write(cacheKey, cacheValue)
    return
  end
end