stormpath-sdk 0.4.0 → 1.0.0.beta
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.
- data/.gitignore +6 -0
 - data/.ruby-gemset +1 -0
 - data/.ruby-version +1 -0
 - data/.travis.yml +27 -0
 - data/CHANGES.md +21 -1
 - data/Gemfile +1 -2
 - data/README.md +457 -11
 - data/Rakefile +15 -1
 - data/lib/stormpath-sdk.rb +52 -33
 - data/lib/stormpath-sdk/{resource/group_list.rb → api_key.rb} +5 -9
 - data/lib/stormpath-sdk/auth/authentication_result.rb +3 -13
 - data/lib/stormpath-sdk/auth/basic_authenticator.rb +5 -11
 - data/lib/stormpath-sdk/auth/basic_login_attempt.rb +6 -8
 - data/lib/stormpath-sdk/auth/username_password_request.rb +2 -5
 - data/lib/stormpath-sdk/cache/cache.rb +54 -0
 - data/lib/stormpath-sdk/cache/cache_entry.rb +33 -0
 - data/lib/stormpath-sdk/cache/cache_manager.rb +22 -0
 - data/lib/stormpath-sdk/cache/cache_stats.rb +35 -0
 - data/lib/stormpath-sdk/cache/memory_store.rb +29 -0
 - data/lib/stormpath-sdk/cache/redis_store.rb +32 -0
 - data/lib/stormpath-sdk/client.rb +111 -0
 - data/lib/stormpath-sdk/data_store.rb +241 -0
 - data/lib/stormpath-sdk/{client/api_key.rb → error.rb} +16 -10
 - data/lib/stormpath-sdk/{util → ext}/hash.rb +1 -2
 - data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +8 -4
 - data/lib/stormpath-sdk/http/http_client_request_executor.rb +8 -7
 - data/lib/stormpath-sdk/http/request.rb +4 -8
 - data/lib/stormpath-sdk/{util/request_utils.rb → http/utils.rb} +17 -38
 - data/lib/stormpath-sdk/resource/account.rb +12 -108
 - data/lib/stormpath-sdk/resource/application.rb +35 -171
 - data/lib/stormpath-sdk/resource/associations.rb +97 -0
 - data/lib/stormpath-sdk/resource/base.rb +256 -0
 - data/lib/stormpath-sdk/resource/collection.rb +94 -0
 - data/lib/stormpath-sdk/resource/directory.rb +11 -68
 - data/lib/stormpath-sdk/resource/email_verification_token.rb +3 -9
 - data/lib/stormpath-sdk/resource/error.rb +4 -38
 - data/lib/stormpath-sdk/resource/expansion.rb +28 -0
 - data/lib/stormpath-sdk/resource/group.rb +8 -66
 - data/lib/stormpath-sdk/resource/group_membership.rb +4 -55
 - data/lib/stormpath-sdk/resource/{application_list.rb → instance.rb} +7 -13
 - data/lib/stormpath-sdk/resource/password_reset_token.rb +5 -23
 - data/lib/stormpath-sdk/resource/status.rb +22 -28
 - data/lib/stormpath-sdk/resource/tenant.rb +5 -52
 - data/lib/stormpath-sdk/resource/utils.rb +43 -13
 - data/lib/stormpath-sdk/util/assert.rb +5 -15
 - data/lib/stormpath-sdk/version.rb +3 -3
 - data/spec/api_key_spec.rb +19 -0
 - data/spec/auth/basic_authenticator_spec.rb +25 -0
 - data/spec/auth/sauthc1_signer_spec.rb +42 -0
 - data/spec/cache/cache_entry_spec.rb +157 -0
 - data/spec/cache/cache_spec.rb +89 -0
 - data/spec/cache/cache_stats_spec.rb +106 -0
 - data/spec/client_spec.rb +538 -0
 - data/spec/data_store_spec.rb +130 -0
 - data/spec/resource/account_spec.rb +74 -0
 - data/spec/resource/application_spec.rb +148 -0
 - data/spec/resource/base_spec.rb +114 -0
 - data/spec/resource/collection_spec.rb +169 -0
 - data/spec/resource/directory_spec.rb +30 -0
 - data/spec/resource/expansion_spec.rb +100 -0
 - data/spec/resource/group_spec.rb +49 -0
 - data/spec/spec_helper.rb +135 -0
 - data/spec/support/resource_factory.rb +48 -0
 - data/spec/support/resource_matchers.rb +27 -0
 - data/spec/support/test_cache_stores.rb +9 -0
 - data/spec/support/test_request_executor.rb +11 -0
 - data/stormpath-sdk.gemspec +14 -4
 - data/support/api.rb +55 -0
 - metadata +214 -44
 - data/lib/stormpath-sdk/client/client.rb +0 -38
 - data/lib/stormpath-sdk/client/client_application.rb +0 -38
 - data/lib/stormpath-sdk/client/client_application_builder.rb +0 -351
 - data/lib/stormpath-sdk/client/client_builder.rb +0 -305
 - data/lib/stormpath-sdk/ds/data_store.rb +0 -210
 - data/lib/stormpath-sdk/ds/resource_factory.rb +0 -37
 - data/lib/stormpath-sdk/resource/account_list.rb +0 -32
 - data/lib/stormpath-sdk/resource/collection_resource.rb +0 -91
 - data/lib/stormpath-sdk/resource/directory_list.rb +0 -30
 - data/lib/stormpath-sdk/resource/group_membership_list.rb +0 -32
 - data/lib/stormpath-sdk/resource/instance_resource.rb +0 -28
 - data/lib/stormpath-sdk/resource/resource.rb +0 -327
 - data/lib/stormpath-sdk/resource/resource_error.rb +0 -47
 - data/test/client/client.yml +0 -16
 - data/test/client/client_application_builder_spec.rb +0 -114
 - data/test/client/client_builder_spec.rb +0 -176
 - data/test/client/read_spec.rb +0 -254
 - data/test/client/write_spec.rb +0 -420
 - data/test/resource/resource_spec.rb +0 -41
 - data/test/resource/test_resource.rb +0 -28
 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'redis'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Stormpath
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cache
         
     | 
