vidibus-service 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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