cerner-oauth1a 2.0.0.rc2 → 2.0.0.rc3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +11 -0
 - data/lib/cerner/oauth1a.rb +2 -0
 - data/lib/cerner/oauth1a/access_token.rb +35 -5
 - data/lib/cerner/oauth1a/access_token_agent.rb +11 -6
 - data/lib/cerner/oauth1a/cache.rb +83 -29
 - data/lib/cerner/oauth1a/cache_rails.rb +50 -0
 - data/lib/cerner/oauth1a/protocol.rb +4 -0
 - data/lib/cerner/oauth1a/version.rb +1 -1
 - metadata +4 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d2a4ccfde185aca59fd7d639c4f15db74883c8932d38cc461b4ec1ad38a86e95
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 051e4b68e33bdff8b347f5ec044e2d2a234455a49d6e9b1eef8487973c87fd3f
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 43460c5fe1996222164227d1fb8d98a93b7cedb16cf2dd6703a6e89324daab116a0c8994ebb13249aa8c5f8afa8fa5e708b8448ff0ef0d0d533924920d900688
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 23fcbc356390d70b89dc1df139b6edb680e8077521b6b475916bc85f77312fd6b3e3777be9e30c2bc03bfcbe52179200198cefaada61a2c338335770d7935045
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -77,6 +77,17 @@ implement that: 
     | 
|
| 
       77 
77 
     | 
    
         
             
                # (xoauth_principal)
         
     | 
| 
       78 
78 
     | 
    
         
             
                consumer_principal = access_token.consumer_principal
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
      
 80 
     | 
    
         
            +
            ## Caching
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            The AccessTokenAgent class provides built-in memory caching. AccessTokens and Keys are cached
         
     | 
| 
      
 83 
     | 
    
         
            +
            behind their respective retrieve methods. The caching can be disabled via parameters passed to the
         
     | 
| 
      
 84 
     | 
    
         
            +
            constructor. See the class-level documentation for details.
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            ### Caching in Rails
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            When the gem is loaded within a Rails application, it will attach a Railtie for initializing the
         
     | 
| 
      
 89 
     | 
    
         
            +
            cache to use an implementation that stores the AccessTokens and Keys within Rails.cache.
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
       80 
91 
     | 
    
         
             
            ## References
         
     | 
| 
       81 
92 
     | 
    
         
             
            * https://wiki.ucern.com/display/public/reference/Cerner%27s+OAuth+Specification
         
     | 
| 
       82 
93 
     | 
    
         
             
              * http://oauth.net/core/1.0a
         
     | 
    
        data/lib/cerner/oauth1a.rb
    CHANGED
    
    | 
         @@ -2,6 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'cerner/oauth1a/access_token'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'cerner/oauth1a/access_token_agent'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'cerner/oauth1a/cache'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'cerner/oauth1a/cache_rails' if defined?(::Rails) && defined?(::Rails.cache)
         
     | 
| 
       5 
7 
     | 
    
         
             
            require 'cerner/oauth1a/keys'
         
     | 
| 
       6 
8 
     | 
    
         
             
            require 'cerner/oauth1a/protocol'
         
     | 
| 
       7 
9 
     | 
    
         
             
            require 'cerner/oauth1a/version'
         
     | 
| 
         @@ -211,6 +211,7 @@ module Cerner 
     | 
|
| 
       211 
211 
     | 
    
         
             
                  def expired?(now: Time.now, fudge_sec: 300)
         
     | 
| 
       212 
212 
     | 
    
         
             
                    # if @expires_at is nil, return true now
         
     | 
| 
       213 
213 
     | 
    
         
             
                    return true unless @expires_at
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
       214 
215 
     | 
    
         
             
                    now = convert_to_time(now)
         
     | 
| 
       215 
216 
     | 
    
         
             
                    now.tv_sec >= @expires_at.tv_sec - fudge_sec
         
     | 
| 
       216 
217 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -254,7 +255,8 @@ module Cerner 
     | 
|
| 
       254 
255 
     | 
    
         
             
                      token: @token,
         
     | 
| 
       255 
256 
     | 
    
         
             
                      token_secret: @token_secret,
         
     | 
| 
       256 
257 
     | 
    
         
             
                      signature_method: @signature_method,
         
     | 
| 
       257 
     | 
    
         
            -
                      signature: @signature
         
     | 