| 
      
 5 
     | 
    
         
            +
                class RedisStore
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(opts = {})
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @redis = Redis.new opts
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def get(key)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    entry = @redis.get key
         
     | 
| 
      
 12 
     | 
    
         
            +
                    entry && Stormpath::Cache::CacheEntry.from_h(MultiJson.load(entry))
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def put(key, entry)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @redis.set key, MultiJson.dump(entry.to_h)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def delete(key)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @redis.del key
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def clear
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @redis.flushdb
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def size
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @redis.dbsize
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright 2012 Stormpath, Inc.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         
     | 
| 
      
 5 
     | 
    
         
            +
            # you may not use this file except in compliance with the License.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # You may obtain a copy of the License at
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            # Unless required by applicable law or agreed to in writing, software
         
     | 
| 
      
 11 
     | 
    
         
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         
     | 
| 
      
 12 
     | 
    
         
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         
     | 
| 
      
 13 
     | 
    
         
            +
            # See the License for the specific language governing permissions and
         
     | 
| 
      
 14 
     | 
    
         
            +
            # limitations under the License.
         
     | 
| 
      
 15 
     | 
    
         
            +
            #
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'java_properties'
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            module Stormpath
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              class Client
         
     | 
| 
      
 21 
     | 
    
         
            +
                include Stormpath::Util::Assert
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                attr_reader :data_store, :application
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def initialize(options)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  api_key = options[:api_key]
         
     | 
| 
      
 27 
     | 
    
         
            +
                  base_url = options[:base_url]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  cache_opts = options[:cache] || {}
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  api_key = if api_key
         
     | 
| 
      
 31 
     | 
    
         
            +
                    case api_key
         
     | 
| 
      
 32 
     | 
    
         
            +
                    when ApiKey then api_key
         
     | 
