summon-faraday_middleware 0.1.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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/README.md +41 -0
- data/Rakefile +4 -0
- data/lib/summon/faraday_middleware.rb +12 -0
- data/lib/summon/faraday_middleware/summon_authentication.rb +93 -0
- data/lib/summon/faraday_middleware/version.rb +5 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/summon/faraday_middleware/summon_authentication_spec.rb +98 -0
- data/spec/summon/faraday_middleware_spec.rb +8 -0
- data/summon-faraday_middleware.gemspec +23 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Summon::FaradayMiddleware
|
2
|
+
|
3
|
+
[Faraday](https://github.com/lostisland/faraday) middleware to authenticate against the [Serials Solutions Summon Unified Discovery Service](http://www.serialssolutions.com/en/services/summon/) API.
|
4
|
+
For more information on the API, see http://api.summon.serialssolutions.com/help/api/.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'summon-faraday_middleware'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install summon-faraday_middleware
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
conn = Faraday.new(:url => 'http://api.summon.serialssolutions.com') do |builder|
|
23
|
+
builder.request :summon_auth,
|
24
|
+
:access_id => 'my_access_id', :secret_key => 'my_secret_key'
|
25
|
+
builder.adapter Faraday.default_adapter # or any other adapter
|
26
|
+
end
|
27
|
+
|
28
|
+
response = conn.get('/2.0.0/search') do |req|
|
29
|
+
req.headers['Accept'] = 'application/json' # or xml
|
30
|
+
req.params['s.q'] = 'My Query'
|
31
|
+
end
|
32
|
+
|
33
|
+
puts response.body
|
34
|
+
|
35
|
+
## Contributing
|
36
|
+
|
37
|
+
1. Fork it
|
38
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
39
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
40
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
41
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "summon/faraday_middleware/version"
|
2
|
+
require 'summon/faraday_middleware/summon_authentication'
|
3
|
+
|
4
|
+
module Summon
|
5
|
+
module FaradayMiddleware
|
6
|
+
if Faraday.respond_to? :register_middleware
|
7
|
+
Faraday.register_middleware :request,
|
8
|
+
:summon_auth => lambda { SummonAuthentication }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'time'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module Summon
|
6
|
+
module FaradayMiddleware
|
7
|
+
class SummonAuthentication < ::Faraday::Middleware
|
8
|
+
|
9
|
+
AUTH_HEADER = 'Authorization'.freeze
|
10
|
+
HOST_HEADER = 'Host'
|
11
|
+
SUMMON_PREFIX = 'Summon'.freeze
|
12
|
+
SUMMON_DATE = 'x-summon-date'.freeze
|
13
|
+
SUMMON_SESSION = 'x-summon-session-id'.freeze
|
14
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
15
|
+
ACCEPT_HEADER = 'Accept'.freeze
|
16
|
+
TYPE_URLENCODED = 'application/x-www-form-urlencoded; charset=utf8'.freeze
|
17
|
+
|
18
|
+
Error = Class.new(StandardError)
|
19
|
+
AuthenticationError = Class.new(Error)
|
20
|
+
|
21
|
+
attr_accessor :access_id, :secret_key
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
uri = env[:url]
|
25
|
+
headers = env[:request_headers]
|
26
|
+
headers[CONTENT_TYPE] = TYPE_URLENCODED
|
27
|
+
headers[HOST_HEADER] = "#{uri.host}:#{uri.port}"
|
28
|
+
headers[SUMMON_DATE] = httpdate
|
29
|
+
headers[SUMMON_SESSION] = session_id
|
30
|
+
headers[AUTH_HEADER] = authorization(env)
|
31
|
+
@app.call(env)
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(app, options = {})
|
35
|
+
super(app)
|
36
|
+
@access_id = options.fetch(:access_id) { |name| handle_missing_parameter(name) }
|
37
|
+
@secret_key = options.fetch(:secret_key) { |name| handle_missing_parameter(name) }
|
38
|
+
@client_key = options[:client_key]
|
39
|
+
@session_id = options[:session_id]
|
40
|
+
end
|
41
|
+
|
42
|
+
def httpdate
|
43
|
+
Time.now.httpdate
|
44
|
+
end
|
45
|
+
|
46
|
+
def session_id
|
47
|
+
@session_id ||= generate_session_id
|
48
|
+
end
|
49
|
+
|
50
|
+
def client_key
|
51
|
+
@client_key.upcase if @client_key
|
52
|
+
end
|
53
|
+
|
54
|
+
def authorization(env)
|
55
|
+
value = [access_id, client_key, digest(env)].compact.join(';')
|
56
|
+
"#{SUMMON_PREFIX} #{value}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def digest(env)
|
60
|
+
uri = env[:url]
|
61
|
+
headers = env[:request_headers]
|
62
|
+
data = []
|
63
|
+
data << headers.fetch(ACCEPT_HEADER) { |name| handle_missing_header(name) }
|
64
|
+
data << headers.fetch(SUMMON_DATE) { |name| handle_missing_header(name) }
|
65
|
+
data << headers.fetch(HOST_HEADER) { |name| handle_missing_header(name) }
|
66
|
+
data << uri.path
|
67
|
+
data << sort_query_params(uri.query)
|
68
|
+
data << ''
|
69
|
+
Digest::HMAC.base64digest(data.join("\n"), @secret_key, Digest::SHA1).chomp
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def generate_session_id
|
75
|
+
require 'socket'
|
76
|
+
"SUMMON-SESSION-#{Socket.gethostname}-#{$$}-#{object_id}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def handle_missing_parameter(name)
|
80
|
+
raise AuthenticationError, "Missing required parameter: :#{name}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def handle_missing_header(name)
|
84
|
+
raise AuthenticationError, "Missing required header: #{name}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def sort_query_params(query)
|
88
|
+
query.split('&').sort.join('&')
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Summon::FaradayMiddleware::SummonAuthentication do
|
4
|
+
|
5
|
+
def perform(params = {}, headers = {})
|
6
|
+
env = {
|
7
|
+
:url => URI('http://example.com/search?' + ::Faraday::Utils.build_query(params)),
|
8
|
+
:request_headers => ::Faraday::Utils::Headers.new.update(headers)
|
9
|
+
}
|
10
|
+
env[:request_headers]['Accept'] = accept if defined? accept
|
11
|
+
app = make_app
|
12
|
+
app.call(env)
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_app
|
16
|
+
described_class.new(lambda{|env| env}, options.reject { |o| o.nil? })
|
17
|
+
end
|
18
|
+
|
19
|
+
context "required parameters: " do
|
20
|
+
context "an access_id" do
|
21
|
+
let(:options) { {:secret_key => 'bar'} }
|
22
|
+
it 'is required' do
|
23
|
+
expect { perform }.to raise_error, "Missing required parameter: :access_id"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
context "a secret_key" do
|
27
|
+
let(:options) { {:access_id => 'foo'} }
|
28
|
+
it 'is required' do
|
29
|
+
expect { perform }.to raise_error, "Missing required parameter: :secret_key"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "headers" do
|
35
|
+
let(:options) { {:access_id => 'foo',
|
36
|
+
:secret_key => 'bar',
|
37
|
+
:client_key => 'abcd1234' } }
|
38
|
+
|
39
|
+
it "must include 'Accept'" do
|
40
|
+
expect { perform }.to raise_error, "Missing required header: Accept"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "applying the middleware" do
|
45
|
+
let(:session_id) { nil }
|
46
|
+
let(:client_key) { nil }
|
47
|
+
let(:accept) { 'application/json' }
|
48
|
+
let(:options) { {:access_id => 'foo',
|
49
|
+
:secret_key => 'bar',
|
50
|
+
:client_key => client_key,
|
51
|
+
:session_id => session_id } }
|
52
|
+
let(:env) { perform("s.q" => "Summon") }
|
53
|
+
let(:headers) { env[:request_headers] }
|
54
|
+
|
55
|
+
before do
|
56
|
+
Time.stub(:now) { Time.new(2012, 1, 2, 3, 4, 5, 3600*8) }
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets the summon date header" do
|
60
|
+
headers['x-summon-date'].should eql "Sun, 01 Jan 2012 19:04:05 GMT"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "sets a host header" do
|
64
|
+
headers['Host'].should eql "example.com:80"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "sets the urlencoded content-type header" do
|
68
|
+
headers['Content-Type'].should eql 'application/x-www-form-urlencoded; charset=utf8'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "sets the authorization header" do
|
72
|
+
headers['Authorization'].should eql 'Summon foo;oGfYSxLUZBYt43MoZpI+w85P1vI='
|
73
|
+
end
|
74
|
+
|
75
|
+
context "without a session id" do
|
76
|
+
let(:session_id) { nil }
|
77
|
+
it "generates a session id" do
|
78
|
+
headers['x-summon-session-id'].should_not be_nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "with a session id" do
|
83
|
+
let(:session_id) { "provided-session-id" }
|
84
|
+
it "uses the provided session id" do
|
85
|
+
headers['x-summon-session-id'].should eql 'provided-session-id'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with a custom client id" do
|
90
|
+
let(:client_key) { 'abcd1234' }
|
91
|
+
|
92
|
+
it "adds the client key to the authentication header, in caps" do
|
93
|
+
headers['Authorization'].should eql "Summon foo;ABCD1234;oGfYSxLUZBYt43MoZpI+w85P1vI="
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'summon/faraday_middleware/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "summon-faraday_middleware"
|
8
|
+
gem.version = Summon::FaradayMiddleware::VERSION
|
9
|
+
gem.authors = ["Daniël van de Burgt"]
|
10
|
+
gem.email = ["daniel.vandeburgt@serialssolutions.com"]
|
11
|
+
gem.description = %q{A Faraday Middleware for signing Summon API requests}
|
12
|
+
gem.summary = gem.description
|
13
|
+
gem.homepage = "https://github.com/summon/summon-faraday_middleware"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "faraday", "~> 0.8.4"
|
21
|
+
gem.add_development_dependency "rake", ">= 0.9.2"
|
22
|
+
gem.add_development_dependency "rspec", ">= 2.12.0"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: summon-faraday_middleware
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniël van de Burgt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: faraday
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.8.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.8.4
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.9.2
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.9.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.12.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.12.0
|
62
|
+
description: A Faraday Middleware for signing Summon API requests
|
63
|
+
email:
|
64
|
+
- daniel.vandeburgt@serialssolutions.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- lib/summon/faraday_middleware.rb
|
74
|
+
- lib/summon/faraday_middleware/summon_authentication.rb
|
75
|
+
- lib/summon/faraday_middleware/version.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/summon/faraday_middleware/summon_authentication_spec.rb
|
78
|
+
- spec/summon/faraday_middleware_spec.rb
|
79
|
+
- summon-faraday_middleware.gemspec
|
80
|
+
homepage: https://github.com/summon/summon-faraday_middleware
|
81
|
+
licenses: []
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.8.24
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: A Faraday Middleware for signing Summon API requests
|
104
|
+
test_files:
|
105
|
+
- spec/spec_helper.rb
|
106
|
+
- spec/summon/faraday_middleware/summon_authentication_spec.rb
|
107
|
+
- spec/summon/faraday_middleware_spec.rb
|