| 
      
 258 
     | 
    
         
            +
                      signature: @signature,
         
     | 
| 
      
 259 
     | 
    
         
            +
                      consumer_principal: @consumer_principal
         
     | 
| 
       258 
260 
     | 
    
         
             
                    }
         
     | 
| 
       259 
261 
     | 
    
         
             
                  end
         
     | 
| 
       260 
262 
     | 
    
         | 
| 
         @@ -267,6 +269,7 @@ module Cerner 
     | 
|
| 
       267 
269 
     | 
    
         
             
                  # Returns a Time instance in the UTC time zone.
         
     | 
| 
       268 
270 
     | 
    
         
             
                  def convert_to_time(time)
         
     | 
| 
       269 
271 
     | 
    
         
             
                    raise ArgumentError, 'time is nil' unless time
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
       270 
273 
     | 
    
         
             
                    if time.is_a? Time
         
     | 
| 
       271 
274 
     | 
    
         
             
                      time.utc
         
     | 
| 
       272 
275 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -280,14 +283,36 @@ module Cerner 
     | 
|
| 
       280 
283 
     | 
    
         
             
                  #
         
     | 
| 
       281 
284 
     | 
    
         
             
                  # Raises OAuthError if the parameter is invalid or expired
         
     | 
| 
       282 
285 
     | 
    
         
             
                  def verify_expiration(expires_on)
         
     | 
| 
       283 
     | 
    
         
            -
                     
     | 
| 
      
 286 
     | 
    
         
            +
                    unless expires_on
         
     | 
| 
      
 287 
     | 
    
         
            +
                      raise OAuthError.new(
         
     | 
| 
      
 288 
     | 
    
         
            +
                        'token missing ExpiresOn',
         
     | 
| 
      
 289 
     | 
    
         
            +
                        nil,
         
     | 
| 
      
 290 
     | 
    
         
            +
                        'oauth_parameters_rejected',
         
     | 
| 
      
 291 
     | 
    
         
            +
                        'oauth_token'
         
     | 
| 
      
 292 
     | 
    
         
            +
                      )
         
     | 
| 
      
 293 
     | 
    
         
            +
                    end
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
       284 
295 
     | 
    
         
             
                    expires_on = convert_to_time(expires_on)
         
     | 
| 
       285 
296 
     | 
    
         
             
                    now = convert_to_time(Time.now)
         
     | 
| 
       286 
     | 
    
         
            -
                     
     | 
| 
      
 297 
     | 
    
         
            +
                    if now.tv_sec >= expires_on.tv_sec
         
     | 
| 
      
 298 
     | 
    
         
            +
                      raise OAuthError.new(
         
     | 
| 
      
 299 
     | 
    
         
            +
                        'token has expired',
         
     | 
| 
      
 300 
     | 
    
         
            +
                        nil,
         
     | 
| 
      
 301 
     | 
    
         
            +
                        'token_expired'
         
     | 
| 
      
 302 
     | 
    
         
            +
                      )
         
     | 
| 
      
 303 
     | 
    
         
            +
                    end
         
     | 
| 
       287 
304 
     | 
    
         
             
                  end
         
     | 
| 
       288 
305 
     | 
    
         | 
| 
       289 
306 
     | 
    
         
             
                  def load_keys(access_token_agent, keys_version)
         
     | 
| 
       290 
     | 
    
         
            -
                     
     | 
| 
      
 307 
     | 
    
         
            +
                    unless keys_version
         
     | 
| 
      
 308 
     | 
    
         
            +
                      raise OAuthError.new(
         
     | 
| 
      
 309 
     | 
    
         
            +
                        'token missing KeysVersion',
         
     | 
| 
      
 310 
     | 
    
         
            +
                        nil,
         
     | 
| 
      
 311 
     | 
    
         
            +
                        'oauth_parameters_rejected',
         
     | 
| 
      
 312 
     | 
    
         
            +
                        'oauth_token'
         
     | 
| 
      
 313 
     | 
    
         
            +
                      )
         
     | 
| 
      
 314 
     | 
    
         
            +
                    end
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
       291 
316 
     | 
    
         
             
                    begin
         
     | 
| 
       292 
317 
     | 
    
         
             
                      access_token_agent.retrieve_keys(keys_version)
         
     | 
| 
       293 
318 
     | 
    
         
             
                    rescue OAuthError
         
     | 