| 
      
 33 
     | 
    
         
            +
                    when Hash then ApiKey.new api_key[:id], api_key[:secret]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  elsif options[:api_key_file_location]
         
     | 
| 
      
 36 
     | 
    
         
            +
                    load_api_key_file options[:api_key_file_location],
         
     | 
| 
      
 37 
     | 
    
         
            +
                      options[:api_key_id_property_name],
         
     | 
| 
      
 38 
     | 
    
         
            +
                      options[:api_key_secret_property_name]
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  assert_not_nil api_key, "No API key has been provided.  Please " +
         
     | 
| 
      
 42 
     | 
    
         
            +
                      "pass an 'api_key' or 'api_key_file_location' to the " +
         
     | 
| 
      
 43 
     | 
    
         
            +
                      "Stormpath::Client constructor."
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  request_executor = Stormpath::Http::HttpClientRequestExecutor.new(api_key, proxy: options[:proxy])
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @data_store = Stormpath::DataStore.new(request_executor, cache_opts, self, base_url)
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def tenant
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Stormpath::Resource::Tenant.new '/tenants/current', self
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def client
         
     | 
| 
      
 54 
     | 
    
         
            +
                  self
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def cache_stats
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @data_source.cache_stats
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                include Stormpath::Resource::Associations
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                has_many :applications, href: '/applications', can: [:get, :create], delegate: true
         
     | 
| 
      
 64 
     | 
    
         
            +
                has_many :directories, href: '/directories', can: [:get, :create], delegate: true
         
     | 
| 
      
 65 
     | 
    
         
            +
                has_many(:accounts, href: '/accounts', can: :get) do
         
     | 
| 
      
 66 
     | 
    
         
            +
                  def verify_email_token(token)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    token_href = "#{href}/emailVerificationTokens/#{token}"
         
     | 
| 
      
 68 
     | 
    
         
            +
                    token = Stormpath::Resource::EmailVerificationToken.new(
         
     | 
| 
      
 69 
     | 
    
         
            +
                      token_href,
         
     | 
| 
      
 70 
     | 
    
         
            +
                      client
         
     | 
| 
      
 71 
     | 
    
         
            +
                    )
         
     | 
| 
      
 72 
     | 
    
         
            +
                    data_store.save token, Stormpath::Resource::Account
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
                has_many :groups, href: '/groups', can: :get
         
     | 
| 
      
 76 
     | 
    
         
            +
                has_many :group_memberships, href: '/groupMemberships', can: [:get, :create]
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                private
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def load_api_key_file(api_key_file_location, id_property_name, secret_property_name)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 82 
     | 
    
         
            +
                    api_key_properties = JavaProperties::Properties.new api_key_file_location
         
     | 
| 
      
 83 
     | 
    
         
            +
                  rescue
         
     | 
| 
      
 84 
     | 
    
         
            +
                    raise ArgumentError,
         
     | 
| 
      
 85 
     | 
    
         
            +
                      "No API Key file could be found or loaded from '" +
         
     | 
| 
      
 86 
     | 
    
         
            +
                      api_key_file_location +
         
     | 
| 
      
 87 
     | 
    
         
            +
                      "'."
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  id_property_name ||= 'apiKey.id'
         
     | 
| 
      
 91 
     | 
    
         
            +
                  secret_property_name ||= 'apiKey.secret'
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                  api_key_id = api_key_properties[id_property_name]
         
     | 
| 
      
 94 
     | 
    
         
            +
                  assert_not_nil api_key_id,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    "No API id in properties. Please provide a 'apiKey.id' property in '" +
         
     | 
| 
      
 96 
     | 
    
         
            +
                    api_key_file_location +
         
     | 
| 
      
 97 
     | 
    
         
            +
                    "' or pass in an 'api_key_id_property_name' to the Stormpath::Client " +
         
     | 
| 
      
 98 
     | 
    
         
            +
                    "constructor to specify an alternative property."
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  api_key_secret = api_key_properties[secret_property_name]
         
     | 
