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 ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format nested
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
@@ -0,0 +1,4 @@
1
+ class Service
2
+ include Mongoid::Document
3
+ include Vidibus::Service::Mongoid
4
+ end
@@ -0,0 +1,5 @@
1
+ en:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ secret_not_allowed_for_connector: "is not allowed for a Connector"
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "service/connector_app"
2
+
3
+ Rails.application.routes.draw do
4
+ match "/connector" => Vidibus::Service::ConnectorApp
5
+ end
@@ -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