castle-rb 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/castle-rb/client.rb +12 -120
  3. data/lib/castle-rb/errors.rb +0 -1
  4. data/lib/castle-rb/ext/her.rb +1 -1
  5. data/lib/castle-rb/models/event.rb +0 -2
  6. data/lib/castle-rb/models/model.rb +2 -11
  7. data/lib/castle-rb/models/user.rb +0 -16
  8. data/lib/castle-rb/request.rb +0 -25
  9. data/lib/castle-rb/utils.rb +0 -1
  10. data/lib/castle-rb/version.rb +1 -1
  11. data/lib/castle-rb.rb +0 -9
  12. metadata +3 -37
  13. data/lib/castle-rb/models/backup_codes.rb +0 -4
  14. data/lib/castle-rb/models/challenge.rb +0 -7
  15. data/lib/castle-rb/models/monitoring.rb +0 -6
  16. data/lib/castle-rb/models/pairing.rb +0 -11
  17. data/lib/castle-rb/models/recommendation.rb +0 -3
  18. data/lib/castle-rb/models/session.rb +0 -6
  19. data/lib/castle-rb/models/trusted_device.rb +0 -5
  20. data/lib/castle-rb/session_store.rb +0 -35
  21. data/lib/castle-rb/session_token.rb +0 -39
  22. data/lib/castle-rb/token_store.rb +0 -30
  23. data/spec/fixtures/vcr_cassettes/challenge_create.yml +0 -48
  24. data/spec/fixtures/vcr_cassettes/challenge_verify.yml +0 -42
  25. data/spec/fixtures/vcr_cassettes/session_create.yml +0 -47
  26. data/spec/fixtures/vcr_cassettes/session_refresh.yml +0 -47
  27. data/spec/fixtures/vcr_cassettes/session_verify.yml +0 -47
  28. data/spec/fixtures/vcr_cassettes/user_find.yml +0 -44
  29. data/spec/fixtures/vcr_cassettes/user_find_non_existing.yml +0 -42
  30. data/spec/fixtures/vcr_cassettes/user_import.yml +0 -46
  31. data/spec/fixtures/vcr_cassettes/user_update.yml +0 -47
  32. data/spec/helpers_spec.rb +0 -38
  33. data/spec/jwt_spec.rb +0 -67
  34. data/spec/utils_spec.rb +0 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 746bd18a03497a62f707772ea478816011e590f0
4
- data.tar.gz: bce6362eb4c5db47f08b5294af0fbf472b9b20d2
3
+ metadata.gz: 640bc0f13f0393b62ee5de5d1f47e43b9932f513
4
+ data.tar.gz: 47c64d6658e5b6f9674c5efde4a071391b6d3116
5
5
  SHA512:
6
- metadata.gz: 008277ce9a2c0d07c19c1920b2e97013c17fd40b4af40f1d4c325d46d39bccc4975b8c1b1a11a895084ec9a45ff9df9d23d0b9c17f59457db3fc32e342f6bf1c
7
- data.tar.gz: b68d88ec6d2fdeb8f44db528c9b56b509c1eac4707790932c993ba255d8018c0fd090d5d1335d2fe6d897c197e0b00cd9acb3fafa48e019c7dbc176ef5f9f8fa
6
+ metadata.gz: 947c9f2e92959262be33039e4de4c91f5a14b9da7c0f7488d090dadbd4fadfedf235ca96cd1954724d3f1ef0800a324a704ad0310bef95acc036598010f0eee2
7
+ data.tar.gz: 5cbea1e70be0616b133011aa5a77acc2b44962074eda994edf56457c62430c165ff452fd3dc3120e57cef637e87389df9542c1074fc3e0260497fd64b138fb2a
@@ -3,144 +3,36 @@ module Castle
3
3
 
4
4
  attr_accessor :request_context
5
5
 
6
- def self.install_proxy_methods(*names)
7
- names.each do |name|
8
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
9
- def #{name}(*args)
10
- Castle::User.new('$current').#{name}(*args)
11
- end
12
- RUBY
13
- end
14
- end
15
-
16
- install_proxy_methods :challenges, :events, :sessions, :pairings,
17
- :backup_codes, :generate_backup_codes, :trusted_devices,
18
- :enable_mfa!, :disable_mfa!
19
-
20
6
  def initialize(request, response, opts = {})
21
7
  # Save a reference in the per-request store so that the request
22
8
  # middleware in request.rb can access it
23
9
  RequestStore.store[:castle] = self
24
10
 
25
- if response.class.name == 'ActionDispatch::Cookies::CookieJar'
26
- cookies = Castle::CookieStore::Rack.new(response)
27
- else
28
- cookies = Castle::CookieStore::Base.new(request, response)
29
- end
30
-
31
- @store = Castle::TokenStore.new(cookies)
32
-
33
11
  @request_context = {
34
12
  ip: request.ip,
35
13
  user_agent: request.user_agent,
36
- cookie_id: cookies['__cid'] || '',
14
+ cookie_id: extract_cookies(request, response)['__cid'] || '',
37
15
  headers: header_string(request)
38
16
  }
39
17
  end
40
18
 
41
- def session_token
42
- @store.session_token
43
- end
44
-
45
- def session_token=(session_token)
46
- @store.session_token = session_token
47
- end
48
-
49
- def authorize!
50
- unless @store.session_token
51
- raise Castle::UserUnauthorizedError,
52
- 'Need to call login before authorize'
53
- end
54
-
55
- if @store.session_token.expired?
56
- Castle::Monitoring.heartbeat
57
- end
58
-
59
- if mfa_in_progress?
60
- logout
61
- raise Castle::UserUnauthorizedError,
62
- 'Logged out due to being unverified'
63
- end
64
-
65
- if mfa_required? && !device_trusted?
66
- raise Castle::ChallengeRequiredError
67
- end
68
- end
69
-
70
- def authorized?
71
- !!@store.session_token
72
- end
73
-
74
- def login(user_id, user_attrs = {})
75
- # Clear the session token if any
76
- @store.session_token = nil
77
-
78
- user = Castle::User.new(user_id.to_s)
79
- session = user.sessions.create(
80
- user: user_attrs, trusted_device_token: @store.trusted_device_token)
81
-
82
- # Set the session token for use in all subsequent requests
83
- @store.session_token = session.token
84
-
85
- session
19
+ def track(opts = {})
20
+ # Castle::Event.post('/v1/events', opts)
21
+ Castle::Event.create(opts)
86
22
  end