| 
      
 101 
     | 
    
         
            +
                  assert_not_nil api_key_secret,
         
     | 
| 
      
 102 
     | 
    
         
            +
                    "No API secret in properties. Please provide a 'apiKey.secret' property in '" +
         
     | 
| 
      
 103 
     | 
    
         
            +
                    api_key_file_location +
         
     | 
| 
      
 104 
     | 
    
         
            +
                    "' or pass in an 'api_key_secret_property_name' to the Stormpath::Client " +
         
     | 
| 
      
 105 
     | 
    
         
            +
                    "constructor to specify an alternative property."
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  ApiKey.new api_key_id, api_key_secret
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,241 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # Copyright 2012 Stormpath, Inc.
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Licensed under the Apache License, Version 2.0 (the "License");
         
     | 
| 
      
 5 
     | 
    
         
            +
            # you may not use this file except in compliance with the License.
         
     | 
| 
      
 6 
     | 
    
         
            +
            # You may obtain a copy of the License at
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            #     http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            # Unless required by applicable law or agreed to in writing, software
         
     | 
| 
      
 11 
     | 
    
         
            +
            # distributed under the License is distributed on an "AS IS" BASIS,
         
     | 
| 
      
 12 
     | 
    
         
            +
            # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         
     | 
| 
      
 13 
     | 
    
         
            +
            # See the License for the specific language governing permissions and
         
     | 
| 
      
 14 
     | 
    
         
            +
            # limitations under the License.
         
     | 
| 
      
 15 
     | 
    
         
            +
            #
         
     | 
| 
      
 16 
     | 
    
         
            +
            class Stormpath::DataStore
         
     | 
| 
      
 17 
     | 
    
         
            +
              include Stormpath::Http
         
     | 
| 
      
 18 
     | 
    
         
            +
              include Stormpath::Util::Assert
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              DEFAULT_SERVER_HOST = "api.stormpath.com"
         
     | 
| 
      
 21 
     | 
    
         
            +
              DEFAULT_API_VERSION = 1
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              CACHE_REGIONS = %w( applications directories accounts groups groupMemberships tenants )
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              attr_reader :client, :request_executor
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              def initialize(request_executor, cache_opts, client, *base_url)
         
     | 
| 
      
 28 
     | 
    
         
            +
                assert_not_nil request_executor, "RequestExecutor cannot be null."
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                @client = client
         
     | 
| 
      
 31 
     | 
    
         
            +
                @base_url = get_base_url(*base_url)
         
     | 
| 
      
 32 
     | 
    
         
            +
                @request_executor = request_executor
         
     | 
| 
      
 33 
     | 
    
         
            +
                initialize_cache cache_opts
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              def initialize_cache(cache_opts)
         
     | 
| 
      
 37 
     | 
    
         
            +
                @cache_manager = Stormpath::Cache::CacheManager.new
         
     | 
| 
      
 38 
     | 
    
         
            +
                regions_opts = cache_opts[:regions] || {}
         
     | 
| 
      
 39 
     | 
    
         
            +
                CACHE_REGIONS.each do |region|
         
     | 
| 
      
 40 
     | 
    
         
            +
                  region_opts = regions_opts[region.to_sym] || {}
         
     | 
| 
      
 41 
     | 
    
         
            +
                  region_opts[:store] ||= cache_opts[:store]
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @cache_manager.create_cache region, region_opts
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              def instantiate(clazz, properties = {})
         
     | 
| 
      
 47 
     | 
    
         
            +
                clazz.new properties, client
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def get_resource(href, clazz, query=nil)
         
     | 
| 
      
 51 
     | 
    
         
            +
                q_href = if needs_to_be_fully_qualified href
         
     | 
| 
      
 52 
     | 
    
         
            +
                           qualify href
         
     | 
| 
      
 53 
     | 
    
         
            +
                         else
         
     | 
| 
      
 54 
     | 
    
         
            +
                           href
         
     | 
| 
      
 55 
     | 
    
         
            +
                         end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                data = execute_request('get', q_href, nil, query)
         
     | 
