vidibus-service 0.0.1
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/.bundle/config +2 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +135 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/app/models/service.rb +4 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +5 -0
- data/lib/vidibus/service/client.rb +66 -0
- data/lib/vidibus/service/connector_app.rb +154 -0
- data/lib/vidibus/service/controller_validations.rb +35 -0
- data/lib/vidibus/service/mongoid.rb +130 -0
- data/lib/vidibus/service.rb +15 -0
- data/lib/vidibus-service.rb +14 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/vidibus/service/client_spec.rb +73 -0
- data/spec/vidibus/service/connector_app_spec.rb +246 -0
- data/spec/vidibus/service/controller_validations_spec.rb +5 -0
- data/spec/vidibus/service/mongoid_spec.rb +226 -0
- data/spec/vidibus/service_spec.rb +14 -0
- data/vidibus-service.gemspec +92 -0
- metadata +199 -0
data/.bundle/config
ADDED
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem "mongoid", "~> 2.0.0.beta.20"
|
4
|
+
gem "vidibus-core_extensions"
|
5
|
+
gem "vidibus-secure"
|
6
|
+
gem "vidibus-uuid"
|
7
|
+
gem "vidibus-validate_uri"
|
8
|
+
|
9
|
+
gem "httparty"
|
10
|
+
gem "json"
|
11
|
+
|
12
|
+
# Development dependecies
|
13
|
+
gem "jeweler"
|
14
|
+
gem "rake"
|
15
|
+
gem "rspec", "~> 2.0.0.beta.20"
|
16
|
+
gem "rr"
|
17
|
+
gem "relevance-rcov"
|
18
|
+
gem "webmock"
|
19
|
+
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
actionmailer (3.0.0)
|
6
|
+
actionpack (= 3.0.0)
|
7
|
+
mail (~> 2.2.5)
|
8
|
+
actionpack (3.0.0)
|
9
|
+
activemodel (= 3.0.0)
|
10
|
+
activesupport (= 3.0.0)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
erubis (~> 2.6.6)
|
13
|
+
i18n (~> 0.4.1)
|
14
|
+
rack (~> 1.2.1)
|
15
|
+
rack-mount (~> 0.6.12)
|
16
|
+
rack-test (~> 0.5.4)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activemodel (3.0.0)
|
19
|
+
activesupport (= 3.0.0)
|
20
|
+
builder (~> 2.1.2)
|
21
|
+
i18n (~> 0.4.1)
|
22
|
+
activerecord (3.0.0)
|
23
|
+
activemodel (= 3.0.0)
|
24
|
+
activesupport (= 3.0.0)
|
25
|
+
arel (~> 1.0.0)
|
26
|
+
tzinfo (~> 0.3.23)
|
27
|
+
activeresource (3.0.0)
|
28
|
+
activemodel (= 3.0.0)
|
29
|
+
activesupport (= 3.0.0)
|
30
|
+
activesupport (3.0.0)
|
31
|
+
addressable (2.2.1)
|
32
|
+
arel (1.0.1)
|
33
|
+
activesupport (~> 3.0.0)
|
34
|
+
bson (1.0.4)
|
35
|
+
builder (2.1.2)
|
36
|
+
crack (0.1.8)
|
37
|
+
diff-lcs (1.1.2)
|
38
|
+
erubis (2.6.6)
|
39
|
+
abstract (>= 1.0.0)
|
40
|
+
gemcutter (0.6.1)
|
41
|
+
git (1.2.5)
|
42
|
+
httparty (0.6.1)
|
43
|
+
crack (= 0.1.8)
|
44
|
+
i18n (0.4.1)
|
45
|
+
jeweler (1.4.0)
|
46
|
+
gemcutter (>= 0.1.0)
|
47
|
+
git (>= 1.2.5)
|
48
|
+
rubyforge (>= 2.0.0)
|
49
|
+
json (1.4.6)
|
50
|
+
json_pure (1.4.6)
|
51
|
+
macaddr (1.0.0)
|
52
|
+
mail (2.2.6)
|
53
|
+
activesupport (>= 2.3.6)
|
54
|
+
mime-types
|
55
|
+
treetop (>= 1.4.5)
|
56
|
+
mime-types (1.16)
|
57
|
+
mongo (1.0.7)
|
58
|
+
bson (>= 1.0.4)
|
59
|
+
mongoid (2.0.0.beta.17)
|
60
|
+
activemodel (~> 3.0.0)
|
61
|
+
bson (= 1.0.4)
|
62
|
+
mongo (= 1.0.7)
|
63
|
+
tzinfo (~> 0.3.22)
|
64
|
+
will_paginate (~> 3.0.pre)
|
65
|
+
polyglot (0.3.1)
|
66
|
+
rack (1.2.1)
|
67
|
+
rack-mount (0.6.13)
|
68
|
+
rack (>= 1.0.0)
|
69
|
+
rack-test (0.5.4)
|
70
|
+
rack (>= 1.0)
|
71
|
+
rails (3.0.0)
|
72
|
+
actionmailer (= 3.0.0)
|
73
|
+
actionpack (= 3.0.0)
|
74
|
+
activerecord (= 3.0.0)
|
75
|
+
activeresource (= 3.0.0)
|
76
|
+
activesupport (= 3.0.0)
|
77
|
+
bundler (~> 1.0.0)
|
78
|
+
railties (= 3.0.0)
|
79
|
+
railties (3.0.0)
|
80
|
+
actionpack (= 3.0.0)
|
81
|
+
activesupport (= 3.0.0)
|
82
|
+
rake (>= 0.8.4)
|
83
|
+
thor (~> 0.14.0)
|
84
|
+
rake (0.8.7)
|
85
|
+
relevance-rcov (0.9.2.1)
|
86
|
+
rr (1.0.0)
|
87
|
+
rspec (2.0.0.beta.20)
|
88
|
+
rspec-core (= 2.0.0.beta.20)
|
89
|
+
rspec-expectations (= 2.0.0.beta.20)
|
90
|
+
rspec-mocks (= 2.0.0.beta.20)
|
91
|
+
rspec-core (2.0.0.beta.20)
|
92
|
+
rspec-expectations (2.0.0.beta.20)
|
93
|
+
diff-lcs (>= 1.1.2)
|
94
|
+
rspec-mocks (2.0.0.beta.20)
|
95
|
+
rubyforge (2.0.4)
|
96
|
+
json_pure (>= 1.1.7)
|
97
|
+
thor (0.14.0)
|
98
|
+
treetop (1.4.8)
|
99
|
+
polyglot (>= 0.3.1)
|
100
|
+
tzinfo (0.3.23)
|
101
|
+
uuid (2.3.1)
|
102
|
+
macaddr (~> 1.0)
|
103
|
+
vidibus-core_extensions (0.3.5)
|
104
|
+
vidibus-secure (0.0.1)
|
105
|
+
activesupport (~> 3.0.0)
|
106
|
+
mongoid (~> 2.0.0.beta.17)
|
107
|
+
rack
|
108
|
+
vidibus-core_extensions
|
109
|
+
vidibus-uuid (0.3.7)
|
110
|
+
mongoid (~> 2.0.0.beta.17)
|
111
|
+
uuid (~> 2.3.1)
|
112
|
+
vidibus-validate_uri (0.1.1)
|
113
|
+
rails (~> 3.0.0.rc)
|
114
|
+
webmock (1.3.5)
|
115
|
+
addressable (>= 2.1.1)
|
116
|
+
crack (>= 0.1.7)
|
117
|
+
will_paginate (3.0.pre2)
|
118
|
+
|
119
|
+
PLATFORMS
|
120
|
+
ruby
|
121
|
+
|
122
|
+
DEPENDENCIES
|
123
|
+
httparty
|
124
|
+
jeweler
|
125
|
+
json
|
126
|
+
mongoid (~> 2.0.0.beta.20)
|
127
|
+
rake
|
128
|
+
relevance-rcov
|
129
|
+
rr
|
130
|
+
rspec (~> 2.0.0.beta.20)
|
131
|
+
vidibus-core_extensions
|
132
|
+
vidibus-secure
|
133
|
+
vidibus-uuid
|
134
|
+
vidibus-validate_uri
|
135
|
+
webmock
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Andre Pankratz
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= vidibus-service
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Andre Pankratz. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
require "rake/rdoctask"
|
4
|
+
require "rspec"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "jeweler"
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = "vidibus-service"
|
11
|
+
gem.summary = %Q{Provides tools for Vidibus services}
|
12
|
+
gem.description = %Q{Description...}
|
13
|
+
gem.email = "andre@vidibus.com"
|
14
|
+
gem.homepage = "http://github.com/vidibus/vidibus-service"
|
15
|
+
gem.authors = ["Andre Pankratz"]
|
16
|
+
gem.add_dependency "mongoid", "~> 2.0.0.beta.20"
|
17
|
+
gem.add_dependency "vidibus-core_extensions"
|
18
|
+
gem.add_dependency "vidibus-uuid"
|
19
|
+
gem.add_dependency "vidibus-secure"
|
20
|
+
gem.add_dependency "vidibus-validate_uri"
|
21
|
+
gem.add_dependency "httparty"
|
22
|
+
gem.add_dependency "json"
|
23
|
+
end
|
24
|
+
Jeweler::GemcutterTasks.new
|
25
|
+
rescue LoadError
|
26
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
27
|
+
end
|
28
|
+
|
29
|
+
Rspec::Core::RakeTask.new(:rcov) do |t|
|
30
|
+
t.pattern = "spec/**/*_spec.rb"
|
31
|
+
t.rcov = true
|
32
|
+
t.rcov_opts = ["--exclude", "^spec,/gems/"]
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
version = File.exist?("VERSION") ? File.read("VERSION") : ""
|
37
|
+
rdoc.rdoc_dir = "rdoc"
|
38
|
+
rdoc.title = "vidibus-service #{version}"
|
39
|
+
rdoc.rdoc_files.include("README*")
|
40
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
41
|
+
rdoc.options << "--charset=utf-8"
|
42
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/config/routes.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "httparty"
|
2
|
+
|
3
|
+
module Vidibus
|
4
|
+
module Service
|
5
|
+
class Client
|
6
|
+
include HTTParty
|
7
|
+
format :json
|
8
|
+
|
9
|
+
class ServiceError < Error; end
|
10
|
+
|
11
|
+
attr_accessor :base_uri, :service, :this
|
12
|
+
|
13
|
+
# Initializes a new client for given service.
|
14
|
+
def initialize(service)
|
15
|
+
raise ServiceError.new("Service required") unless service and service.is_a?(::Service)
|
16
|
+
self.service = service
|
17
|
+
self.this = ::Service.this
|
18
|
+
self.base_uri = service.url or raise(ServiceError.new("URL of service required"))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Sends a GET request to given path.
|
22
|
+
def get(path, options = {})
|
23
|
+
request(:get, path, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sends a POST request to given path.
|
27
|
+
def post(path, options = {})
|
28
|
+
request(:post, path, options)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sends a PUT request to given path.
|
32
|
+
def put(path, options = {})
|
33
|
+
request(:put, path, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sends a DELETE request to given path.
|
37
|
+
def delete(path, options = {})
|
38
|
+
request(:delete, path, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
# Extends given query options and sends request with given verb.
|
44
|
+
def request(verb, path, options)
|
45
|
+
options_type = %w[post put].include?(verb.to_s) ? :body : :query
|
46
|
+
options[options_type] = {:realm => service.realm_uuid, :service => this.uuid}.merge(options[options_type] || {})
|
47
|
+
uri = build_uri(path)
|
48
|
+
Vidibus::Secure.sign_request(verb, uri, options[options_type], secret)
|
49
|
+
self.class.send(verb, uri, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Builds URI from base URI of service and given path.
|
53
|
+
def build_uri(path)
|
54
|
+
path = path.to_s
|
55
|
+
raise("Expected path, got #{path}") unless path.match(/^\//)
|
56
|
+
base_uri + path
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns secret to use depending on given service. If a Connector is about to be contacted,
|
60
|
+
# the secret of this service will be used, otherwise the secret of the contacted service.
|
61
|
+
def secret
|
62
|
+
(@service.connector? and @service.secret == nil) ? @this.secret : @service.secret
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Vidibus
|
4
|
+
module Service
|
5
|
+
class ConnectorApp
|
6
|
+
class SignatureError < StandardError; end
|
7
|
+
|
8
|
+
def self.call(env)
|
9
|
+
self.new.call(env)
|
10
|
+
end
|
11
|
+
|
12
|
+
# This is just a rack endpoint for Remote authentication. It will be called
|
13
|
+
# by the Remote after requesting an authentication code.
|
14
|
+
def call(env)
|
15
|
+
@request = Rack::Request.new(env)
|
16
|
+
unless @request.path == "/connector"
|
17
|
+
return response(:error => "This app must be configured to respond to /connector path.")
|
18
|
+
end
|
19
|
+
method = @request.request_method.downcase
|
20
|
+
if respond_to?(method)
|
21
|
+
send(method)
|
22
|
+
else
|
23
|
+
response(:error => "Invalid request method: #{method}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# Creates this service and, unless it has already been set up, a Connector service.
|
30
|
+
# Once this service has been created, a secret will be traded for given nonce.
|
31
|
+
def post
|
32
|
+
unless this = service.where(:this => true, :realm => nil).first
|
33
|
+
unless connector = service.local(:connector)
|
34
|
+
connector_data = @request.params["connector"] or
|
35
|
+
return response(:error => "No Connector data given.")
|
36
|
+
connector = service.new(connector_data.merge(:function => "connector"))
|
37
|
+
unless connector.save
|
38
|
+
return response(:error => "Setting up the Connector failed: #{connector.errors.full_messages}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
this_data = @request.params["this"] or
|
42
|
+
return response(:error => "No data for this service given.")
|
43
|
+
this = service.new(this_data.merge(:this => true))
|
44
|
+
this.secret = "this is just a mock"
|
45
|
+
if this.valid?
|
46
|
+
nonce = @request.params["this"]["nonce"]
|
47
|
+
unless nonce == ""
|
48
|
+
uri = "#{connector.url}/services/#{this.uuid}/secret"
|
49
|
+
res = HTTParty.get(uri, :format => :json)
|
50
|
+
end
|
51
|
+
unless nonce.to_s.length > 5 and Vidibus::Secure.sign(res["secret"], nonce) == res["sign"]
|
52
|
+
return response(:error => "Nonce is invalid.")
|
53
|
+
end
|
54
|
+
this.secret = Vidibus::Secure.decrypt(res["secret"], nonce)
|
55
|
+
if this.save
|
56
|
+
return response({:success => "Setup successful"}, 201)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
response(:error => "Setting up this service failed: #{this.errors.full_messages}")
|
60
|
+
else
|
61
|
+
response(:error => "Service has already been set up.")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns settings of this and Connector.
|
66
|
+
# This action must only be called by Connector. Thus it is signed
|
67
|
+
# with the Service's secret.
|
68
|
+
def get
|
69
|
+
verify_request!
|
70
|
+
out = {:this => this.public_data}
|
71
|
+
if connector = service.local(:connector)
|
72
|
+
out[:connector] = connector.public_data
|
73
|
+
end
|
74
|
+
response(out)
|
75
|
+
rescue => e
|
76
|
+
response(:error => e.message)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Updates data of given services.
|
80
|
+
# If a service does not exist, it will be created.
|
81
|
+
def put
|
82
|
+
verify_request!
|
83
|
+
for function, attributes in @request.params.except("sign")
|
84
|
+
_service = service.local(function) || service.new(:function => function)
|
85
|
+
_service.attributes = attributes
|
86
|
+
unless _service.save
|
87
|
+
return response(:error => "Updating #{function} failed: #{_service.errors.full_messages}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
response(:success => "Services updated.")
|
91
|
+
rescue => e
|
92
|
+
response(:error => e.message)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Deletes services by their UUID.
|
96
|
+
def delete
|
97
|
+
verify_request!
|
98
|
+
raise ArgumentError.new("Provide list of :uuids") unless uuids = @request.params["uuids"]
|
99
|
+
for uuid in uuids
|
100
|
+
if found = service.where(:uuid => uuid).first
|
101
|
+
found.destroy
|
102
|
+
end
|
103
|
+
end
|
104
|
+
response(:success => "Services have been deleted.")
|
105
|
+
rescue => e
|
106
|
+
response(:error => e.message)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Verifies that signature is valid.
|
110
|
+
def verify_request!
|
111
|
+
Vidibus::Secure.verify_request(@request.request_method, @request.url, @request.params, this.secret) or
|
112
|
+
raise SignatureError.new("Invalid signature.")
|
113
|
+
end
|
114
|
+
|
115
|
+
# Renders response.
|
116
|
+
def response(data, status = nil, type = :js)
|
117
|
+
if data[:error]
|
118
|
+
status ||= 400
|
119
|
+
else
|
120
|
+
status ||= 200
|
121
|
+
end
|
122
|
+
Rack::Response.new([data.to_json], status, content_type(type)).finish
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sets content type for response.
|
126
|
+
def content_type(type = nil)
|
127
|
+
string = case type
|
128
|
+
when :js
|
129
|
+
"text/javascript; charset=utf-8"
|
130
|
+
else
|
131
|
+
"text/html; charset=utf-8"
|
132
|
+
end
|
133
|
+
{ 'Content-Type' => string }
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns service class.
|
137
|
+
def service
|
138
|
+
@service ||= ::Service
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns data of this service.
|
142
|
+
# It will raise an error if this service is unconfigured.
|
143
|
+
def this
|
144
|
+
@this ||= service.this
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns data of the Connector.
|
148
|
+
# It will raise an error if this service is unconfigured.
|
149
|
+
def connector
|
150
|
+
@connector ||= service.connector
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Vidibus
|
2
|
+
module Service
|
3
|
+
module ControllerValidations
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
skip_before_filter :verify_authenticity_token
|
8
|
+
before_filter :ensure_realm!
|
9
|
+
before_filter :ensure_service!
|
10
|
+
before_filter :validate_signature!
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
# Ensures that +realm+ parameter is given and valid.
|
16
|
+
def ensure_realm!
|
17
|
+
@realm = params[:realm] or raise "no realm given"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Ensures that +service+ parameter is given and valid.
|
21
|
+
def ensure_service!
|
22
|
+
service = params[:service] or raise "no service given"
|
23
|
+
@service = Service(service, @realm) or raise "invalid service"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Validates +sign+ parameter.
|
27
|
+
def validate_signature!
|
28
|
+
params[:sign] or raise "no signature given"
|
29
|
+
unless valid_request?(@service.secret)
|
30
|
+
raise "invalid signature"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Vidibus
|
2
|
+
module Service
|
3
|
+
module Mongoid
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include Vidibus::Secure::Mongoid
|
6
|
+
|
7
|
+
class ConfigurationError < Error; end
|
8
|
+
class ConnectorError < Error; end
|
9
|
+
|
10
|
+
included do
|
11
|
+
field :url
|
12
|
+
field :uuid
|
13
|
+
field :function
|
14
|
+
field :realm_uuid
|
15
|
+
field :this, :type => Boolean
|
16
|
+
|
17
|
+
attr_encrypted :secret
|
18
|
+
|
19
|
+
validates :url, :uri => {:protocol => [:http, :https], :accessible => false}
|
20
|
+
validates :uuid, :uuid => true, :uniqueness => {:scope => :realm_uuid}
|
21
|
+
validates :realm_uuid, :uuid => {:allow_blank => true}
|
22
|
+
validates :function, :presence => true
|
23
|
+
validates :secret, :presence => true, :unless => :connector?
|
24
|
+
validates :realm_uuid, :presence => true, :unless => Proc.new {|s| s.connector? or s.this?}
|
25
|
+
|
26
|
+
validate :dont_allow_secret_for_connector, :if => :connector?
|
27
|
+
|
28
|
+
# Removes trailing slash from given value.
|
29
|
+
def url=(value)
|
30
|
+
value.gsub!(/\/+$/, "") if value
|
31
|
+
self.write_attribute(:url, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if this service is a connector
|
35
|
+
def connector?
|
36
|
+
@is_connector ||= function == "connector"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sends a GET request to given path.
|
40
|
+
def get(path, options = {})
|
41
|
+
client.get(path, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sends a POST request to given path.
|
45
|
+
def post(path, options = {})
|
46
|
+
client.post(path, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sends a PUT request to given path.
|
50
|
+
def put(path, options = {})
|
51
|
+
client.put(path, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sends a DELETE request to given path.
|
55
|
+
def delete(path, options = {})
|
56
|
+
client.delete(path, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns publicly requestable data.
|
60
|
+
def public_data
|
61
|
+
attributes.only(%w[uuid function url])
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns url without protocol.
|
65
|
+
def domain
|
66
|
+
url.gsub(/https?:\/\//, "") if url
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
# Returns a Client for current service.
|
72
|
+
def client
|
73
|
+
@client ||= Client.new(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets an error if secret is given for Connector service.
|
77
|
+
def dont_allow_secret_for_connector
|
78
|
+
errors.add(:secret, :secret_not_allowed_for_connector) if connector? and secret
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module ClassMethods
|
83
|
+
|
84
|
+
# Returns this service, if it has been configured, or raises an ConfigurationError.
|
85
|
+
def this
|
86
|
+
where(:this => true).and(:realm_uuid => nil).first or
|
87
|
+
raise ConfigurationError.new("This service has not been configured yet. Use your Connector to set it up.")
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns Connector service, if it has been configured, or raises an ConfigurationError.
|
91
|
+
def connector
|
92
|
+
where(:function => "connector").and(:realm_uuid => nil).first or
|
93
|
+
raise ConfigurationError.new("No Connector has been assigned to this service yet. Use your Connector to perform the assignment.")
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns best service by function or UUID within given realm.
|
97
|
+
# If a service can be found in stored, it will be fetched from Connector.
|
98
|
+
def discover(wanted, realm = nil)
|
99
|
+
unless service = local(wanted, realm)
|
100
|
+
service = remote(wanted, realm)
|
101
|
+
end
|
102
|
+
service
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns stored service by function or UUID within given realm.
|
106
|
+
def local(wanted, realm = nil)
|
107
|
+
key = Vidibus::Uuid.validate(wanted) ? :uuid : :function
|
108
|
+
where(key => wanted).and(:realm_uuid => realm).first
|
109
|
+
end
|
110
|
+
|
111
|
+
# Requests service from Connector and stores it.
|
112
|
+
# Wanted may be a function or an UUID.
|
113
|
+
# This method should not be called directly. Use #discover to avoid unneccessary lookups.
|
114
|
+
def remote(wanted, realm)
|
115
|
+
unless realm
|
116
|
+
raise ArgumentError.new("Please provide a valid realm to discover an appropriate service.")
|
117
|
+
end
|
118
|
+
if response = connector.get("/services/#{wanted}", :query => {:realm => realm})
|
119
|
+
secret = response["secret"] || raise(ConnectorError.new("The Connector did not return a secret for #{wanted}. Response was: #{response.parsed_response.inspect}"))
|
120
|
+
secret = Vidibus::Secure.decrypt(secret, this.secret)
|
121
|
+
attributes = response.only(%w[uuid function url]).merge(:realm_uuid => realm, :secret => secret)
|
122
|
+
create!(attributes)
|
123
|
+
else
|
124
|
+
raise "no service found"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|