87
23
 
88
- def logout
89
- return unless @store.session_token
90
-
91
- # Destroy the current session specified in the session token
92
- begin
93
- sessions.destroy('$current')
94
- rescue Castle::ApiError # ignored
95
- end
96
-
97
- # Clear the session token
98
- @store.session_token = nil
99
- end
24
+ private
100
25
 
101
- def trust_device(attrs = {})
102
- unless @store.session_token
103
- raise Castle::UserUnauthorizedError,
104
- 'Need to call login before trusting device'
26
+ def extract_cookies(request, response)
27
+ # Extract the cookie set by the Castle Javascript
28
+ if response.class.name == 'ActionDispatch::Cookies::CookieJar'
29
+ Castle::CookieStore::Rack.new(response)
30
+ else
31
+ Castle::CookieStore::Base.new(request, response)
105
32
  end
106
- trusted_device = trusted_devices.create(attrs)
107
-
108
- # Set the session token for use in all subsequent requests
109
- @store.trusted_device_token = trusted_device.token
110
- end
111
-
112
- def mfa_enabled?
113
- @store.session_token ? @store.session_token.mfa_enabled? : false
114
33
  end
115
34
 
116
- def device_trusted?
117
- @store.session_token ? @store.session_token.device_trusted? : false
118
- end
119
-
120
- def mfa_in_progress?
121
- @store.session_token ? @store.session_token.mfa_in_progress? : false
122
- end
123
-
124
- def mfa_required?
125
- @store.session_token ? @store.session_token.mfa_required? : false
126
- end
127
-
128
- def has_default_pairing?
129
- @store.session_token ? @store.session_token.has_default_pairing? : false
130
- end
131
-
132
- def track(opts = {})
133
- Castle::Event.post('/v1/events', opts)
134
- end
135
-
136
- def recommendation(opts = {})
137
- Castle::Recommendation.get('/v1/recommendation', opts)
138
- end
139
-
140
- alias_method :recommend, :recommendation
141
-
142
- private
143
-
35
+ # Serialize HTTP headers
144
36
  def header_string(request)
145
37
  scrub_headers = ['Cookie']
146
38
 
@@ -13,4 +13,3 @@ class Castle::UserUnauthorizedError < Castle::ApiError; end
13
13
  class Castle::InvalidParametersError < Castle::ApiError; end
14
14
 
15
15
  class Castle::UnauthorizedError < Castle::ApiError; end
16
- class Castle::ChallengeRequiredError < Castle::ApiError; end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Add destroy to association: user.challenges.destroy(id)
2
+ # Add destroy to association: user.events.destroy(id)
3
3
  #
4
4
  module Her::Model::Associations
5
5
  class AssociationProxy
@@ -1,7 +1,5 @@
1
1
  module Castle
2
2
  class Event < Model
3
- collection_path "users/:user_id/events"
4
- belongs_to :user
5
3
  has_one :context
6
4
  end
7
5
  end
@@ -28,15 +28,6 @@ module Castle
28
28
  attrs
29
29
  end
30
30
 
31
- # Remove the auto-generated embedded User model to prevent recursion
32
- def to_json
33
- attrs = attributes
34
- if attrs['user'] && attrs['user']['id'] == '$current'
35
- attrs.delete 'user'
36
- end
37
- attrs.to_json
38
- end
39
-
40
31
  METHODS.each do |method|
41
32
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
42
33
  def self.instance_#{method}(action)
@@ -47,7 +38,7 @@ module Castle
47
38
 
48
39
  def self.instance_custom(method, action)
49
40
  #
50
- # Add method calls to association: user.challenges.verify(id, attributes)
41
+ # Add method calls to association: user.events.some_method(id, attributes)
51
42
  #
52
43
  AssociationProxy.class_eval <<-RUBY, __FILE__, __LINE__ + 1
53
44
  install_proxy_methods :association, :#{action}
@@ -59,7 +50,7 @@ module Castle
59
50
  RUBY
60
51
 
61
52
  #
62
- # Add method call to instance: user.enable_mfa
53
+ # Add method call to instance: user.enable_something
63
54
  #
64
55
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
65
56
  def #{action}(params={})
@@ -1,20 +1,4 @@
1
1
  module Castle
2
2
  class User < Model
3
- instance_post :enable_mfa!
4
- instance_post :disable_mfa!
5
-
6
- has_many :challenges
7
- has_many :events
8
- has_many :pairings
9
- has_many :sessions
10
- has_many :trusted_devices
11
-
12
- def backup_codes(params={})
13
- Castle::BackupCodes.get("/v1/users/#{id}/backup_codes", params)
14
- end
15
-
16
- def generate_backup_codes(params={})
17
- Castle::BackupCodes.post("/v1/users/#{id}/backup_codes", params)
18
- end
19
3
  end
20
4
  end
@@ -73,31 +73,6 @@ module Castle
73
73
  end
74
74
  end
75
75
 