| 
      
 58 
     | 
    
         
            +
                instantiate clazz, data.to_hash
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              def create(parent_href, resource, return_type)
         
     | 
| 
      
 62 
     | 
    
         
            +
                save_resource(parent_href, resource, return_type).tap do |returned_resource|
         
     | 
| 
      
 63 
     | 
    
         
            +
                  if resource.kind_of? return_type
         
     | 
| 
      
 64 
     | 
    
         
            +
                    resource.set_properties to_hash(returned_resource)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              def save(resource, clazz = nil)
         
     | 
| 
      
 70 
     | 
    
         
            +
                assert_not_nil resource, "resource argument cannot be null."
         
     | 
| 
      
 71 
     | 
    
         
            +
                assert_kind_of Stormpath::Resource::Base, resource, "resource argument must be instance of Stormpath::Resource::Base"
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                href = resource.href
         
     | 
| 
      
 74 
     | 
    
         
            +
                assert_true href.length > 0, "save may only be called on objects that have already been persisted (i.e. they have an existing href)."
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                href = if needs_to_be_fully_qualified(href)
         
     | 
| 
      
 77 
     | 
    
         
            +
                         qualify(href)
         
     | 
| 
      
 78 
     | 
    
         
            +
                       else
         
     | 
| 
      
 79 
     | 
    
         
            +
                         href
         
     | 
| 
      
 80 
     | 
    
         
            +
                       end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                clazz ||= resource.class
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                save_resource(href, resource, clazz).tap do |return_value|
         
     | 
| 
      
 85 
     | 
    
         
            +
                  resource.set_properties return_value
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              def delete(resource)
         
     | 
| 
      
 90 
     | 
    
         
            +
                assert_not_nil resource, "resource argument cannot be null."
         
     | 
| 
      
 91 
     | 
    
         
            +
                assert_kind_of Stormpath::Resource::Base, resource, "resource argument must be instance of Stormpath::Resource::Base"
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                execute_request('delete', resource.href)
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
              def cache_manager
         
     | 
| 
      
 97 
     | 
    
         
            +
                @cache_manager
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
              protected
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
              def needs_to_be_fully_qualified(href)
         
     | 
| 
      
 103 
     | 
    
         
            +
                !href.downcase.start_with? 'http'
         
     | 
| 
      
 104 
     | 
    
         
            +
              end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
              def qualify(href)
         
     | 
| 
      
 107 
     | 
    
         
            +
                slash_added = ''
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                if !href.start_with? '/'
         
     | 
| 
      
 110 
     | 
    
         
            +
                  slash_added = '/'
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                @base_url + slash_added + href
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
              private
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
              def execute_request(http_method, href, body=nil, query=nil)
         
     | 
| 
      
 119 
     | 
    
         
            +
                if http_method == 'get' && (cache = cache_for href)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  cached_result = cache.get href
         
     | 
| 
      
 121 
     | 
    
         
            +
                  return cached_result if cached_result
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                request = Request.new(http_method, href, query, Hash.new, body)
         
     | 
| 
      
 125 
     | 
    
         
            +
                apply_default_request_headers request
         
     | 
| 
      
 126 
     | 
    
         
            +
                response = @request_executor.execute_request request
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                result = response.body.length > 0 ? MultiJson.load(response.body) : ''
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                if response.error?
         
     | 
| 
      
 131 
     | 
    
         
            +
                  error = Stormpath::Resource::Error.new result
         
     | 
| 
      
 132 
     | 
    
         
            +
                  #puts "Error with request: #{http_method.upcase}: #{href}"
         
     | 
| 
      
 133 
     | 
    
         
            +
                  raise Stormpath::Error.new error
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                if http_method == 'delete'
         
     | 
| 
      
 137 
     | 
    
         
            +
                  cache = cache_for href
         
     | 
| 
      
 138 
     | 
    
         
            +
                  cache.delete href if cache
         
     | 
| 
      
 139 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                if result['href']
         
     | 
