stormpath-sdk 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +3 -3
  4. data/CHANGES.md +8 -0
  5. data/lib/stormpath-sdk.rb +8 -0
  6. data/lib/stormpath-sdk/auth/create_factor.rb +64 -0
  7. data/lib/stormpath-sdk/data_store.rb +17 -1
  8. data/lib/stormpath-sdk/oauth/authenticator.rb +2 -1
  9. data/lib/stormpath-sdk/oauth/challenge_factor_grant.rb +25 -0
  10. data/lib/stormpath-sdk/oauth/challenge_factor_grant_request.rb +16 -0
  11. data/lib/stormpath-sdk/resource/account.rb +6 -0
  12. data/lib/stormpath-sdk/resource/account_link.rb +1 -1
  13. data/lib/stormpath-sdk/resource/challenge.rb +26 -0
  14. data/lib/stormpath-sdk/resource/collection.rb +0 -1
  15. data/lib/stormpath-sdk/resource/directory.rb +1 -0
  16. data/lib/stormpath-sdk/resource/factor.rb +26 -0
  17. data/lib/stormpath-sdk/resource/field.rb +20 -0
  18. data/lib/stormpath-sdk/resource/linked_account.rb +1 -1
  19. data/lib/stormpath-sdk/resource/phone.rb +21 -0
  20. data/lib/stormpath-sdk/resource/schema.rb +21 -0
  21. data/lib/stormpath-sdk/version.rb +2 -2
  22. data/spec/auth/create_factor_spec.rb +92 -0
  23. data/spec/auth/http_basic_authentication_spec.rb +3 -3
  24. data/spec/auth/http_bearer_authentication_spec.rb +3 -3
  25. data/spec/client_spec.rb +25 -25
  26. data/spec/oauth/access_token_authentication_result_spec.rb +3 -3
  27. data/spec/provider/provider_spec.rb +2 -2
  28. data/spec/resource/account_creation_policy_spec.rb +2 -2
  29. data/spec/resource/account_link_spec.rb +2 -2
  30. data/spec/resource/account_spec.rb +196 -12
  31. data/spec/resource/account_store_mapping_spec.rb +3 -3
  32. data/spec/resource/account_store_spec.rb +4 -4
  33. data/spec/resource/api_key_spec.rb +3 -3
  34. data/spec/resource/application_spec.rb +74 -33
  35. data/spec/resource/challenge_spec.rb +53 -0
  36. data/spec/resource/collection_spec.rb +6 -6
  37. data/spec/resource/custom_data_spec.rb +2 -2
  38. data/spec/resource/directory_spec.rb +27 -21
  39. data/spec/resource/email_template_spec.rb +2 -2
  40. data/spec/resource/factor_spec.rb +124 -0
  41. data/spec/resource/field_spec.rb +35 -0
  42. data/spec/resource/group_membership_spec.rb +3 -3
  43. data/spec/resource/group_spec.rb +3 -3
  44. data/spec/resource/linked_account_spec.rb +2 -2
  45. data/spec/resource/organization_spec.rb +6 -6
  46. data/spec/resource/password_policy_spec.rb +2 -2
  47. data/spec/resource/password_strength_spec.rb +2 -2
  48. data/spec/resource/phone_spec.rb +63 -0
  49. data/spec/resource/schema_spec.rb +39 -0
  50. data/spec/resource/status_spec.rb +4 -4
  51. data/spec/spec_helper.rb +6 -3
  52. data/spec/support/custom_data_storage_behavior.rb +2 -2
  53. data/spec/support/mocked_provider_accounts.rb +106 -0
  54. data/spec/support/resource_helpers.rb +20 -16
  55. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7c94bbec690d16f6c04eda0f7e46dd79c9406747
4
- data.tar.gz: 10271a383fb9537813d22cacc1646df9c67b709d
3
+ metadata.gz: f4ee6a6b7b3e99f340ad7056d571cc497cc47163
4
+ data.tar.gz: b4191c5270f3d690590d288553609fdef02a4174
5
5
  SHA512:
