flexmls_api 0.4.5 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -17
- data/Gemfile.lock +35 -27
- data/README.md +23 -1
- data/Rakefile +18 -5
- data/VERSION +1 -1
- data/bin/flexmls_api +8 -0
- data/lib/flexmls_api.rb +2 -0
- data/lib/flexmls_api/authentication.rb +5 -6
- data/lib/flexmls_api/authentication/api_auth.rb +4 -2
- data/lib/flexmls_api/authentication/oauth2.rb +51 -99
- data/lib/flexmls_api/authentication/oauth2_impl/grant_type_base.rb +85 -0
- data/lib/flexmls_api/authentication/oauth2_impl/grant_type_code.rb +48 -0
- data/lib/flexmls_api/authentication/oauth2_impl/grant_type_password.rb +45 -0
- data/lib/flexmls_api/authentication/oauth2_impl/grant_type_refresh.rb +36 -0
- data/lib/flexmls_api/authentication/oauth2_impl/middleware.rb +39 -0
- data/lib/flexmls_api/cli.rb +132 -0
- data/lib/flexmls_api/cli/api_auth.rb +8 -0
- data/lib/flexmls_api/cli/oauth2.rb +43 -0
- data/lib/flexmls_api/cli/setup.rb +44 -0
- data/lib/flexmls_api/configuration.rb +6 -6
- data/lib/flexmls_api/faraday.rb +11 -21
- data/lib/flexmls_api/models.rb +3 -0
- data/lib/flexmls_api/models/account.rb +48 -5
- data/lib/flexmls_api/models/base.rb +27 -2
- data/lib/flexmls_api/models/contact.rb +28 -9
- data/lib/flexmls_api/models/listing_cart.rb +72 -0
- data/lib/flexmls_api/models/note.rb +0 -2
- data/lib/flexmls_api/models/saved_search.rb +16 -0
- data/lib/flexmls_api/models/shared_listing.rb +35 -0
- data/lib/flexmls_api/multi_client.rb +37 -0
- data/lib/flexmls_api/paginate.rb +5 -0
- data/lib/flexmls_api/request.rb +7 -3
- data/script/console +6 -0
- data/script/example.rb +27 -0
- data/spec/fixtures/accounts/all.json +160 -0
- data/spec/fixtures/accounts/my.json +74 -0
- data/spec/fixtures/accounts/my_portal.json +20 -0
- data/spec/fixtures/accounts/my_put.json +5 -0
- data/spec/fixtures/accounts/my_save.json +5 -0
- data/spec/fixtures/accounts/office.json +142 -0
- data/spec/fixtures/base.json +13 -0
- data/spec/fixtures/contact_my.json +19 -0
- data/spec/fixtures/contact_new.json +11 -0
- data/spec/fixtures/contact_new_empty.json +8 -0
- data/spec/fixtures/contact_new_notify.json +11 -0
- data/spec/fixtures/contact_tags.json +11 -0
- data/spec/fixtures/contacts.json +6 -3
- data/spec/fixtures/contacts_post.json +10 -0
- data/spec/fixtures/empty.json +3 -0
- data/spec/fixtures/errors/failure.json +5 -0
- data/spec/fixtures/listing_cart.json +19 -0
- data/spec/fixtures/listing_cart_add_listing.json +13 -0
- data/spec/fixtures/listing_cart_add_listing_post.json +5 -0
- data/spec/fixtures/listing_cart_empty.json +5 -0
- data/spec/fixtures/listing_cart_new.json +12 -0
- data/spec/fixtures/listing_cart_post.json +10 -0
- data/spec/fixtures/listing_cart_remove_listing.json +13 -0
- data/spec/fixtures/note_new.json +5 -0
- data/spec/fixtures/{oauth2_access.json → oauth2/access.json} +0 -0
- data/spec/fixtures/oauth2/access_with_old_refresh.json +5 -0
- data/spec/fixtures/oauth2/access_with_refresh.json +5 -0
- data/spec/fixtures/oauth2/authorization_code_body.json +7 -0
- data/spec/fixtures/oauth2/error.json +3 -0
- data/spec/fixtures/oauth2/password_body.json +7 -0
- data/spec/fixtures/oauth2/refresh_body.json +7 -0
- data/spec/fixtures/saved_search.json +17 -0
- data/spec/fixtures/shared_listing_new.json +9 -0
- data/spec/fixtures/shared_listing_post.json +10 -0
- data/spec/mock_helper.rb +123 -0
- data/spec/oauth2_helper.rb +69 -0
- data/spec/spec_helper.rb +1 -57
- data/spec/unit/flexmls_api/authentication/api_auth_spec.rb +1 -0
- data/spec/unit/flexmls_api/authentication/oauth2_impl/grant_type_base_spec.rb +10 -0
- data/spec/unit/flexmls_api/authentication/oauth2_spec.rb +74 -79
- data/spec/unit/flexmls_api/configuration_spec.rb +25 -4
- data/spec/unit/flexmls_api/models/account_spec.rb +152 -85
- data/spec/unit/flexmls_api/models/base_spec.rb +69 -25
- data/spec/unit/flexmls_api/models/contact_spec.rb +48 -34
- data/spec/unit/flexmls_api/models/document_spec.rb +1 -7
- data/spec/unit/flexmls_api/models/listing_cart_spec.rb +114 -0
- data/spec/unit/flexmls_api/models/listing_spec.rb +8 -56
- data/spec/unit/flexmls_api/models/note_spec.rb +8 -38
- data/spec/unit/flexmls_api/models/photo_spec.rb +1 -11
- data/spec/unit/flexmls_api/models/saved_search_spec.rb +34 -0
- data/spec/unit/flexmls_api/models/shared_listing_spec.rb +30 -0
- data/spec/unit/flexmls_api/models/standard_fields_spec.rb +50 -30
- data/spec/unit/flexmls_api/models/tour_of_home_spec.rb +1 -7
- data/spec/unit/flexmls_api/models/video_spec.rb +1 -10
- data/spec/unit/flexmls_api/models/virtual_tour_spec.rb +1 -7
- data/spec/unit/flexmls_api/multi_client_spec.rb +48 -0
- data/spec/unit/flexmls_api/request_spec.rb +42 -5
- metadata +239 -93
- data/spec/unit/flexmls_api/standard_fields_spec.rb +0 -86
data/Gemfile
CHANGED
@@ -1,20 +1,5 @@
|
|
1
1
|
source :rubygems
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
gem 'faraday_middleware', '0.3.1'
|
6
|
-
gem 'multi_json', '0.0.5'
|
7
|
-
gem 'json', '1.4.6'
|
8
|
-
gem 'yajl-ruby', '0.7.8'
|
9
|
-
gem 'builder', '2.1.2'
|
3
|
+
# Refer to the flexmls_api.gemspec or Rakefile for dependency information
|
4
|
+
gemspec :development_group => :test
|
10
5
|
|
11
|
-
gem 'will_paginate', '~> 3.0.pre2'
|
12
|
-
|
13
|
-
group :test do
|
14
|
-
gem 'rspec'
|
15
|
-
gem 'webmock'
|
16
|
-
gem 'jeweler'
|
17
|
-
gem 'typhoeus'
|
18
|
-
gem 'ci_reporter', '>=1.6.3'
|
19
|
-
gem 'rcov'
|
20
|
-
end
|
data/Gemfile.lock
CHANGED
@@ -1,28 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
flexmls_api (0.6.4)
|
5
|
+
addressable (~> 2.2.5)
|
6
|
+
builder (< 4.0.0, >= 2.1.2)
|
7
|
+
curb (~> 0.7.15)
|
8
|
+
faraday (~> 0.6.1)
|
9
|
+
faraday_middleware (~> 0.6.3)
|
10
|
+
flexmls_api
|
11
|
+
json (~> 1.5.1)
|
12
|
+
multi_json (~> 1.0.0)
|
13
|
+
will_paginate (< 4.0.0, >= 3.0.pre2)
|
14
|
+
yajl-ruby (~> 0.8.2)
|
15
|
+
|
1
16
|
GEM
|
2
17
|
remote: http://rubygems.org/
|
3
18
|
specs:
|
4
|
-
addressable (2.2.
|
19
|
+
addressable (2.2.6)
|
5
20
|
builder (2.1.2)
|
6
21
|
ci_reporter (1.6.3)
|
7
22
|
builder (>= 2.1.2)
|
8
23
|
crack (0.1.8)
|
9
|
-
curb (0.7.
|
24
|
+
curb (0.7.15)
|
10
25
|
diff-lcs (1.1.2)
|
11
|
-
faraday (0.
|
12
|
-
addressable (~> 2.2.
|
13
|
-
multipart-post (~> 1.0
|
14
|
-
rack (>= 1.1.0
|
15
|
-
faraday_middleware (0.
|
16
|
-
faraday (~> 0.
|
26
|
+
faraday (0.6.1)
|
27
|
+
addressable (~> 2.2.4)
|
28
|
+
multipart-post (~> 1.1.0)
|
29
|
+
rack (< 2, >= 1.1.0)
|
30
|
+
faraday_middleware (0.6.5)
|
31
|
+
faraday (~> 0.6.0)
|
17
32
|
git (1.2.5)
|
18
33
|
jeweler (1.5.2)
|
19
34
|
bundler (~> 1.0.0)
|
20
35
|
git (>= 1.2.5)
|
21
36
|
rake
|
22
|
-
json (1.
|
23
|
-
multi_json (
|
24
|
-
multipart-post (1.
|
25
|
-
rack (1.
|
37
|
+
json (1.5.3)
|
38
|
+
multi_json (1.0.3)
|
39
|
+
multipart-post (1.1.2)
|
40
|
+
rack (1.3.1)
|
26
41
|
rake (0.8.7)
|
27
42
|
rcov (0.9.9)
|
28
43
|
rspec (2.3.0)
|
@@ -38,23 +53,16 @@ GEM
|
|
38
53
|
addressable (>= 2.2.2)
|
39
54
|
crack (>= 0.1.7)
|
40
55
|
will_paginate (3.0.pre2)
|
41
|
-
yajl-ruby (0.
|
56
|
+
yajl-ruby (0.8.2)
|
42
57
|
|
43
58
|
PLATFORMS
|
44
59
|
ruby
|
45
60
|
|
46
61
|
DEPENDENCIES
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
multi_json (= 0.0.5)
|
55
|
-
rcov
|
56
|
-
rspec
|
57
|
-
typhoeus
|
58
|
-
webmock
|
59
|
-
will_paginate (~> 3.0.pre2)
|
60
|
-
yajl-ruby (= 0.7.8)
|
62
|
+
ci_reporter (~> 1.6.3)
|
63
|
+
flexmls_api!
|
64
|
+
jeweler (~> 1.5.2)
|
65
|
+
rcov (~> 0.9.9)
|
66
|
+
rspec (~> 2.3.0)
|
67
|
+
typhoeus (~> 0.2.0)
|
68
|
+
webmock (~> 1.4.0)
|
data/README.md
CHANGED
@@ -14,6 +14,8 @@ Installation
|
|
14
14
|
|
15
15
|
Usage Examples
|
16
16
|
------------------------
|
17
|
+
|
18
|
+
#### Ruby Script
|
17
19
|
# initialize the gem with your key/secret
|
18
20
|
# api_key and _api_secret are the only required settings
|
19
21
|
# other options and their defaults:
|
@@ -31,6 +33,26 @@ Usage Examples
|
|
31
33
|
|
32
34
|
# Grab your listings!
|
33
35
|
my_listings = Listing.my()
|
36
|
+
|
37
|
+
|
38
|
+
#### Interactive Console
|
39
|
+
Included in the gem is a simple setup script to run the client in IRB. To use it, first create the file called _.flexmls_api_testing_ filling in the credentials for your account.
|
40
|
+
|
41
|
+
API_USER="20110101000000000000000000" # ID for an api user
|
42
|
+
API_ENDPOINT="http://api.developers.flexmls.com"
|
43
|
+
API_KEY="my_test_key"
|
44
|
+
API_SECRET="my_test_secret"
|
45
|
+
|
46
|
+
export API_USER API_ENDPOINT API_KEY API_SECRET
|
47
|
+
|
48
|
+
Now, to run with this setup, run the following from the command line:
|
49
|
+
|
50
|
+
> source .flexmls_api_testing
|
51
|
+
> bin/flexmls_api
|
52
|
+
flemxlsApi> FlexmlsApi.client.get '/my/account'
|
53
|
+
|
54
|
+
You can also provide these options from the command line, see "script/console -h" for more information
|
55
|
+
|
34
56
|
|
35
57
|
Authentication
|
36
58
|
--------------
|
@@ -40,7 +62,7 @@ Authentication is handled transparently by the request framework in the gem, so
|
|
40
62
|
Usually supplied for a single user, this authentication mode is the simplest, and is setup as the default. The example usage above demonstrates how to get started using this authentication mode.
|
41
63
|
|
42
64
|
#### OAuth2 Authentication
|
43
|
-
Authentication mode the separates application and user authentication. This mode requires further setup which is described in
|
65
|
+
Authentication mode the separates application and user authentication. This mode requires further setup which is described in _lib/flexmls_api/authentication/oauth2.rb_
|
44
66
|
|
45
67
|
Error Codes
|
46
68
|
---------------------
|
data/Rakefile
CHANGED
@@ -15,11 +15,24 @@ begin
|
|
15
15
|
gemspec.homepage = "https://github.com/flexmls/flexmls_api"
|
16
16
|
gemspec.authors = ["Brandon Hornseth", "Wade McEwen"]
|
17
17
|
# Need to skip spec/reports for CI builds
|
18
|
-
gemspec.files = FileList["[A-Z]*", "{lib,spec/fixtures,spec/unit}/**/*", "spec/*.rb"]
|
19
|
-
|
20
|
-
gemspec.
|
21
|
-
gemspec.
|
22
|
-
gemspec.
|
18
|
+
gemspec.files = FileList["[A-Z]*", "{bin,lib,spec/fixtures,script,spec/unit}/**/*", "spec/*.rb"]
|
19
|
+
# GEMS
|
20
|
+
gemspec.add_dependency 'curb', '~> 0.7.15'
|
21
|
+
gemspec.add_dependency 'faraday', '~> 0.6.1'
|
22
|
+
gemspec.add_dependency 'faraday_middleware', '~> 0.6.3'
|
23
|
+
gemspec.add_dependency 'multi_json', '~> 1.0.0'
|
24
|
+
gemspec.add_dependency 'json', '~> 1.5.1'
|
25
|
+
gemspec.add_dependency 'yajl-ruby', '~> 0.8.2'
|
26
|
+
gemspec.add_dependency 'builder', '>= 2.1.2', '< 4.0.0'
|
27
|
+
gemspec.add_dependency 'addressable', '~> 2.2.5'
|
28
|
+
gemspec.add_dependency 'will_paginate', '>= 3.0.pre2', '< 4.0.0'
|
29
|
+
# TEST GEMS
|
30
|
+
gemspec.add_development_dependency 'rspec', '~> 2.3.0'
|
31
|
+
gemspec.add_development_dependency 'webmock', '~> 1.4.0'
|
32
|
+
gemspec.add_development_dependency 'jeweler', '~> 1.5.2'
|
33
|
+
gemspec.add_development_dependency 'typhoeus', '~> 0.2.0'
|
34
|
+
gemspec.add_development_dependency 'ci_reporter', '~> 1.6.3'
|
35
|
+
gemspec.add_development_dependency 'rcov', '~> 0.9.9'
|
23
36
|
end
|
24
37
|
Jeweler::GemcutterTasks.new
|
25
38
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4
|
1
|
+
0.6.4
|
data/bin/flexmls_api
ADDED
data/lib/flexmls_api.rb
CHANGED
@@ -6,6 +6,7 @@ require 'logger'
|
|
6
6
|
|
7
7
|
require File.expand_path('../flexmls_api/version', __FILE__)
|
8
8
|
require File.expand_path('../flexmls_api/configuration', __FILE__)
|
9
|
+
require File.expand_path('../flexmls_api/multi_client', __FILE__)
|
9
10
|
require File.expand_path('../flexmls_api/authentication', __FILE__)
|
10
11
|
require File.expand_path('../flexmls_api/paginate', __FILE__)
|
11
12
|
require File.expand_path('../flexmls_api/request', __FILE__)
|
@@ -16,6 +17,7 @@ require File.expand_path('../flexmls_api/models', __FILE__)
|
|
16
17
|
|
17
18
|
module FlexmlsApi
|
18
19
|
extend Configuration
|
20
|
+
extend MultiClient
|
19
21
|
|
20
22
|
def self.logger
|
21
23
|
if @logger.nil?
|
@@ -5,9 +5,9 @@ require 'faraday_middleware'
|
|
5
5
|
require 'yajl'
|
6
6
|
require 'date'
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
8
|
+
require 'flexmls_api/authentication/base_auth'
|
9
|
+
require 'flexmls_api/authentication/api_auth'
|
10
|
+
require 'flexmls_api/authentication/oauth2'
|
11
11
|
|
12
12
|
module FlexmlsApi
|
13
13
|
# =Authentication
|
@@ -66,7 +66,6 @@ module FlexmlsApi
|
|
66
66
|
end
|
67
67
|
conn = Faraday::Connection.new(opts) do |builder|
|
68
68
|
builder.adapter Faraday.default_adapter
|
69
|
-
builder.use Faraday::Response::ParseJson
|
70
69
|
builder.use FlexmlsApi::FaradayExt::FlexmlsMiddleware
|
71
70
|
end
|
72
71
|
FlexmlsApi.logger.debug("Connection: #{conn.inspect}")
|
@@ -78,8 +77,8 @@ module FlexmlsApi
|
|
78
77
|
{
|
79
78
|
:accept => 'application/json',
|
80
79
|
:content_type => 'application/json',
|
81
|
-
:user_agent =>
|
82
|
-
|
80
|
+
:user_agent => Configuration::DEFAULT_USER_AGENT,
|
81
|
+
Configuration::X_FLEXMLS_API_USER_AGENT => user_agent
|
83
82
|
}
|
84
83
|
end
|
85
84
|
|
@@ -23,6 +23,7 @@ module FlexmlsApi
|
|
23
23
|
resp = @client.connection(true).post request_path, ""
|
24
24
|
request_time = Time.now - start_time
|
25
25
|
FlexmlsApi.logger.info("[#{(request_time * 1000).to_i}ms] Api: POST #{request_path}")
|
26
|
+
FlexmlsApi.logger.debug("Authentication Response: #{resp.inspect}")
|
26
27
|
@session = Session.new(resp.body.results.first)
|
27
28
|
FlexmlsApi.logger.debug("Authentication: #{@session.inspect}")
|
28
29
|
@session
|
@@ -59,6 +60,7 @@ module FlexmlsApi
|
|
59
60
|
|
60
61
|
# Perform an HTTP request (no data)
|
61
62
|
def request(method, path, body, options)
|
63
|
+
escaped_path = URI.escape(path)
|
62
64
|
request_opts = {
|
63
65
|
"AuthToken" => @session.auth_token
|
64
66
|
}
|
@@ -66,8 +68,8 @@ module FlexmlsApi
|
|
66
68
|
request_opts.merge!(:ApiUser => "#{@client.api_user}")
|
67
69
|
end
|
68
70
|
request_opts.merge!(options)
|
69
|
-
sig = sign_token(
|
70
|
-
request_path = "#{
|
71
|
+
sig = sign_token(escaped_path, request_opts, body)
|
72
|
+
request_path = "#{escaped_path}?#{build_url_parameters({"ApiSig"=>sig}.merge(request_opts))}"
|
71
73
|
FlexmlsApi.logger.debug("Request: #{request_path}")
|
72
74
|
if body.nil?
|
73
75
|
response = @client.connection.send(method, request_path)
|
@@ -1,8 +1,18 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
|
+
|
3
4
|
module FlexmlsApi
|
4
5
|
|
5
6
|
module Authentication
|
7
|
+
|
8
|
+
module OAuth2Impl
|
9
|
+
require 'flexmls_api/authentication/oauth2_impl/middleware'
|
10
|
+
require 'flexmls_api/authentication/oauth2_impl/grant_type_base'
|
11
|
+
require 'flexmls_api/authentication/oauth2_impl/grant_type_refresh'
|
12
|
+
require 'flexmls_api/authentication/oauth2_impl/grant_type_code'
|
13
|
+
require 'flexmls_api/authentication/oauth2_impl/grant_type_password'
|
14
|
+
end
|
15
|
+
|
6
16
|
#=OAuth2 Authentication
|
7
17
|
# Auth implementation to the API using the OAuth2 service endpoint. Current adheres to the 10
|
8
18
|
# draft of the OAuth2 specification. With OAuth2, the application supplies credentials for the
|
@@ -19,60 +29,31 @@ module FlexmlsApi
|
|
19
29
|
# Implementation the BaseAuth interface for API style authentication
|
20
30
|
class OAuth2 < BaseAuth
|
21
31
|
|
22
|
-
def session
|
23
|
-
@provider.load_session()
|
24
|
-
end
|
25
|
-
def session=(s)
|
26
|
-
@provider.save_session(s)
|
27
|
-
end
|
28
|
-
|
29
32
|
def initialize(client)
|
30
33
|
@client = client
|
31
34
|
@provider = client.oauth2_provider
|
32
35
|
end
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
params = {
|
37
|
-
"client_id" => @provider.client_id,
|
38
|
-
"response_type" => "code",
|
39
|
-
"redirect_uri" => @provider.redirect_uri
|
40
|
-
}
|
41
|
-
"#{@provider.authorization_uri}?#{build_url_parameters(params)}"
|
37
|
+
def session
|
38
|
+
@provider.load_session()
|
42
39
|
end
|
43
|
-
|
44
|
-
|
45
|
-
params = {
|
46
|
-
"client_id" => @provider.client_id,
|
47
|
-
"client_secret" => @provider.client_secret,
|
48
|
-
"grant_type" => "authorization_code",
|
49
|
-
"code" => @provider.code,
|
50
|
-
"redirect_uri" => @provider.redirect_uri
|
51
|
-
}
|
52
|
-
"?#{build_url_parameters(params)}"
|
40
|
+
def session=(s)
|
41
|
+
@provider.save_session(s)
|
53
42
|
end
|
54
43
|
|
55
44
|
def authenticate
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
FlexmlsApi.logger.debug("Authenticating to #{@provider.access_uri}")
|
61
|
-
uri = URI.parse(@provider.access_uri)
|
62
|
-
request_path = "#{uri.path}#{token_params}"
|
63
|
-
response = oauth_access_connection("#{uri.scheme}://#{uri.host}").post(request_path, "").body
|
64
|
-
response.expires_in = @provider.session_timeout if response.expires_in.nil?
|
65
|
-
self.session=response
|
66
|
-
response
|
45
|
+
granter = OAuth2Impl::GrantTypeBase.create(@client, @provider, session)
|
46
|
+
self.session = granter.authenticate
|
47
|
+
session
|
67
48
|
end
|
68
49
|
|
69
50
|
# Perform an HTTP request (no data)
|
70
|
-
def request(method, path, body, options)
|
51
|
+
def request(method, path, body, options={})
|
52
|
+
escaped_path = URI.escape(path)
|
71
53
|
connection = @client.connection(true) # SSL Only!
|
72
54
|
connection.headers.merge!(self.auth_header)
|
73
|
-
|
74
|
-
|
75
|
-
request_path = "#{path}?#{build_url_parameters({:access_token => session.access_token}.merge(options))}"
|
55
|
+
parameter_string = options.size > 0 ? "?#{build_url_parameters(options)}" : ""
|
56
|
+
request_path = "#{escaped_path}#{parameter_string}"
|
76
57
|
FlexmlsApi.logger.debug("Request: #{request_path}")
|
77
58
|
if body.nil?
|
78
59
|
response = connection.send(method, request_path)
|
@@ -86,6 +67,15 @@ module FlexmlsApi
|
|
86
67
|
def logout
|
87
68
|
@provider.save_session(nil)
|
88
69
|
end
|
70
|
+
|
71
|
+
def authorization_url()
|
72
|
+
params = {
|
73
|
+
"client_id" => @provider.client_id,
|
74
|
+
"response_type" => "code",
|
75
|
+
"redirect_uri" => @provider.redirect_uri
|
76
|
+
}
|
77
|
+
"#{@provider.authorization_uri}?#{build_url_parameters(params)}"
|
78
|
+
end
|
89
79
|
|
90
80
|
|
91
81
|
protected
|
@@ -94,35 +84,29 @@ module FlexmlsApi
|
|
94
84
|
{"Authorization"=> "OAuth #{session.access_token}"}
|
95
85
|
end
|
96
86
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
opts[:ssl] = {:verify => false }
|
103
|
-
opts[:url] = endpoint
|
104
|
-
conn = Faraday::Connection.new(opts) do |builder|
|
105
|
-
builder.adapter Faraday.default_adapter
|
106
|
-
builder.use Faraday::Response::ParseJson
|
107
|
-
builder.use FlexmlsApi::Authentication::FlexmlsOAuth2Middleware
|
108
|
-
end
|
87
|
+
def provider
|
88
|
+
@provider
|
89
|
+
end
|
90
|
+
def client
|
91
|
+
@client
|
109
92
|
end
|
93
|
+
|
110
94
|
end
|
111
95
|
|
112
96
|
# Representation of a session with the api using oauth2
|
113
97
|
class OAuthSession
|
114
|
-
attr_accessor :access_token, :expires_in, :scope, :refresh_token
|
98
|
+
attr_accessor :access_token, :expires_in, :scope, :refresh_token, :refresh_timeout
|
115
99
|
def initialize(options={})
|
116
100
|
@access_token = options["access_token"]
|
117
|
-
# TODO The current oauth2 service does not send an expiration time. I'm setting it to default to 1 hour.
|
118
101
|
@expires_in = options["expires_in"]
|
119
102
|
@scope = options["scope"]
|
120
103
|
@refresh_token = options["refresh_token"]
|
121
104
|
@start_time = DateTime.now
|
105
|
+
@refresh_timeout = 3600
|
122
106
|
end
|
123
107
|
# Is the user session token expired?
|
124
108
|
def expired?
|
125
|
-
@start_time + Rational(@expires_in,
|
109
|
+
@start_time + Rational(@expires_in - @refresh_timeout, 86400) < DateTime.now
|
126
110
|
end
|
127
111
|
end
|
128
112
|
|
@@ -137,7 +121,16 @@ module FlexmlsApi
|
|
137
121
|
# @client_secret - OAuth2 provided password for the client id
|
138
122
|
class BaseOAuth2Provider
|
139
123
|
|
140
|
-
attr_accessor :authorization_uri, :
|
124
|
+
attr_accessor :authorization_uri, :access_uri, :grant_type, :client_id, :client_secret
|
125
|
+
|
126
|
+
# Requirements for authorization_code grant type
|
127
|
+
attr_accessor :code, :redirect_uri
|
128
|
+
# Requirements for password grant type
|
129
|
+
attr_accessor :username, :password
|
130
|
+
|
131
|
+
def grant_type
|
132
|
+
:authorization_code
|
133
|
+
end
|
141
134
|
|
142
135
|
# Application using the client must handle user redirect for user authentication. For
|
143
136
|
# command line applications, this method is called prior to initial client requests so that
|
@@ -168,52 +161,11 @@ module FlexmlsApi
|
|
168
161
|
# Provides a default session time out
|
169
162
|
# returns - the session timeout length (in seconds)
|
170
163
|
def session_timeout
|
171
|
-
|
164
|
+
86400 # 1.day
|
172
165
|
end
|
173
|
-
|
174
|
-
end
|
175
166
|
|
176
|
-
#==OAuth2 Faraday response middleware
|
177
|
-
# HTTP Response after filter to package oauth2 responses and bubble up basic api errors.
|
178
|
-
class FlexmlsOAuth2Middleware < Faraday::Response::Middleware
|
179
|
-
begin
|
180
|
-
def self.register_on_complete(env)
|
181
|
-
env[:response].on_complete do |finished_env|
|
182
|
-
validate_and_build_response(finished_env)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
rescue LoadError, NameError => e
|
186
|
-
self.load_error = e
|
187
|
-
end
|
188
|
-
|
189
|
-
def self.validate_and_build_response(finished_env)
|
190
|
-
body = finished_env[:body]
|
191
|
-
FlexmlsApi.logger.debug("Response Body: #{body.inspect}")
|
192
|
-
unless body.is_a?(Hash)
|
193
|
-
raise InvalidResponse, "The server response could not be understood"
|
194
|
-
end
|
195
|
-
case finished_env[:status]
|
196
|
-
when 200..299
|
197
|
-
FlexmlsApi.logger.debug("Success!")
|
198
|
-
session = OAuthSession.new(body)
|
199
|
-
else
|
200
|
-
# Handle the WWW-Authenticate Response Header Field if present. This can be returned by
|
201
|
-
# OAuth2 implementations and wouldn't hurt to log.
|
202
|
-
auth_header_error = finished_env[:request_headers]["WWW-Authenticate"]
|
203
|
-
FlexmlsApi.logger.warn("Authentication error #{auth_header_error}") unless auth_header_error.nil?
|
204
|
-
raise ClientError.new(0, finished_env[:status]), body["error"]
|
205
|
-
end
|
206
|
-
FlexmlsApi.logger.debug("Session= #{session.inspect}")
|
207
|
-
finished_env[:body] = session
|
208
|
-
end
|
209
|
-
|
210
|
-
def initialize(app)
|
211
|
-
super
|
212
|
-
@parser = nil
|
213
|
-
end
|
214
|
-
|
215
167
|
end
|
216
|
-
|
168
|
+
|
217
169
|
end
|
218
170
|
|
219
171
|
end
|