| 
         @@ -320,7 +345,12 @@ module Cerner 
     | 
|
| 
       320 
345 
     | 
    
         
             
                    begin
         
     | 
| 
       321 
346 
     | 
    
         
             
                      secrets = keys.decrypt_hmac_secrets(hmac_secrets)
         
     | 
| 
       322 
347 
     | 
    
         
             
                    rescue ArgumentError, OpenSSL::PKey::RSAError => e
         
     | 
| 
       323 
     | 
    
         
            -
                      raise OAuthError.new( 
     | 
| 
      
 348 
     | 
    
         
            +
                      raise OAuthError.new(
         
     | 
| 
      
 349 
     | 
    
         
            +
                        "unable to decrypt HMACSecrets: #{e.message}",
         
     | 
| 
      
 350 
     | 
    
         
            +
                        nil,
         
     | 
| 
      
 351 
     | 
    
         
            +
                        'oauth_parameters_rejected',
         
     | 
| 
      
 352 
     | 
    
         
            +
                        'oauth_token'
         
     | 
| 
      
 353 
     | 
    
         
            +
                      )
         
     | 
| 
       324 
354 
     | 
    
         
             
                    end
         
     | 
| 
       325 
355 
     | 
    
         | 
| 
       326 
356 
     | 
    
         
             
                    secrets_parts = Protocol.parse_url_query_string(secrets)
         
     | 
| 
         @@ -76,8 +76,8 @@ module Cerner 
     | 
|
| 
       76 
76 
     | 
    
         
             
                    @open_timeout = (open_timeout ? open_timeout.to_i : 5)
         
     | 
| 
       77 
77 
     | 
    
         
             
                    @read_timeout = (read_timeout ? read_timeout.to_i : 5)
         
     | 
| 
       78 
78 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
                    @keys_cache = cache_keys ? Cache. 
     | 
| 
       80 
     | 
    
         
            -
                    @access_token_cache = cache_access_tokens ? Cache. 
     | 
| 
      
 79 
     | 
    
         
            +
                    @keys_cache = cache_keys ? Cache.instance : nil
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @access_token_cache = cache_access_tokens ? Cache.instance : nil
         
     | 
| 
       81 
81 
     | 
    
         
             
                  end
         
     | 
| 
       82 
82 
     | 
    
         | 
| 
       83 
83 
     | 
    
         
             
                  # Public: Retrieves the service provider keys from the configured Access Token service endpoint
         
     | 
| 
         @@ -96,14 +96,14 @@ module Cerner 
     | 
|
| 
       96 
96 
     | 
    
         
             
                    raise ArgumentError, 'keys_version is nil' unless keys_version
         
     | 
| 
       97 
97 
     | 
    
         | 
| 
       98 
98 
     | 
    
         
             
                    if @keys_cache
         
     | 
| 
       99 
     | 
    
         
            -
                      cache_entry = @keys_cache.get(keys_version)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      cache_entry = @keys_cache.get('cerner-oauth/keys', keys_version)
         
     | 
| 
       100 
100 
     | 
    
         
             
                      return cache_entry.value if cache_entry
         
     | 
| 
       101 
101 
     | 
    
         
             
                    end
         
     | 
| 
       102 
102 
     | 
    
         | 
| 
       103 
103 
     | 
    
         
             
                    request = retrieve_keys_prepare_request(keys_version)
         
     | 
| 
       104 
104 
     | 
    
         
             
                    response = http_client.request(request)
         
     | 
| 
       105 
105 
     | 
    
         
             
                    keys = retrieve_keys_handle_response(keys_version, response)
         
     | 
| 
       106 
     | 
    
         
            -
                    @keys_cache&.put(keys_version, Cache::KeysEntry.new(keys, Cache::TWENTY_FOUR_HOURS))
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @keys_cache&.put('cerner-oauth/keys', keys_version, Cache::KeysEntry.new(keys, Cache::TWENTY_FOUR_HOURS))
         
     | 
| 
       107 
107 
     | 
    
         
             
                    keys
         
     | 
| 
       108 
108 
     | 
    
         
             
                  end
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
         @@ -120,7 +120,7 @@ module Cerner 
     | 
|
| 
       120 
120 
     | 
    
         
             
                  def retrieve(principal = nil)
         
     | 
| 
       121 
121 
     | 
    
         
             
                    cache_key = "#{@consumer_key}&#{principal}"
         
     | 
| 
       122 
122 
     | 
    
         
             
                    if @access_token_cache
         
     | 
| 
       123 
     | 
    
         
            -
                      cache_entry = @access_token_cache.get(cache_key)
         
     | 
| 
      
 123 
     | 
    
         
            +
                      cache_entry = @access_token_cache.get('cerner-oauth/access-tokens', cache_key)
         
     | 
| 
       124 
124 
     | 
    
         
             
                      return cache_entry.value if cache_entry
         
     | 
| 
       125 
125 
     | 
    
         
             
                    end
         
     | 
| 
       126 
126 
     | 
    
         | 
| 
         @@ -132,7 +132,7 @@ module Cerner 
     | 
|
| 
       132 
132 
     | 
    
         
             
                    request = retrieve_prepare_request(timestamp, nonce, accessor_secret, principal)
         
     | 
| 
       133 
133 
     | 
    
         
             
                    response = http_client.request(request)
         
     | 
| 
       134 
134 
     | 
    
         
             
                    access_token = retrieve_handle_response(response, timestamp, nonce, accessor_secret)
         
     | 
| 
       135 
     | 
    
         
            -
                    @access_token_cache&.put(cache_key, Cache::AccessTokenEntry.new(access_token))
         
     | 
| 
      
 135 
     | 
    
         
            +
                    @access_token_cache&.put('cerner-oauth/access-tokens', cache_key, Cache::AccessTokenEntry.new(access_token))
         
     | 
| 
       136 
136 
     | 
    
         
             
                    access_token
         
     | 
| 
       137 
137 
     | 
    
         
             
                  end
         
     | 
| 
       138 
138 
     | 
    
         | 
| 
         @@ -191,6 +191,7 @@ module Cerner 
     | 
|
| 
       191 
191 
     | 
    
         
             
                  # Raises ArgumentError if access_token_url is nil, invalid or not an HTTP/HTTPS URI
         
     | 
| 
       192 
192 
     | 
    
         
             
                  def convert_to_http_uri(access_token_url)
         
     | 
| 
       193 
193 
     | 
    
         
             
                    raise ArgumentError, 'access_token_url is nil' unless access_token_url
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
       194 
195 
     | 
    
         
             
                    if access_token_url.is_a? URI
         
     | 
| 
       195 
196 
     | 
    
         
             
                      uri = access_token_url
         
     | 
| 
       196 
197 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -201,7 +202,9 @@ module Cerner 
     | 
|
| 
       201 
202 
     | 
    
         
             
                        raise ArgumentError, 'access_token_url is invalid'
         
     | 
| 
       202 
203 
     | 
    
         
             
                      end
         
     | 
| 
       203 
204 
     | 
    
         
             
                    end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
       204 
206 
     | 
    
         
             
                    raise ArgumentError, 'access_token_url must be an HTTP or HTTPS URI' unless uri.is_a?(URI::HTTP)
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
       205 
208 
     | 
    
         
             
                    uri
         
     | 
| 
       206 
209 
     | 
    
         
             
                  end
         
     | 
| 
       207 
210 
     | 
    
         | 
| 
         @@ -269,8 +272,10 @@ module Cerner 
     | 
|
| 
       269 
272 
     | 
    
         
             
                      parsed_response = JSON.parse(response.body)
         
     | 
| 
       270 
273 
     | 
    
         
             
                      aes_key = parsed_response.dig('aesKey', 'secretKey')
         
     | 
| 
       271 
274 
     | 
    
         
             
                      raise OAuthError, 'AES secret key retrieved was invalid' unless aes_key
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
       272 
276 
     | 
    
         
             
                      rsa_key = parsed_response.dig('rsaKey', 'publicKey')
         
     | 
| 
       273 
277 
     | 
    
         
             
                      raise OAuthError, 'RSA public key retrieved was invalid' unless rsa_key
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
       274 
279 
     | 
    
         
             
                      Keys.new(
         
     | 
| 
       275 
280 
     | 
    
         
             
                        version: keys_version,
         
     | 
| 
       276 
281 
     | 
    
         
             
                        aes_secret_key: Base64.decode64(aes_key),
         
     | 
    
        data/lib/cerner/oauth1a/cache.rb
    CHANGED
    
    | 
         @@ -4,13 +4,33 @@ module Cerner 
     | 
|
| 
       4 
4 
     | 
    
         
             
              module OAuth1a
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Internal: A simple cache abstraction for use by AccessTokenAgent only.
         
     | 
| 
       6 
6 
     | 
    
         
             
                class Cache
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @cache_instance_lock = Mutex.new
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def self.instance=(cache_impl)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    raise ArgumentError, 'cache_impl must not be nil' unless cache_impl
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    @cache_instance_lock.synchronize do
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @cache_instance = cache_impl
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def self.instance
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @cache_instance_lock.synchronize do
         
     | 
| 
      
 19 
     | 
    
         
            +
                      return @cache_instance if @cache_instance
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                      @cache_instance = DefaultCache.new(max: 50)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
       7 
25 
     | 
    
         
             
                  # Internal: A cache entry class for Keys values.
         
     | 
| 
       8 
26 
     | 
    
         
             
                  class KeysEntry
         
     | 
| 
       9 
27 
     | 
    
         
             
                    attr_reader :value
         
     | 
| 
      
 28 
     | 
    
         
            +
                    attr_reader :expires_in
         
     | 
| 
       10 
29 
     | 
    
         | 
| 
       11 
30 
     | 
    
         
             
                    def initialize(keys, expires_in)
         
     | 
| 
       12 
31 
     | 
    
         
             
                      @value = keys
         
     | 
| 
       13 
     | 
    
         
            -
                      @ 
     | 
| 
      
 32 
     | 
    
         
            +
                      @expires_in = expires_in
         
     | 
| 
      
 33 
     | 
    
         
            +
                      @expires_at = Time.now.utc.to_i + @expires_in
         
     | 
| 
       14 
34 
     | 
    
         
             
                    end
         
     | 
| 
       15 
35 
     | 
    
         | 
| 
       16 
36 
     | 
    
         
             
                    def expired?(now)
         
     | 
| 
         @@ -26,6 +46,10 @@ module Cerner 
     | 
|
| 
       26 
46 
     | 
    
         
             
                      @value = access_token
         
     | 
| 
       27 
47 
     | 
    
         
             
                    end
         
     | 
| 
       28 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                    def expires_in
         
     | 
| 
      
 50 
     | 
    
         
            +
                      @value.expires_at.to_i - Time.now.utc.to_i
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
       29 
53 
     | 
    
         
             
                    def expired?(now)
         
     | 
| 
       30 
54 
     | 
    
         
             
                      @value.expired?(now: now)
         
     | 
| 
       31 
55 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -34,45 +58,75 @@ module Cerner 
     | 
|
| 
       34 
58 
     | 
    
         
             
                  ONE_HOUR = 3600
         
     | 
| 
       35 
59 
     | 
    
         
             
                  TWENTY_FOUR_HOURS = 24 * ONE_HOUR
         
     | 
| 
       36 
60 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                   
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                     
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
                  # Internal: The default implementation of the Cerner::OAuth1a::Cache interface.
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # This implementation just maintains a capped list of entries in memory.
         
     | 
| 
      
 63 
     | 
    
         
            +
                  class DefaultCache < Cerner::OAuth1a::Cache
         
     | 
| 
      
 64 
     | 
    
         
            +
                    def initialize(max:)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      super()
         
     | 
| 
      
 66 
     | 
    
         
            +
                      @max = max
         
     | 
| 
      
 67 
     | 
    
         
            +
                      @lock = Mutex.new
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @entries = {}
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
       42 
70 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                    def put(namespace, key, entry)
         
     | 
| 
      
 72 
     | 
    
         
            +
                      @lock.synchronize do
         
     | 
| 
      
 73 
     | 
    
         
            +
                        now = Time.now.utc.to_i
         
     | 
| 
      
 74 
     | 
    
         
            +
                        prune_expired(now)
         
     | 
| 
      
 75 
     | 
    
         
            +
                        @entries[full_key(namespace, key)] = entry
         
     | 
| 
      
 76 
     | 
    
         
            +
                        prune_size
         
     | 
| 
      
 77 
     | 
    
         
            +
                      end
         
     | 
| 
       49 
78 
     | 
    
         
             
                    end
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
       51 
79 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
      
 80 
     | 
    
         
            +
                    def get(namespace, key)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      @lock.synchronize do
         
     | 
| 
      
 82 
     | 
    
         
            +
                        prune_expired(Time.now.utc.to_i)
         
     | 
| 
      
 83 
     | 
    
         
            +
                        @entries[full_key(namespace, key)]
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
       56 
85 
     | 
    
         
             
                    end
         
     | 
| 
       57 
     | 
    
         
            -
                  end
         
     | 
| 
       58 
86 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 87 
     | 
    
         
            +
                    private
         
     | 
| 
       60 
88 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
      
 89 
     | 
    
         
            +
                    def prune_expired(now)
         
     | 
| 
      
 90 
     | 
    
         
            +
                      return if @entries.empty?
         
     | 
| 
       63 
91 
     | 
    
         | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
      
 92 
     | 
    
         
            +
                      @entries.delete_if { |_, v| v.expired?(now) }
         
     | 
| 
       65 
93 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
      
 94 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                    def prune_size
         
     | 
| 
      
 98 
     | 
    
         
            +
                      return if @entries.empty? || @entries.size <= @max
         
     | 
| 
       68 
99 
     | 
    
         | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
      
 100 
     | 
    
         
            +
                      num_to_prune = @entries.size - @max
         
     | 
| 
      
 101 
     | 
    
         
            +
                      num_to_prune.times { @entries.shift }
         
     | 
| 
       71 
102 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                     
     | 
| 
      
 103 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
       74 
106 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
      
 107 
     | 
    
         
            +
                  # Internal: The base constructor for the interface.
         
     | 
| 
      
 108 
     | 
    
         
            +
                  def initialize; end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  # Internal: The abstract operation for putting (storing) data in the cache.
         
     | 
| 
      
 111 
     | 
    
         
            +
                  #
         
     | 
| 
      
 112 
     | 
    
         
            +
                  # namespace - The namespace for the cache entries.
         
     | 
| 
      
 113 
     | 
    
         
            +
                  # key       - The key for the cache entries, which is qualified by namespace.
         
     | 
| 
      
 114 
     | 
    
         
            +
                  # entry     - The entry to be stored in the cache.
         
     | 
| 
      
 115 
     | 
    
         
            +
                  def put(namespace, key, entry); end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  # Internal: Retrieves the entry, if available, from the cache store.
         
     | 
| 
      
 118 
     | 
    
         
            +
                  #
         
     | 
| 
      
 119 
     | 
    
         
            +
                  # namespace - The namespace for the cache entries.
         
     | 
| 
      
 120 
     | 
    
         
            +
                  # key       - The key for the cache entries.
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def get(namespace, key); end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  # Internal: Constructs a single, fully qualified key based on the namespace and key value
         
     | 
| 
      
 124 
     | 
    
         
            +
                  # passed.
         
     | 
| 
      
 125 
     | 
    
         
            +
                  #
         
     | 
| 
      
 126 
     | 
    
         
            +
                  # namespace - The namespace for the cache entries.
         
     | 
| 
      
 127 
     | 
    
         
            +
                  # key       - The key for the cache entries.
         
     | 
| 
      
 128 
     | 
    
         
            +
                  def full_key(namespace, key)
         
     | 
| 
      
 129 
     | 
    
         
            +
                    "#{namespace}:#{key}"
         
     | 
| 
       76 
130 
     | 
    
         
             
                  end
         
     | 
| 
       77 
131 
     | 
    
         
             
                end
         
     | 
| 
       78 
132 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Cerner
         
     | 
| 
      
 4 
     | 
    
         
            +
              module OAuth1a
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Internal: A Railtie that initializer the cache implementation to use Rails.cache.
         
     | 
| 
      
 7 
     | 
    
         
            +
                # This will be picked up automatically if ::Rails and ::Rails.cache are defined.
         
     | 
| 
      
 8 
     | 
    
         
            +
                class CacheRailtie < ::Rails::Railtie
         
     | 
| 
      
 9 
     | 
    
         
            +
                  initializer 'cerner-oauth1a.cache_initialization' do |_app|
         
     | 
| 
      
 10 
     | 
    
         
            +
                    ::Rails.logger.info "#{CacheRailtie.name}: configuring cache to use Rails.cache"
         
     | 
| 
      
 11 
     | 
    
         
            +
                    Cerner::OAuth1a::Cache.instance = RailsCache.new(::Rails.cache)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # Internal: An implementation of the Cerner::OAuth1a::Cache interface that utilizes
         
     | 
| 
      
 16 
     | 
    
         
            +
                # ::Rails.cache.
         
     | 
| 
      
 17 
     | 
    
         
            +
                class RailsCache < Cerner::OAuth1a::Cache
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # Internal: Constructs an instance with a instance of ActiveSupport::Cache::Store, which
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # is generally ::Rails.cache.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # rails_cache - An instance of ActiveSupport::Cache::Store.
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def initialize(rails_cache)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @cache = rails_cache
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  # Internal: Writes the entry to the cache store.
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # namespace - The namespace for the cache entries.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # key       - The key for the cache entries, which is qualified by namespace.
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # entry     - The entry to be stored in the cache.
         
     | 
| 
      
 31 
     | 
    
         
            +
                  def put(namespace, key, entry)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @cache.write(
         
     | 
| 
      
 33 
     | 
    
         
            +
                      key,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      entry,
         
     | 
| 
      
 35 
     | 
    
         
            +
                      namespace: namespace,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      expires_in: entry.expires_in,
         
     | 
| 
      
 37 
     | 
    
         
            +
                      race_condition_ttl: 5
         
     | 
| 
      
 38 
     | 
    
         
            +
                    )
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # Internal: Retrieves the entry, if available, from the cache store.
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #
         
     | 
| 
      
 43 
     | 
    
         
            +
                  # namespace - The namespace for the cache entries.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  # key       - The key for the cache entries.
         
     | 
| 
      
 45 
     | 
    
         
            +
                  def get(namespace, key)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    @cache.read(key, namespace: namespace)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -122,9 +122,13 @@ module Cerner 
     | 
|
| 
       122 
122 
     | 
    
         
             
                  #   parameter.
         
     | 
| 
       123 
123 
     | 
    
         
             
                  def self.convert_problem_to_http_status(problem, default = :unauthorized)
         
     | 
| 
       124 
124 
     | 
    
         
             
                    return default unless problem
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
       125 
126 
     | 
    
         
             
                    problem = problem.to_s
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
       126 
128 
     | 
    
         
             
                    return :unauthorized if UNAUTHORIZED_PROBLEMS.include?(problem)
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
       127 
130 
     | 
    
         
             
                    return :bad_request if BAD_REQUEST_PROBLEMS.include?(problem)
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
       128 
132 
     | 
    
         
             
                    default
         
     | 
| 
       129 
133 
     | 
    
         
             
                  end
         
     | 
| 
       130 
134 
     | 
    
         
             
                end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: cerner-oauth1a
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 2.0.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 2.0.0.rc3
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Nathan Beyer
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2018- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2018-12-12 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies: []
         
     | 
| 
       13 
13 
     | 
    
         
             
            description: |
         
     | 
| 
       14 
14 
     | 
    
         
             
              A minimal dependency library for interacting with a Cerner OAuth 1.0a Access
         
     | 
| 
         @@ -29,6 +29,7 @@ files: 
     | 
|
| 
       29 
29 
     | 
    
         
             
            - lib/cerner/oauth1a/access_token.rb
         
     | 
| 
       30 
30 
     | 
    
         
             
            - lib/cerner/oauth1a/access_token_agent.rb
         
     | 
| 
       31 
31 
     | 
    
         
             
            - lib/cerner/oauth1a/cache.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
            - lib/cerner/oauth1a/cache_rails.rb
         
     | 
| 
       32 
33 
     | 
    
         
             
            - lib/cerner/oauth1a/keys.rb
         
     | 
| 
       33 
34 
     | 
    
         
             
            - lib/cerner/oauth1a/oauth_error.rb
         
     | 
| 
       34 
35 
     | 
    
         
             
            - lib/cerner/oauth1a/protocol.rb
         
     | 
| 
         @@ -53,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       53 
54 
     | 
    
         
             
                  version: 1.3.1
         
     | 
| 
       54 
55 
     | 
    
         
             
            requirements: []
         
     | 
| 
       55 
56 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       56 
     | 
    
         
            -
            rubygems_version: 2.7. 
     | 
| 
      
 57 
     | 
    
         
            +
            rubygems_version: 2.7.7
         
     | 
| 
       57 
58 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       58 
59 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       59 
60 
     | 
    
         
             
            summary: Cerner OAuth 1.0a Consumer and Service Provider Library.
         
     |