6
- metadata.gz: 284ad0976afabc1777161def9266669f855f2eb3bcb6eaaa026bb66e195de22537da218f7cea5b33d68554202d28d5f4714e39e9c7e0e01f91de2b94dabf68e0
7
- data.tar.gz: dc7e80f1a5501e989c7fab8f5b1f2ee889b3c71ae9f75bb1a91bb023e593bed70c83d8ee6bf1da8288556f73a709405c9f6245a12d2019f6d469326a1ff07c59
6
+ metadata.gz: f7600ac17e42f60a5b62df5d396a5534fa9907b19cbd1ce77115846c7df88dbfe0409e9cba0781f5e9261743cd36d4e3de8844aa7d91a03a84213c4a93f42f6c
7
+ data.tar.gz: 8762d8e4df8a3f557a4f2c48505593d89fd27050a5dd9dc6c2a3e6b3d058c1c18bdf69353412b8608dd90cc55f276b4bae6d4e6c11148cac98aec892b507af68
data/.gitignore CHANGED
@@ -13,4 +13,4 @@ tmp/*
13
13
  *.gem
14
14
  .bundle/
15
15
  dump.rdb
16
- .ruby-version
16
+ .ruby-version
@@ -6,8 +6,8 @@ services:
6
6
  - redis-server
7
7
  - memcached
8
8
  before_install:
9
- - gem install bundler
9
+ - gem install bundler
10
10
  env:
11
11
  global:
12
- - secure: MeyjZGgySZvpYVRm2i7wkrhvu9KUeU7eQ5aKj7FXqIYlQe3T67k+KKA3Ejp6WC3wUEVPUFseWMZCuNkRc0UeGA5/4e4LLc++XuaZn1jLTm1yNofh/CFAAjt5VdIYz4R7sKxpyLxs0orK2+HcaiCoqSDj7ehw2SlDca9VEi0GoQk=
13
- - secure: MrtbhfH1IfwDkkvf0pq6trgj68to/fK4c+L1daKvMaNiNvwggbA3s0ea9QjHxXfWmPqL5bf8Q5N7YqXUw8cLpRPrKUA65JkyhyzIju8FgzXz83aCvjJD+5XhJIGzpLM8qHeKh7F0K6/iURTKIUgZXbguK4HpEeCMrrdPYcof3Ew=
12
+ - secure: JObfQKlPYrwupzv2ASkCQWD7TMqD6D9OfbVdUe/sot91fVgoQIs7vGlQPYNz6aTgoAZfEKptrzXzA0KOsGKRDjN0MSkY/PevPxdb+81YTDdldKD5GCc5srWVDpwhRJvKU8ufHdrTcvf+Weulu4egUHoqOerlBcexTO/Erbe8/M4=
13
+ - secure: K24I2/DC4Z6SeosQaR4suZij4yacteVzXqLexJ+LSlxZP7j1T72O3JLtc7/SLm8RFOJkiH/csTgbZmLNAWZO8c0Y4fWAvIC/I1xfoCr57udfQPIe83qdtpVetyYs1BGcqlRboGpqxtOewGHHuHtIge4bjD5l1hHA+WaIdVa4GfI=
data/CHANGES.md CHANGED
@@ -1,6 +1,14 @@
1
1
  stormpath-sdk-ruby Changelog
2
2
  ============================
3
3
 
4
+ Version 1.4.0
5
+ -------------
6
+
7
+ Released on November 22, 2016
8
+
9
+ - Implement Multifactor Authentication with SMS and google-authenticator
10
+
11
+
4
12
  Version 1.3.1
5
13
  -------------
6
14
 
@@ -60,6 +60,11 @@ module Stormpath
60
60
  autoload :PasswordPolicy, 'stormpath-sdk/resource/password_policy'
61
61
  autoload :EmailTemplate, 'stormpath-sdk/resource/email_template'
62
62
  autoload :PasswordStrength, 'stormpath-sdk/resource/password_strength'
63
+ autoload :Phone, 'stormpath-sdk/resource/phone'
64
+ autoload :Factor, 'stormpath-sdk/resource/factor'
65
+ autoload :Challenge, 'stormpath-sdk/resource/challenge'
66
+ autoload :Schema, 'stormpath-sdk/resource/schema'
67
+ autoload :Field, 'stormpath-sdk/resource/field'
63
68
  end
64
69
 
65
70
  module Cache
@@ -80,6 +85,7 @@ module Stormpath
80
85
  autoload :BasicAuthenticator, 'stormpath-sdk/auth/basic_authenticator'
81
86
  autoload :HttpBasicAuthentication, 'stormpath-sdk/auth/http_basic_authentication'
82
87
  autoload :HttpBearerAuthentication, 'stormpath-sdk/auth/http_bearer_authentication'
88
+ autoload :CreateFactor, 'stormpath-sdk/auth/create_factor'
83
89
  end
84
90
 
85
91
  module Provider
@@ -140,5 +146,7 @@ module Stormpath
140
146
  autoload :ClientCredentialsGrant, 'stormpath-sdk/oauth/client_credentials_grant'
141
147
  autoload :SocialGrantRequest, 'stormpath-sdk/oauth/social_grant_request'
142
148
  autoload :SocialGrant, 'stormpath-sdk/oauth/social_grant'
149
+ autoload :ChallengeFactorGrantRequest, 'stormpath-sdk/oauth/challenge_factor_grant_request'
150
+ autoload :ChallengeFactorGrant, 'stormpath-sdk/oauth/challenge_factor_grant'
143
151
  end
144
152
  end
@@ -0,0 +1,64 @@
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 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
+ data_store.execute_raw_request(href, resource, Stormpath::Resource::Factor)
32
+ end
33
+
34
+ private
35
+
36
+ def href
37
+ "#{account.href}/factors#{'?challenge=true' if challenge}"
38
+ end
39
+
40
+ def resource
41
+ {}.tap do |body|
42
+ body[:type] = type
43
+ body[:phone] = phone if phone
44
+ body[:challenge] = { message: "#{challenge[:message]} ${code}" } if challenge
45
+ add_custom_options(body)
46
+ end
47
+ end
48
+
49
+ def determine_type(type)
50
+ raise Stormpath::Error unless type == :sms || type == :google_authenticator
51
+ type.to_s.sub('_', '-')
52
+ end
53
+
54
+ def add_custom_options(body)
55
+ if custom_options
56
+ body[:accountName] = custom_options[:account_name] if custom_options[:account_name]
57
+ body[:issuer] = custom_options[:issuer] if custom_options[:issuer]
58
+ body[:status] = custom_options[:status] if custom_options[:status]
59
+ end
60
+ body
61
+ end
62
+ end
63
+ end
64
+ end
@@ -101,6 +101,21 @@ class Stormpath::DataStore
101
101
  return nil
102
102
  end
103
103
 
104
+ def execute_raw_request(href, body, klass)
105
+ request = Request.new('POST', href, nil, {}, body.to_json, @api_key)
106
+ apply_default_request_headers(request)
107
+ response = @request_executor.execute_request(request)
108
+ result = response.body.length > 0 ? MultiJson.load(response.body) : ''
109
+
110
+ if response.error?
111
+ error = Stormpath::Resource::Error.new result
112
+ raise Stormpath::Error.new(error)
113
+ end
114
+
115
+ cache_walk(result)
116
+ instantiate(klass, result)
117
+ end
118
+
104
119
  private
105
120
 
106
121
  def needs_to_be_fully_qualified?(href)
@@ -296,7 +311,8 @@ class Stormpath::DataStore
296
311
  property = resource.get_property name, ignore_camelcasing: ignore_camelcasing
297
312
 
298
313
  # Special use cases are with Custom Data, Provider and ProviderData, their hashes should not be simplified
299
- if property.kind_of?(Hash) and !resource_nested_submittable(resource, name) and name != "items"
314
+ # As of the implementation for MFA, Phone resource is added too
315
+ if property.kind_of?(Hash) and !resource_nested_submittable(resource, name) and name != "items" and name != 'phone'
300
316
  property = to_simple_reference name, property
301
317
  end
302
318
 
@@ -24,7 +24,8 @@ module Stormpath
24
24
  id_site_token: IdSiteGrant,
25
25
  stormpath_token: StormpathTokenGrant,
26
26
  client_credentials: ClientCredentialsGrant,
27
- stormpath_social: SocialGrant
27
+ stormpath_social: SocialGrant,
28
+ stormpath_factor_challenge: ChallengeFactorGrant
28
29
  }.freeze
29
30
  end
30
31
  end
@@ -0,0 +1,25 @@
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
@@ -0,0 +1,16 @@
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
@@ -40,6 +40,9 @@ class Stormpath::Resource::Account < Stormpath::Resource::Instance
40
40
 
41
41
  has_many :api_keys, can: [:create]
42
42
 
43
+ has_many :phones, can: [:get, :create]
44
+ has_many :factors, can: [:get, :create]
45
+
43
46
  def add_group group
44
47
  client.group_memberships.create group: group, account: self
45
48
  end
@@ -64,4 +67,7 @@ class Stormpath::Resource::Account < Stormpath::Resource::Instance
64
67
  instance_variable_set "@_provider_data", provider_data
65
68
  end
66
69
 
70
+ def create_factor(type, options = {})
71
+ Stormpath::Authentication::CreateFactor.new(client, self, type, options).save
72
+ end
67
73
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2012 Stormpath, Inc.
2
+ # Copyright 2016 Stormpath, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,26 @@
1
+ #
2
+ # Copyright 2012 Stormpath, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ class Stormpath::Resource::Challenge < Stormpath::Resource::Instance
17
+ prop_accessor :message
18
+ prop_reader :status, :created_at, :modified_at
19
+
20
+ belongs_to :factor
21
+ belongs_to :account
22
+
23
+ def validate(code)
24
+ data_store.execute_raw_request href, { code: code }, Stormpath::Resource::Challenge
25
+ end
26
+ end
@@ -80,7 +80,6 @@ class Stormpath::Resource::Collection
80
80
  iterate(collection_href, client, item_class, criteria, &block)
81
81
  end
82
82
  end
83
-
84
83
  end
85
84
 
86
85
  class CollectionPage < Stormpath::Resource::Base
@@ -28,6 +28,7 @@ class Stormpath::Resource::Directory < Stormpath::Resource::Instance
28
28
  has_one :custom_data
29
29
  has_one :password_policy
30
30
  has_one :account_creation_policy
31
+ has_one :account_schema, class_name: :schema
31
32
 
32
33
  def provider
33
34
  internal_instance = instance_variable_get "@_provider"
@@ -0,0 +1,26 @@
1
+ #
2
+ # Copyright 2012 Stormpath, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ class Stormpath::Resource::Factor < Stormpath::Resource::Instance
17
+ prop_accessor :type, :account_name, :issuer, :status
18
+ prop_reader :verification_status, :secret, :key_uri, :base64_q_r_image
19
+ alias_method :qr_code, :base64_q_r_image
20
+
21
+ has_many :challenges, can: [:get, :create]
22
+ has_one :most_recent_challenge, class_name: :challenge
23
+ has_one :phone
24
+
25
+ belongs_to :account
26
+ end
@@ -0,0 +1,20 @@
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
+ class Stormpath::Resource::Field < Stormpath::Resource::Instance
17
+ prop_reader :name, :required, :created_at, :modified_at
18
+
19
+ belongs_to :schema
20
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2012 Stormpath, Inc.
2
+ # Copyright 2016 Stormpath, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,21 @@
1
+ #
2
+ # Copyright 2012 Stormpath, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ class Stormpath::Resource::Phone < Stormpath::Resource::Instance
17
+ prop_accessor :number, :name, :description
18
+ prop_reader :verification_status, :status, :created_at, :modified_at
19
+
20
+ belongs_to :account
21
+ end
@@ -0,0 +1,21 @@
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
+ class Stormpath::Resource::Schema < Stormpath::Resource::Instance
17
+ prop_reader :created_at, :modified_at
18
+
19
+ has_many :fields
20
+ belongs_to :directory
21
+ end
@@ -14,6 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
- VERSION = '1.3.1'
18
- VERSION_DATE = '2016-11-07'
17
+ VERSION = '1.4.0'
18
+ VERSION_DATE = '2016-11-22'
19
19
  end
@@ -0,0 +1,92 @@
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