| 
      
 143 
     | 
    
         
            +
                  cache_walk result
         
     | 
| 
      
 144 
     | 
    
         
            +
                else
         
     | 
| 
      
 145 
     | 
    
         
            +
                  result
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
              end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
              def cache_walk(resource)
         
     | 
| 
      
 150 
     | 
    
         
            +
                assert_not_nil resource['href'], "resource must have 'href' property"
         
     | 
| 
      
 151 
     | 
    
         
            +
                items = resource['items']
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                if items # collection resource
         
     | 
| 
      
 154 
     | 
    
         
            +
                  resource['items'] = items.map do |item|
         
     | 
| 
      
 155 
     | 
    
         
            +
                    cache_walk item
         
     | 
| 
      
 156 
     | 
    
         
            +
                    { 'href' => item['href'] }
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
                else     # single resource
         
     | 
| 
      
 159 
     | 
    
         
            +
                  resource.each do |attr, value|
         
     | 
| 
      
 160 
     | 
    
         
            +
                    if value.is_a? Hash
         
     | 
| 
      
 161 
     | 
    
         
            +
                      walked = cache_walk value
         
     | 
| 
      
 162 
     | 
    
         
            +
                      resource[attr] = { 'href' => value['href'] }
         
     | 
| 
      
 163 
     | 
    
         
            +
                      resource[attr]['items'] = walked['items'] if walked['items']
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  cache resource if resource.length > 1
         
     | 
| 
      
 167 
     | 
    
         
            +
                end
         
     | 
| 
      
 168 
     | 
    
         
            +
                resource
         
     | 
| 
      
 169 
     | 
    
         
            +
              end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
              def cache(resource)
         
     | 
| 
      
 172 
     | 
    
         
            +
                cache = cache_for resource['href']
         
     | 
| 
      
 173 
     | 
    
         
            +
                cache.put resource['href'], resource if cache
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
              def cache_for(href)
         
     | 
| 
      
 177 
     | 
    
         
            +
                @cache_manager.get_cache(region_for href)
         
     | 
| 
      
 178 
     | 
    
         
            +
              end
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
              def region_for(href)
         
     | 
| 
      
 181 
     | 
    
         
            +
                return nil unless href
         
     | 
| 
      
 182 
     | 
    
         
            +
                region = href.split('/')[-2]
         
     | 
| 
      
 183 
     | 
    
         
            +
                CACHE_REGIONS.include?(region) ? region : nil
         
     | 
| 
      
 184 
     | 
    
         
            +
              end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
              def apply_default_request_headers(request)
         
     | 
| 
      
 187 
     | 
    
         
            +
                request.http_headers.store 'Accept', 'application/json'
         
     | 
| 
      
 188 
     | 
    
         
            +
                request.http_headers.store 'User-Agent', 'Stormpath-RubySDK/' + Stormpath::VERSION
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                if !request.body.nil? and request.body.length > 0
         
     | 
| 
      
 191 
     | 
    
         
            +
                  request.http_headers.store 'Content-Type', 'application/json'
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
              end
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
              def save_resource(href, resource, return_type)
         
     | 
| 
      
 196 
     | 
    
         
            +
                assert_not_nil resource, "resource argument cannot be null."
         
     | 
| 
      
 197 
     | 
    
         
            +
                assert_not_nil return_type, "returnType class cannot be null."
         
     | 
| 
      
 198 
     | 
    
         
            +
                assert_kind_of Stormpath::Resource::Base, resource, "resource argument must be instance of Stormpath::Resource::Base"
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                q_href = if needs_to_be_fully_qualified href
         
     | 
| 
      
 201 
     | 
    
         
            +
                           qualify href
         
     | 
| 
      
 202 
     | 
    
         
            +
                         else
         
     | 
| 
      
 203 
     | 
    
         
            +
                           href
         
     | 
| 
      
 204 
     | 
    
         
            +
                         end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                response = execute_request('post', q_href, MultiJson.dump(to_hash(resource)))
         
     | 