76
- # Sends the active session token in a header, and extracts the returned
77
- # session token and sets it locally.
78
- #
79
- class SessionToken < Faraday::Middleware
80
- def call(env)
81
- castle = RequestStore.store[:castle]
82
- return @app.call(env) unless castle
83
-
84
- # get the session token from our local store
85
- if castle.session_token
86
- env[:request_headers]['X-Castle-Session-Token'] =
87
- castle.session_token.to_s
88
- end
89
-
90
- # call the API
91
- response = @app.call(env)
92
-
93
- # update the local store with the updated session token
94
- token = response.env.response_headers['X-Castle-set-session-token']
95
- castle.session_token = token if token
96
-
97
- response
98
- end
99
- end
100
-
101
76
  # Adds request context like IP address and user agent to any request.
102
77
  #
103
78
  class ContextHeaders < Faraday::Middleware
@@ -12,7 +12,6 @@ module Castle
12
12
  c.use Castle::Request::Middleware::RequestErrorHandler
13
13
  c.use Castle::Request::Middleware::EnvironmentHeaders
14
14
  c.use Castle::Request::Middleware::ContextHeaders
15
- c.use Castle::Request::Middleware::SessionToken
16
15
  c.use FaradayMiddleware::EncodeJson
17
16
  c.use Castle::Request::Middleware::JSONParser
18
17
  c.use Faraday::Adapter::NetHttp
@@ -1,3 +1,3 @@
1
1
  module Castle
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/castle-rb.rb CHANGED
@@ -12,11 +12,9 @@ require 'castle-rb/version'
12
12
  require 'castle-rb/configuration'
13
13
  require 'castle-rb/client'
14
14
  require 'castle-rb/errors'
15
- require 'castle-rb/token_store'
16
15
  require 'castle-rb/jwt'
17
16
  require 'castle-rb/utils'
18
17
  require 'castle-rb/request'
19
- require 'castle-rb/session_token'
20
18
 
21
19
  require 'castle-rb/support/cookie_store'
22
20
  require 'castle-rb/support/rails' if defined?(Rails::Railtie)
@@ -40,12 +38,5 @@ end
40
38
  require 'castle-rb/models/model'
41
39
  require 'castle-rb/models/account'
42
40
  require 'castle-rb/models/event'
43
- require 'castle-rb/models/challenge'
44
41
  require 'castle-rb/models/context'
45
- require 'castle-rb/models/monitoring'
46
- require 'castle-rb/models/pairing'
47
- require 'castle-rb/models/backup_codes'
48
- require 'castle-rb/models/recommendation'
49
- require 'castle-rb/models/session'
50
- require 'castle-rb/models/trusted_device'
51
42
  require 'castle-rb/models/user'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: castle-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Johan
7
+ - Johan Brissmyr
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-17 00:00:00.000000000 Z
11
+ date: 2015-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: her
@@ -193,43 +193,21 @@ files:
193
193
  - lib/castle-rb/ext/her.rb
194
194
  - lib/castle-rb/jwt.rb
195
195
  - lib/castle-rb/models/account.rb
196
- - lib/castle-rb/models/backup_codes.rb
197
- - lib/castle-rb/models/challenge.rb
198
196
  - lib/castle-rb/models/context.rb
199
197
  - lib/castle-rb/models/event.rb
200
198
  - lib/castle-rb/models/model.rb
201
- - lib/castle-rb/models/monitoring.rb
202
- - lib/castle-rb/models/pairing.rb
203
- - lib/castle-rb/models/recommendation.rb
204
- - lib/castle-rb/models/session.rb
205
- - lib/castle-rb/models/trusted_device.rb
206
199
  - lib/castle-rb/models/user.rb
207
200
  - lib/castle-rb/request.rb
208
- - lib/castle-rb/session_store.rb
209
- - lib/castle-rb/session_token.rb
210
201
  - lib/castle-rb/support/cookie_store.rb
211
202
  - lib/castle-rb/support/padrino.rb
212
203
  - lib/castle-rb/support/rails.rb
213
204
  - lib/castle-rb/support/sinatra.rb
214
- - lib/castle-rb/token_store.rb
215
205
  - lib/castle-rb/utils.rb
216
206
  - lib/castle-rb/version.rb
217
- - spec/fixtures/vcr_cassettes/challenge_create.yml
218
- - spec/fixtures/vcr_cassettes/challenge_verify.yml
219
- - spec/fixtures/vcr_cassettes/session_create.yml
220
- - spec/fixtures/vcr_cassettes/session_refresh.yml
221
- - spec/fixtures/vcr_cassettes/session_verify.yml
222
- - spec/fixtures/vcr_cassettes/user_find.yml
223
- - spec/fixtures/vcr_cassettes/user_find_non_existing.yml
224
- - spec/fixtures/vcr_cassettes/user_import.yml
225
- - spec/fixtures/vcr_cassettes/user_update.yml
226
- - spec/helpers_spec.rb
227
- - spec/jwt_spec.rb
228
207
  - spec/models/challenge_spec.rb
229
208
  - spec/models/session_spec.rb
230
209
  - spec/models/user_spec.rb
231
210
  - spec/spec_helper.rb
232
- - spec/utils_spec.rb
233
211
  homepage: https://castle.io
234
212
  licenses:
235
213
  - MIT
@@ -255,19 +233,7 @@ signing_key:
255
233
  specification_version: 4
256
234
  summary: Castle
257
235
  test_files:
258
- - spec/fixtures/vcr_cassettes/challenge_create.yml
259
- - spec/fixtures/vcr_cassettes/challenge_verify.yml
260
- - spec/fixtures/vcr_cassettes/session_create.yml
261
- - spec/fixtures/vcr_cassettes/session_refresh.yml
262
- - spec/fixtures/vcr_cassettes/session_verify.yml
263
- - spec/fixtures/vcr_cassettes/user_find.yml
264
- - spec/fixtures/vcr_cassettes/user_find_non_existing.yml
265
- - spec/fixtures/vcr_cassettes/user_import.yml
266
- - spec/fixtures/vcr_cassettes/user_update.yml
267
- - spec/helpers_spec.rb
268
- - spec/jwt_spec.rb
269
236
  - spec/models/challenge_spec.rb
