├── .gitignore ├── .rspec ├── .rubocop.yml ├── .ruby-gemset ├── .travis.yml ├── CHANGES.md ├── Gemfile ├── README.md ├── Rakefile ├── lib ├── stormpath-sdk.rb └── stormpath-sdk │ ├── api_key.rb │ ├── auth │ ├── authentication_result.rb │ ├── basic_authenticator.rb │ ├── basic_login_attempt.rb │ ├── challenge_factor_attempt.rb │ ├── challenge_validator.rb │ ├── create_factor.rb │ ├── http_basic_authentication.rb │ ├── http_bearer_authentication.rb │ ├── register_service_provider.rb │ └── username_password_request.rb │ ├── cache │ ├── cache.rb │ ├── cache_entry.rb │ ├── cache_manager.rb │ ├── cache_stats.rb │ ├── disabled_cache_store.rb │ ├── memcached_store.rb │ ├── memory_store.rb │ └── redis_store.rb │ ├── client.rb │ ├── data_store.rb │ ├── error.rb │ ├── http │ ├── authc │ │ └── sauthc1_signer.rb │ ├── http_client_request_executor.rb │ ├── request.rb │ ├── response.rb │ └── utils.rb │ ├── id_site │ └── id_site_result.rb │ ├── oauth │ ├── access_token_authentication_result.rb │ ├── authenticator.rb │ ├── challenge_factor_grant.rb │ ├── challenge_factor_grant_request.rb │ ├── client_credentials_grant.rb │ ├── client_credentials_grant_request.rb │ ├── error.rb │ ├── id_site_grant.rb │ ├── id_site_grant_request.rb │ ├── local_access_token_verification.rb │ ├── password_grant.rb │ ├── password_grant_request.rb │ ├── refresh_grant_request.rb │ ├── refresh_token.rb │ ├── remote_access_token_verification.rb │ ├── social_grant.rb │ ├── social_grant_request.rb │ ├── stormpath_grant_request.rb │ ├── stormpath_token_grant.rb │ ├── verify_access_token.rb │ └── verify_token_result.rb │ ├── provider │ ├── account_access.rb │ ├── account_request.rb │ ├── account_resolver.rb │ ├── account_result.rb │ ├── facebook │ │ ├── facebook_provider.rb │ │ └── facebook_provider_data.rb │ ├── github │ │ ├── github_provider.rb │ │ └── github_provider_data.rb │ ├── google │ │ ├── google_provider.rb │ │ └── google_provider_data.rb │ ├── ldap │ │ └── ldap_provider.rb │ ├── linkedin │ │ ├── linkedin_provider.rb │ │ └── linkedin_provider_data.rb │ ├── provider.rb │ ├── provider_data.rb │ ├── saml │ │ ├── saml_provider.rb │ │ └── saml_provider_data.rb │ ├── stormpath │ │ ├── stormpath_provider.rb │ │ └── stormpath_provider_data.rb │ └── twitter │ │ ├── twitter_provider.rb │ │ └── twitter_provider_data.rb │ ├── resource │ ├── access_token.rb │ ├── account.rb │ ├── account_creation_policy.rb │ ├── account_link.rb │ ├── account_linking_policy.rb │ ├── account_membership.rb │ ├── account_overrides.rb │ ├── account_store.rb │ ├── account_store_mapping.rb │ ├── agent.rb │ ├── api_key.rb │ ├── application.rb │ ├── application_web_config.rb │ ├── associations.rb │ ├── attribute_statement_mapping_rules.rb │ ├── base.rb │ ├── challenge.rb │ ├── collection.rb │ ├── custom_data.rb │ ├── custom_data_hash_methods.rb │ ├── custom_data_storage.rb │ ├── directory.rb │ ├── email_template.rb │ ├── email_verification_token.rb │ ├── error.rb │ ├── expansion.rb │ ├── factor.rb │ ├── field.rb │ ├── group.rb │ ├── group_membership.rb │ ├── instance.rb │ ├── linked_account.rb │ ├── oauth_policy.rb │ ├── organization.rb │ ├── organization_account_store_mapping.rb │ ├── password_policy.rb │ ├── password_reset_token.rb │ ├── password_strength.rb │ ├── phone.rb │ ├── refresh_token.rb │ ├── registered_saml_service_provider.rb │ ├── saml_identity_provider.rb │ ├── saml_identity_provider_metadata.rb │ ├── saml_policy.rb │ ├── saml_service_provider.rb │ ├── saml_service_provider_metadata.rb │ ├── saml_service_provider_registration.rb │ ├── schema.rb │ ├── tenant.rb │ ├── user_info_mapping_rules.rb │ ├── utils.rb │ ├── verification_email.rb │ └── x_509_certificate.rb │ ├── util │ ├── assert.rb │ └── uri_builder.rb │ └── version.rb ├── spec ├── api_key_spec.rb ├── auth │ ├── basic_authenticator_spec.rb │ ├── challenge_validator_spec.rb │ ├── create_factor_spec.rb │ ├── http_basic_authentication_spec.rb │ ├── http_bearer_authentication_spec.rb │ ├── register_service_provider_spec.rb │ └── sauthc1_signer_spec.rb ├── cache │ ├── cache_entry_spec.rb │ ├── cache_spec.rb │ └── cache_stats_spec.rb ├── client_spec.rb ├── data_store_spec.rb ├── oauth │ └── access_token_authentication_result_spec.rb ├── provider │ ├── account_resolver_spec.rb │ └── provider_spec.rb ├── resource │ ├── account_creation_policy_spec.rb │ ├── account_link_spec.rb │ ├── account_linking_policy_spec.rb │ ├── account_spec.rb │ ├── account_store_mapping_spec.rb │ ├── account_store_spec.rb │ ├── agent_spec.rb │ ├── api_key_spec.rb │ ├── application_spec.rb │ ├── application_web_config_spec.rb │ ├── base_spec.rb │ ├── challenge_spec.rb │ ├── collection_spec.rb │ ├── custom_data_spec.rb │ ├── directory_spec.rb │ ├── email_template_spec.rb │ ├── expansion_spec.rb │ ├── factor_spec.rb │ ├── field_spec.rb │ ├── group_membership_spec.rb │ ├── group_spec.rb │ ├── linked_account_spec.rb │ ├── organization_spec.rb │ ├── password_policy_spec.rb │ ├── password_strength_spec.rb │ ├── phone_spec.rb │ ├── registered_saml_service_provider_spec.rb │ ├── saml_identity_provider_metadata_spec.rb │ ├── saml_identity_provider_spec.rb │ ├── saml_policy_spec.rb │ ├── saml_service_provider_registration_spec.rb │ ├── saml_service_provider_spec.rb │ ├── schema_spec.rb │ ├── status_spec.rb │ └── tenant_spec.rb ├── spec_helper.rb ├── support │ ├── api_key_helpers.rb │ ├── custom_data_save_period.rb │ ├── custom_data_storage_behavior.rb │ ├── env_names_warning.rb │ ├── mocked_provider_accounts.rb │ ├── mocked_saml_responses.rb │ ├── resource_factory.rb │ ├── resource_helpers.rb │ ├── resource_matchers.rb │ ├── test_cache_stores.rb │ └── test_request_executor.rb └── util │ └── uri_builder_spec.rb └── stormpath-sdk.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | !.travis.yml 3 | pkg/* 4 | Gemfile.lock 5 | coverage 6 | spec/fixtures/vcr_cassettes 7 | *.ipr 8 | *.iws 9 | *.iml 10 | .idea 11 | Guardfile 12 | tmp/* 13 | *.gem 14 | .bundle/ 15 | dump.rdb 16 | .ruby-version 17 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color --format Fivemat 2 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | LineLength: 2 | Max: 100 3 | 4 | Documentation: 5 | Enabled: False 6 | 7 | Style/FirstMethodArgumentLineBreak: 8 | Description: >- 9 | Checks for a line break before the first argument in a 10 | multi-line method call. 11 | Enabled: True 12 | 13 | WordArray: 14 | Enabled: False 15 | 16 | AllCops: 17 | Exclude: 18 | - 'db/schema.rb' 19 | - 'db/migrate/*.rb' 20 | Rails: 21 | Enabled: true 22 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | stormpath-sdk-ruby 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1.5 4 | - 2.3.1 5 | services: 6 | - redis-server 7 | - memcached 8 | before_install: 9 | - gem install bundler 10 | env: 11 | global: 12 | - secure: JObfQKlPYrwupzv2ASkCQWD7TMqD6D9OfbVdUe/sot91fVgoQIs7vGlQPYNz6aTgoAZfEKptrzXzA0KOsGKRDjN0MSkY/PevPxdb+81YTDdldKD5GCc5srWVDpwhRJvKU8ufHdrTcvf+Weulu4egUHoqOerlBcexTO/Erbe8/M4= 13 | - secure: K24I2/DC4Z6SeosQaR4suZij4yacteVzXqLexJ+LSlxZP7j1T72O3JLtc7/SLm8RFOJkiH/csTgbZmLNAWZO8c0Y4fWAvIC/I1xfoCr57udfQPIe83qdtpVetyYs1BGcqlRboGpqxtOewGHHuHtIge4bjD5l1hHA+WaIdVa4GfI= 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rubygems' 3 | require 'rubygems/package_task' 4 | require 'rspec/core/rake_task' 5 | require 'stormpath-sdk' 6 | 7 | spec = eval(File.read('stormpath-sdk.gemspec')) 8 | 9 | Gem::PackageTask.new(spec) do |p| 10 | p.gem_spec = spec 11 | end 12 | 13 | RSpec::Core::RakeTask.new do |t| 14 | t.pattern = '**/*_spec.rb' 15 | t.rspec_opts = ['-c'] 16 | end 17 | 18 | task default: :spec 19 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/api_key.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | class ApiKey 18 | attr_accessor :id, :secret 19 | 20 | def initialize(id, secret) 21 | @id = id 22 | @secret = secret 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/authentication_result.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Authentication 18 | class AuthenticationResult < Stormpath::Resource::Base 19 | has_one :account 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/basic_authenticator.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Authentication 18 | class BasicAuthenticator 19 | include Stormpath::Util::Assert 20 | 21 | def initialize(data_store) 22 | @data_store = data_store 23 | end 24 | 25 | def authenticate(parent_href, request) 26 | assert_not_nil parent_href, 'parentHref argument must be specified' 27 | assert_kind_of UsernamePasswordRequest, request, 'Only UsernamePasswordRequest instances are supported.' 28 | 29 | username = request.principals 30 | username ||= '' 31 | 32 | password = request.credentials 33 | pw_string = password.join 34 | 35 | value = username + ':' + pw_string 36 | 37 | value = Base64.encode64(value).tr("\n", '') 38 | 39 | attempt = @data_store.instantiate(BasicLoginAttempt, nil) 40 | attempt.type = 'basic' 41 | attempt.value = value 42 | 43 | attempt.account_store = request.account_store if request.account_store 44 | 45 | href = parent_href + '/loginAttempts' 46 | 47 | @data_store.create(href, attempt, AuthenticationResult) 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/basic_login_attempt.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Authentication 18 | class BasicLoginAttempt < Stormpath::Resource::Base 19 | TYPE = 'type'.freeze 20 | VALUE = 'value'.freeze 21 | ACCOUNT_STORE = 'account_store'.freeze 22 | 23 | def account_store 24 | get_property ACCOUNT_STORE 25 | end 26 | 27 | def account_store=(account_store) 28 | if account_store.is_a? Stormpath::Resource::Base 29 | set_property ACCOUNT_STORE, HREF_PROP_NAME => account_store.href 30 | elsif account_store.is_a? Hash 31 | set_property ACCOUNT_STORE, sanitize(account_store) 32 | else 33 | raise ArgumentError, 'account_store should be a Stormpath::Resource::Instance or a Hash' 34 | end 35 | end 36 | 37 | def type 38 | get_property TYPE 39 | end 40 | 41 | def type=(type) 42 | set_property TYPE, type 43 | end 44 | 45 | def value 46 | get_property VALUE 47 | end 48 | 49 | def value=(value) 50 | set_property VALUE, value 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/challenge_factor_attempt.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Authentication 3 | class ChallengeFactorAttempt < Stormpath::Resource::Base 4 | CODE = 'code'.freeze 5 | 6 | def code 7 | get_property CODE 8 | end 9 | 10 | def code=(code) 11 | set_property CODE, code 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/challenge_validator.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Authentication 3 | class ChallengeValidator 4 | attr_reader :data_store, :href 5 | 6 | def initialize(data_store, href) 7 | @data_store = data_store 8 | @href = href 9 | end 10 | 11 | def validate(code) 12 | attempt.code = code 13 | data_store.create(href, attempt, Stormpath::Resource::Challenge) 14 | end 15 | 16 | private 17 | 18 | def attempt 19 | @attempt ||= data_store.instantiate(Stormpath::Authentication::ChallengeFactorAttempt, nil) 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/create_factor.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Authentication 18 | class CreateFactor < Stormpath::Resource::Base 19 | attr_reader :client, :account, :type, :phone, :challenge, :custom_options 20 | 21 | def initialize(client, account, type, options = {}) 22 | @client = client 23 | @account = account 24 | @type = determine_type(type) 25 | @phone = options[:phone] || nil 26 | @challenge = options[:challenge] || nil 27 | @custom_options = options[:custom_options] || nil 28 | end 29 | 30 | def save 31 | account.factors.create(factor_attrs) 32 | end 33 | 34 | private 35 | 36 | def factor_attrs 37 | {}.tap do |body| 38 | body[:type] = type 39 | body[:phone] = phone if phone 40 | body[:challenge] = { message: "#{challenge[:message]} ${code}" } if challenge 41 | add_custom_options(body) 42 | end 43 | end 44 | 45 | def determine_type(type) 46 | raise Stormpath::Error unless type == :sms || type == :google_authenticator 47 | type.to_s.sub('_', '-') 48 | end 49 | 50 | def add_custom_options(body) 51 | if custom_options 52 | body[:accountName] = custom_options[:account_name] if custom_options[:account_name] 53 | body[:issuer] = custom_options[:issuer] if custom_options[:issuer] 54 | body[:status] = custom_options[:status] if custom_options[:status] 55 | end 56 | body 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/http_basic_authentication.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Authentication 3 | class HttpBasicAuthentication 4 | BASIC_PATTERN = /^Basic / 5 | attr_reader :application, :authorization_header 6 | 7 | def initialize(application, authorization_header) 8 | @application = application 9 | @authorization_header = authorization_header 10 | raise Stormpath::Error if authorization_header.nil? 11 | end 12 | 13 | def authenticate! 14 | raise Stormpath::Error if fetched_api_key.nil? 15 | raise Stormpath::Error if fetched_api_key.secret != api_key_secret 16 | fetched_api_key 17 | end 18 | 19 | private 20 | 21 | def fetched_api_key 22 | @fetched_api_key ||= application.api_keys.search(id: api_key_id).first 23 | end 24 | 25 | def api_key_id 26 | decoded_authorization_header.first 27 | end 28 | 29 | def api_key_secret 30 | decoded_authorization_header.last 31 | end 32 | 33 | def decoded_authorization_header 34 | @decoded_authorization_header ||= begin 35 | api_key_and_secret = Base64.decode64(basic_authorization_header).split(':') 36 | raise Stormpath::Error if api_key_and_secret.count != 2 37 | api_key_and_secret 38 | end 39 | end 40 | 41 | def basic_authorization_header 42 | raise Stormpath::Error unless authorization_header =~ BASIC_PATTERN 43 | authorization_header.gsub(BASIC_PATTERN, '') 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/http_bearer_authentication.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Authentication 3 | class HttpBearerAuthentication 4 | BEARER_PATTERN = /^Bearer / 5 | attr_reader :application, :authorization_header, :local 6 | 7 | def initialize(application, authorization_header, options = {}) 8 | @application = application 9 | @authorization_header = authorization_header 10 | @local = options[:local] || false 11 | raise Stormpath::Error if authorization_header.nil? 12 | end 13 | 14 | def authenticate! 15 | Stormpath::Oauth::VerifyAccessToken.new(application, local: local) 16 | .verify(bearer_access_token) 17 | end 18 | 19 | private 20 | 21 | def bearer_access_token 22 | raise Stormpath::Error unless authorization_header =~ BEARER_PATTERN 23 | authorization_header.gsub(BEARER_PATTERN, '') 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/register_service_provider.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Authentication 3 | class RegisterServiceProvider 4 | attr_reader :client, :identity_provider, :options 5 | 6 | def initialize(identity_provider, options = {}) 7 | @client = identity_provider.client 8 | @identity_provider = identity_provider 9 | @options = options 10 | end 11 | 12 | def call 13 | map_identity_provider_and_registered_service_provider 14 | registered_service_provider 15 | end 16 | 17 | private 18 | 19 | def map_identity_provider_and_registered_service_provider 20 | identity_provider.saml_service_provider_registrations.create( 21 | service_provider: { href: registered_service_provider.href } 22 | ) 23 | end 24 | 25 | def registered_service_provider 26 | @registered_service_provider ||= 27 | client.registered_saml_service_providers.create(registered_service_provider_params) 28 | end 29 | 30 | def registered_service_provider_params 31 | {}.tap do |body| 32 | body[:assertion_consumer_service_url] = options[:assertion_consumer_service_url] 33 | body[:entity_id] = options[:entity_id] 34 | body[:name] = options[:name] 35 | body[:description] = options[:description] 36 | body[:name_id_format] = options[:name_id_format] 37 | end.compact 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/auth/username_password_request.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Authentication 18 | class UsernamePasswordRequest 19 | attr_reader :host, :account_store 20 | 21 | def initialize(username, password, options = {}) 22 | @username = username 23 | @password = (password || '').chars.to_a 24 | @host = options[:host] 25 | @account_store = options[:account_store] 26 | end 27 | 28 | def principals 29 | @username 30 | end 31 | 32 | def credentials 33 | @password 34 | end 35 | 36 | def clear 37 | @username = nil 38 | @host = nil 39 | @account_store = nil 40 | 41 | @password.each { |_pass_char| pass_char = 0x00 } 42 | @password = nil 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/cache.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | DEFAULT_STORE = MemoryStore 4 | DEFAULT_TTL_SECONDS = 5 * 60 5 | DEFAULT_TTI_SECONDS = 5 * 60 6 | 7 | class Cache 8 | attr_reader :stats, :ttl_seconds, :tti_seconds 9 | 10 | def initialize(opts = {}) 11 | @ttl_seconds = opts[:ttl_seconds] || DEFAULT_TTL_SECONDS 12 | @tti_seconds = opts[:tti_seconds] || DEFAULT_TTI_SECONDS 13 | store_opts = opts[:store_opts] || {} 14 | @store = (opts[:store] || DEFAULT_STORE).new(store_opts) 15 | @stats = CacheStats.new 16 | end 17 | 18 | def get(k) 19 | if entry = @store.get(k) 20 | if entry.expired? @ttl_seconds, @tti_seconds 21 | @stats.miss true 22 | @store.delete(k) 23 | nil 24 | else 25 | @stats.hit 26 | entry.touch 27 | entry.value 28 | end 29 | else 30 | @stats.miss 31 | nil 32 | end 33 | end 34 | 35 | def put(k, v) 36 | @store.put k, CacheEntry.new(v) 37 | @stats.put 38 | end 39 | 40 | def delete(k) 41 | @store.delete(k) 42 | @stats.delete 43 | end 44 | 45 | def clear 46 | @store.clear 47 | end 48 | 49 | def size 50 | @stats.size 51 | end 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/cache_entry.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | class CacheEntry 4 | attr_accessor :value, :created_at, :last_accessed_at 5 | 6 | def initialize(value) 7 | self.value = value 8 | self.created_at = Time.now 9 | self.last_accessed_at = created_at 10 | end 11 | 12 | def touch 13 | self.last_accessed_at = Time.now 14 | end 15 | 16 | def expired?(ttl_seconds, tti_seconds) 17 | now = Time.now 18 | now > (created_at + ttl_seconds) || now > (last_accessed_at + tti_seconds) 19 | end 20 | 21 | def to_h 22 | { 'value' => value, 'created_at' => created_at, 'last_accessed_at' => last_accessed_at } 23 | end 24 | 25 | def self.from_h(hash) 26 | CacheEntry.new(hash['value']).tap do |cache_entry| 27 | cache_entry.created_at = Time.parse(hash['created_at']) 28 | cache_entry.last_accessed_at = Time.parse(hash['last_accessed_at']) 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/cache_manager.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | class CacheManager 4 | def initialize(_opts = nil) 5 | @caches = {} 6 | end 7 | 8 | def create_cache(region, opts) 9 | @caches[region] = Cache.new(opts) 10 | end 11 | 12 | def get_cache(region) 13 | @caches[region] 14 | end 15 | 16 | def stats 17 | Hash[@caches.map { |region, cache| [region, cache.stats] }] 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/cache_stats.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | class CacheStats 4 | attr_accessor :puts, :hits, :misses, :expirations, :size 5 | 6 | def initialize 7 | @puts = @hits = @misses = @expirations = @size = 0 8 | end 9 | 10 | def put 11 | @puts += 1 12 | @size += 1 13 | end 14 | 15 | def hit 16 | @hits += 1 17 | end 18 | 19 | def miss(expired = false) 20 | @misses += 1 21 | @expirations += 1 if expired 22 | end 23 | 24 | def delete 25 | @size -= 1 if @size > 0 26 | end 27 | 28 | def summary 29 | [@puts, @hits, @misses, @expirations, @size] 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/disabled_cache_store.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | class DisabledCacheStore 4 | def initialize(opts = nil); end 5 | 6 | def get(key); end 7 | 8 | def put(_key, entry) 9 | entry 10 | end 11 | 12 | def delete(key); end 13 | 14 | def clear 15 | {} 16 | end 17 | 18 | def size 19 | 0 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/memcached_store.rb: -------------------------------------------------------------------------------- 1 | require 'memcached' 2 | 3 | module Stormpath 4 | module Cache 5 | class MemcachedStore 6 | DEFAULT_SERVER_HOST = 'localhost:11211'.freeze 7 | attr_reader :memcached, :options 8 | 9 | def initialize(opts = {}) 10 | @options = opts.blank? ? { host: DEFAULT_SERVER_HOST } : opts 11 | @memcached = Memcached.new(options[:host], options_without_host) 12 | end 13 | 14 | def get(key) 15 | begin 16 | entry = memcached.get(key) 17 | entry && Stormpath::Cache::CacheEntry.from_h(MultiJson.load(entry)) 18 | rescue Memcached::NotFound 19 | nil 20 | end 21 | end 22 | 23 | def put(key, entry) 24 | memcached.set(key, MultiJson.dump(entry.to_h)) 25 | end 26 | 27 | def delete(key) 28 | memcached.delete(key) 29 | end 30 | 31 | def clear 32 | memcached.flush 33 | end 34 | 35 | def size 36 | memcached.stats[:curr_items] 37 | end 38 | 39 | def options_without_host 40 | options.tap { |hs| hs.delete(:host) } 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/memory_store.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Cache 3 | class MemoryStore 4 | def initialize(opts = nil) 5 | @store = {} 6 | end 7 | 8 | def get(key) 9 | @store[key] 10 | end 11 | 12 | def put(key, entry) 13 | @store[key] = entry 14 | end 15 | 16 | def delete(key) 17 | @store.delete(key) 18 | end 19 | 20 | def clear 21 | @store.clear 22 | end 23 | 24 | def size 25 | @store.size 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/cache/redis_store.rb: -------------------------------------------------------------------------------- 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 33 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/error.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | class Error < RuntimeError 18 | attr_reader :status, :code, :developer_message, :more_info, :request_id 19 | 20 | def initialize(error = NilError.new) 21 | super error.message 22 | @status = error.status 23 | @code = error.code 24 | @developer_message = error.developer_message 25 | @more_info = error.more_info 26 | @request_id = error.request_id 27 | end 28 | 29 | private 30 | 31 | class NilError 32 | def message 33 | '' 34 | end 35 | 36 | def status 37 | -1 38 | end 39 | 40 | def code 41 | -1 42 | end 43 | 44 | def developer_message; end 45 | 46 | def more_info; end 47 | 48 | def request_id; end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/http/http_client_request_executor.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | module Http 18 | class HttpClientRequestExecutor 19 | include Stormpath::Http::Authc 20 | include Stormpath::Util::Assert 21 | 22 | def initialize(options = {}) 23 | @signer = Sauthc1Signer.new 24 | @http_client = HTTPClient.new(options[:proxy]) 25 | end 26 | 27 | def execute_request(request, redirects_limit = 10) 28 | assert_not_nil request, 'Request argument cannot be null.' 29 | 30 | @redirect_response = nil 31 | 32 | @signer.sign_request request 33 | 34 | domain = if request.query_string.present? 35 | [request.href, request.to_s_query_string(true)].join '?' 36 | else 37 | request.href 38 | end 39 | 40 | if request.http_headers['Content-Type'] == 'application/x-www-form-urlencoded' 41 | @http_client.set_auth(request.href, request.api_key.id, request.api_key.secret) 42 | end 43 | 44 | method = @http_client.method(request.http_method.downcase) 45 | 46 | response = method.call domain, request.body, request.http_headers 47 | 48 | if response.redirect? && redirects_limit > 0 49 | request.href = response.http_header['location'][0] 50 | redirects_limit -= 1 51 | @redirect_response = execute_request request, redirects_limit 52 | return @redirect_response 53 | end 54 | 55 | Response.new( 56 | response.http_header.status_code, 57 | response.http_header.body_type, 58 | response.content, 59 | response.http_header.body_size 60 | ) 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/http/request.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Http 18 | class Request 19 | include Stormpath::Http::Utils 20 | 21 | attr_accessor :http_method, :href, :query_string, :http_headers, :body, :api_key 22 | 23 | def initialize(http_method, href, query_string, http_headers, body, api_key) 24 | splitted = href.split '?' 25 | 26 | @query_string = query_string || {} 27 | 28 | if splitted && splitted.length > 1 29 | @href = splitted[0] 30 | query_string_str = splitted[1] 31 | query_string_arr = query_string_str.split '&' 32 | query_string_arr.each do |pair| 33 | pair_arr = pair.split '=' 34 | @query_string.store pair_arr[0], pair_arr[1] 35 | end 36 | else 37 | @href = href 38 | end 39 | 40 | @http_method = http_method.upcase 41 | @http_headers = http_headers 42 | @body = body 43 | @api_key = api_key 44 | 45 | @http_headers.store 'Content-Length', @body.bytesize if body 46 | end 47 | 48 | def resource_uri 49 | URI href 50 | end 51 | 52 | def to_s_query_string(canonical) 53 | result = '' 54 | 55 | unless @query_string.empty? 56 | Hash[@query_string.sort_by(&:to_s)].each do |key, value| 57 | enc_key = encode_url key, false, canonical 58 | enc_value = encode_url value, false, canonical 59 | 60 | result << '&' unless result.empty? 61 | result << camelize(enc_key) << '=' << enc_value 62 | end 63 | end 64 | 65 | result 66 | end 67 | 68 | def camelize(key) 69 | custom_data_params?(key) ? key : key.camelize(:lower) 70 | end 71 | 72 | def custom_data_params?(key) 73 | key.starts_with?('customData.') 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/http/response.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Http 18 | class Response 19 | attr_reader :http_status, :body 20 | attr_accessor :headers 21 | 22 | def initialize(http_status, content_type, body, content_length) 23 | @http_status = http_status 24 | @headers = HTTP::Message::Headers.new 25 | @body = body 26 | @headers.content_type = content_type 27 | @headers.body_size = content_length 28 | end 29 | 30 | def client_error? 31 | (http_status >= 400) && http_status < 500 32 | end 33 | 34 | def server_error? 35 | (http_status >= 500) && http_status < 600 36 | end 37 | 38 | def error? 39 | client_error? || server_error? 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/http/utils.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Http 18 | module Utils 19 | def default_port?(uri) 20 | scheme = uri.scheme.downcase 21 | port = uri.port 22 | port <= 0 || (port == 80 && scheme.eql?('http')) || (port == 443 && scheme.eql?('https')) 23 | end 24 | 25 | def encode_url(value, path, canonical) 26 | value = value.to_s 27 | return encoded_chars?(value) ? URI.encode(URI.decode(value)) : URI.encode(value) if path 28 | 29 | CGI.escape(value.to_s).tap do |encoded| 30 | str_map = { '+' => '%20', '%7E' => '~' } 31 | str_map.each do |key, str_value| 32 | encoded.gsub!(key, str_value) if encoded.include? key 33 | end 34 | end 35 | end 36 | 37 | def encoded_chars?(string) 38 | string.include?('%2E') 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/id_site/id_site_result.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module IdSite 3 | class IdSiteResult 4 | attr_accessor :jwt_response, :account_href, :state, :status, :is_new_account 5 | 6 | alias new_account? is_new_account 7 | 8 | def initialize(jwt_response) 9 | @jwt_response = jwt_response 10 | @account_href = jwt_response['sub'] 11 | @status = jwt_response['status'] 12 | @state = jwt_response['state'] 13 | @is_new_account = jwt_response['isNewSub'] 14 | end 15 | 16 | def jwt_invalid?(api_key_id) 17 | @jwt_response['aud'] != api_key_id 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/access_token_authentication_result.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class AccessTokenAuthenticationResult < Stormpath::Resource::Instance 4 | prop_reader :access_token, :refresh_token, :token_type, :expires_in, :stormpath_access_token_href 5 | 6 | alias href stormpath_access_token_href 7 | 8 | def delete 9 | data_store.delete(self) unless href.respond_to?(:empty) && href.empty? 10 | end 11 | 12 | def account 13 | client.accounts.get(account_href) 14 | end 15 | 16 | private 17 | 18 | def account_href 19 | @account_href ||= jwt_response['sub'] 20 | end 21 | 22 | def jwt_response 23 | JWT.decode(access_token, data_store.api_key.secret).first 24 | rescue JWT::ExpiredSignature => error 25 | raise Stormpath::Oauth::Error, :jwt_expired 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/authenticator.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class Authenticator 4 | include Stormpath::Util::Assert 5 | 6 | def initialize(data_store) 7 | @data_store = data_store 8 | end 9 | 10 | def authenticate(parent_href, request) 11 | assert_not_nil parent_href, 'parent_href must be specified' 12 | 13 | clazz = GRANT_CLASSES_BY_TYPE[request.grant_type.to_sym] 14 | attempt = @data_store.instantiate(clazz) 15 | attempt.set_options(request) 16 | href = parent_href + '/oauth/token' 17 | 18 | @data_store.create(href, attempt, Stormpath::Oauth::AccessTokenAuthenticationResult) 19 | end 20 | 21 | GRANT_CLASSES_BY_TYPE = { 22 | password: PasswordGrant, 23 | refresh_token: RefreshToken, 24 | id_site_token: IdSiteGrant, 25 | stormpath_token: StormpathTokenGrant, 26 | client_credentials: ClientCredentialsGrant, 27 | stormpath_social: SocialGrant, 28 | stormpath_factor_challenge: ChallengeFactorGrant 29 | }.freeze 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/challenge_factor_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class ChallengeFactorGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :challenge, :code 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | challenge: challenge, 10 | code: code 11 | } 12 | end 13 | 14 | def set_options(request) 15 | set_property :grant_type, request.grant_type 16 | set_property :challenge, request.challenge 17 | set_property :code, request.code 18 | end 19 | 20 | def form_data? 21 | true 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/challenge_factor_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class ChallengeFactorGrantRequest 4 | attr_reader :challenge, :code 5 | 6 | def initialize(challenge, code) 7 | @challenge = challenge 8 | @code = code 9 | end 10 | 11 | def grant_type 12 | 'stormpath_factor_challenge' 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/client_credentials_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class ClientCredentialsGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :api_key_id, :api_key_secret 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | apiKeyId: api_key_id, 10 | apiKeySecret: api_key_secret 11 | } 12 | end 13 | 14 | def set_options(request) 15 | set_property :api_key_id, request.api_key_id 16 | set_property :api_key_secret, request.api_key_secret 17 | set_property :grant_type, request.grant_type 18 | end 19 | 20 | def form_data? 21 | true 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/client_credentials_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class ClientCredentialsGrantRequest 4 | attr_reader :api_key_id, :api_key_secret 5 | 6 | def initialize(api_key_id, api_key_secret) 7 | @api_key_id = api_key_id 8 | @api_key_secret = api_key_secret 9 | end 10 | 11 | def grant_type 12 | 'client_credentials' 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/error.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class Error < Stormpath::Error 4 | attr_accessor :status, :code, :message, :developer_message, :more_info, :request_id 5 | 6 | def initialize(type) 7 | @status = errors[type][:status] 8 | @code = errors[type][:code] 9 | @message = errors[type][:message] 10 | @developer_message = errors[type][:developer_message] 11 | @request_id = errors[type][:request_id] 12 | super(self) 13 | end 14 | 15 | private 16 | 17 | def errors 18 | { 19 | jwt_cb_uri_incorrect: { 20 | status: 400, 21 | code: 400, 22 | message: 'The specified callback URI (cb_uri) is not valid', 23 | developer_message: 'The specified callback URI (cb_uri) is not valid. Make '\ 24 | 'sure the callback URI specified in your ID Site configuration matches the value specified.', 25 | request_id: 'Oauth error UUID' 26 | }, 27 | jwt_expired: { 28 | status: 400, 29 | code: 10_011, 30 | message: 'Token is invalid', 31 | developer_message: 'Token is no longer valid because it has expired', 32 | request_id: 'Oauth error UUID' 33 | }, 34 | jwt_invalid: { 35 | status: 400, 36 | code: 10_012, 37 | message: 'Token is invalid', 38 | developer_message: 'Token is invalid because the issued at time (iat) is after the current time', 39 | request_id: 'Oauth error UUID' 40 | }, 41 | jwt_invalid_issuer: { 42 | status: 400, 43 | code: 10_014, 44 | message: 'Token is invalid', 45 | developer_message: 'Token is invalid because the issuer of the token does not match the Application validating the token.', 46 | request_id: 'Oauth error UUID' 47 | }, 48 | jwt_invalid_signature: { 49 | status: 400, 50 | code: 10_017, 51 | message: 'Token is invalid', 52 | developer_message: 'Token is invalid because verifying the signature of a JWT failed.', 53 | request_id: 'Oauth error UUID' 54 | }, 55 | jwt_invalid_stt: { 56 | status: 400, 57 | code: nil, 58 | message: 'Token is invalid', 59 | developer_message: "Token is invalid because the stt header doesn't match the right type", 60 | request_id: 'Oauth error UUID' 61 | } 62 | } 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/id_site_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class IdSiteGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :token 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | token: token 10 | } 11 | end 12 | 13 | def set_options(request) 14 | set_property :grant_type, request.grant_type 15 | set_property :token, request.token 16 | end 17 | 18 | def form_data? 19 | true 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/id_site_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class IdSiteGrantRequest 4 | attr_accessor :grant_type, :token 5 | 6 | def initialize(token) 7 | @token = token 8 | @grant_type = 'id_site_token' 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/local_access_token_verification.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class LocalAccessTokenVerification 4 | attr_reader :application, :access_token 5 | 6 | def initialize(application, access_token) 7 | @application = application 8 | @access_token = access_token 9 | end 10 | 11 | def verify 12 | validate_jwt_is_an_access_token 13 | validate_jwt_has_a_valid_issuer 14 | LocalAccessTokenVerificationResult.new(application, decoded_jwt) 15 | end 16 | 17 | private 18 | 19 | def decoded_jwt 20 | begin 21 | @decoded_jwt ||= JWT.decode(access_token, application.client.data_store.api_key.secret) 22 | rescue JWT::ExpiredSignature 23 | raise Stormpath::Oauth::Error, :jwt_expired 24 | end 25 | end 26 | 27 | def validate_jwt_is_an_access_token 28 | return if decoded_jwt.second['stt'] == 'access' 29 | raise Stormpath::Oauth::Error, :jwt_invalid_stt 30 | end 31 | 32 | def validate_jwt_has_a_valid_issuer 33 | return if decoded_jwt.first['iss'] == application.href 34 | raise Stormpath::Oauth::Error, :jwt_invalid_issuer 35 | end 36 | end 37 | 38 | class LocalAccessTokenVerificationResult 39 | attr_reader :account 40 | def initialize(application, decoded_jwt) 41 | @account = application.client.accounts.get(decoded_jwt.first['sub']) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/password_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class PasswordGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :username, :password, :organization_name_key 5 | 6 | def form_properties 7 | {}.tap do |form| 8 | form[:grant_type] = grant_type 9 | form[:username] = username 10 | form[:password] = password 11 | form[:organizationNameKey] = organization_name_key if organization_name_key.present? 12 | end 13 | end 14 | 15 | def set_options(request) 16 | set_property :grant_type, request.grant_type 17 | set_property :username, request.username 18 | set_property :password, request.password 19 | set_property :organization_name_key, request.organization_name_key 20 | end 21 | 22 | def form_data? 23 | true 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/password_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class PasswordGrantRequest 4 | attr_accessor :grant_type, :username, :password, :organization_name_key 5 | 6 | def initialize(username, password, options = {}) 7 | @username = username 8 | @password = password 9 | @grant_type = 'password' 10 | @organization_name_key = options[:organization_name_key] 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/refresh_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class RefreshGrantRequest 4 | attr_accessor :grant_type, :refresh_token 5 | 6 | def initialize(refresh_token) 7 | @refresh_token = refresh_token 8 | @grant_type = 'refresh_token' 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/refresh_token.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class RefreshToken < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :refresh_token 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | refresh_token: refresh_token 10 | } 11 | end 12 | 13 | def set_options(request) 14 | set_property :refresh_token, request.refresh_token 15 | set_property :grant_type, request.grant_type 16 | end 17 | 18 | def form_data? 19 | true 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/remote_access_token_verification.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class RemoteAccessTokenVerification 4 | attr_reader :application, :app_href, :data_store, :access_token 5 | 6 | def initialize(application, access_token) 7 | @application = application 8 | @app_href = application.href 9 | @data_store = application.client.data_store 10 | @access_token = access_token 11 | validate_access_token 12 | end 13 | 14 | def verify 15 | data_store.get_resource("#{app_href}/authTokens/#{access_token}", VerifyTokenResult) 16 | end 17 | 18 | def validate_access_token 19 | raise Stormpath::Oauth::Error, :jwt_invalid_stt unless decoded_jwt.second['stt'] == 'access' 20 | raise Stormpath::Oauth::Error, :jwt_invalid_issuer unless decoded_jwt.first['iss'] == application.href 21 | end 22 | 23 | def decoded_jwt 24 | @decoded_jwt ||= JWT.decode(access_token, application.client.data_store.api_key.secret) 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/social_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class SocialGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :provider_id, :code, :access_token, :redirect_uri 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | providerId: provider_id, 10 | code: code, 11 | accessToken: access_token, 12 | redirectUri: redirect_uri 13 | } 14 | end 15 | 16 | def set_options(request) 17 | set_property :provider_id, request.provider_id 18 | set_property :code, request.code if request.code 19 | set_property :access_token, request.access_token if request.access_token 20 | set_property :redirect_uri, request.redirect_uri if request.redirect_uri 21 | set_property :grant_type, request.grant_type 22 | end 23 | 24 | def form_data? 25 | true 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/social_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class SocialGrantRequest 4 | attr_accessor :grant_type, :provider_id, :code, :access_token, :redirect_uri 5 | 6 | def initialize(provider_id, options = {}) 7 | @provider_id = provider_id.to_s 8 | @code = options[:code] 9 | @access_token = options[:access_token] 10 | @redirect_uri = options[:redirect_uri] 11 | @grant_type = 'stormpath_social' 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/stormpath_grant_request.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class StormpathGrantRequest 4 | def initialize(account, application, api_key, status = :authenticated) 5 | @account = account 6 | @application = application 7 | @api_key = api_key 8 | @status = status.to_s.upcase 9 | end 10 | 11 | def token 12 | @token ||= JWT.encode(payload, api_key.secret, 'HS256') 13 | end 14 | 15 | def grant_type 16 | 'stormpath_token' 17 | end 18 | 19 | private 20 | 21 | attr_accessor :account, :application, :api_key, :status 22 | 23 | def payload 24 | { 25 | sub: account.href, 26 | iat: Time.now.to_i, 27 | iss: application.href, 28 | status: status, 29 | aud: api_key.id 30 | } 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/stormpath_token_grant.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class StormpathTokenGrant < Stormpath::Resource::Base 4 | prop_accessor :grant_type, :token 5 | 6 | def form_properties 7 | { 8 | grant_type: grant_type, 9 | token: token 10 | } 11 | end 12 | 13 | def set_options(request) 14 | set_property :token, request.token 15 | set_property :grant_type, request.grant_type 16 | end 17 | 18 | def form_data? 19 | true 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/verify_access_token.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class VerifyAccessToken 4 | attr_reader :application, :verify_locally 5 | 6 | def initialize(application, options = {}) 7 | @application = application 8 | @verify_locally = options[:local] || false 9 | end 10 | 11 | def verify(access_token) 12 | if verify_locally 13 | LocalAccessTokenVerification.new(application, access_token).verify 14 | else 15 | RemoteAccessTokenVerification.new(application, access_token).verify 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/oauth/verify_token_result.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Oauth 3 | class VerifyTokenResult < Stormpath::Resource::Base 4 | prop_reader :href, :jwt, :expanded_jwt 5 | 6 | belongs_to :account 7 | belongs_to :application 8 | belongs_to :tenant 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/account_access.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class AccountAccess < Stormpath::Resource::Base 19 | PROVIDER_DATA = :provider_data 20 | 21 | def provider_data=(provider_data) 22 | set_property PROVIDER_DATA, provider_data 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/account_request.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class AccountRequest 19 | attr_accessor :provider, :token_type, :token_value, :account_store 20 | 21 | def initialize(provider, token_type, token_value, account_store: {}) 22 | @provider = provider 23 | @token_type = token_type 24 | @token_value = token_value 25 | @account_store = account_store 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/account_resolver.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class AccountResolver 19 | include Stormpath::Util::Assert 20 | attr_reader :data_store, :parent_href, :request 21 | 22 | def initialize(data_store, parent_href, request) 23 | @data_store = data_store 24 | @parent_href = parent_href 25 | @request = request 26 | assert_not_nil(parent_href, 'parent_href argument must be specified') 27 | assert_kind_of(AccountRequest, request, "Only #{AccountRequest} instances are supported.") 28 | end 29 | 30 | def resolve_provider_account 31 | attempt.provider_data = provider_data 32 | data_store.create(href, attempt, Stormpath::Provider::AccountResult) 33 | end 34 | 35 | def provider_data 36 | # TODO: need to add an options hash and pass all attributes from the providers? 37 | # https://stormpath.atlassian.net/wiki/display/AM/Social+Login+V2/#SocialLoginV2-ClientAPIChanges 38 | @provider_data ||= {}.tap do |body| 39 | body[request.token_type.to_s.camelize(:lower)] = request.token_value 40 | body['providerId'] = request.provider 41 | body['accountStore'] = request_account_store_hash if request.account_store.present? 42 | end 43 | end 44 | 45 | private 46 | 47 | def attempt 48 | @attempt ||= data_store.instantiate(AccountAccess) 49 | end 50 | 51 | def href 52 | "#{parent_href}/accounts" 53 | end 54 | 55 | def request_account_store_hash 56 | request.account_store.transform_keys { |key| key.to_s.camelize(:lower) } 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/account_result.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class AccountResult < Stormpath::Resource::Base 19 | prop_reader :is_new_account 20 | 21 | alias is_new_account? is_new_account 22 | 23 | has_one :account 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/facebook/facebook_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class FacebookProvider < Stormpath::Provider::Provider 19 | prop_reader :client_id, :client_secret 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/facebook/facebook_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class FacebookProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :access_token 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/github/github_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class GithubProvider < Stormpath::Provider::Provider 19 | prop_reader :client_id, :client_secret 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/github/github_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class GithubProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :access_token 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/google/google_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class GoogleProvider < Stormpath::Provider::Provider 19 | prop_accessor :hd, :display, :access_type 20 | prop_reader :client_id, :client_secret, :redirect_uri 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/google/google_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class GoogleProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :access_token, :refresh_token 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/ldap/ldap_provider.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Provider 3 | class LdapProvider < Stormpath::Provider::Provider 4 | prop_reader :provider_id 5 | 6 | has_one :agent 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/linkedin/linkedin_provider.rb: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Copyright 2014 Stormpath, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | module Stormpath 18 | module Provider 19 | class LinkedinProvider < Stormpath::Provider::Provider 20 | prop_reader :client_id, :client_secret 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/linkedin/linkedin_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class LinkedinProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :access_token 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class Provider < Stormpath::Resource::Instance 19 | prop_accessor :scope 20 | prop_reader :provider_id, :created_at, :modified_at 21 | 22 | has_one :user_info_mapping_rules 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class ProviderData < Stormpath::Resource::Base 19 | prop_reader :provider_id, :created_at, :modified_at, :user_info 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/saml/saml_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class SamlProvider < Stormpath::Provider::Provider 19 | prop_reader :provider_id, :sso_login_url, :sso_logout_url, 20 | :encoded_x509_signing_cert, :request_signature_algorithm 21 | 22 | has_one :attribute_statement_mapping_rules 23 | has_one :service_provider_metadata, class_name: :samlServiceProviderMetadata 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/saml/saml_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class SamlProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :href, :created_at, :modified_at, :provider_id, :sso_log_in_url, :sso_logout_url 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/stormpath/stormpath_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class StormpathProvider < Stormpath::Provider::Provider 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/stormpath/stormpath_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Provider 18 | class StormpathProviderData < Stormpath::Provider::ProviderData 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/twitter/twitter_provider.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class TwitterProvider < Stormpath::Provider::Provider 19 | prop_reader :client_id, :client_secret 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/provider/twitter/twitter_provider_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Provider 18 | class TwitterProviderData < Stormpath::Provider::ProviderData 19 | prop_reader :access_token 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/access_token.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class AccessToken < Stormpath::Resource::Instance 4 | prop_reader :jwt, :expanded_jwt 5 | 6 | belongs_to :account 7 | belongs_to :application 8 | belongs_to :tenant 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Account < Stormpath::Resource::Instance 19 | include Stormpath::Resource::CustomDataStorage 20 | 21 | prop_accessor :username, :email, :given_name, :middle_name, :surname, :status 22 | prop_writer :password 23 | prop_reader :full_name, :created_at, :modified_at, :password_modified_at 24 | prop_non_printable :password 25 | 26 | belongs_to :directory 27 | belongs_to :tenant 28 | 29 | has_one :email_verification_token 30 | 31 | has_many :groups 32 | has_many :group_memberships 33 | has_many :applications 34 | 35 | has_many :linked_accounts, class_name: :Account 36 | has_many :account_links 37 | 38 | has_one :custom_data 39 | 40 | has_many :access_tokens 41 | has_many :refresh_tokens 42 | 43 | has_many :api_keys, can: [:create] 44 | 45 | has_many :phones, can: [:get, :create] 46 | has_many :factors, can: [:get, :create] 47 | 48 | def add_group(group) 49 | client.group_memberships.create(group: group, account: self) 50 | end 51 | 52 | def remove_group(group) 53 | group_membership = group_memberships.find do |membership| 54 | membership.group.href == group.href 55 | end 56 | group_membership.delete if group_membership 57 | end 58 | 59 | def provider_data 60 | internal_instance = instance_variable_get('@_provider_data') 61 | return internal_instance if internal_instance 62 | 63 | provider_data_href = "#{href}/providerData" 64 | 65 | clazz_proc = proc do |data| 66 | provider_id = data['providerId'] 67 | "Stormpath::Provider::#{provider_id.capitalize}ProviderData".constantize 68 | end 69 | 70 | provider_data = data_store.get_resource(provider_data_href, clazz_proc) 71 | instance_variable_set('@_provider_data', provider_data) 72 | end 73 | 74 | def create_factor(type, options = {}) 75 | Stormpath::Authentication::CreateFactor.new(client, self, type, options).save 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_creation_policy.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class AccountCreationPolicy < Stormpath::Resource::Instance 4 | prop_accessor( 5 | :verification_email_status, 6 | :verification_success_email_status, 7 | :welcome_email_status, 8 | :email_domain_whitelist, 9 | :email_domain_blacklist 10 | ) 11 | 12 | has_many :verification_email_templates, class_name: :emailTemplate 13 | has_many :verification_success_email_templates, class_name: :emailTemplate 14 | has_many :welcome_email_templates, class_name: :emailTemplate 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_link.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class AccountLink < Stormpath::Resource::Instance 19 | prop_accessor :right_account, :left_account 20 | prop_reader :created_at, :modified_at 21 | 22 | belongs_to :right_account, class_name: :Account, href: '/rightAccount' 23 | belongs_to :left_account, class_name: :Account, href: '/leftAccount' 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_linking_policy.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class AccountLinkingPolicy < Stormpath::Resource::Instance 19 | prop_accessor :status, :automatic_provisioning, :matching_property 20 | prop_reader :created_at, :modified_at 21 | 22 | belongs_to :tenant 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_membership.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | Stormpath::Resource::AccountMembership = Stormpath::Resource::GroupMembership 17 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_overrides.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | module AccountOverrides 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | def create_account(account, registration_workflow_enabled = nil) 8 | href = accounts.href 9 | if registration_workflow_enabled == false 10 | href += "?registrationWorkflowEnabled=#{registration_workflow_enabled}" 11 | end 12 | 13 | resource = case account 14 | when Stormpath::Resource::Base 15 | account 16 | else 17 | Stormpath::Resource::Account.new(account, client) 18 | end 19 | 20 | resource.apply_custom_data_updates_if_necessary 21 | data_store.create(href, resource, Stormpath::Resource::Account) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_store.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | module Resource 18 | class AccountStore < Stormpath::Resource::Instance 19 | def self.new(*args) 20 | href = args.first[HREF_PROP_NAME] 21 | if href =~ /directories/ 22 | Stormpath::Resource::Directory.new(*args) 23 | elsif href =~ /group/ 24 | Stormpath::Resource::Group.new(*args) 25 | elsif href =~ /organizations/ 26 | Stormpath::Resource::Organization.new(*args) 27 | else 28 | raise 'inappropriate type of an account store' 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/account_store_mapping.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | module Resource 18 | class AccountStoreMapping < Stormpath::Resource::Instance 19 | prop_accessor :list_index, :is_default_account_store, :is_default_group_store 20 | 21 | belongs_to :application 22 | 23 | has_one :account_store 24 | 25 | alias default_account_store is_default_account_store 26 | alias default_account_store? is_default_account_store 27 | 28 | alias default_account_store= is_default_account_store= 29 | 30 | alias default_group_store is_default_group_store 31 | alias default_group_store? is_default_group_store 32 | 33 | alias default_group_store= is_default_group_store= 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/agent.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class Agent < Stormpath::Resource::Instance 4 | prop_reader :id, :download, :created_at, :modified_at 5 | prop_accessor :status, :config 6 | 7 | belongs_to :directory 8 | belongs_to :tenant 9 | 10 | alias download_prop_reader download 11 | 12 | def download 13 | download_prop_reader['href'] 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/api_key.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class ApiKey < Instance 19 | prop_accessor :name, :description, :status 20 | prop_reader :id, :secret 21 | 22 | belongs_to :account 23 | belongs_to :tenant 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/application_web_config.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class ApplicationWebConfig < Stormpath::Resource::Instance 4 | ENDPOINTS = [:oauth2, :register, :login, :verify_email, :forgot_password, :change_password, :me].freeze 5 | prop_accessor :dns_label, :status, *ENDPOINTS 6 | prop_reader :domain_name, :created_at, :modified_at 7 | 8 | has_one :signing_api_key, class_name: :api_key 9 | belongs_to :application 10 | belongs_to :tenant 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/attribute_statement_mapping_rules.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class AttributeStatementMappingRules < Stormpath::Resource::Instance 4 | prop_accessor :items 5 | prop_reader :href, :created_at, :modified_at 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/challenge.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class Challenge < Stormpath::Resource::Instance 4 | prop_accessor :message 5 | prop_reader :status, :created_at, :modified_at 6 | 7 | belongs_to :factor 8 | belongs_to :account 9 | 10 | def validate(code) 11 | Stormpath::Authentication::ChallengeValidator.new(data_store, href).validate(code) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/collection.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Collection 19 | include Enumerable 20 | 21 | attr_reader :href, :client, :item_class, :collection_href, :criteria 22 | 23 | def initialize(href, item_class, client, options = {}) 24 | @client = client 25 | @href = href 26 | @item_class = item_class 27 | @collection_href = options[:collection_href] || @href 28 | @criteria ||= {} 29 | end 30 | 31 | def data_store 32 | client.data_store 33 | end 34 | 35 | def search(query) 36 | query_hash = if query.is_a? String 37 | { q: query } 38 | elsif query.is_a? Hash 39 | query 40 | end 41 | 42 | criteria.merge! query_hash 43 | self 44 | end 45 | 46 | def offset(offset) 47 | criteria[:offset] = offset 48 | self 49 | end 50 | 51 | def limit(limit) 52 | criteria[:limit] = limit 53 | self 54 | end 55 | 56 | def order(statement) 57 | criteria[:order_by] = statement 58 | self 59 | end 60 | 61 | def each(&block) 62 | PaginatedIterator.iterate(collection_href, client, item_class, @criteria, &block) 63 | end 64 | 65 | def current_page 66 | page = CollectionPage.new(collection_href, client, criteria) 67 | page.item_type = item_class 68 | page 69 | end 70 | 71 | private 72 | 73 | module PaginatedIterator 74 | def self.iterate(collection_href, client, item_class, criteria, &block) 75 | page = CollectionPage.new(collection_href, client, criteria) 76 | page.item_type = item_class 77 | 78 | unless page.items.count.zero? 79 | page.items.each(&block) 80 | criteria[:offset] = page.offset + page.limit 81 | iterate(collection_href, client, item_class, criteria, &block) 82 | end 83 | end 84 | end 85 | 86 | class CollectionPage < Stormpath::Resource::Base 87 | ITEMS = 'items'.freeze 88 | 89 | prop_accessor :offset, :limit, :size 90 | 91 | attr_accessor :item_type 92 | 93 | def items 94 | to_resource_array(get_property(ITEMS)) 95 | end 96 | 97 | def to_resource(properties) 98 | data_store.instantiate(item_type, properties) 99 | end 100 | 101 | def to_resource_array(vals) 102 | [].tap do |items| 103 | if vals.is_a? Array 104 | vals.each do |val| 105 | resource = to_resource val 106 | items << resource 107 | end 108 | end 109 | end 110 | end 111 | end # class Stormpath::Resource::Collection::CollectionPage 112 | end # Stormpath::Resource::Collection 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/custom_data.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | module Resource 18 | class CustomData < Stormpath::Resource::Instance 19 | include Stormpath::Resource::CustomDataHashMethods 20 | 21 | prop_reader :created_at, :modified_at 22 | 23 | def [](property_name) 24 | get_property property_name, ignore_camelcasing: true 25 | end 26 | 27 | def []=(property_name, property_value) 28 | set_property property_name, property_value, ignore_camelcasing: true 29 | end 30 | 31 | def save 32 | delete_removed_properties if has_removed_properties? 33 | super if has_new_properties? 34 | end 35 | 36 | def delete(name = nil) 37 | if name.nil? 38 | @properties = { HREF_PROP_NAME => @properties[HREF_PROP_NAME] } 39 | @dirty_properties.clear 40 | @deleted_properties.clear 41 | return super() 42 | end 43 | 44 | @write_lock.lock 45 | property_name = name.to_s 46 | begin 47 | @properties.delete(property_name) 48 | @dirty_properties.delete(property_name) 49 | @deleted_properties << property_name 50 | @dirty = true 51 | ensure 52 | @write_lock.unlock 53 | end 54 | end 55 | 56 | private 57 | 58 | def sanitize(properties) 59 | {}.tap do |sanitized_properties| 60 | properties.map do |key, value| 61 | property_name = key.to_s 62 | sanitized_properties[property_name] = value 63 | end 64 | end 65 | end 66 | 67 | def has_removed_properties? 68 | @read_lock.lock 69 | begin 70 | !@deleted_properties.empty? 71 | ensure 72 | @read_lock.unlock 73 | end 74 | end 75 | 76 | def has_new_properties? 77 | @read_lock.lock 78 | begin 79 | !@dirty_properties.empty? 80 | ensure 81 | @read_lock.unlock 82 | end 83 | end 84 | 85 | def delete_removed_properties 86 | @deleted_properties.delete_if do |deleted_property_name| 87 | data_store.delete(self, deleted_property_name) 88 | true 89 | end 90 | end 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/custom_data_hash_methods.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | module CustomDataHashMethods 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | def has_key?(key) 8 | materialize unless materialized? 9 | properties.key? key.to_s 10 | end 11 | 12 | alias_method :include?, :has_key? 13 | 14 | def has_value?(value) 15 | materialize unless materialized? 16 | properties.value? value 17 | end 18 | 19 | def store(key, value) 20 | materialize unless materialized? 21 | self[key] = value 22 | end 23 | 24 | def keys 25 | materialize unless materialized? 26 | properties.keys 27 | end 28 | 29 | def values 30 | materialize unless materialized? 31 | properties.values 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/custom_data_storage.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 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 | module Stormpath 17 | module Resource 18 | module CustomDataStorage 19 | extend ActiveSupport::Concern 20 | 21 | CUSTOM_DATA = 'custom_data'.freeze 22 | 23 | included do 24 | def save 25 | apply_custom_data_updates_if_necessary 26 | super 27 | end 28 | 29 | def apply_custom_data_updates_if_necessary 30 | if custom_data.send(:has_removed_properties?) 31 | custom_data.send(:delete_removed_properties) 32 | end 33 | 34 | if custom_data.send(:has_new_properties?) 35 | set_property(CUSTOM_DATA, custom_data.dirty_properties) 36 | end 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/directory.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class Directory < Stormpath::Resource::Instance 4 | include Stormpath::Resource::CustomDataStorage 5 | include Stormpath::Resource::AccountOverrides 6 | 7 | prop_accessor :name, :description, :status 8 | prop_reader :created_at, :modified_at 9 | 10 | belongs_to :tenant 11 | 12 | has_many :accounts, can: [:get, :create] 13 | has_many :groups, can: [:get, :create] 14 | has_many :organizations, can: :get 15 | has_one :custom_data 16 | has_one :password_policy 17 | has_one :account_creation_policy 18 | has_one :account_schema, class_name: :schema 19 | 20 | delegate :attribute_statement_mapping_rules, to: :provider 21 | delegate :service_provider_metadata, to: :provider 22 | delegate :user_info_mapping_rules, to: :provider 23 | 24 | def provider 25 | internal_instance = instance_variable_get '@_provider' 26 | return internal_instance if internal_instance 27 | 28 | provider_href = href + '/provider' 29 | 30 | clazz_proc = proc do |data| 31 | provider_id = data['providerId'] 32 | "Stormpath::Provider::#{provider_id.capitalize}Provider".constantize 33 | end 34 | 35 | provider = data_store.get_resource provider_href, clazz_proc 36 | instance_variable_set '@_provider', provider 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/email_template.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class EmailTemplate < Stormpath::Resource::Instance 4 | prop_accessor :name, :description, :subject, :from_email_address, :text_body, :html_body, :mime_type 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/email_verification_token.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class EmailVerificationToken < Stormpath::Resource::Instance 19 | def token 20 | href.split('/').last 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/error.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Error < Stormpath::Resource::Base 19 | prop_reader :status, :code, :message, :developer_message, :more_info, :request_id 20 | 21 | def initialize(body) 22 | super(body, nil) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/expansion.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | module Resource 18 | class Expansion 19 | attr_reader :query 20 | 21 | def initialize(*names) 22 | @query = {} 23 | @properties = {} 24 | 25 | names.each { |name| add_property name } 26 | end 27 | 28 | def add_property(name, options = {}) 29 | @properties[name] = if options[:offset] || options[:limit] 30 | pagination = [] 31 | pagination.push("offset:#{options[:offset]}") if options[:offset] 32 | pagination.push("limit:#{options[:limit]}") if options[:limit] 33 | 34 | "#{name}(#{pagination.join(',')})" 35 | else 36 | name 37 | end 38 | end 39 | 40 | def to_query 41 | { expand: @properties.values.join(',') } if @properties.any? 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/factor.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Factor < Stormpath::Resource::Instance 19 | prop_accessor :type, :account_name, :issuer, :status 20 | prop_reader :verification_status, :secret, :key_uri, :base64_q_r_image 21 | alias qr_code base64_q_r_image 22 | 23 | has_many :challenges, can: [:get, :create] 24 | has_one :most_recent_challenge, class_name: :challenge 25 | has_one :phone 26 | 27 | belongs_to :account 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/field.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class Field < Stormpath::Resource::Instance 19 | prop_accessor :required 20 | prop_reader :name, :created_at, :modified_at 21 | 22 | belongs_to :schema 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/group.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Group < Stormpath::Resource::Instance 19 | include Stormpath::Resource::CustomDataStorage 20 | 21 | prop_accessor :name, :description, :status 22 | prop_reader :created_at, :modified_at 23 | 24 | belongs_to :tenant 25 | belongs_to :directory 26 | 27 | has_many :accounts 28 | has_many :account_memberships 29 | 30 | has_one :custom_data 31 | 32 | def add_account(account) 33 | client.group_memberships.create(group: self, account: account) 34 | end 35 | 36 | def remove_account(account) 37 | account_membership = account_memberships.find do |membership| 38 | membership.account.href == account.href 39 | end 40 | account_membership.delete if account_membership 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/group_membership.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class GroupMembership < Stormpath::Resource::Instance 19 | has_one :account 20 | has_one :group 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/instance.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class Instance < Stormpath::Resource::Base 19 | def save 20 | data_store.save(self) 21 | end 22 | 23 | def delete 24 | data_store.delete(self) unless new? 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/linked_account.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class LinkedAccount < Stormpath::Resource::Instance 19 | include Stormpath::Resource::CustomDataStorage 20 | 21 | belongs_to :account 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/oauth_policy.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class OauthPolicy < Stormpath::Resource::Instance 4 | prop_accessor :access_token_ttl, :refresh_token_ttl 5 | 6 | belongs_to :application 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/organization.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class Organization < Stormpath::Resource::Instance 4 | include Stormpath::Resource::CustomDataStorage 5 | 6 | prop_accessor :name, :description, :name_key, :status, :account_store_mappings, 7 | :default_account_store_mapping, :default_group_store_mapping 8 | 9 | prop_reader :created_at, :modified_at 10 | 11 | has_many :groups 12 | has_many :accounts, can: [:get, :create] 13 | belongs_to :tenant 14 | 15 | has_one :custom_data 16 | has_one :account_linking_policy 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/organization_account_store_mapping.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class OrganizationAccountStoreMapping < Stormpath::Resource::Instance 4 | prop_accessor :is_default_account_store, :is_default_group_store, :list_index 5 | 6 | belongs_to :organization 7 | belongs_to :account_store 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/password_policy.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class PasswordPolicy < Stormpath::Resource::Instance 4 | prop_accessor :reset_token_ttl, :reset_email_status, :reset_success_email_status 5 | has_one :strength, class_name: :passwordStrength 6 | has_many :reset_email_templates, class_name: :emailTemplate 7 | has_many :reset_success_email_templates, class_name: :emailTemplate 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/password_reset_token.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class PasswordResetToken < Stormpath::Resource::Base 19 | prop_reader :email, :account 20 | 21 | belongs_to :account 22 | 23 | def token 24 | href.split('/').last 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/password_strength.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class PasswordStrength < Stormpath::Resource::Instance 4 | prop_accessor( 5 | :min_length, 6 | :max_length, 7 | :min_lower_case, 8 | :min_upper_case, 9 | :min_numeric, 10 | :min_symbol, 11 | :min_diacritic, 12 | :prevent_reuse 13 | ) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/phone.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Phone < Stormpath::Resource::Instance 19 | prop_accessor :number, :name, :description 20 | prop_reader :verification_status, :status, :created_at, :modified_at 21 | 22 | belongs_to :account 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/refresh_token.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class RefreshToken < AccessToken 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/registered_saml_service_provider.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class RegisteredSamlServiceProvider < Stormpath::Resource::Instance 4 | prop_accessor :name, :description, :assertion_consumer_service_url, :entity_id, :name_id_format 5 | prop_reader :encoded_x509_certificate, :created_at, :modified_at 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_identity_provider.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class SamlIdentityProvider < Stormpath::Resource::Instance 4 | prop_reader :sso_login_endpoint, :signature_algorithm, :sha_fingerprint, :created_at, :modified_at 5 | prop_accessor :status 6 | 7 | has_one :metadata, class_name: :samlIdentityProviderMetadata 8 | has_one :attribute_statement_mapping_rules 9 | has_one :x509_signing_cert, class_name: :x509Certificate 10 | has_many :registered_saml_service_providers 11 | has_many :saml_service_provider_registrations, can: [:get, :create] 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_identity_provider_metadata.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class SamlIdentityProviderMetadata < Stormpath::Resource::Instance 4 | prop_reader :entity_id 5 | belongs_to :identity_provider, class_name: :samlIdentityProvider 6 | has_one :x509_signing_cert, class_name: :x509Certificate 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_policy.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class SamlPolicy < Stormpath::Resource::Instance 4 | prop_reader :created_at, :modified_at 5 | 6 | has_one :service_provider, class_name: :samlServiceProvider 7 | has_one :identity_provider, class_name: :samlIdentityProvider 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_service_provider.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class SamlServiceProvider < Stormpath::Resource::Instance 4 | prop_reader :created_at, :modified_at, :sso_initiation_endpoint 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_service_provider_metadata.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class SamlServiceProviderMetadata < Stormpath::Resource::Instance 19 | prop_reader :href, :created_at, :modified_at, :entity_id, :x509_signing_cert, 20 | :assertion_consumer_service_post_endpoint 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/saml_service_provider_registration.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class SamlServiceProviderRegistration < Stormpath::Resource::Instance 4 | prop_reader :created_at, :modified_at 5 | prop_accessor :status, :default_relay_state 6 | 7 | has_one :service_provider, class_name: :registeredSamlServiceProvider 8 | has_one :identity_provider, class_name: :samlIdentityProvider 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/schema.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class Schema < Stormpath::Resource::Instance 19 | prop_reader :created_at, :modified_at 20 | 21 | has_many :fields 22 | belongs_to :directory 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/tenant.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | class Tenant < Stormpath::Resource::Instance 19 | include Stormpath::Resource::CustomDataStorage 20 | 21 | prop_reader :name, :key, :created_at, :modified_at 22 | 23 | has_many :applications 24 | has_many :directories 25 | has_many :organizations 26 | has_one :custom_data 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/user_info_mapping_rules.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016 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 | module Stormpath 17 | module Resource 18 | class UserInfoMappingRules < Stormpath::Resource::Instance 19 | prop_accessor :items 20 | prop_reader :href, :created_at, :modified_at 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/utils.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Resource 18 | module Utils 19 | include ActiveSupport::Inflector 20 | include Stormpath::Util::Assert 21 | 22 | def inspect 23 | ''.tap do |str| 24 | str << %(#<#{class_name_with_id} @properties={) 25 | @read_lock.lock 26 | begin 27 | str << properties.map do |key, value| 28 | next unless printable_property? key 29 | if value.is_a?(Hash) && value.key?(Stormpath::Resource::Base::HREF_PROP_NAME) 30 | value = %({ "#{Stormpath::Resource::Base::HREF_PROP_NAME}" => "#{value[Stormpath::Resource::Base::HREF_PROP_NAME]}" }) 31 | end 32 | %("#{key} => #{value}") 33 | end.compact.join(',') 34 | ensure 35 | @read_lock.unlock 36 | end 37 | str << '}>' 38 | end 39 | end 40 | 41 | def to_s 42 | "#<#{class_name_with_id}>" 43 | end 44 | 45 | def to_yaml 46 | "--- !ruby/object: #{self.class.name}\n".tap do |yaml| 47 | @read_lock.lock 48 | 49 | begin 50 | properties_yaml = properties.each do |key, value| 51 | " #{key}: #{value} \n" if printable_property? key 52 | end.compact.join("\n") 53 | unless properties_yaml.empty? 54 | yaml << " properties\n " 55 | yaml << properties_yaml 56 | end 57 | ensure 58 | @read_lock.unlock 59 | end 60 | end 61 | end 62 | 63 | def class_name_with_id 64 | object_id_hex = '%x' % (object_id << 1) 65 | "#{self.class.name}:0x#{object_id_hex}" 66 | end 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/verification_email.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class VerificationEmail < Stormpath::Resource::Instance 4 | prop_accessor :login, :account_store 5 | 6 | belongs_to :application 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/resource/x_509_certificate.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Resource 3 | class X509Certificate < Stormpath::Resource::Instance 4 | prop_accessor :encoded_x_509_certificate, :encoded_private_key 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/util/assert.rb: -------------------------------------------------------------------------------- 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 | module Stormpath 17 | module Util 18 | module Assert 19 | def assert_not_nil(object, message) 20 | raise(ArgumentError, message, caller) if object.nil? 21 | end 22 | 23 | def assert_kind_of(clazz, object, message) 24 | raise(ArgumentError, message, caller) unless object.is_a?(clazz) 25 | end 26 | 27 | def assert_true(arg, message) 28 | raise(ArgumentError, message, caller) unless arg 29 | end 30 | 31 | def assert_false(arg, message) 32 | raise(ArgumentError, message, caller) if arg 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/util/uri_builder.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | module Stormpath 3 | module Util 4 | class UriBuilder 5 | attr_reader :composite_url, :escaped_url, :userinfo, :uri 6 | 7 | def initialize(composite_url) 8 | @composite_url = composite_url 9 | end 10 | 11 | def escaped_url 12 | @escaped_url ||= composite_url.gsub(userinfo_pattern, "://#{escaped_userinfo}@api") 13 | end 14 | 15 | def userinfo 16 | @userinfo ||= composite_url.scan(userinfo_pattern).flatten.first 17 | end 18 | 19 | def uri 20 | begin 21 | @uri ||= URI(escaped_url) 22 | rescue URI::InvalidURIError 23 | raise StandardError, 'Something is wrong with the composite url' 24 | end 25 | end 26 | 27 | private 28 | 29 | def escaped_userinfo 30 | URI.escape(userinfo, '/') 31 | end 32 | 33 | def userinfo_pattern 34 | /:\/\/(.*?)@api/ 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/stormpath-sdk/version.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 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 | module Stormpath 17 | VERSION = '1.7.0'.freeze 18 | VERSION_DATE = '2017-02-09'.freeze 19 | end 20 | -------------------------------------------------------------------------------- /spec/api_key_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::ApiKey do 4 | describe '.new' do 5 | context 'given an id and secret' do 6 | id = 'an_api_id' 7 | secret = 'a_secret' 8 | let(:apiKey) { Stormpath::ApiKey.new(id, secret) } 9 | 10 | it 'sets the id' do 11 | expect(apiKey.id).to eq(id) 12 | end 13 | 14 | it 'sets the secret' do 15 | expect(apiKey.secret).to eq(secret) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/auth/challenge_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Authentication::ChallengeValidator, vcr: true do 4 | let(:data_store) { test_api_client.data_store } 5 | let(:application) { test_api_client.applications.create(application_attrs) } 6 | let(:directory) { test_api_client.directories.create(directory_attrs) } 7 | before { map_account_store(application, directory, 0, true, true) } 8 | let(:account) { directory.accounts.create(account_attrs) } 9 | let(:code) { '1234567' } 10 | let(:validate_challenge) do 11 | Stormpath::Authentication::ChallengeValidator.new(data_store, challenge.href).validate(code) 12 | end 13 | 14 | let(:factor) do 15 | account.factors.create( 16 | type: 'SMS', 17 | phone: { 18 | number: '+12025550173', 19 | name: 'test phone', 20 | description: 'this is a testing phone number' 21 | } 22 | ) 23 | end 24 | let(:challenge) { factor.challenges.create(message: 'Enter code: ${code}') } 25 | 26 | after do 27 | application.delete 28 | directory.delete 29 | end 30 | 31 | describe 'valid code' do 32 | before do 33 | stub_request(:post, "#{factor.href}/challenges") 34 | .to_return(body: Stormpath::Test.mocked_successfull_challenge) 35 | stub_request(:post, challenge.href) 36 | .to_return(body: Stormpath::Test.mocked_successfull_challenge) 37 | end 38 | 39 | it 'should respond with a Challenge' do 40 | expect(validate_challenge).to be_a Stormpath::Resource::Challenge 41 | expect(validate_challenge.status).to eq 'SUCCESS' 42 | end 43 | 44 | it 'should have status SUCCESS' do 45 | expect(validate_challenge.status).to eq 'SUCCESS' 46 | end 47 | end 48 | 49 | describe 'invalid code' do 50 | before do 51 | stub_request(:post, "#{factor.href}/challenges") 52 | .to_return(body: Stormpath::Test.mocked_failed_challenge) 53 | stub_request(:post, challenge.href) 54 | .to_return(body: Stormpath::Test.mocked_failed_challenge) 55 | end 56 | 57 | it 'should respond with a Challenge' do 58 | expect(validate_challenge).to be_a Stormpath::Resource::Challenge 59 | end 60 | 61 | it 'should have status FAILED' do 62 | expect(validate_challenge.status).to eq 'FAILED' 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/auth/create_factor_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'CreateFactor', vcr: true do 4 | let(:client) { test_api_client } 5 | let(:directory) { client.directories.create(directory_attrs) } 6 | let(:account) { directory.accounts.create(account_attrs) } 7 | 8 | after { directory.delete } 9 | 10 | context 'type sms' do 11 | context 'with challenge' do 12 | before do 13 | stub_request(:post, "#{account.href}/factors?challenge=true") 14 | .to_return(body: Stormpath::Test.mocked_factor_response) 15 | stub_request(:get, "#{factor.href}/challenges") 16 | .to_return(body: Stormpath::Test.mocked_challenges_response) 17 | stub_request(:get, "#{factor.href}/challenges?offset=25") 18 | .to_return(body: Stormpath::Test.mocked_challenges_response) 19 | end 20 | let(:factor) do 21 | Stormpath::Authentication::CreateFactor.new( 22 | client, 23 | account, 24 | :sms, 25 | phone: { number: '+12025550173', 26 | name: 'Rspec test phone', 27 | description: 'This is a testing phone number' }, 28 | challenge: { message: 'Enter code please: ' } 29 | ).save 30 | end 31 | 32 | it 'should create factor' do 33 | expect(factor.href).to be 34 | end 35 | end 36 | 37 | context 'without challenge' do 38 | before do 39 | stub_request(:post, "#{account.href}/factors") 40 | .to_return(body: Stormpath::Test.mocked_factor_response) 41 | stub_request(:get, "#{factor.href}/challenges") 42 | .to_return(body: Stormpath::Test.mocked_empty_challenge_response) 43 | stub_request(:get, "#{factor.href}/challenges?offset=25") 44 | .to_return(body: Stormpath::Test.mocked_empty_challenge_response) 45 | end 46 | let(:factor) do 47 | Stormpath::Authentication::CreateFactor.new( 48 | client, 49 | account, 50 | :sms, 51 | phone: { number: '+12025550173', 52 | name: 'Rspec test phone', 53 | description: 'This is a testing phone number' } 54 | ).save 55 | end 56 | 57 | it 'should create factor without challenge' do 58 | expect(factor.href).to be 59 | expect(factor.challenges.count).to eq 0 60 | end 61 | end 62 | end 63 | 64 | context 'type google-authenticator' do 65 | let(:factor) do 66 | Stormpath::Authentication::CreateFactor.new( 67 | client, 68 | account, 69 | :google_authenticator, 70 | custom_options: { 71 | account_name: "marko.cilimkovic#{default_domain}", 72 | issuer: 'ACME', 73 | status: 'ENABLED' 74 | } 75 | ).save 76 | end 77 | 78 | it 'should create factor' do 79 | expect(factor.href).to be 80 | end 81 | end 82 | 83 | context 'bad type' do 84 | let(:factor) do 85 | Stormpath::Authentication::CreateFactor.new(client, account, :invalid_factor_type).save 86 | end 87 | 88 | it 'should raise error' do 89 | expect { factor }.to raise_error(Stormpath::Error) 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /spec/auth/http_basic_authentication_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'HttpBasicAuthentication', vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:account) { application.accounts.create(account_attrs) } 7 | let(:api_key) { account.api_keys.create({}) } 8 | let(:api_key_id) { api_key.id } 9 | let(:api_key_secret) { api_key.secret } 10 | let(:encoded_api_key) { Base64.encode64("#{api_key_id}:#{api_key_secret}") } 11 | let(:basic_authorization_header) { "Basic #{encoded_api_key}" } 12 | let(:authenticator) { Stormpath::Authentication::HttpBasicAuthentication } 13 | let(:authenticate) { authenticator.new(application, basic_authorization_header).authenticate! } 14 | 15 | before { map_account_store(application, directory, 1, true, true) } 16 | 17 | after do 18 | account.delete 19 | directory.delete 20 | application.delete 21 | end 22 | 23 | describe 'with valid api key id and secret' do 24 | it 'should return the apikey resource' do 25 | expect(authenticate).to be_kind_of Stormpath::Resource::ApiKey 26 | end 27 | 28 | it 'should return the account' do 29 | expect(authenticate.account).to eq(account) 30 | end 31 | end 32 | 33 | describe 'with invalid api key id and secret' do 34 | let(:encoded_api_key) { Base64.encode64('bad_api_key_id:bad_api_key_secret') } 35 | 36 | it 'should raise error' do 37 | expect do 38 | authenticate 39 | end.to raise_error(Stormpath::Error) 40 | end 41 | end 42 | 43 | describe 'with valid api key id and bad secret' do 44 | let(:encoded_api_key) { Base64.encode64("#{api_key_id}:bad_api_key_secret") } 45 | 46 | it 'should raise error' do 47 | expect do 48 | authenticate 49 | end.to raise_error(Stormpath::Error) 50 | end 51 | end 52 | 53 | describe 'with no basic authorization header provided' do 54 | let(:basic_authorization_header) { nil } 55 | it 'should raise error' do 56 | expect do 57 | authenticate 58 | end.to raise_error(Stormpath::Error) 59 | end 60 | end 61 | 62 | context 'with invalid authorization header type' do 63 | let(:basic_authorization_header) { "Bearer #{encoded_api_key}" } 64 | 65 | it 'should raise error' do 66 | expect do 67 | authenticate 68 | end.to raise_error(Stormpath::Error) 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /spec/auth/http_bearer_authentication_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'HttpBearerAuthentication', vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:password_grant_request) do 7 | Stormpath::Oauth::PasswordGrantRequest.new("test#{default_domain}", 'P@$$w0rd') 8 | end 9 | let(:aquire_token) { application.authenticate_oauth(password_grant_request) } 10 | 11 | let(:access_token) { aquire_token.access_token } 12 | let(:bearer_authorization_header) { "Bearer #{access_token}" } 13 | let(:authenticator) { Stormpath::Authentication::HttpBearerAuthentication } 14 | let(:authenticate_locally) do 15 | authenticator.new(application, bearer_authorization_header, local: true).authenticate! 16 | end 17 | let(:authenticate_remotely) do 18 | authenticator.new(application, bearer_authorization_header).authenticate! 19 | end 20 | before { map_account_store(application, directory, 1, true, true) } 21 | let!(:account) do 22 | application.accounts.create(account_attrs(email: 'test', password: 'P@$$w0rd')) 23 | end 24 | 25 | after do 26 | account.delete 27 | directory.delete 28 | application.delete 29 | end 30 | 31 | describe 'remote authentication' do 32 | context 'with a valid bearer authorization header' do 33 | it 'should return VerifyTokenResult' do 34 | expect(authenticate_remotely).to be_kind_of(Stormpath::Oauth::VerifyTokenResult) 35 | expect(authenticate_remotely.account).to eq(account) 36 | end 37 | 38 | it 'should contain the account' do 39 | expect(authenticate_remotely.account).to eq(account) 40 | end 41 | end 42 | 43 | context 'with no bearer authorization header' do 44 | let(:bearer_authorization_header) { nil } 45 | 46 | it 'should raise error' do 47 | expect do 48 | authenticate_remotely 49 | end.to raise_error(Stormpath::Error) 50 | end 51 | end 52 | 53 | context 'with invalid authorization header type' do 54 | let(:bearer_authorization_header) { "Basic #{access_token}" } 55 | 56 | it 'should raise error' do 57 | expect do 58 | authenticate_remotely 59 | end.to raise_error(Stormpath::Error) 60 | end 61 | end 62 | end 63 | 64 | describe 'local authentication' do 65 | context 'with a valid bearer authorization header' do 66 | it 'should return account' do 67 | expect(authenticate_locally) 68 | .to be_kind_of(Stormpath::Oauth::LocalAccessTokenVerificationResult) 69 | expect(authenticate_locally.account).to eq(account) 70 | end 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /spec/auth/register_service_provider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'RegisterServiceProvider', vcr: true do 4 | let(:client) { test_api_client } 5 | let(:application) { test_api_client.applications.create(application_attrs) } 6 | let(:identity_provider) { application.saml_policy.identity_provider } 7 | let(:assertion_consumer_service_url) { "http://example#{random_number}.zendesk.com/access/saml" } 8 | let(:entity_id) { "unique-name-#{random_number}" } 9 | let(:registered_service_provider) do 10 | Stormpath::Authentication::RegisterServiceProvider.new(identity_provider, options).call 11 | end 12 | let(:options) do 13 | { 14 | assertion_consumer_service_url: assertion_consumer_service_url, 15 | entity_id: entity_id 16 | } 17 | end 18 | 19 | after { application.delete } 20 | 21 | describe 'successfull service provider registration' do 22 | after { registered_service_provider.delete } 23 | 24 | context 'without optional parameters' do 25 | it 'should successfully create a registered_service_provider' do 26 | expect(registered_service_provider).to( 27 | be_a(Stormpath::Resource::RegisteredSamlServiceProvider) 28 | ) 29 | end 30 | 31 | it 'should successfully map the registered_service_provider to the identity_provider' do 32 | expect(identity_provider.registered_saml_service_providers).to( 33 | include(registered_service_provider) 34 | ) 35 | end 36 | end 37 | 38 | context 'with optional parameters' do 39 | before do 40 | options[:name] = "service-provider-name-#{random_number}" 41 | options[:description] = 'stormpath example' 42 | options[:name_id_format] = 'PERSISTENT' 43 | end 44 | 45 | it 'should successfully create a registered_service_provider' do 46 | expect(registered_service_provider).to( 47 | be_a(Stormpath::Resource::RegisteredSamlServiceProvider) 48 | ) 49 | end 50 | 51 | it 'should successfully map the registered_service_provider to the identity_provider' do 52 | expect(identity_provider.registered_saml_service_providers).to( 53 | include(registered_service_provider) 54 | ) 55 | end 56 | end 57 | end 58 | 59 | describe 'unsuccessfull service provider registration' do 60 | before do 61 | options.delete(:assertion_consumer_service_url) 62 | end 63 | 64 | it 'should raise Stormpath::Error' do 65 | expect { registered_service_provider }.to raise_error(Stormpath::Error) 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/auth/sauthc1_signer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'timecop' 3 | 4 | describe Stormpath::Http::Authc::Sauthc1Signer do 5 | let(:fake_uuid_generator) do 6 | proc { 'fake-uuid' } 7 | end 8 | let(:signer) do 9 | Stormpath::Http::Authc::Sauthc1Signer.new(fake_uuid_generator) 10 | end 11 | 12 | after do 13 | Timecop.return 14 | end 15 | 16 | describe '#sign_request' do 17 | context 'for two GET requests to the same URL' do 18 | context 'with one request using the query_string hash' do 19 | let(:fake_api_key) { Stormpath::ApiKey.new('foo', 'bar') } 20 | 21 | let(:empty_query_hash_request) do 22 | Stormpath::Http::Request.new( 23 | 'get', 'http://example.com/resources/abc123?q=red blue', nil, {}, nil, test_api_key 24 | ) 25 | end 26 | 27 | let(:filled_query_hash_request) do 28 | Stormpath::Http::Request.new( 29 | 'get', 'http://example.com/resources/abc123', { 'q' => 'red blue' }, {}, nil, test_api_key 30 | ) 31 | end 32 | 33 | before do 34 | Timecop.freeze(Time.now) 35 | signer.sign_request empty_query_hash_request 36 | signer.sign_request filled_query_hash_request 37 | end 38 | 39 | it 'assigns identical headers to both requests' do 40 | expect(empty_query_hash_request.http_headers['Host']).to eq(filled_query_hash_request.http_headers['Host']) 41 | expect(empty_query_hash_request.http_headers['Authorization']).to eq(filled_query_hash_request.http_headers['Authorization']) 42 | end 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/cache/cache_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'timecop' 3 | 4 | describe Stormpath::Cache::Cache do 5 | let(:cache) { Stormpath::Cache::Cache.new(ttl_seconds: 7, tti_seconds: 3) } 6 | let(:now) { Time.now } 7 | 8 | before do 9 | cache.put 'foo', 'bar' 10 | end 11 | 12 | after do 13 | Timecop.return 14 | end 15 | 16 | describe '#put' do 17 | it 'adds entry to the cache' do 18 | expect(cache.size).to eq(1) 19 | expect(cache.stats.summary).to eq [1, 0, 0, 0, 1] 20 | end 21 | end 22 | 23 | describe '#get' do 24 | context 'miss' do 25 | before do 26 | @foo = cache.get('not-foo') 27 | end 28 | 29 | it 'gets nil' do 30 | expect(@foo).not_to be 31 | expect(cache.stats.summary).to eq [1, 0, 1, 0, 1] 32 | end 33 | end 34 | 35 | context 'live before tti' do 36 | before do 37 | Timecop.freeze now + 2 38 | @foo = cache.get('foo') 39 | end 40 | 41 | it 'gets bar' do 42 | expect(@foo).to eq('bar') 43 | expect(cache.stats.summary).to eq [1, 1, 0, 0, 1] 44 | end 45 | end 46 | 47 | context 'live after tti' do 48 | before do 49 | Timecop.freeze now + 2 50 | cache.get('foo') 51 | Timecop.freeze now + 5 52 | @foo = cache.get('foo') 53 | end 54 | 55 | it 'gets bar' do 56 | expect(@foo).to eq('bar') 57 | expect(cache.stats.summary).to eq [1, 2, 0, 0, 1] 58 | end 59 | end 60 | 61 | context 'expired by tti' do 62 | before do 63 | Timecop.freeze now + 4 64 | @foo = cache.get('foo') 65 | end 66 | 67 | it 'gets nil' do 68 | expect(@foo).not_to be 69 | expect(cache.stats.summary).to eq [1, 0, 1, 1, 1] 70 | end 71 | end 72 | 73 | context 'expired by ttl' do 74 | before do 75 | Timecop.freeze now + 2 76 | cache.get('foo') 77 | Timecop.freeze now + 5 78 | cache.get('foo') 79 | Timecop.freeze now + 8 80 | @foo = cache.get('foo') 81 | end 82 | 83 | it 'gets nil' do 84 | expect(@foo).not_to be 85 | expect(cache.stats.summary).to eq [1, 2, 1, 1, 1] 86 | end 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/cache/cache_stats_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Cache::CacheStats do 4 | let(:cache_stats) do 5 | Stormpath::Cache::CacheStats.new 6 | end 7 | 8 | context 'by default' do 9 | it 'intializes counters' do 10 | expect(cache_stats.puts).to eq 0 11 | expect(cache_stats.hits).to eq 0 12 | expect(cache_stats.misses).to eq 0 13 | expect(cache_stats.expirations).to eq 0 14 | expect(cache_stats.size).to eq 0 15 | end 16 | end 17 | 18 | describe '#put' do 19 | before { cache_stats.put } 20 | 21 | it 'increments puts' do 22 | expect(cache_stats.puts).to eq 1 23 | end 24 | 25 | it 'increments size' do 26 | expect(cache_stats.puts).to eq 1 27 | end 28 | 29 | it 'updates summary' do 30 | expect(cache_stats.summary).to eq [1, 0, 0, 0, 1] 31 | end 32 | end 33 | 34 | describe '#hit' do 35 | before { cache_stats.hit } 36 | 37 | it 'increments hits' do 38 | expect(cache_stats.hits).to eq 1 39 | end 40 | 41 | it 'updates summary' do 42 | expect(cache_stats.summary).to eq [0, 1, 0, 0, 0] 43 | end 44 | end 45 | 46 | describe '#miss=' do 47 | context 'expired is true' do 48 | before { cache_stats.miss true } 49 | 50 | it 'increments misses' do 51 | expect(cache_stats.misses).to eq 1 52 | end 53 | 54 | it 'increments expirations' do 55 | expect(cache_stats.expirations).to eq 1 56 | end 57 | 58 | it 'updates summary' do 59 | expect(cache_stats.summary).to eq [0, 0, 1, 1, 0] 60 | end 61 | end 62 | 63 | context 'expired is true' do 64 | before { cache_stats.miss false } 65 | 66 | it 'increments misses' do 67 | expect(cache_stats.misses).to eq 1 68 | end 69 | 70 | it 'does not increment expirations' do 71 | expect(cache_stats.expirations).to eq 0 72 | end 73 | 74 | it 'updates summary' do 75 | expect(cache_stats.summary).to eq [0, 0, 1, 0, 0] 76 | end 77 | end 78 | end 79 | 80 | describe '#delete' do 81 | context 'when size is greater than zero' do 82 | before do 83 | 3.times { cache_stats.put } 84 | cache_stats.delete 85 | end 86 | 87 | it 'decrements size' do 88 | expect(cache_stats.size).to eq 2 89 | end 90 | 91 | it 'updates summary' do 92 | expect(cache_stats.summary).to eq [3, 0, 0, 0, 2] 93 | end 94 | end 95 | 96 | context 'when size is zero' do 97 | before do 98 | cache_stats.delete 99 | end 100 | 101 | it 'does nothing' do 102 | expect(cache_stats.size).to eq 0 103 | end 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /spec/oauth/access_token_authentication_result_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Oauth::AccessTokenAuthenticationResult, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | before { map_account_store(application, directory, 1, true, false) } 7 | let!(:account) do 8 | application.accounts.create(account_attrs(email: 'ruby25', password: 'P@$$w0rd')) 9 | end 10 | let(:password_grant_request) do 11 | Stormpath::Oauth::PasswordGrantRequest.new("ruby25#{default_domain}", 'P@$$w0rd') 12 | end 13 | let(:jwt_authentication_result) { application.authenticate_oauth(password_grant_request) } 14 | 15 | after do 16 | application.delete 17 | directory.delete 18 | account.delete 19 | end 20 | 21 | it 'instances should expose a method to get an account' do 22 | expect(jwt_authentication_result.account).to eq(account) 23 | end 24 | 25 | it 'jwt access token should contain the stt header' do 26 | expect(jwt_authentication_result.access_token).to have_stt_in_header('access') 27 | end 28 | 29 | it 'should be able to delete the access token' do 30 | jwt_authentication_result 31 | 32 | expect(account.access_tokens.count).to eq(1) 33 | 34 | jti = JWT.decode( 35 | jwt_authentication_result.access_token, 36 | test_api_client.data_store.api_key.secret 37 | ).first['jti'] 38 | 39 | fetched_access_token = test_api_client.access_tokens.get(jti) 40 | 41 | fetched_access_token.delete 42 | 43 | expect(account.access_tokens.count).to eq(0) 44 | end 45 | 46 | it 'jwt refresh token should contain the stt header' do 47 | expect(jwt_authentication_result.refresh_token).to have_stt_in_header('refresh') 48 | end 49 | 50 | it 'should be able to delete the refresh token' do 51 | jwt_authentication_result 52 | 53 | expect(account.refresh_tokens.count).to eq(1) 54 | 55 | jti = JWT.decode( 56 | jwt_authentication_result.refresh_token, 57 | test_api_client.data_store.api_key.secret 58 | ).first['jti'] 59 | 60 | fetched_refresh_token = test_api_client.refresh_tokens.get(jti) 61 | 62 | fetched_refresh_token.delete 63 | 64 | expect(account.refresh_tokens.count).to eq(0) 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/provider/account_resolver_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'ProviderAccountResolver' do 4 | context 'given an instance of ProviderAccountResolver' do 5 | let(:data_store) { Stormpath::DataStore.new('', '', {}, '') } 6 | let(:provider_account_resolver) do 7 | Stormpath::Provider::AccountResolver.new(data_store, 'foo/bar', account_request) 8 | end 9 | let(:response) do 10 | provider_account_resolver.resolve_provider_account 11 | end 12 | 13 | before do 14 | allow(test_api_client).to receive(:data_store).and_return(data_store) 15 | auth_result = Stormpath::Provider::AccountResult.new({}, test_api_client) 16 | allow(data_store).to receive(:create).and_return(auth_result) 17 | provider_account_resolver 18 | end 19 | 20 | context 'when integrating' do 21 | context 'without an account store' do 22 | let(:account_request) do 23 | Stormpath::Provider::AccountRequest.new(:facebook, :access_token, 'some-token') 24 | end 25 | 26 | it 'a ProviderResult is returned' do 27 | expect(response).to be_a Stormpath::Provider::AccountResult 28 | end 29 | end 30 | 31 | context 'with account store as a parameter' do 32 | let(:account_request) do 33 | Stormpath::Provider::AccountRequest.new( 34 | :facebook, 35 | :access_token, 36 | 'some-token', 37 | account_store: { name_key: 'app1' } 38 | ) 39 | end 40 | 41 | it 'a ProviderResult is returned' do 42 | expect(response).to be_a Stormpath::Provider::AccountResult 43 | end 44 | 45 | it 'should have account_store parameter' do 46 | expect(provider_account_resolver.provider_data.keys).to include 'accountStore' 47 | end 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/resource/account_link_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::AccountLink, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory1) { test_api_client.directories.create(directory_attrs) } 6 | let(:directory2) { test_api_client.directories.create(directory_attrs) } 7 | let(:username1) { "jekyll-#{random_number}" } 8 | let(:username2) { "hyde-#{random_number}" } 9 | 10 | before do 11 | map_account_store(application, directory1, 1, true, false) 12 | map_account_store(application, directory2, 2, false, false) 13 | end 14 | 15 | let!(:account1) { directory1.accounts.create(account_attrs(email: username1, username: username1)) } 16 | let!(:account2) { directory2.accounts.create(account_attrs(email: username2, username: username2)) } 17 | 18 | let!(:account_link) do 19 | test_api_client.account_links.create( 20 | left_account: { 21 | href: account1.href 22 | }, 23 | right_account: { 24 | href: account2.href 25 | } 26 | ) 27 | end 28 | 29 | after do 30 | application.delete 31 | directory1.delete 32 | directory2.delete 33 | end 34 | 35 | describe 'instances should respond to attribute property methods' do 36 | it do 37 | [:left_account, :right_account].each do |property_accessor| 38 | expect(account_link).to respond_to(property_accessor) 39 | expect(account_link).to respond_to("#{property_accessor}=") 40 | expect(account_link.send(property_accessor)).to be_a Stormpath::Resource::Account 41 | end 42 | 43 | [:created_at, :modified_at].each do |property_getter| 44 | expect(account_link).to respond_to(property_getter) 45 | expect(account_link.send(property_getter)).to be_a String 46 | end 47 | 48 | expect(account_link.left_account).to be_a Stormpath::Resource::Account 49 | expect(account_link.right_account).to be_a Stormpath::Resource::Account 50 | end 51 | end 52 | 53 | describe 'account link associations' do 54 | it 'should belong_to right account' do 55 | expect(account_link.right_account).to eq(account2) 56 | end 57 | 58 | it 'should belong_to left account' do 59 | expect(account_link.left_account).to eq(account1) 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/resource/account_linking_policy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::AccountLinkingPolicy, :vcr do 4 | describe 'instances should respond to attribute property methods' do 5 | let!(:application) { test_api_client.applications.create(application_attrs) } 6 | let(:account_linking_policy) { application.account_linking_policy } 7 | 8 | after { application.delete } 9 | 10 | it do 11 | expect(account_linking_policy).to be_a Stormpath::Resource::AccountLinkingPolicy 12 | 13 | [:status, :automatic_provisioning].each do |property_accessor| 14 | expect(account_linking_policy).to respond_to(property_accessor) 15 | expect(account_linking_policy).to respond_to("#{property_accessor}=") 16 | expect(account_linking_policy.send(property_accessor)).to be_a String 17 | end 18 | 19 | expect(account_linking_policy).to respond_to(:matching_property) 20 | expect(account_linking_policy).to respond_to('matching_property=') 21 | expect(account_linking_policy.send(:matching_property)).to be_nil 22 | 23 | [:created_at, :modified_at].each do |property_getter| 24 | expect(account_linking_policy).to respond_to(property_getter) 25 | expect(account_linking_policy.send(property_getter)).to be_a String 26 | end 27 | 28 | expect(account_linking_policy.tenant).to be_a Stormpath::Resource::Tenant 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/resource/account_store_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::AccountStore, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:group) { directory.groups.create(group_attrs) } 7 | let(:organization) { test_api_client.organizations.create(organization_attrs) } 8 | 9 | after do 10 | application.delete if application 11 | group.delete if group 12 | directory.delete if directory 13 | organization.delete if organization 14 | end 15 | 16 | describe 'given an account_store_mapping and a directory' do 17 | let!(:account_store_mapping) { map_account_store(application, directory, 0, true, true) } 18 | let(:reloaded_mapping) { application.account_store_mappings.get(account_store_mapping.href) } 19 | 20 | it 'should return a directory' do 21 | expect(reloaded_mapping.account_store.class).to eq(Stormpath::Resource::Directory) 22 | expect(reloaded_mapping.account_store).to eq(directory) 23 | end 24 | end 25 | 26 | describe 'given an account_store_mapping and a group' do 27 | let!(:account_store_mapping) { map_account_store(application, group, 0, true, false) } 28 | let(:reloaded_mapping) { application.account_store_mappings.get(account_store_mapping.href) } 29 | 30 | it 'should return a group' do 31 | expect(reloaded_mapping.account_store.class).to eq(Stormpath::Resource::Group) 32 | expect(reloaded_mapping.account_store).to eq(group) 33 | end 34 | end 35 | 36 | describe 'given an account_store_mapping and an organization' do 37 | let!(:account_store_mapping) { map_account_store(application, organization, 0, true, false) } 38 | let(:reloaded_mapping) { application.account_store_mappings.get(account_store_mapping.href) } 39 | 40 | it 'should return an organization' do 41 | expect(reloaded_mapping.account_store.class).to eq(Stormpath::Resource::Organization) 42 | expect(reloaded_mapping.account_store).to eq(organization) 43 | end 44 | end 45 | 46 | describe 'given an undefined account_store_mapping' do 47 | it 'should raise an error' do 48 | expect do 49 | map_account_store(application, 'undefined', 0, true, false) 50 | end.to raise_error 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/resource/agent_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Agent, vcr: true do 4 | let(:directory_name) { "rubysdkdirldap-#{random_number}" } 5 | let(:directory) do 6 | test_api_client.directories.create( 7 | name: directory_name, 8 | description: directory_name, 9 | provider: { 10 | provider_id: 'ldap', 11 | agent: ldap_agent_attrs 12 | } 13 | ) 14 | end 15 | let(:agent) { directory.provider.agent } 16 | 17 | after { directory.delete } 18 | 19 | it 'instances should respond to attribute property methods' do 20 | expect(agent).to be_a Stormpath::Resource::Agent 21 | 22 | [:id, :download, :created_at, :modified_at].each do |property_getter| 23 | expect(agent).to respond_to(property_getter) 24 | expect(agent.send(property_getter)).to be_a String 25 | end 26 | 27 | [:config, :status].each do |property_accessor| 28 | expect(agent).to respond_to(property_accessor) 29 | expect(agent).to respond_to("#{property_accessor}=") 30 | end 31 | 32 | expect(agent.config).to be_a Hash 33 | expect(agent.status).to be_a String 34 | end 35 | 36 | describe 'associations' do 37 | it 'should respond to directory' do 38 | expect(agent.directory).to eq directory 39 | end 40 | 41 | it 'should respond to tenant' do 42 | expect(agent.tenant).to eq test_api_client.tenant 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/resource/api_key_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::ApiKey, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:tenant) { application.tenant } 7 | let(:account) { application.accounts.create(account_attrs) } 8 | let(:api_key) { account.api_keys.create({}) } 9 | before { map_account_store(application, directory, 1, true, false) } 10 | 11 | after do 12 | application.delete 13 | directory.delete 14 | account.delete 15 | end 16 | 17 | describe 'instances should respond to attribute property methods' do 18 | it do 19 | [:name, :description, :status].each do |property_accessor| 20 | expect(api_key).to respond_to(property_accessor) 21 | expect(api_key).to respond_to("#{property_accessor}=") 22 | end 23 | 24 | [:id, :secret].each do |property_getter| 25 | expect(api_key).to respond_to(property_getter) 26 | expect(api_key.send(property_getter)).to be_a String 27 | end 28 | 29 | expect(api_key.tenant).to be_a Stormpath::Resource::Tenant 30 | expect(api_key.account).to be_a Stormpath::Resource::Account 31 | end 32 | end 33 | 34 | describe 'api_key_associations' do 35 | it 'should belong_to account' do 36 | expect(api_key.account).to eq(account) 37 | end 38 | 39 | it 'should belong_to tenant' do 40 | expect(api_key.tenant).to eq(tenant) 41 | end 42 | 43 | it 'apps can fetch api keys' do 44 | fetched_api_key = application.api_keys.search(id: api_key.id).first 45 | expect(fetched_api_key).to eq(api_key) 46 | end 47 | 48 | it 'accounts can fetch api keys' do 49 | api_key 50 | expect(account.api_keys.count).to eq(1) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/resource/application_web_config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::ApplicationWebConfig, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:web_config) { application.web_config } 6 | after { application.delete } 7 | 8 | describe 'instances should respond to attribute property methods' do 9 | it do 10 | expect(web_config).to be_a Stormpath::Resource::ApplicationWebConfig 11 | 12 | [:dns_label, :status].each do |property_accessor| 13 | expect(web_config).to respond_to(property_accessor) 14 | expect(web_config).to respond_to("#{property_accessor}=") 15 | expect(web_config.send(property_accessor)).to be_a String 16 | end 17 | 18 | [:domain_name, :created_at, :modified_at].each do |property_getter| 19 | expect(web_config).to respond_to(property_getter) 20 | expect(web_config.send(property_getter)).to be_a String 21 | end 22 | 23 | expect(web_config.tenant).to be_a Stormpath::Resource::Tenant 24 | expect(web_config.application).to be_a Stormpath::Resource::Application 25 | expect(web_config.signing_api_key).to be_a Stormpath::Resource::ApiKey 26 | end 27 | 28 | it 'should respond to endpoints' do 29 | Stormpath::Resource::ApplicationWebConfig::ENDPOINTS.each do |endpoint| 30 | expect(web_config).to respond_to(endpoint) 31 | expect(web_config).to respond_to("#{endpoint}=") 32 | expect(web_config.send(endpoint)).to be_a Hash 33 | end 34 | end 35 | end 36 | 37 | describe 'enabling/disabling endpoints' do 38 | it 'should be able to switch to enabled and disabled' do 39 | Stormpath::Resource::ApplicationWebConfig::ENDPOINTS.each do |endpoint_name| 40 | web_config.send("#{endpoint_name}=", enabled: false) 41 | web_config.save 42 | 43 | expect(application.web_config.send(endpoint_name).send(:[], 'enabled')).to eq false 44 | end 45 | end 46 | 47 | it 'should switch configuration options for the /me endpoint' do 48 | web_config.me = { 49 | enabled: true, 50 | expand: { 51 | tenant: true, 52 | directory: true, 53 | groups: false, 54 | providerData: true 55 | } 56 | } 57 | 58 | web_config.save 59 | expect(application.web_config.me['expand']['tenant']).to eq true 60 | expect(application.web_config.me['expand']['directory']).to eq true 61 | expect(application.web_config.me['expand']['groups']).to eq false 62 | expect(application.web_config.me['expand']['providerData']).to eq true 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/resource/base_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Base do 4 | describe '.prop_accessor' do 5 | context 'given property names' do 6 | class TestResource < Stormpath::Resource::Base 7 | prop_accessor :username, :given_name 8 | end 9 | let(:resource) { TestResource.new({ 'username' => 'bar', 'givenName' => 'foo' }, nil) } 10 | 11 | it 'generates a getter method for each property' do 12 | expect(resource.username).to eq('bar') 13 | expect(resource.given_name).to eq('foo') 14 | end 15 | 16 | it 'generates a setter for each property' do 17 | resource.username = 'foo' 18 | resource.given_name = 'bar' 19 | expect(resource.properties).to include('username' => 'foo') 20 | expect(resource.properties).to include('givenName' => 'bar') 21 | end 22 | end 23 | end 24 | 25 | describe '.non_printable' do 26 | context 'given property names' do 27 | class TestResource < Stormpath::Resource::Base 28 | prop_non_printable :password 29 | end 30 | let(:resource) { TestResource.new({ 'username' => 'bar', 'password' => 'P@$$w0rd' }, nil) } 31 | 32 | it 'marks that property as not being printable' do 33 | expect(resource.inspect).to include('username') 34 | expect(resource.inspect).to_not include('password') 35 | end 36 | end 37 | end 38 | 39 | describe '.get_property' do 40 | context 'given the name of a dirty property' do 41 | class TestResource < Stormpath::Resource::Base 42 | prop_accessor :username 43 | end 44 | 45 | let(:resource) do 46 | TestResource.new('http://foo.com/test/123', nil).tap do |resource| 47 | resource.username = 'foo' 48 | end 49 | end 50 | 51 | it 'does NOT attempt to materialize the entire resource' do 52 | expect(resource.username).to eq('foo') 53 | end 54 | end 55 | end 56 | 57 | describe '#==' do 58 | class TestResource < Stormpath::Resource::Base; end 59 | 60 | context 'compared against an object of the same class' do 61 | let(:resource) { TestResource.new('http://foo.com/test/123') } 62 | 63 | context 'href matches' do 64 | let(:other) { TestResource.new('http://foo.com/test/123') } 65 | 66 | it 'passes' do 67 | expect(resource).to eq(other) 68 | end 69 | end 70 | 71 | context 'href does not match' do 72 | let(:other) { TestResource.new('http://foo.com/test/456') } 73 | 74 | it 'fails' do 75 | expect(resource).to_not eq(other) 76 | end 77 | end 78 | end 79 | 80 | context 'compared against an object of another class' do 81 | class NotAResource; end 82 | let(:resource) { TestResource.new('http://foo.com/test/123') } 83 | let(:other) { NotAResource.new } 84 | 85 | it 'fails' do 86 | expect(resource).to_not eq(other) 87 | end 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /spec/resource/challenge_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Challenge, :vcr do 4 | let(:directory) { test_api_client.directories.create(directory_attrs) } 5 | let(:account) { directory.accounts.create(account_attrs) } 6 | let(:factor) do 7 | account.factors.create( 8 | type: 'SMS', 9 | phone: { 10 | number: '+12025550173', 11 | name: 'test phone', 12 | description: 'this is a testing phone number' 13 | } 14 | ) 15 | end 16 | 17 | let(:challenge) { factor.challenges.create(message: 'Enter code: ${code}') } 18 | let(:validate_challenge) { challenge.validate('123456') } 19 | 20 | before do 21 | stub_request(:post, "#{factor.href}/challenges") 22 | .to_return(body: Stormpath::Test.mocked_challenge) 23 | 24 | stub_request(:post, challenge.href) 25 | .to_return(body: Stormpath::Test.mocked_successfull_challenge) 26 | end 27 | 28 | after { directory.delete } 29 | 30 | describe 'instances should respond to attribute property methods' do 31 | it do 32 | [:message].each do |property_accessor| 33 | expect(challenge).to respond_to(property_accessor) 34 | expect(challenge).to respond_to("#{property_accessor}=") 35 | expect(challenge.send(property_accessor)).to be_a String 36 | end 37 | 38 | [:status, :created_at, :modified_at].each do |property_getter| 39 | expect(challenge).to respond_to(property_getter) 40 | expect(challenge.send(property_getter)).to be_a String 41 | end 42 | 43 | expect(challenge.factor).to be_a Stormpath::Resource::Factor 44 | expect(challenge.account).to be_a Stormpath::Resource::Account 45 | end 46 | end 47 | 48 | describe '#validate' do 49 | it 'should return successfull challenge for valid code from sms' do 50 | expect(validate_challenge.status).to eq 'SUCCESS' 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/resource/custom_data_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::CustomData, :vcr do 4 | after do 5 | directory.delete if directory 6 | end 7 | 8 | context 'wuth caching regions' do 9 | let(:directory) { test_api_client.directories.create(directory_attrs) } 10 | 11 | it_behaves_like 'account_custom_data' 12 | it_behaves_like 'group_custom_data' 13 | end 14 | 15 | context 'without caching regions' do 16 | let(:disabled_cache_client) do 17 | @disabled_cache_client ||= Stormpath::Client.new(api_key: test_api_key, cache: { store: Stormpath::Cache::DisabledCacheStore }) 18 | end 19 | 20 | let(:directory) { disabled_cache_client.directories.create(directory_attrs) } 21 | 22 | it_behaves_like 'account_custom_data' 23 | it_behaves_like 'group_custom_data' 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/resource/email_template_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::EmailTemplate, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | 6 | after { application.delete } 7 | 8 | describe 'instances should respond to attribute property methods' do 9 | let(:directory) { test_api_client.directories.create(directory_attrs) } 10 | let(:password_policy) { directory.password_policy } 11 | let(:reset_email_template) { password_policy.reset_email_templates.first } 12 | 13 | before do 14 | map_account_store(application, directory, 1, false, false) 15 | end 16 | 17 | after { directory.delete } 18 | 19 | it do 20 | expect(reset_email_template).to be_a Stormpath::Resource::EmailTemplate 21 | 22 | [:name, 23 | :description, 24 | :subject, 25 | :from_email_address, 26 | :text_body, 27 | :html_body, 28 | :mime_type].each do |property_accessor| 29 | expect(reset_email_template).to respond_to(property_accessor) 30 | expect(reset_email_template).to respond_to("#{property_accessor}=") 31 | end 32 | end 33 | 34 | it 'can change attributes' do 35 | reset_email_template.name = 'Default Password Reset Template' 36 | reset_email_template.description = 'This is the password reset email template' 37 | reset_email_template.subject = 'Please reset your password' 38 | reset_email_template.from_email_address = "email#{default_domain}" 39 | reset_email_template.text_body = 'You forgot your password! ${sptoken}' 40 | reset_email_template.html_body = '
You forgot your password!
${sptoken}' 41 | reset_email_template.mime_type = 'text/plain' 42 | 43 | reset_email_template.save 44 | 45 | reloaded_reset_email_template = password_policy.reset_email_templates.first 46 | 47 | expect(reloaded_reset_email_template.name).to eq('Default Password Reset Template') 48 | expect(reloaded_reset_email_template.description).to eq('This is the password reset email template') 49 | expect(reloaded_reset_email_template.subject).to eq('Please reset your password') 50 | expect(reloaded_reset_email_template.from_email_address).to eq("email#{default_domain}") 51 | expect(reloaded_reset_email_template.text_body).to eq('You forgot your password! ${sptoken}') 52 | expect(reloaded_reset_email_template.html_body).to eq('You forgot your password!
${sptoken}') 53 | expect(reloaded_reset_email_template.mime_type).to eq('text/plain') 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/resource/expansion_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Expansion, :vcr do 4 | describe '#initialize' do 5 | context 'given a single property name' do 6 | let(:expansion) do 7 | Stormpath::Resource::Expansion.new('foo') 8 | end 9 | 10 | it 'can be transmuted to a simple hash' do 11 | expect(expansion.to_query).to eq(expand: 'foo') 12 | end 13 | end 14 | context 'given a list of property names' do 15 | let(:expansion) do 16 | Stormpath::Resource::Expansion.new('foo', 'bar') 17 | end 18 | 19 | it 'can be transmuted to a simple hash' do 20 | expect(expansion.to_query).to eq(expand: 'foo,bar') 21 | end 22 | end 23 | 24 | context 'given no arguments are passed to constructor' do 25 | let(:expansion) do 26 | Stormpath::Resource::Expansion.new 27 | end 28 | 29 | it 'will transmute to an empty hash' do 30 | expect(expansion.to_query).to be_nil 31 | end 32 | end 33 | end 34 | 35 | describe '#add_property' do 36 | context 'given a simple property name' do 37 | let(:expansion) { Stormpath::Resource::Expansion.new } 38 | 39 | before do 40 | expansion.add_property :foo 41 | end 42 | 43 | it 'can be transmuted to a simple hash' do 44 | expect(expansion.to_query).to eq(expand: 'foo') 45 | end 46 | end 47 | 48 | context 'given two simple property names' do 49 | let(:expansion) { Stormpath::Resource::Expansion.new } 50 | 51 | before do 52 | expansion.add_property :foo 53 | expansion.add_property :bar 54 | end 55 | 56 | it 'can be transmuted to a simple hash' do 57 | expect(expansion.to_query).to eq(expand: 'foo,bar') 58 | end 59 | end 60 | 61 | context 'given a duplicate property name' do 62 | let(:expansion) { Stormpath::Resource::Expansion.new } 63 | 64 | before do 65 | expansion.add_property :foo 66 | expansion.add_property :bar 67 | expansion.add_property :bar 68 | end 69 | 70 | it 'will not duplicate the property' do 71 | expect(expansion.to_query).to eq(expand: 'foo,bar') 72 | end 73 | end 74 | 75 | context 'given a property name, offset, and limit' do 76 | let(:expansion) { Stormpath::Resource::Expansion.new } 77 | 78 | before do 79 | expansion.add_property :foo, offset: 5, limit: 100 80 | end 81 | 82 | it 'can be transmuted to a simple hash' do 83 | expect(expansion.to_query).to eq(expand: 'foo(offset:5,limit:100)') 84 | end 85 | end 86 | 87 | context 'given two calls to add the same property' do 88 | let(:expansion) { Stormpath::Resource::Expansion.new } 89 | 90 | before do 91 | expansion.add_property :foo, offset: 5, limit: 100 92 | expansion.add_property :foo, offset: 25 93 | end 94 | 95 | it 'allows the last call to win out over the first' do 96 | expect(expansion.to_query).to eq(expand: 'foo(offset:25)') 97 | end 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /spec/resource/field_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Field, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:schema) { directory.account_schema } 7 | let(:field) { schema.fields.first } 8 | 9 | after do 10 | directory.delete 11 | application.delete 12 | end 13 | 14 | describe 'instances should respond to attribute property methods' do 15 | it do 16 | expect(field).to be_a Stormpath::Resource::Field 17 | 18 | [:name, :created_at, :modified_at].each do |property_getter| 19 | expect(field).to respond_to(property_getter) 20 | expect(field.send(property_getter)).to be_a String 21 | end 22 | 23 | expect(field).to respond_to(:required) 24 | expect(field.required).to eq !!field.required 25 | end 26 | end 27 | 28 | describe 'field associations' do 29 | context '#schema' do 30 | it 'should be able to get the account schema' do 31 | expect(field.schema).to be_a Stormpath::Resource::Schema 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/resource/group_membership_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::GroupMembership, :vcr do 4 | it 'should be the same as AccountMembership' do 5 | expect(Stormpath::Resource::GroupMembership).to eq(Stormpath::Resource::AccountMembership) 6 | end 7 | 8 | describe '#add_account' do 9 | context 'given an account and a group' do 10 | let(:directory) { test_api_client.directories.create(directory_attrs) } 11 | let(:group) { directory.groups.create(group_attrs) } 12 | let(:account) { directory.accounts.create(account_attrs) } 13 | 14 | before { group.add_account account } 15 | 16 | after do 17 | group.delete 18 | account.delete 19 | directory.delete 20 | end 21 | 22 | it 'group membership and account membership should correspond to each other' do 23 | expect(group.account_memberships.count).to eq(1) 24 | expect(account.group_memberships.count).to eq(1) 25 | expect(group.accounts).to include(account) 26 | expect(account.groups).to include(group) 27 | expect(group.account_memberships.first).to be_a(Stormpath::Resource::GroupMembership) 28 | expect(account.group_memberships.first).to be_a(Stormpath::Resource::GroupMembership) 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/resource/group_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Group, :vcr do 4 | let(:directory) { test_api_client.directories.create(directory_attrs) } 5 | after { directory.delete } 6 | 7 | describe 'instances should respond to attribute property methods' do 8 | let(:group) { directory.groups.create(group_attrs) } 9 | 10 | after { group.delete } 11 | 12 | it do 13 | [:name, :description, :status].each do |property_accessor| 14 | expect(group).to respond_to(property_accessor) 15 | expect(group).to respond_to("#{property_accessor}=") 16 | expect(group.send(property_accessor)).to be_a String 17 | end 18 | 19 | [:created_at, :modified_at].each do |property_getter| 20 | expect(group).to respond_to(property_getter) 21 | expect(group.send(property_getter)).to be_a String 22 | end 23 | 24 | expect(group.tenant).to be_a Stormpath::Resource::Tenant 25 | expect(group.directory).to be_a Stormpath::Resource::Directory 26 | expect(group.custom_data).to be_a Stormpath::Resource::CustomData 27 | expect(group.accounts).to be_a Stormpath::Resource::Collection 28 | expect(group.account_memberships).to be_a Stormpath::Resource::Collection 29 | end 30 | end 31 | 32 | describe '#create_group_with_custom_data' do 33 | it 'creates a directory with custom data' do 34 | directory.custom_data['category'] = 'classified' 35 | 36 | directory.save 37 | expect(directory.custom_data['category']).to eq('classified') 38 | end 39 | end 40 | 41 | describe '#add_or_remove_account' do 42 | context 'given an account' do 43 | let(:group) { directory.groups.create(group_attrs) } 44 | let(:account) { directory.accounts.create(account_attrs) } 45 | 46 | before { group.add_account(account) } 47 | 48 | after do 49 | group.delete 50 | account.delete 51 | end 52 | 53 | it 'adds the account to the group' do 54 | expect(group.accounts).to include(account) 55 | end 56 | 57 | it 'has one account membership resource' do 58 | expect(group.account_memberships.count).to eq(1) 59 | end 60 | 61 | it 'adds and removes the group from the account' do 62 | expect(group.accounts).to include(account) 63 | group.remove_account(account) 64 | expect(group.accounts).not_to include(account) 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/resource/linked_account_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::LinkedAccount, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory1) { test_api_client.directories.create(directory_attrs) } 6 | let(:directory2) { test_api_client.directories.create(directory_attrs) } 7 | let(:username_1) { "jekyll-#{random_number}" } 8 | let(:username_2) { "hyde-#{random_number}" } 9 | let(:account1) do 10 | directory1.accounts.create(account_attrs(email: username_1, username: username_1)) 11 | end 12 | let(:account2) do 13 | directory2.accounts.create(account_attrs(email: username_2, username: username_2)) 14 | end 15 | 16 | before do 17 | map_account_store(application, directory1, 1, true, false) 18 | map_account_store(application, directory2, 2, false, false) 19 | 20 | test_api_client.account_links.create( 21 | left_account: { 22 | href: account1.href 23 | }, 24 | right_account: { 25 | href: account2.href 26 | } 27 | ) 28 | end 29 | 30 | let(:linked_account) { account1.linked_accounts.first } 31 | 32 | after do 33 | application.delete 34 | directory1.delete 35 | directory2.delete 36 | end 37 | 38 | describe 'account link associations' do 39 | it 'should belong_to account' do 40 | expect(linked_account).to eq account2 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/resource/password_policy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::PasswordPolicy, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | 6 | after { application.delete } 7 | 8 | describe 'instances should respond to attribute property methods' do 9 | let(:directory) { test_api_client.directories.create(directory_attrs) } 10 | let(:password_policy) { directory.password_policy } 11 | 12 | before do 13 | map_account_store(application, directory, 1, false, false) 14 | end 15 | 16 | after { directory.delete } 17 | 18 | it do 19 | expect(password_policy).to be_a Stormpath::Resource::PasswordPolicy 20 | 21 | [:reset_token_ttl, :reset_email_status, :reset_success_email_status].each do |property_accessor| 22 | expect(password_policy).to respond_to(property_accessor) 23 | expect(password_policy).to respond_to("#{property_accessor}=") 24 | end 25 | 26 | expect(password_policy.strength).to be_a Stormpath::Resource::PasswordStrength 27 | expect(password_policy.reset_email_templates).to be_a Stormpath::Resource::Collection 28 | expect(password_policy.reset_success_email_templates).to be_a Stormpath::Resource::Collection 29 | 30 | expect(password_policy.reset_email_templates.first).to be_a Stormpath::Resource::EmailTemplate 31 | expect(password_policy.reset_success_email_templates.first).to be_a Stormpath::Resource::EmailTemplate 32 | end 33 | 34 | it 'can change reset_token_ttl' do 35 | expect(directory.password_policy.reset_token_ttl).to eq(24) 36 | password_policy.reset_token_ttl = 10 37 | password_policy.save 38 | expect(directory.password_policy.reset_token_ttl).to eq(10) 39 | end 40 | 41 | it 'can change reset_email_status' do 42 | expect(directory.password_policy.reset_email_status).to eq('ENABLED') 43 | password_policy.reset_email_status = 'DISABLED' 44 | password_policy.save 45 | expect(directory.password_policy.reset_email_status).to eq('DISABLED') 46 | end 47 | 48 | it 'can change reset_success_email_status' do 49 | expect(directory.password_policy.reset_success_email_status).to eq('ENABLED') 50 | password_policy.reset_success_email_status = 'DISABLED' 51 | password_policy.save 52 | expect(directory.password_policy.reset_success_email_status).to eq('DISABLED') 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/resource/password_strength_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::PasswordStrength, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | 6 | after { application.delete } 7 | 8 | describe 'instances should respond to attribute property methods' do 9 | let(:directory) { test_api_client.directories.create(directory_attrs) } 10 | let(:password_policy) { directory.password_policy } 11 | let(:password_strength) { password_policy.strength } 12 | 13 | before do 14 | map_account_store(application, directory, 1, false, false) 15 | end 16 | 17 | after { directory.delete } 18 | 19 | it do 20 | expect(password_strength).to be_a Stormpath::Resource::PasswordStrength 21 | 22 | [:min_length, 23 | :max_length, 24 | :min_lower_case, 25 | :min_upper_case, 26 | :min_numeric, 27 | :min_symbol, 28 | :min_diacritic, 29 | :prevent_reuse].each do |property_accessor| 30 | expect(password_strength).to respond_to(property_accessor) 31 | expect(password_strength).to respond_to("#{property_accessor}=") 32 | end 33 | end 34 | 35 | it 'can change attributes' do 36 | expect(password_policy.strength.min_length).to eq(8) 37 | expect(password_policy.strength.max_length).to eq(100) 38 | expect(password_policy.strength.min_lower_case).to eq(1) 39 | expect(password_policy.strength.min_upper_case).to eq(1) 40 | expect(password_policy.strength.min_numeric).to eq(1) 41 | expect(password_policy.strength.min_symbol).to eq(0) 42 | expect(password_policy.strength.min_diacritic).to eq(0) 43 | expect(password_policy.strength.prevent_reuse).to eq(0) 44 | 45 | password_strength.min_length = 10 46 | password_strength.max_length = 99 47 | password_strength.min_lower_case = 2 48 | password_strength.min_upper_case = 2 49 | password_strength.min_numeric = 2 50 | password_strength.min_symbol = 1 51 | password_strength.min_diacritic = 1 52 | password_strength.prevent_reuse = 1 53 | 54 | password_strength.save 55 | 56 | expect(password_policy.strength.min_length).to eq(10) 57 | expect(password_policy.strength.max_length).to eq(99) 58 | expect(password_policy.strength.min_lower_case).to eq(2) 59 | expect(password_policy.strength.min_upper_case).to eq(2) 60 | expect(password_policy.strength.min_numeric).to eq(2) 61 | expect(password_policy.strength.min_symbol).to eq(1) 62 | expect(password_policy.strength.min_diacritic).to eq(1) 63 | expect(password_policy.strength.prevent_reuse).to eq(1) 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/resource/phone_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Phone, :vcr do 4 | describe 'instances should respond to attribute property methods' do 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:account) { directory.accounts.create(account_attrs) } 7 | let(:phone) do 8 | account.phones.create( 9 | number: '+12025550173', 10 | name: 'test phone', 11 | description: 'this is a testing phone number' 12 | ) 13 | end 14 | 15 | after do 16 | phone.delete 17 | account.delete 18 | directory.delete 19 | end 20 | 21 | it do 22 | [:number, :name, :description].each do |property_accessor| 23 | expect(phone).to respond_to(property_accessor) 24 | expect(phone).to respond_to("#{property_accessor}=") 25 | expect(phone.send(property_accessor)).to be_a String 26 | end 27 | 28 | [:verification_status, :status, :created_at, :modified_at].each do |property_getter| 29 | expect(phone).to respond_to(property_getter) 30 | expect(phone.send(property_getter)).to be_a String 31 | end 32 | 33 | expect(phone.account).to be_a Stormpath::Resource::Account 34 | end 35 | end 36 | 37 | describe 'phone associations' do 38 | let(:app) { test_api_client.applications.create(application_attrs) } 39 | let(:application) { test_api_client.applications.get(app.href) } 40 | let(:directory) { test_api_client.directories.create(directory_attrs) } 41 | 42 | before { map_account_store(app, directory, 1, true, true) } 43 | let(:account) { directory.accounts.create(account_attrs) } 44 | let(:phone) do 45 | account.phones.create( 46 | number: '+12025550173', 47 | name: 'test phone', 48 | description: 'this is a testing phone number' 49 | ) 50 | end 51 | 52 | it 'should belong_to account' do 53 | expect(phone.account).to eq(account) 54 | end 55 | 56 | after do 57 | application.delete if application 58 | account.delete if account 59 | directory.delete if directory 60 | phone.delete if phone 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/resource/registered_saml_service_provider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::RegisteredSamlServiceProvider, vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:identity_provider) { application.saml_policy.identity_provider } 6 | let(:assertion_consumer_service_url) { 'https://some.sp.com/saml/sso/post' } 7 | let(:entity_id) { 'urn:sp:A1B2C3' } 8 | let(:registered_service_provider) do 9 | application.register_service_provider( 10 | assertion_consumer_service_url: assertion_consumer_service_url, entity_id: entity_id 11 | ) 12 | end 13 | 14 | after do 15 | registered_service_provider.delete 16 | application.delete 17 | end 18 | 19 | it 'instances should respond to attribute property methods' do 20 | expect(registered_service_provider).to be_a Stormpath::Resource::RegisteredSamlServiceProvider 21 | 22 | [:created_at, :modified_at].each do |prop_reader| 23 | expect(registered_service_provider).to respond_to(prop_reader) 24 | expect(registered_service_provider.send(prop_reader)).to be_a String 25 | end 26 | 27 | [:name, :description, :assertion_consumer_service_url, 28 | :entity_id, :name_id_format].each do |prop_accessor| 29 | expect(registered_service_provider).to respond_to(prop_accessor) 30 | expect(registered_service_provider).to respond_to("#{prop_accessor}=") 31 | end 32 | 33 | expect(registered_service_provider.encoded_x509_certificate).to be_nil 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/resource/saml_identity_provider_metadata_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::SamlIdentityProviderMetadata, vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:metadata) { application.saml_policy.identity_provider.metadata } 6 | 7 | after { application.delete } 8 | 9 | it 'instances should respond to attribute property methods' do 10 | expect(metadata).to be_a Stormpath::Resource::SamlIdentityProviderMetadata 11 | 12 | [:entity_id].each do |property_getter| 13 | expect(metadata).to respond_to(property_getter) 14 | expect(metadata.send(property_getter)).to be_a String 15 | end 16 | end 17 | 18 | describe 'saml identity provider metadata associations' do 19 | it 'should respond to identity provider' do 20 | expect(metadata.identity_provider).to be_a Stormpath::Resource::SamlIdentityProvider 21 | end 22 | 23 | it 'should respond to x509_signing_cert' do 24 | expect(metadata.x509_signing_cert).to be_a Stormpath::Resource::X509Certificate 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/resource/saml_identity_provider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::SamlIdentityProvider, vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:identity_provider) { application.saml_policy.identity_provider } 6 | 7 | after { application.delete } 8 | 9 | it 'instances should respond to attribute property methods' do 10 | expect(identity_provider).to be_a Stormpath::Resource::SamlIdentityProvider 11 | 12 | [:sso_login_endpoint].each do |property_getter| 13 | expect(identity_provider).to respond_to(property_getter) 14 | expect(identity_provider.send(property_getter)).to be_a Hash 15 | end 16 | 17 | [:signature_algorithm, :sha_fingerprint, :created_at, :modified_at].each do |property_getter| 18 | expect(identity_provider).to respond_to(property_getter) 19 | expect(identity_provider.send(property_getter)).to be_a String 20 | end 21 | 22 | [:status].each do |property_accessor| 23 | expect(application).to respond_to(property_accessor) 24 | expect(application).to respond_to("#{property_accessor}=") 25 | expect(application.send(property_accessor)).to be_a String 26 | end 27 | end 28 | 29 | describe 'saml identity provider associations' do 30 | it 'should respond to registered_saml_service_providers' do 31 | expect(identity_provider.registered_saml_service_providers).to( 32 | be_a(Stormpath::Resource::Collection) 33 | ) 34 | end 35 | 36 | it 'should respond to saml_service_provider_registrations' do 37 | expect(identity_provider.saml_service_provider_registrations).to( 38 | be_a(Stormpath::Resource::Collection) 39 | ) 40 | end 41 | 42 | it 'should respond to metadata' do 43 | expect(identity_provider.metadata).to be_a Stormpath::Resource::SamlIdentityProviderMetadata 44 | end 45 | 46 | describe 'attribute_statement_mapping_rules' do 47 | let(:rule) do 48 | { name: 'email', 49 | name_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity', 50 | account_attributes: ['email'] } 51 | end 52 | let(:response_rule) { camelize_keys(rule) } 53 | 54 | before do 55 | identity_provider.attribute_statement_mapping_rules.items = [rule] 56 | identity_provider.attribute_statement_mapping_rules.save 57 | end 58 | 59 | it 'should respond with attribute_statement_mapping_rules' do 60 | expect(identity_provider.attribute_statement_mapping_rules).to( 61 | be_a(Stormpath::Resource::AttributeStatementMappingRules) 62 | ) 63 | end 64 | 65 | it 'should contain the saved rule' do 66 | expect(identity_provider.attribute_statement_mapping_rules.items).to include(response_rule) 67 | end 68 | end 69 | 70 | it 'should respond to x509_signing_cert' do 71 | expect(identity_provider.x509_signing_cert).to be_a Stormpath::Resource::X509Certificate 72 | end 73 | end 74 | 75 | describe 'map existing registered service provider' do 76 | let(:assertion_consumer_service_url) { 'https://some.sp.com/saml/sso/post' } 77 | let(:entity_id) { 'urn:sp:A1B2C3' } 78 | let!(:service_provider) do 79 | test_api_client.registered_saml_service_providers.create( 80 | assertion_consumer_service_url: assertion_consumer_service_url, 81 | entity_id: entity_id 82 | ) 83 | end 84 | 85 | before do 86 | identity_provider.saml_service_provider_registrations.create( 87 | service_provider: { href: service_provider.href } 88 | ) 89 | end 90 | after { service_provider.delete } 91 | 92 | it 'should successfully map with the identity provider' do 93 | expect(identity_provider.registered_saml_service_providers).to include(service_provider) 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /spec/resource/saml_policy_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::SamlPolicy, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:saml_policy) { application.saml_policy } 6 | 7 | after { application.delete } 8 | 9 | it 'instances should respond to attribute property methods' do 10 | expect(saml_policy).to be_a Stormpath::Resource::SamlPolicy 11 | 12 | [:created_at, :modified_at].each do |property_getter| 13 | expect(saml_policy).to respond_to(property_getter) 14 | expect(saml_policy.send(property_getter)).to be_a String 15 | end 16 | end 17 | 18 | describe 'saml policy associations' do 19 | it 'should respond to service_provider' do 20 | expect(saml_policy.service_provider).to be_a Stormpath::Resource::SamlServiceProvider 21 | end 22 | 23 | it 'should respond to identity_provider' do 24 | expect(saml_policy.identity_provider).to be_a Stormpath::Resource::SamlIdentityProvider 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/resource/saml_service_provider_registration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::SamlServiceProviderRegistration, vcr: true do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:identity_provider) { application.saml_policy.identity_provider } 6 | let(:assertion_consumer_service_url) { 'https://some.sp.com/saml/sso/post' } 7 | let(:entity_id) { random_number } 8 | let(:options) do 9 | { 10 | assertion_consumer_service_url: assertion_consumer_service_url, 11 | entity_id: entity_id 12 | } 13 | end 14 | let(:service_provider) do 15 | Stormpath::Authentication::RegisterServiceProvider.new(identity_provider, options).call 16 | end 17 | let(:service_provider_registration) { identity_provider.saml_service_provider_registrations.first } 18 | 19 | before do 20 | service_provider 21 | service_provider_registration.default_relay_state = 'example_jwt' 22 | service_provider_registration.save 23 | end 24 | 25 | after do 26 | service_provider.delete 27 | application.delete 28 | end 29 | 30 | it 'instances should respond to attribute property methods' do 31 | expect(service_provider_registration).to be_a Stormpath::Resource::SamlServiceProviderRegistration 32 | 33 | [:created_at, :modified_at].each do |prop_reader| 34 | expect(service_provider_registration).to respond_to(prop_reader) 35 | expect(service_provider_registration.send(prop_reader)).to be_a String 36 | end 37 | 38 | [:status, :default_relay_state].each do |property_accessor| 39 | expect(service_provider_registration).to respond_to(property_accessor) 40 | expect(service_provider_registration).to respond_to("#{property_accessor}=") 41 | expect(service_provider_registration.send(property_accessor)).to be_a String 42 | end 43 | end 44 | 45 | describe 'associations' do 46 | it 'should respond to identity_provider' do 47 | expect(service_provider_registration.identity_provider).to( 48 | be_a(Stormpath::Resource::SamlIdentityProvider) 49 | ) 50 | end 51 | 52 | it 'should respond to service_provider' do 53 | expect(service_provider_registration.service_provider).to( 54 | be_a(Stormpath::Resource::RegisteredSamlServiceProvider) 55 | ) 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/resource/saml_service_provider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::SamlServiceProvider, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:service_provider) { application.saml_policy.service_provider } 6 | 7 | after { application.delete } 8 | 9 | it 'instances should respond to attribute property methods' do 10 | expect(service_provider).to be_a Stormpath::Resource::SamlServiceProvider 11 | 12 | [:created_at, :modified_at].each do |property_getter| 13 | expect(service_provider).to respond_to(property_getter) 14 | expect(service_provider.send(property_getter)).to be_a String 15 | end 16 | 17 | expect(service_provider.sso_initiation_endpoint).to be_a Hash 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/resource/schema_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Schema, :vcr do 4 | let(:application) { test_api_client.applications.create(application_attrs) } 5 | let(:directory) { test_api_client.directories.create(directory_attrs) } 6 | let(:schema) { directory.account_schema } 7 | 8 | after do 9 | directory.delete 10 | application.delete 11 | end 12 | 13 | describe 'instances should respond to attribute property methods' do 14 | it do 15 | expect(schema).to be_a Stormpath::Resource::Schema 16 | 17 | [:created_at, :modified_at].each do |property_getter| 18 | expect(schema).to respond_to(property_getter) 19 | expect(schema.send(property_getter)).to be_a String 20 | end 21 | end 22 | end 23 | 24 | describe 'schema associations' do 25 | context '#fields' do 26 | it 'should be able to get a list of fields' do 27 | expect(schema.fields).to be_a Stormpath::Resource::Collection 28 | end 29 | 30 | it 'should be able to update the required property' do 31 | surname_field = schema.fields.search(name: 'surname').first 32 | expect(surname_field.required).to be(false) 33 | 34 | surname_field.required = true 35 | surname_field.save 36 | 37 | expect(schema.fields.search(name: 'surname').first.required).to eq true 38 | end 39 | end 40 | 41 | context '#directory' do 42 | it 'should be able to fetch the directory' do 43 | expect(schema.directory).to eq directory 44 | end 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/resource/status_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'StatusOnDirectoryAndAccount', :vcr do 4 | let(:username) { "rubytest-#{random_number}" } 5 | let(:auth_request) do 6 | Stormpath::Authentication::UsernamePasswordRequest.new("#{username}#{default_domain}", 'P@$$w0rd') 7 | end 8 | let(:authenticate_user) do 9 | application.authenticate_account(auth_request) 10 | end 11 | let(:directory) { test_api_client.directories.create(directory_attrs) } 12 | let(:application) { test_api_client.applications.create(application_attrs) } 13 | let(:group) { directory.groups.create(group_attrs) } 14 | let!(:account) do 15 | directory.accounts.create(account_attrs(email: username, password: 'P@$$w0rd')) 16 | end 17 | let(:reloaded_account) { test_api_client.accounts.get(account.href) } 18 | before { map_account_store(application, directory, 0, true, true) } 19 | 20 | after do 21 | application.delete if application 22 | directory.delete if directory 23 | end 24 | 25 | it 'should respond to status getter and setter' do 26 | expect(directory.respond_to?(:status)).to be_truthy 27 | expect(directory.respond_to?(:status=)).to be_truthy 28 | 29 | expect(application.respond_to?(:status)).to be_truthy 30 | expect(application.respond_to?(:status=)).to be_truthy 31 | 32 | expect(group.respond_to?(:status)).to be_truthy 33 | expect(group.respond_to?(:status=)).to be_truthy 34 | 35 | expect(account.respond_to?(:status)).to be_truthy 36 | expect(account.respond_to?(:status=)).to be_truthy 37 | end 38 | 39 | it 'users status by default should be ENABLED' do 40 | expect(account.status).to eq('ENABLED') 41 | end 42 | 43 | it 'change user status' do 44 | account.status = 'DISABLED' 45 | account.save 46 | expect(reloaded_account.status).to eq('DISABLED') 47 | end 48 | 49 | it 'authenticate user with status ENABLED' do 50 | expect(authenticate_user.properties['account']['href']).to eq(account.href) 51 | end 52 | 53 | it "shouldn't authenticate users with status DISABLED, UNVERIFIED or LOCKED" do 54 | ['DISABLED', 'UNVERIFIED', 'LOCKED'].each do |status| 55 | account.status = status 56 | account.save 57 | expect { authenticate_user }.to raise_exception(Stormpath::Error) 58 | end 59 | end 60 | 61 | it 'assigning inappropriate status states should fail silently' do 62 | account.status = 'INVALID_STATUS_VALUE' 63 | expect { account.save }.to raise_error(Stormpath::Error) 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/resource/tenant_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Resource::Tenant, :vcr do 4 | describe 'instances should respond to attribute property methods' do 5 | let(:tenant) { test_api_client.tenant } 6 | 7 | it do 8 | expect(tenant).to be_a Stormpath::Resource::Tenant 9 | 10 | [:name, :key, :created_at, :modified_at].each do |property_getter| 11 | expect(tenant).to respond_to(property_getter) 12 | expect(tenant.send(property_getter)).to be_a String 13 | end 14 | 15 | expect(tenant.applications).to be_a Stormpath::Resource::Collection 16 | expect(tenant.directories).to be_a Stormpath::Resource::Collection 17 | expect(tenant.organizations).to be_a Stormpath::Resource::Collection 18 | expect(tenant.custom_data).to be_a Stormpath::Resource::CustomData 19 | end 20 | end 21 | 22 | describe '#create_tenant_with_custom_data' do 23 | let(:tenant) { test_api_client.tenant } 24 | 25 | it 'creates an tenant with custom data' do 26 | tenant.custom_data['category'] = 'classified' 27 | 28 | tenant.save 29 | expect(tenant.custom_data['category']).to eq('classified') 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Note: If SimpleCov starts after your application code is already loaded (via require), 2 | # it won't be able to track your files and their coverage! The SimpleCov.start must be 3 | # issued before any of your application code is required! 4 | require 'simplecov' 5 | SimpleCov.start do 6 | add_filter { |src| src.filename =~ /spec/ } 7 | end 8 | 9 | require 'stormpath-sdk' 10 | require 'pry' 11 | require 'webmock/rspec' 12 | require 'vcr' 13 | require 'jwt' 14 | require 'uuidtools' 15 | 16 | Dir['./spec/support/*.rb'].each { |file| require file } 17 | 18 | WebMock.allow_net_connect! 19 | 20 | VCR.configure do |c| 21 | c.cassette_library_dir = 'spec/fixtures/vcr_cassettes' 22 | c.hook_into :webmock 23 | c.configure_rspec_metadata! 24 | 25 | c.before_record do |i| 26 | i.request.headers.delete('Authorization') 27 | u = URI.parse(i.request.uri) 28 | i.request.uri.sub!(/:\/\/.*#{Regexp.escape(u.host)}/, "://#{u.host}") 29 | end 30 | end 31 | 32 | RSpec.configure do |c| 33 | c.mock_with :rspec do |cm| 34 | cm.syntax = :expect 35 | end 36 | 37 | c.expect_with :rspec do |ce| 38 | ce.syntax = :expect 39 | end 40 | 41 | c.include Stormpath::Test::ApiKeyHelpers 42 | c.include Stormpath::Test::EnvNamesWarning 43 | c.include Stormpath::Test::ResourceHelpers 44 | c.include Stormpath::Test::CustomDataSavePeriod 45 | 46 | Stormpath::Test::EnvNamesWarning.check_env_variable_names 47 | end 48 | -------------------------------------------------------------------------------- /spec/support/api_key_helpers.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Test 3 | module ApiKeyHelpers 4 | def test_api_key_id 5 | ENV['STORMPATH_CLIENT_APIKEY_ID'] || ENV['STORMPATH_SDK_TEST_API_KEY_ID'] 6 | end 7 | 8 | def test_api_key_secret 9 | ENV['STORMPATH_CLIENT_APIKEY_SECRET'] || ENV['STORMPATH_SDK_TEST_API_KEY_SECRET'] 10 | end 11 | 12 | def test_api_key 13 | Stormpath::ApiKey.new(test_api_key_id, test_api_key_secret) 14 | end 15 | 16 | def test_api_client 17 | @test_api_client ||= Stormpath::Client.new(api_key: test_api_key) 18 | end 19 | 20 | def get_cache_data(href) 21 | data_store = test_api_client.send :data_store 22 | data_store.send :cache_for, href 23 | end 24 | 25 | def fixture_path 26 | File.expand_path('../../fixtures/response', __FILE__) 27 | end 28 | 29 | def fixture(file) 30 | File.new(fixture_path + '/' + file) 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/support/custom_data_save_period.rb: -------------------------------------------------------------------------------- 1 | # The wait_for_custom_data_indexing method is used throughout the specs when we search 2 | # the recently saved custom data. Since Elasticsearch is being used in the backend, 3 | # a small time period is needed for the data to finish indexing. 4 | module Stormpath 5 | module Test 6 | module CustomDataSavePeriod 7 | def wait_for_custom_data_indexing 8 | sleep 5 9 | end 10 | 11 | def wait_for_resource_creation 12 | sleep rand(2..6) 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/env_names_warning.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Test 3 | module EnvNamesWarning 4 | TEST_ENV_VARS = { 5 | required: { 6 | STORMPATH_CLIENT_APIKEY_ID: 'The id from your Stormpath API Key', 7 | STORMPATH_CLIENT_APIKEY_SECRET: 'The secret from your Stormpath API Key' 8 | }, 9 | deprecated: { 10 | STORMPATH_SDK_TEST_API_KEY_ID: 'The id from your Stormpath API Key', 11 | STORMPATH_SDK_TEST_API_KEY_SECRET: 'The secret from your Stormpath API Key' 12 | } 13 | }.freeze 14 | 15 | def self.test_missing_deprecated_env_vars 16 | TEST_ENV_VARS[:deprecated].reject do |var, _| 17 | ENV[var.to_s] 18 | end 19 | end 20 | 21 | def self.test_missing_required_env_vars 22 | TEST_ENV_VARS[:required].reject do |var, _| 23 | ENV[var.to_s] 24 | end 25 | end 26 | 27 | def self.env_vars_not_set? 28 | !test_missing_deprecated_env_vars.empty? && !test_missing_required_env_vars.empty? 29 | end 30 | 31 | def self.check_env_variable_names 32 | unless Stormpath::Test::EnvNamesWarning.test_missing_required_env_vars.empty? 33 | warn_message = "\n\n" 34 | 40.times { warn_message << '*' } 35 | warn_message << 'STORMPATH RUBY SDK' 36 | 52.times { warn_message << '*' } 37 | warn_message << "\n\n" 38 | warn_message << TEST_ENV_VARS[:deprecated].map do |var, _| 39 | "\t#{var} will be deprecated in the next release of the Ruby SDK." 40 | end.join("\n") 41 | warn_message << "\n\tPlease update your environment variables to use the new names:\n" 42 | warn_message << "\n\t\texport STORMPATH_CLIENT_APIKEY_ID=your_api_key_id" 43 | warn_message << "\n\t\texport STORMPATH_CLIENT_APIKEY_SECRET=your_api_key_secret\n\n" 44 | 110.times { warn_message << '*' } 45 | warn "#{warn_message}\n\n" 46 | end 47 | 48 | if Stormpath::Test::EnvNamesWarning.env_vars_not_set? 49 | set_up_message = "In order to run the specs of the Stormpath SDK you need to setup the following environment variables:\n\t" 50 | set_up_message << Stormpath::Test::EnvNamesWarning.test_missing_required_env_vars.map do |var, message| 51 | "#{var} : #{message}" 52 | end.join("\n\t") 53 | set_up_message << "\nBe sure to configure these before running the specs again." 54 | raise set_up_message 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/support/resource_factory.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Test 3 | class ResourceFactory 4 | URL_PREFIX = Stormpath::DataStore::DEFAULT_BASE_URL 5 | 6 | def initialize 7 | @id_count = 0 8 | end 9 | 10 | def resource(type, depth = 1, associations = []) 11 | id = id_for type 12 | plural = "#{type}s" 13 | resource = { 'href' => "#{URL_PREFIX}/#{plural}/#{id}" } 14 | 15 | if depth > 0 16 | resource['name'] = "#{type} #{id}" 17 | associations.each do |assoc| 18 | resource[assoc] = if assoc =~ /s$/ 19 | collection type, assoc.sub(/s$/, ''), depth - 1 20 | else 21 | resource assoc, depth - 1 22 | end 23 | end 24 | end 25 | 26 | resource 27 | end 28 | 29 | def collection(parent, type, depth = 1, associations = []) 30 | id = id_for parent 31 | collection = { 32 | 'href' => "#{URL_PREFIX}/#{parent}s/#{id}/#{type}s", 33 | 'items' => [ 34 | resource(type, depth, associations), 35 | resource(type, depth, associations) 36 | ] 37 | } 38 | 39 | collection 40 | end 41 | 42 | def id_for(type) 43 | @id_count += 1 44 | "#{type[0, 3]}#{@id_count}" 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/support/resource_matchers.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :be_link do 2 | match do |actual| 3 | actual.length == 1 && actual['href'] 4 | end 5 | end 6 | 7 | RSpec::Matchers.define :be_resource do 8 | match do |actual| 9 | actual.length > 1 && actual['href'] && !actual['items'] 10 | end 11 | end 12 | 13 | RSpec::Matchers.define :be_link_collection do 14 | match do |actual| 15 | actual['href'] && actual['items'] && actual['items'].all? do |item| 16 | item && item.length == 1 && item['href'] 17 | end 18 | end 19 | end 20 | 21 | RSpec::Matchers.define :be_resource_collection do 22 | match do |actual| 23 | actual['href'] && actual['items'] && actual['items'].all? do |item| 24 | item && item.length > 1 && item['href'] && !item['items'] 25 | end 26 | end 27 | end 28 | 29 | RSpec::Matchers.define :have_stt_in_header do |expected| 30 | match do |jwt| 31 | header = JSON.parse(Base64.decode64(jwt.split('.').first)) 32 | header.include?('stt') && header['stt'] == expected 33 | end 34 | end 35 | 36 | RSpec::Matchers.define :be_boolean do 37 | match do |actual| 38 | actual == true || actual == false 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/support/test_cache_stores.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Test 3 | class FakeStore1 < Stormpath::Cache::MemoryStore 4 | end 5 | 6 | class FakeStore2 < Stormpath::Cache::MemoryStore 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/support/test_request_executor.rb: -------------------------------------------------------------------------------- 1 | module Stormpath 2 | module Test 3 | class TestRequestExecutor 4 | attr_writer :response 5 | 6 | def execute_request(_request) 7 | Stormpath::Http::Response.new(200, 'text/json', @response, @response.length) 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/util/uri_builder_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Stormpath::Util::UriBuilder do 4 | context 'url contains forward slash' do 5 | let(:url) { 'https://kfsdlk34223lke:3o5pfd9jlc/s29kf@api.stormpath.com/accounts' } 6 | let(:builder) { Stormpath::Util::UriBuilder.new(url) } 7 | 8 | it 'should contain escaped url' do 9 | expect(builder.escaped_url).to eq 'https://kfsdlk34223lke:3o5pfd9jlc%2Fs29kf@api.stormpath.com/accounts' 10 | end 11 | 12 | it 'should contain userinfo' do 13 | expect(builder.userinfo).to eq 'kfsdlk34223lke:3o5pfd9jlc/s29kf' 14 | end 15 | 16 | it 'should contain uri' do 17 | expect(builder.uri).to eq URI('https://kfsdlk34223lke:3o5pfd9jlc%2Fs29kf@api.stormpath.com/accounts') 18 | end 19 | end 20 | 21 | context "url doesn't contain forward slash" do 22 | let(:url) { 'https://kfsdlk34223lke:3o5pfd9jlcs29kf@api.stormpath.com/accounts' } 23 | let(:builder) { Stormpath::Util::UriBuilder.new(url) } 24 | 25 | it 'should contain escaped url' do 26 | expect(builder.escaped_url).to eq 'https://kfsdlk34223lke:3o5pfd9jlcs29kf@api.stormpath.com/accounts' 27 | end 28 | 29 | it 'should contain userinfo' do 30 | expect(builder.userinfo).to eq 'kfsdlk34223lke:3o5pfd9jlcs29kf' 31 | end 32 | 33 | it 'should contain uri' do 34 | expect(builder.uri).to eq URI('https://kfsdlk34223lke:3o5pfd9jlcs29kf@api.stormpath.com/accounts') 35 | end 36 | end 37 | 38 | context 'url is invalid' do 39 | let(:url) { 'invalid url' } 40 | 41 | it 'should raise error' do 42 | expect do 43 | Stormpath::Util::UriBuilder.new(url).uri 44 | end.to raise_error 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /stormpath-sdk.gemspec: -------------------------------------------------------------------------------- 1 | require "./lib/stormpath-sdk/version" 2 | 3 | Gem::Specification.new do |s| 4 | s.name = 'stormpath-sdk' 5 | s.version = Stormpath::VERSION 6 | s.date = Stormpath::VERSION_DATE 7 | s.summary = "Stormpath SDK" 8 | s.description = "Stormpath SDK used to interact with the Stormpath REST API" 9 | s.authors = ["Stormpath, Inc", "Elder Crisostomo"] 10 | s.email = 'support@stormpath.com' 11 | s.homepage = 'https://github.com/stormpath/stormpath-sdk-ruby' 12 | s.license = 'Apache-2.0' 13 | 14 | s.platform = Gem::Platform::RUBY 15 | s.require_paths = %w[lib] 16 | s.files = `git ls-files`.split("\n") 17 | 18 | s.add_dependency('multi_json', '>= 1.3.6') 19 | s.add_dependency('httpclient', '>= 2.2.5') 20 | s.add_dependency('uuidtools', '>= 2.1.3') 21 | if RUBY_VERSION < '2.2.2' 22 | s.add_dependency('activesupport', '>= 3.2.8', '< 5.0') 23 | else 24 | s.add_dependency('activesupport', '>= 3.2.8') 25 | end 26 | s.add_dependency('properties-ruby', "~> 0.0.4") 27 | s.add_dependency('http-cookie', "~> 1.0.2") 28 | s.add_dependency('java_properties') 29 | s.add_dependency('jwt', '>= 1.5.0') 30 | 31 | s.add_development_dependency 'rake', '~> 0.9.2' 32 | s.add_development_dependency 'rspec', '~> 3.0.0' 33 | s.add_development_dependency 'guard-rspec', '~> 4.2.10' 34 | s.add_development_dependency 'rack', '~> 1.4.1' 35 | s.add_development_dependency 'webmock', '~> 1.17.4' 36 | s.add_development_dependency 'simplecov', '~> 0.7.1' 37 | s.add_development_dependency 'pry', '~> 0.9.12.1' 38 | s.add_development_dependency 'vcr', '~> 2.9.2' 39 | s.add_development_dependency 'timecop', '~> 0.6.1' 40 | s.add_development_dependency 'redis', '~> 3.0.4' 41 | s.add_development_dependency 'memcached', '~> 1.8.0' 42 | s.add_development_dependency 'listen', '~> 3.0.6' 43 | s.add_development_dependency 'fivemat', '~> 1.3.2' 44 | 45 | s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'stormpath-sdk', '--main'] 46 | end 47 | --------------------------------------------------------------------------------