| 
      
 207 
     | 
    
         
            +
                instantiate return_type, response.to_hash
         
     | 
| 
      
 208 
     | 
    
         
            +
              end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
              def get_base_url(*base_url)
         
     | 
| 
      
 211 
     | 
    
         
            +
                (!base_url.empty? and !base_url[0].nil?) ?
         
     | 
| 
      
 212 
     | 
    
         
            +
                  base_url[0] :
         
     | 
| 
      
 213 
     | 
    
         
            +
                  "https://" + DEFAULT_SERVER_HOST + "/v" + DEFAULT_API_VERSION.to_s
         
     | 
| 
      
 214 
     | 
    
         
            +
              end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
              def to_hash(resource)
         
     | 
| 
      
 217 
     | 
    
         
            +
                Hash.new.tap do |properties|
         
     | 
| 
      
 218 
     | 
    
         
            +
                  resource.get_property_names.each do |name|
         
     | 
| 
      
 219 
     | 
    
         
            +
                    property = resource.get_property name
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    if property.kind_of? Hash
         
     | 
| 
      
 222 
     | 
    
         
            +
                      property = to_simple_reference name, property
         
     | 
| 
      
 223 
     | 
    
         
            +
                    end
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                    properties.store name, property
         
     | 
| 
      
 226 
     | 
    
         
            +
                  end
         
     | 
| 
      
 227 
     | 
    
         
            +
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
              end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
              def to_simple_reference(property_name, hash)
         
     | 
| 
      
 231 
     | 
    
         
            +
                href_prop_name = Stormpath::Resource::Base::HREF_PROP_NAME
         
     | 
| 
      
 232 
     | 
    
         
            +
                assert_true(
         
     | 
| 
      
 233 
     | 
    
         
            +
                  (hash.kind_of?(Hash) and !hash.empty? and hash.has_key?(href_prop_name)),
         
     | 
| 
      
 234 
     | 
    
         
            +
                  "Nested resource '#{property_name}' must have an 'href' property."
         
     | 
| 
      
 235 
     | 
    
         
            +
                )
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                href = hash[href_prop_name]
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                {href_prop_name => href}
         
     | 
| 
      
 240 
     | 
    
         
            +
              end
         
     | 
| 
      
 241 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -13,21 +13,27 @@ 
     | 
|
| 
       13 
13 
     | 
    
         
             
            # See the License for the specific language governing permissions and
         
     | 
| 
       14 
14 
     | 
    
         
             
            # limitations under the License.
         
     | 
| 
       15 
15 
     | 
    
         
             
            #
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
            class Stormpath::Error < RuntimeError
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
               
     | 
| 
      
 18 
     | 
    
         
            +
              def initialize error = nil
         
     | 
| 
      
 19 
     | 
    
         
            +
                super !error.nil? ? error.message : ''
         
     | 
| 
      
 20 
     | 
    
         
            +
                @error = error
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
       19 
22 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
              def status
         
     | 
| 
      
 24 
     | 
    
         
            +
                !@error.nil? ? @error.status : -1
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
       21 
26 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
              def code
         
     | 
| 
      
 28 
     | 
    
         
            +
                !@error.nil? ? @error.code : -1
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
       23 
30 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                  end
         
     | 
| 
       28 
     | 
    
         
            -
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              def developer_message
         
     | 
| 
      
 32 
     | 
    
         
            +
                !@error.nil? ? @error.developer_message : nil
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
       29 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
              def more_info
         
     | 
| 
      
 36 
     | 
    
         
            +
                !@error.nil? ? @error.more_info : nil
         
     | 
| 
       30 
37 
     | 
    
         
             
              end
         
     | 
| 
       31 
38 
     | 
    
         | 
| 
       32 
39 
     | 
    
         
             
            end
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
         @@ -15,8 +15,6 @@ 
     | 
|
| 
       15 
15 
     | 
    
         
             
            #
         
     | 
| 
       16 
16 
     | 
    
         
             
            class Hash
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
              # implementation borrowed from the vine project at
         
     | 