270
237
  - spec/models/session_spec.rb
271
238
  - spec/models/user_spec.rb
272
239
  - spec/spec_helper.rb
273
- - spec/utils_spec.rb
@@ -1,4 +0,0 @@
1
- module Castle
2
- class BackupCodes < Model
3
- end
4
- end
@@ -1,7 +0,0 @@
1
- module Castle
2
- class Challenge < Model
3
- collection_path "users/:user_id/challenges"
4
- has_one :pairing
5
- instance_post :verify
6
- end
7
- end
@@ -1,6 +0,0 @@
1
- module Castle
2
- class Monitoring < Model
3
- collection_path '/v1' # Her doesn't accept the empty string
4
- custom_post :heartbeat
5
- end
6
- end
@@ -1,11 +0,0 @@
1
- module Castle
2
- class Pairing < Model
3
- collection_path "users/:user_id/pairings"
4
- instance_post :verify
5
- instance_post :set_default!
6
- belongs_to :user
7
- has_one :config
8
- end
9
-
10
- class Config < Model; end
11
- end
@@ -1,3 +0,0 @@
1
- module Castle
2
- class Recommendation < Model; end
3
- end
@@ -1,6 +0,0 @@
1
- module Castle
2
- class Session < Model
3
- collection_path "users/:user_id/sessions"
4
- has_one :context
5
- end
6
- end
@@ -1,5 +0,0 @@
1
- module Castle
2
- class TrustedDevice < Model
3
- collection_path "users/:user_id/trusted_devices"
4
- end
5
- end
@@ -1,35 +0,0 @@
1
- module Castle
2
- class SessionStore
3
- class Rack < SessionStore
4
- def initialize(session)
5
- @session = session
6
- end
7
-
8
- def user_id
9
- @session['Castleuser_id']
10
- end
11
-
12
- def user_id=(value)
13
- @session['Castleuser_id'] = value
14
- end
15
-
16
- def read
17
- @session[key]
18
- end
19
-
20
- def write(value)
21
- @session[key] = value
22
- end
23
-
24
- def destroy
25
- @session.delete(key)
26
- end
27
-
28
- private
29
-
30
- def key
31
- "Castleuser.#{user_id}"
32
- end
33
- end
34
- end
35
- end
@@ -1,39 +0,0 @@
1
- require 'jwt'
2
-
3
- module Castle
4
- class SessionToken
5
- def initialize(token)
6
- if token
7
- @jwt = Castle::JWT.new(token)
8
- end
9
- end
10
-
11
- def to_s
12
- @jwt.to_token
13
- end
14
-
15
- def expired?
16
- @jwt.expired?
17
- end
18
-
19
- def device_trusted?
20
- @jwt.payload['tru'] == 1
21
- end
22
-
23
- def has_default_pairing?
24
- @jwt.payload['dpr'] > 0
25
- end
26
-
27
- def mfa_enabled?
28
- @jwt.payload['mfa'] == 1
29
- end
30
-
31
- def mfa_in_progress?
32
- @jwt.payload['chg'] == 1
33
- end
34
-
35
- def mfa_required?
36
- @jwt.payload['vfy'] > 0
37
- end
38
- end
39
- end
@@ -1,30 +0,0 @@
1
- module Castle
2
- class TokenStore
3
- def initialize(cookies)
4
- @cookies = cookies
5
- end
6
-
7
- def session_token
8
- token = @cookies['_ubs']
9
- Castle::SessionToken.new(token) if token
10
- end
11
-
12
- def session_token=(value)
13
- @cookies['_ubs'] = value
14
-
15
- if value && value != @cookies['_ubs']
16
- @cookies['_ubs']
17
- elsif !value
18
- @cookies['_ubs'] = nil
19
- end
20
- end
21
-
22
- def trusted_device_token
23
- @cookies['_ubt']
24
- end
25
-
26
- def trusted_device_token=(value)
27
- @cookies['_ubt'] = value
28
- end
29
- end
30
- end
@@ -1,48 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/users/dTxR68nzuRXT4wrB2HJ4hanYtcaGSz2y/challenges
6
- body:
7
- encoding: UTF-8
8
- string: "{}"
9
- headers:
10
- User-Agent:
11
- - Castle/v1 RubyBindings/1.0.4
12
- X-Castle-Client-User-Agent:
13
- - '{"bindings_version":"1.0.4","lang":"ruby","lang_version":"2.1.1 p76 (2014-02-24)","platform":"x86_64-darwin13.0","publisher":"castle","uname":"Darwin
14
- Johans-MacBook-Pro-2.local 13.2.0 Darwin Kernel Version 13.2.0: Thu Apr 17
15
- 23:03:13 PDT 2014; root:xnu-2422.100.13~1/RELEASE_X86_64 x86_64"}'
16
- Content-Type:
17
- - application/json
18
- Accept-Encoding:
19
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
20
- Accept:
21
- - "*/*"
22
- response:
23
- status:
24
- code: 201
25
- message: 'Created '
26
- headers:
27
- Content-Type:
28
- - application/json
29
- Content-Length:
30
- - '476'
31
- X-Ua-Compatible:
32
- - IE=Edge
33
- Etag:
34
- - '"ee1750920e2acc320adbd6826d5299be"'
35
- Cache-Control:
36
- - max-age=0, private, must-revalidate
37
- Server:
38
- - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
39
- Date:
40
- - Sat, 07 Jun 2014 20:42:33 GMT
41
- Connection:
42
- - Keep-Alive
43
- body:
44
- encoding: UTF-8
45
- string: '{"id":"UWwy5FrWf9DTeoTpJz1LpBp4dPkWZ2Ne","created_at":"2014-06-07T20:42:33Z","channel":{"id":"Ff892rfGx3TwNF33sQUz3S51NsV24w7H","created_at":"2014-06-07T20:25:27Z","primary":true,"type":"token","token":{"id":"VVG3qirUxy8mUSkmzy3QpPcuhLN1JY4r","created_at":"2014-06-07T20:24:39Z","verified":true,"qr_url":"https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth%3A%2F%2Ftotp%2FCastle%3Abrissmyr%40gmail.com%3Fsecret%3Dxulnnls324pajcfn%26issuer%3DCastle"}}}'
46
- http_version:
47
- recorded_at: Sat, 07 Jun 2014 20:42:33 GMT
48
- recorded_with: VCR 2.9.0
@@ -1,42 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/challenges/UWwy5FrWf9DTeoTpJz1LpBp4dPkWZ2Ne/verify
6
- body:
7
- encoding: UTF-8
8
- string: '{"response":"000000"}'
9
- headers:
10
- User-Agent:
11
- - Castle/v1 RubyBindings/1.0.4
12
- X-Castle-Client-User-Agent:
13
- - '{"bindings_version":"1.0.4","lang":"ruby","lang_version":"2.1.1 p76 (2014-02-24)","platform":"x86_64-darwin13.0","publisher":"castle","uname":"Darwin
14
- Johans-MacBook-Pro-2.local 13.2.0 Darwin Kernel Version 13.2.0: Thu Apr 17
15
- 23:03:13 PDT 2014; root:xnu-2422.100.13~1/RELEASE_X86_64 x86_64"}'
16
- Content-Type:
17
- - application/json
18
- Accept-Encoding:
19
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
20
- Accept:
21
- - "*/*"
22
- response:
23
- status:
24
- code: 204
25
- message: 'No Content '
26
- headers:
27
- X-Ua-Compatible:
28
- - IE=Edge
29
- Cache-Control:
30
- - no-cache
31
- Server:
32
- - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
33
- Date:
34
- - Sat, 07 Jun 2014 20:52:43 GMT
35
- Connection:
36
- - Keep-Alive
37
- body:
38
- encoding: UTF-8
39
- string: ''
40
- http_version:
41
- recorded_at: Sat, 07 Jun 2014 20:52:43 GMT
42
- recorded_with: VCR 2.9.0
@@ -1,47 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/users/user-2412/sessions
6
- body:
7
- encoding: UTF-8
8
- string: '{"user":{"email":"valid@example.com"}}'
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Content-Type:
13
- - application/json
14
- Accept-Encoding:
15
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
- Accept:
17
- - "*/*"
18
- response:
19
- status:
20
- code: 201
21
- message: 'Created '
22
- headers:
23
- Content-Type:
24
- - application/json
25
- Content-Length:
26
- - '716'
27
- X-Ua-Compatible:
28
- - IE=Edge
29
- Etag:
30
- - '"c323dc2244006efcc5629936b73749ff"'
31
- Cache-Control:
32
- - max-age=0, private, must-revalidate
33
- Server:
34
- - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
35
- Date:
36
- - Wed, 07 May 2014 16:21:05 GMT
37
- Connection:
38
- - Keep-Alive
39
- Set-Cookie:
40
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
41
- body:
42
- encoding: UTF-8
43
- string: '{"id":"S2odxReZnGqhqxPaQ7V7kNkLoXkGZPFz","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlzcyI6InVzZXItMjQxMiIsInN1YiI6IlMyb2R4UmVabkdxaHF4UGFRN1Y3a05rTG9Ya0daUEZ6IiwiYXVkIjoiODAwMDAwMDAwMDAwMDAwIiwiZXhwIjoxMzk5NDc5Njc1LCJpYXQiOjEzOTk0Nzk2NjUsImp0aSI6MH0.eyJjaGFsbGVuZ2UiOnsiaWQiOiJUVENqd3VyM3lwbTRUR1ZwWU43cENzTXFxOW9mWEVBSCIsInR5cGUiOiJvdHBfYXV0aGVudGljYXRvciJ9fQ.LT9mUzJEbsizbFxcpMo3zbms0aCDBzfgMbveMGSi1-s","user":{"id":"8Fpmj9asxpq4mwGzx48MP1EQhdWUHDeb","local_id":"user-2412","created_at":"2014-05-07T15:33:58Z","updated_at":"2014-05-07T16:04:56Z","email":"valid@example.com","username":"valid@example.com","name":"New
44
- Name","first_name":null,"last_name":null,"image":null,"status":"ACTIVE","mfa_enabled":true}}'
45
- http_version:
46
- recorded_at: Wed, 07 May 2014 16:21:05 GMT
47
- recorded_with: VCR 2.9.0
@@ -1,47 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/sessions/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlzcyI6InVzZXItMjQxMiIsInN1YiI6IlMyb2R4UmVabkdxaHF4UGFRN1Y3a05rTG9Ya0daUEZ6IiwiYXVkIjoiODAwMDAwMDAwMDAwMDAwIiwiZXhwIjoxMzk5NDc5Njc1LCJpYXQiOjEzOTk0Nzk2NjUsImp0aSI6MH0.eyJjaGFsbGVuZ2UiOnsiaWQiOiJUVENqd3VyM3lwbTRUR1ZwWU43cENzTXFxOW9mWEVBSCIsInR5cGUiOiJvdHBfYXV0aGVudGljYXRvciJ9fQ.LT9mUzJEbsizbFxcpMo3zbms0aCDBzfgMbveMGSi1-s/refresh
6
- body:
7
- encoding: UTF-8
8
- string: '{"user":{"name":"New Name"}}'
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Content-Type:
13
- - application/json
14
- Accept-Encoding:
15
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
- Accept:
17
- - "*/*"
18
- response:
19
- status:
20
- code: 201
21
- message: 'Created '
22
- headers:
23
- Content-Type:
24
- - application/json
25
- Content-Length:
26
- - '716'
27
- X-Ua-Compatible:
28
- - IE=Edge
29
- Etag:
30
- - '"537ee28e9894002208f8f645f6dd2987"'
31
- Cache-Control:
32
- - max-age=0, private, must-revalidate
33
- Server:
34
- - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
35
- Date:
36
- - Wed, 07 May 2014 16:21:55 GMT
37
- Connection:
38
- - Keep-Alive
39
- Set-Cookie:
40
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
41
- body:
42
- encoding: UTF-8
43
- string: '{"id":"S2odxReZnGqhqxPaQ7V7kNkLoXkGZPFz","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlzcyI6InVzZXItMjQxMiIsInN1YiI6IlMyb2R4UmVabkdxaHF4UGFRN1Y3a05rTG9Ya0daUEZ6IiwiYXVkIjoiODAwMDAwMDAwMDAwMDAwIiwiZXhwIjoxMzk5NDc5NzI1LCJpYXQiOjEzOTk0Nzk3MTUsImp0aSI6MX0.eyJjaGFsbGVuZ2UiOnsiaWQiOiJUVENqd3VyM3lwbTRUR1ZwWU43cENzTXFxOW9mWEVBSCIsInR5cGUiOiJvdHBfYXV0aGVudGljYXRvciJ9fQ.2UuUgl8jKkl1lhU0d2nSKmiw-Qzz130A9XJd7-swvv8","user":{"id":"8Fpmj9asxpq4mwGzx48MP1EQhdWUHDeb","local_id":"user-2412","created_at":"2014-05-07T15:33:58Z","updated_at":"2014-05-07T16:21:55Z","email":"valid@example.com","username":"valid@example.com","name":"New
44
- Name","first_name":null,"last_name":null,"image":null,"status":"ACTIVE","mfa_enabled":true}}'
45
- http_version:
46
- recorded_at: Wed, 07 May 2014 16:21:55 GMT
47
- recorded_with: VCR 2.9.0
@@ -1,47 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/sessions/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlzcyI6InVzZXItMjQxMiIsInN1YiI6IlMyb2R4UmVabkdxaHF4UGFRN1Y3a05rTG9Ya0daUEZ6IiwiYXVkIjoiODAwMDAwMDAwMDAwMDAwIiwiZXhwIjoxMzk5NDc5Njc1LCJpYXQiOjEzOTk0Nzk2NjUsImp0aSI6MH0.eyJjaGFsbGVuZ2UiOnsiaWQiOiJUVENqd3VyM3lwbTRUR1ZwWU43cENzTXFxOW9mWEVBSCIsInR5cGUiOiJvdHBfYXV0aGVudGljYXRvciJ9fQ.LT9mUzJEbsizbFxcpMo3zbms0aCDBzfgMbveMGSi1-s/verify
6
- body:
7
- encoding: UTF-8
8
- string: '{"response":"017010"}'
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Content-Type:
13
- - application/json
14
- Accept-Encoding:
15
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
- Accept:
17
- - "*/*"
18
- response:
19
- status:
20
- code: 201
21
- message: 'Created '
22
- headers:
23
- Content-Type:
24
- - application/json
25
- Content-Length:
26
- - '609'
27
- X-Ua-Compatible:
28
- - IE=Edge
29
- Etag:
30
- - '"27b68d405c62c2c4c2a23acafde76b26"'
31
- Cache-Control:
32
- - max-age=0, private, must-revalidate
33
- Server:
34
- - WEBrick/1.3.1 (Ruby/2.1.1/2014-02-24)
35
- Date:
36
- - Wed, 07 May 2014 16:22:55 GMT
37
- Connection:
38
- - Keep-Alive
39
- Set-Cookie:
40
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
41
- body:
42
- encoding: UTF-8
43
- string: '{"id":"S2odxReZnGqhqxPaQ7V7kNkLoXkGZPFz","token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlzcyI6InVzZXItMjQxMiIsInN1YiI6IlMyb2R4UmVabkdxaHF4UGFRN1Y3a05rTG9Ya0daUEZ6IiwiYXVkIjoiODAwMDAwMDAwMDAwMDAwIiwiZXhwIjoxMzk5NDc5NzI1LCJpYXQiOjEzOTk0Nzk3MTUsImp0aSI6MX0.e30.IRwMbLDd2LqRHB_QZvzG47eTr5vPCBrdWI6xPOPa6x4","user":{"id":"8Fpmj9asxpq4mwGzx48MP1EQhdWUHDeb","local_id":"user-2412","created_at":"2014-05-07T15:33:58Z","updated_at":"2014-05-07T16:21:55Z","email":"valid@example.com","username":"valid@example.com","name":"New
44
- Name","first_name":null,"last_name":null,"image":null,"status":"ACTIVE","mfa_enabled":true}}'
45
- http_version:
46
- recorded_at: Wed, 07 May 2014 16:22:55 GMT
47
- recorded_with: VCR 2.9.0
@@ -1,44 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: get
5
- uri: https://:secretkey@api.castle.io/v1/users/9RA2j3cYDxt8gefQUduKnxUxRRGy6Rz4
6
- body:
7
- encoding: US-ASCII
8
- string: ''
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Accept-Encoding:
13
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
- Accept:
15
- - '*/*'
16
- response:
17
- status:
18
- code: 200
19
- message: OK
20
- headers:
21
- Date:
22
- - Fri, 18 Apr 2014 23:16:44 GMT
23
- Status:
24
- - 200 OK
25
- Connection:
26
- - close
27
- Content-Type:
28
- - application/json
29
- Content-Length:
30
- - '328'
31
- Set-Cookie:
32
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
33
- X-Ua-Compatible:
34
- - IE=Edge
35
- Etag:
36
- - '"73f5664d599cfbc71df7850ca66cda3d"'
37
- Cache-Control:
38
- - max-age=0, private, must-revalidate
39
- body:
40
- encoding: UTF-8
41
- string: '{"id":"9RA2j3cYDxt8gefQUduKnxUxRRGy6Rz4","created_at":"2014-04-18T13:30:22Z","updated_at":"2014-04-18T13:33:51Z","email":"brissmyr@gmail.com","username":"brissmyr@gmail.com","name":null,"first_name":null,"last_name":null,"image":null,"status":"ACTIVE","email_verification_token":"NhFy8wBYccLsEoL-kAVt","identities":[]}'
42
- http_version:
43
- recorded_at: Fri, 18 Apr 2014 23:16:44 GMT
44
- recorded_with: VCR 2.9.0
@@ -1,42 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: get
5
- uri: https://:secretkey@api.castle.io/v1/users/non_existing
6
- body:
7
- encoding: US-ASCII
8
- string: ''
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Accept-Encoding:
13
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
- Accept:
15
- - '*/*'
16
- response:
17
- status:
18
- code: 404
19
- message: Not Found
20
- headers:
21
- Date:
22
- - Fri, 18 Apr 2014 23:29:27 GMT
23
- Status:
24
- - 404 Not Found
25
- Connection:
26
- - close
27
- Content-Type:
28
- - application/json
29
- Content-Length:
30
- - '42'
31
- Set-Cookie:
32
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
33
- X-Ua-Compatible:
34
- - IE=Edge
35
- Cache-Control:
36
- - no-cache
37
- body:
38
- encoding: UTF-8
39
- string: '{"type":"not_found","message":"Not found"}'
40
- http_version:
41
- recorded_at: Fri, 18 Apr 2014 23:29:27 GMT
42
- recorded_with: VCR 2.9.0
@@ -1,46 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://:secretkey@api.castle.io/v1/users/import
6
- body:
7
- encoding: UTF-8
8
- string: '{"users":[{"email":"10@example.com","username":"10"},{"email":"20@example.com","username":"20"}]}'
9
- headers:
10
- User-Agent:
11
- - Faraday v0.9.0
12
- Content-Type:
13
- - application/json
14
- Accept-Encoding:
15
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
- Accept:
17
- - '*/*'
18
- response:
19
- status:
20
- code: 201
21
- message: Created
22
- headers:
23
- Date:
24
- - Thu, 24 Apr 2014 16:19:14 GMT
25
- Status:
26
- - 201 Created
27
- Connection:
28
- - close
29
- Content-Type:
30
- - application/json
31
- Content-Length:
32
- - '85'
33
- Set-Cookie:
34
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
35
- X-Ua-Compatible:
36
- - IE=Edge
37
- Etag:
38
- - '"e6928187afa7cffb7f793a998b7a1c91"'
39
- Cache-Control:
40
- - max-age=0, private, must-revalidate
41
- body:
42
- encoding: UTF-8
43
- string: '[{"id":"fqnvfRSmxa6wqx3c6xmzDqDZrJCvtZ5P"},{"id":"4n9pcvrCSig2iVcZbk7pAMsjngzX9fgv"}]'
44
- http_version:
45
- recorded_at: Thu, 24 Apr 2014 16:19:14 GMT
46
- recorded_with: VCR 2.9.0
@@ -1,47 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: put
5
- uri: https://:secretkey@api.castle.io/v1/users/AKfwtfrAzdDKp55aty8o14MoudkaS9BL
6
- body:
7
- encoding: UTF-8
8
- string: '{"id":"AKfwtfrAzdDKp55aty8o14MoudkaS9BL","email":"updated@example.com","created_at":"2014-04-27
9
- 22:10:22 +0200"}'
10
- headers:
11
- User-Agent:
12
- - Faraday v0.9.0
13
- Content-Type:
14
- - application/json
15
- Accept-Encoding:
16
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
17
- Accept:
18
- - '*/*'
19
- response:
20
- status:
21
- code: 200
22
- message: OK
23
- headers:
24
- Date:
25
- - Sun, 27 Apr 2014 20:10:22 GMT
26
- Status:
27
- - 200 OK
28
- Connection:
29
- - close
30
- Content-Type:
31
- - application/json
32
- Content-Length:
33
- - '252'
34
- Set-Cookie:
35
- - _ubt=; expires=Thu, 01-Jan-1970 00:00:00 GMT
36
- X-Ua-Compatible:
37
- - IE=Edge
38
- Etag:
39
- - '"de56261eb3d3bef170cc8e837af079fd"'
40
- Cache-Control:
41
- - max-age=0, private, must-revalidate
42
- body:
43
- encoding: UTF-8
44
- string: '{"id":"AKfwtfrAzdDKp55aty8o14MoudkaS9BL","created_at":"2014-04-27T20:10:22Z","updated_at":"2014-04-27T20:10:22Z","email":"updated@example.com","username":"updated@example.com","name":null,"first_name":null,"last_name":null,"image":null,"status":"ACTIVE","identities":[]}'
45
- http_version:
46
- recorded_at: Sun, 27 Apr 2014 20:10:22 GMT
47
- recorded_with: VCR 2.9.0
data/spec/helpers_spec.rb DELETED
@@ -1,38 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Castle helpers' do
4
- let(:token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlhdCI6MTM5ODIzOTIwMywiZXhwIjoxMzk4MjQyODAzfQ.eyJ1c2VyX2lkIjoiZUF3djVIdGRiU2s4Yk1OWVpvanNZdW13UXlLcFhxS3IifQ.Apa7EmT5T1sOYz4Af0ERTDzcnUvSalailNJbejZ2ddQ' }
5
-
6
- xit 'creates a session' do
7
- Castle::Session.should_receive(:post).
8
- with("users/user%201234/sessions", user: {email: 'valid@example.com'}).
9
- and_return(Castle::Session.new(token: token))
10
- Castleauthenticate(nil, 'user 1234', properties: {email: 'valid@example.com'})
11
- end
12
-
13
- xit 'refreshes, and does not create a session' do
14
- Castle::Session.should_not_receive(:create)
15
- Castle::Session.any_instance.should_receive(:refresh).
16
- and_return(Castle::Session.new(token: token))
17
- opts = {
18
- user_id: '1234',
19
- properties: {
20
- email: 'valid@example.com'
21
- },
22
- context: {
23
- ip: '8.8.8.8',
24
- user_agent: 'Mozilla'
25
- }
26
- }
27
- Castleauthenticate(token, opts)
28
- end
29
-
30
- xit 'deauthenticates with context' do
31
- Castle::Session.should_receive(:destroy_existing)
32
-
33
- jwt = Castle::JWT.new(token)
34
- jwt.merge!(context: { ip: '8.8.8.8', user_agent: 'Mozilla' })
35
-
36
- Castledeauthenticate(jwt.to_token)
37
- end
38
- end
data/spec/jwt_spec.rb DELETED
@@ -1,67 +0,0 @@
1
- require 'spec_helper'
2
- require 'timecop'
3
-
4
- describe 'Castle::JWT' do
5
- let(:token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImlhdCI6MTM5ODIzOTIwMywiZXhwIjoxMzk4MjQyODAzfQ.eyJ1c2VyX2lkIjoiZUF3djVIdGRiU2s4Yk1OWVpvanNZdW13UXlLcFhxS3IifQ.Apa7EmT5T1sOYz4Af0ERTDzcnUvSalailNJbejZ2ddQ' }
6
-
7
- context 'valid JWT' do
8
- it 'returns a payload' do
9
- payload = Castle::JWT.new(token).to_json
10
- payload['user_id'].should == 'eAwv5HtdbSk8bMNYZojsYumwQyKpXqKr'
11
- end
12
-
13
- it 'verifies that JWT has expired' do
14
- new_time = Time.utc(2014, 4, 23, 8, 46, 44)
15
- Timecop.freeze(new_time) do
16
- Castle::JWT.new(token).should be_expired
17
- end
18
- end
19
-
20
- it 'verifies that JWT has not expired' do
21
- new_time = Time.utc(2014, 4, 23, 8, 46, 43)
22
- Timecop.freeze(new_time) do
23
- Castle::JWT.new(token).should_not be_expired
24
- end
25
- end
26
- end
27
-
28
- context 'invalid JWT' do
29
- let(:token) { 'eyJ0eXhtWWNTU3pEUHp6WFF2WmZp26mn7Kkl6UgE' }
30
-
31
- it 'throws error' do
32
- expect {
33
- payload = Castle::JWT.new(token).to_json
34
- }.to raise_error(Castle::SecurityError)
35
- end
36
- end
37
-
38
- context 'nil JWT' do
39
- let(:token) { nil }
40
-
41
- it 'throws error' do
42
- token = nil
43
- expect {
44
- payload = Castle::JWT.new(token).to_json
45
- }.to raise_error(Castle::SecurityError)
46
- end
47
- end
48
-
49
- context '#to_token' do
50
- it 'returns the same token' do
51
- Castle::JWT.new(token).to_token.should == token
52
- end
53
- end
54
-
55
- context '#merge' do
56
- it 'merges payload' do
57
- jwt = Castle::JWT.new(token)
58
- jwt.merge!(context: { ip: '8.8.8.8' })
59
-
60
- merged_token = jwt.to_token
61
- merged_token.should_not == token
62
- Castle::JWT.new(merged_token).
63
- to_json['context']['ip'].should == '8.8.8.8'
64
- end
65
- end
66
-
67
- end
data/spec/utils_spec.rb DELETED
@@ -1,59 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class MemoryStore < Castle::TokenStore
4
- def initialize
5
- @value = nil
6
- end
7
-
8
- def session_token
9
- @value['_ubs']
10
- end
11
-
12
- def session_token=(value)
13
- @value['_ubs'] = value
14
- end
15
-
16
- def trusted_device_token
17
- @value['_ubt']
18
- end
19
-
20
- def trusted_device_token=(value)
21
- @value['_ubt'] = value
22
- end
23
- end
24
-
25
- describe 'Castle utils' do
26
- describe 'ContextHeaders middleware' do
27
- before do
28
- Castle::User.use_api(api = Her::API.new)
29
- @user = api.setup do |c|
30
- c.use Castle::Request::Middleware::ContextHeaders
31
- c.use Her::Middleware::FirstLevelParseJSON
32
- c.adapter :test do |stub|
33
- stub.post('/users') do |env|
34
- @env = env
35
- [200, {}, [].to_json]
36
- end
37
- end
38
- end
39
- end
40
-
41
- let(:env) do
42
- Rack::MockRequest.env_for('/',
43
- "HTTP_USER_AGENT" => "Mozilla", "REMOTE_ADDR" => "8.8.8.8")
44
- end
45
-
46
- it 'handles non-existing context headers' do
47
- Castle::User.create()
48
- end
49
-
50
- it 'sets context headers from env' do
51
- request = Rack::Request.new(Rack::MockRequest.env_for('/',
52
- "HTTP_USER_AGENT" => "Mozilla", "REMOTE_ADDR" => "8.8.8.8"))
53
- Castle::Client.new(request, session_store: MemoryStore.new)
54
- Castle::User.create()
55
- @env['request_headers']['X-Castle-Ip'].should == '8.8.8.8'
56
- @env['request_headers']['X-Castle-User-Agent'].should == 'Mozilla'
57
- end
58
- end
59
- end