| 
       19 
     | 
    
         
            -
              # https://github.com/guangnan/vine/blob/master/lib/vine.rb
         
     | 
| 
       20 
18 
     | 
    
         
             
              def access(path, separator)
         
     | 
| 
       21 
19 
     | 
    
         
             
                ret = self
         
     | 
| 
       22 
20 
     | 
    
         
             
                path.split(separator).each do |p|
         
     | 
| 
         @@ -29,4 +27,5 @@ class Hash 
     | 
|
| 
       29 
27 
     | 
    
         
             
                end
         
     | 
| 
       30 
28 
     | 
    
         
             
                ret
         
     | 
| 
       31 
29 
     | 
    
         
             
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       32 
31 
     | 
    
         
             
            end
         
     | 
| 
         @@ -23,7 +23,7 @@ module Stormpath 
     | 
|
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
                    include OpenSSL
         
     | 
| 
       25 
25 
     | 
    
         
             
                    include UUIDTools
         
     | 
| 
       26 
     | 
    
         
            -
                    include Stormpath:: 
     | 
| 
      
 26 
     | 
    
         
            +
                    include Stormpath::Http::Utils
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                    DEFAULT_ALGORITHM = "SHA256"
         
     | 
| 
       29 
29 
     | 
    
         
             
                    HOST_HEADER = "Host"
         
     | 
| 
         @@ -40,20 +40,24 @@ module Stormpath 
     | 
|
| 
       40 
40 
     | 
    
         
             
                    #noinspection RubyConstantNamingConvention
         
     | 
| 
       41 
41 
     | 
    
         
             
                    NL = "\n"
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
                    def initialize(uuid_generator=UUID.method(:random_create))
         
     | 
| 
      
 44 
     | 
    
         
            +
                      @uuid_generator = uuid_generator
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       43 
47 
     | 
    
         
             
                    def sign_request request, api_key
         
     | 
| 
       44 
48 
     | 
    
         | 
| 
       45 
49 
     | 
    
         
             
                      time = Time.now
         
     | 
| 
       46 
50 
     | 
    
         
             
                      time_stamp = time.utc.strftime TIMESTAMP_FORMAT
         
     | 
| 
       47 
51 
     | 
    
         
             
                      date_stamp = time.utc.strftime DATE_FORMAT
         
     | 
| 
       48 
52 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
                      nonce =  
     | 
| 
      
 53 
     | 
    
         
            +
                      nonce = @uuid_generator.call.to_s
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
       51 
55 
     | 
    
         
             
                      uri = request.resource_uri
         
     | 
| 
       52 
56 
     | 
    
         | 
| 
       53 
57 
     | 
    
         
             
                      # SAuthc1 requires that we sign the Host header so we
         
     | 
| 
       54 
58 
     | 
    
         
             
                      # have to have it in the request by the time we sign.
         
     | 
| 
       55 
59 
     | 
    
         
             
                      host_header = uri.host
         
     | 
| 
       56 
     | 
    
         
            -
                      if ! 
     | 
| 
      
 60 
     | 
    
         
            +
                      if !default_port?(uri)
         
     | 
| 
       57 
61 
     | 
    
         | 
| 
       58 
62 
     | 
    
         
             
                        host_header << ":" << uri.port.to_s
         
     | 
| 
       59 
63 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -180,7 +184,7 @@ module Stormpath 
     | 
|
| 
       180 
184 
     | 
    
         
             
                      if resource_path.nil? or resource_path.empty?
         
     | 
| 
       181 
185 
     | 
    
         
             
                        '/'
         
     | 
| 
       182 
186 
     | 
    
         
             
                      else
         
     | 
| 
       183 
     | 
    
         
            -
                         
     | 
| 
      
 187 
     | 
    
         
            +
                        encode_url resource_path, true, true
         
     | 
| 
       184 
188 
     | 
    
         
             
                      end
         
     | 
| 
       185 
189 
     | 
    
         
             
                    end
         
     | 
| 
       186 
190 
     | 
    
         |