maestrano-ruby-test 0.8.3

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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +45 -0
  5. data/LICENSE +21 -0
  6. data/README.md +794 -0
  7. data/Rakefile +40 -0
  8. data/bin/maestrano-console +9 -0
  9. data/lib/maestrano.rb +271 -0
  10. data/lib/maestrano/account/bill.rb +14 -0
  11. data/lib/maestrano/account/recurring_bill.rb +14 -0
  12. data/lib/maestrano/api/error/authentication_error.rb +8 -0
  13. data/lib/maestrano/api/error/base_error.rb +24 -0
  14. data/lib/maestrano/api/error/connection_error.rb +8 -0
  15. data/lib/maestrano/api/error/invalid_request_error.rb +14 -0
  16. data/lib/maestrano/api/list_object.rb +37 -0
  17. data/lib/maestrano/api/object.rb +187 -0
  18. data/lib/maestrano/api/operation/base.rb +215 -0
  19. data/lib/maestrano/api/operation/create.rb +18 -0
  20. data/lib/maestrano/api/operation/delete.rb +13 -0
  21. data/lib/maestrano/api/operation/list.rb +18 -0
  22. data/lib/maestrano/api/operation/update.rb +59 -0
  23. data/lib/maestrano/api/resource.rb +47 -0
  24. data/lib/maestrano/api/util.rb +122 -0
  25. data/lib/maestrano/open_struct.rb +11 -0
  26. data/lib/maestrano/saml/attribute_value.rb +15 -0
  27. data/lib/maestrano/saml/metadata.rb +64 -0
  28. data/lib/maestrano/saml/request.rb +93 -0
  29. data/lib/maestrano/saml/response.rb +201 -0
  30. data/lib/maestrano/saml/schemas/saml20assertion_schema.xsd +283 -0
  31. data/lib/maestrano/saml/schemas/saml20protocol_schema.xsd +302 -0
  32. data/lib/maestrano/saml/schemas/xenc_schema.xsd +146 -0
  33. data/lib/maestrano/saml/schemas/xmldsig_schema.xsd +318 -0
  34. data/lib/maestrano/saml/settings.rb +37 -0
  35. data/lib/maestrano/saml/validation_error.rb +7 -0
  36. data/lib/maestrano/sso.rb +86 -0
  37. data/lib/maestrano/sso/base_group.rb +31 -0
  38. data/lib/maestrano/sso/base_membership.rb +25 -0
  39. data/lib/maestrano/sso/base_user.rb +75 -0
  40. data/lib/maestrano/sso/group.rb +24 -0
  41. data/lib/maestrano/sso/session.rb +107 -0
  42. data/lib/maestrano/sso/user.rb +34 -0
  43. data/lib/maestrano/version.rb +3 -0
  44. data/lib/maestrano/xml_security/signed_document.rb +170 -0
  45. data/maestrano.gemspec +32 -0
  46. data/maestrano.png +0 -0
  47. data/test/helpers/api_helpers.rb +115 -0
  48. data/test/helpers/saml_helpers.rb +62 -0
  49. data/test/maestrano/account/bill_test.rb +48 -0
  50. data/test/maestrano/account/recurring_bill_test.rb +49 -0
  51. data/test/maestrano/api/list_object_test.rb +20 -0
  52. data/test/maestrano/api/object_test.rb +28 -0
  53. data/test/maestrano/api/resource_test.rb +343 -0
  54. data/test/maestrano/api/util_test.rb +31 -0
  55. data/test/maestrano/maestrano_test.rb +260 -0
  56. data/test/maestrano/open_struct_test.rb +10 -0
  57. data/test/maestrano/saml/request_test.rb +168 -0
  58. data/test/maestrano/saml/response_test.rb +290 -0
  59. data/test/maestrano/saml/settings_test.rb +51 -0
  60. data/test/maestrano/sso/base_group_test.rb +54 -0
  61. data/test/maestrano/sso/base_membership_test.rb +45 -0
  62. data/test/maestrano/sso/base_user_test.rb +114 -0
  63. data/test/maestrano/sso/group_test.rb +47 -0
  64. data/test/maestrano/sso/session_test.rb +161 -0
  65. data/test/maestrano/sso/user_test.rb +65 -0
  66. data/test/maestrano/sso_test.rb +105 -0
  67. data/test/maestrano/xml_security/signed_document.rb +163 -0
  68. data/test/support/saml/certificates/certificate1 +12 -0
  69. data/test/support/saml/certificates/r1_certificate2_base64 +1 -0
  70. data/test/support/saml/responses/adfs_response_sha1.xml +46 -0
  71. data/test/support/saml/responses/adfs_response_sha256.xml +46 -0
  72. data/test/support/saml/responses/adfs_response_sha384.xml +46 -0
  73. data/test/support/saml/responses/adfs_response_sha512.xml +46 -0
  74. data/test/support/saml/responses/no_signature_ns.xml +48 -0
  75. data/test/support/saml/responses/open_saml_response.xml +56 -0
  76. data/test/support/saml/responses/r1_response6.xml.base64 +1 -0
  77. data/test/support/saml/responses/response1.xml.base64 +1 -0
  78. data/test/support/saml/responses/response2.xml.base64 +79 -0
  79. data/test/support/saml/responses/response3.xml.base64 +66 -0
  80. data/test/support/saml/responses/response4.xml.base64 +93 -0
  81. data/test/support/saml/responses/response5.xml.base64 +102 -0
  82. data/test/support/saml/responses/response_with_ampersands.xml +139 -0
  83. data/test/support/saml/responses/response_with_ampersands.xml.base64 +93 -0
  84. data/test/support/saml/responses/response_with_multiple_attribute_values.xml +57 -0
  85. data/test/support/saml/responses/simple_saml_php.xml +71 -0
  86. data/test/support/saml/responses/starfield_response.xml.base64 +1 -0
  87. data/test/support/saml/responses/wrapped_response_2.xml.base64 +150 -0
  88. data/test/test_helper.rb +47 -0
  89. metadata +315 -0
@@ -0,0 +1,40 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+ Bundler::GemHelper.install_tasks
7
+
8
+
9
+ task :default => [:test]
10
+
11
+ require 'rake/testtask'
12
+ Rake::TestTask.new(:test) do |test|
13
+ test.libs << 'lib' << 'test'
14
+ test.pattern = 'test/**/*_test.rb'
15
+ test.verbose = true
16
+ end
17
+
18
+ Rake::TestTask.new(:saml) do |test|
19
+ test.libs << 'lib' << 'test'
20
+ test.pattern = 'test/maestrano/saml/**/*_test.rb'
21
+ test.verbose = true
22
+ end
23
+
24
+ Rake::TestTask.new(:api) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/maestrano/api/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ Rake::TestTask.new(:sso) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/maestrano/sso{_test.rb,/**/*_test.rb}'
33
+ test.verbose = true
34
+ end
35
+
36
+ Rake::TestTask.new(:xmlsec) do |test|
37
+ test.libs << 'lib' << 'test'
38
+ test.pattern = 'test/maestrano/xml_security/**/*_test.rb'
39
+ test.verbose = true
40
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3
+
4
+ libs = " -r irb/completion"
5
+ libs << " -I #{File.dirname(__FILE__) + '/../lib'}"
6
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/maestrano'}"
7
+ puts ">> Loading Maestrano console"
8
+ puts ">>"
9
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,271 @@
1
+ # libs
2
+ require 'rest_client'
3
+ require 'json'
4
+
5
+ # OpenStruct (Extended)
6
+ require 'ostruct'
7
+ require 'maestrano/open_struct'
8
+
9
+ # Version
10
+ require 'maestrano/version'
11
+
12
+ # XMLSecurity
13
+ require 'maestrano/xml_security/signed_document'
14
+
15
+ # SAML
16
+ require 'maestrano/saml/request'
17
+ require 'maestrano/saml/attribute_value'
18
+ require 'maestrano/saml/response'
19
+ require 'maestrano/saml/settings'
20
+ require 'maestrano/saml/validation_error'
21
+ require 'maestrano/saml/metadata'
22
+
23
+ # SSO
24
+ require 'maestrano/sso'
25
+ require 'maestrano/sso/base_user'
26
+ require 'maestrano/sso/base_group'
27
+ require 'maestrano/sso/base_membership'
28
+ require 'maestrano/sso/session'
29
+ require 'maestrano/sso/user'
30
+ require 'maestrano/sso/group'
31
+
32
+ # API Errors
33
+ require 'maestrano/api/error/base_error'
34
+ require 'maestrano/api/error/authentication_error'
35
+ require 'maestrano/api/error/connection_error'
36
+ require 'maestrano/api/error/invalid_request_error'
37
+
38
+ # API Operations
39
+ require 'maestrano/api/operation/base'
40
+ require 'maestrano/api/operation/create'
41
+ require 'maestrano/api/operation/delete'
42
+ require 'maestrano/api/operation/list'
43
+ require 'maestrano/api/operation/update'
44
+
45
+ # API
46
+ require 'maestrano/api/util'
47
+ require 'maestrano/api/object'
48
+ require 'maestrano/api/list_object'
49
+ require 'maestrano/api/resource'
50
+
51
+ # API - Account Entities
52
+ require 'maestrano/account/bill'
53
+ require 'maestrano/account/recurring_bill'
54
+
55
+ module Maestrano
56
+
57
+ class << self
58
+ attr_accessor :config
59
+ end
60
+
61
+ # Maestrano Configuration block
62
+ def self.configure
63
+ self.config ||= Configuration.new
64
+ yield(config)
65
+ self.config.post_initialize
66
+ return self
67
+ end
68
+
69
+ # Check that app_id and api_key passed
70
+ # in argument match
71
+ def self.authenticate(app_id,api_key)
72
+ self.param(:app_id) == app_id && self.param(:api_key) == api_key
73
+ end
74
+
75
+ # Take a user uid (either real or virtual)
76
+ # and a group id and return the user uid that should
77
+ # be used within the app based on the user_creation_mode
78
+ # parameter:
79
+ # 'real': then the real user uid is returned (usr-4d5sfd)
80
+ # 'virtual': then the virtual user uid is returned (usr-4d5sfd.cld-g4f5d)
81
+ def self.mask_user(user_uid,group_uid)
82
+ sanitized_user_uid = self.unmask_user(user_uid)
83
+ if Maestrano.param('sso.creation_mode') == 'virtual'
84
+ return "#{sanitized_user_uid}.#{group_uid}"
85
+ else
86
+ return sanitized_user_uid
87
+ end
88
+ end
89
+
90
+ # Take a user uid (either real or virtual)
91
+ # and return the real uid part
92
+ def self.unmask_user(user_uid)
93
+ user_uid.split(".").first
94
+ end
95
+
96
+ # Get configuration parameter value
97
+ # E.g:
98
+ # Maestrano.param('api.key')
99
+ # Maestrano.param(:api_key)
100
+ def self.param(parameter)
101
+ self.config.param(parameter)
102
+ end
103
+
104
+ # Return a hash describing the current
105
+ # Maestrano configuration. The metadata
106
+ # will be remotely fetched by Maestrano
107
+ # Exclude any info containing an api key
108
+ def self.to_metadata
109
+ hash = {}
110
+ hash['environment'] = self.param('environment')
111
+
112
+ config_groups = ['app','api','sso','webhook']
113
+ blacklist = ['api.key','api.token']
114
+
115
+ config_groups.each do |cgroup_name|
116
+ cgroup = self.config.send(cgroup_name)
117
+
118
+ attr_list = cgroup.attributes.map(&:to_s)
119
+ attr_list += Configuration::EVT_CONFIG[hash['environment']].keys.select { |k| k =~ Regexp.new("^#{cgroup_name}\.") }.map { |k| k.gsub(Regexp.new("^#{cgroup_name}\."),'') }
120
+ attr_list.uniq!
121
+
122
+ attr_list.each do |first_lvl|
123
+ if cgroup.send(first_lvl).is_a?(OpenStruct)
124
+ c2group = cgroup.send(first_lvl)
125
+ c2group.attributes.each do |secnd_lvl|
126
+ full_param = [cgroup_name,first_lvl,secnd_lvl].join('.')
127
+ unless blacklist.include?(full_param)
128
+ hash[cgroup_name.to_s] ||= {}
129
+ hash[cgroup_name.to_s][first_lvl.to_s] ||= {}
130
+ hash[cgroup_name.to_s][first_lvl.to_s][secnd_lvl.to_s] = self.param(full_param)
131
+ end
132
+ end
133
+ else
134
+ full_param = [cgroup_name,first_lvl].join('.')
135
+ unless blacklist.include?(full_param)
136
+ hash[cgroup_name.to_s] ||= {}
137
+ hash[cgroup_name.to_s][first_lvl.to_s] = self.param(full_param)
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ return hash
144
+ end
145
+
146
+ class Configuration
147
+ attr_accessor :environment, :app, :sso, :api, :webhook
148
+
149
+ def initialize
150
+ @environment = 'test'
151
+
152
+ # App config
153
+ @app = OpenStruct.new({
154
+ host: 'http://localhost:3000'
155
+ })
156
+
157
+ # API Config
158
+ @api = OpenStruct.new({
159
+ id: nil,
160
+ key: nil,
161
+ token: nil,
162
+ version: nil,
163
+ verify_ssl_certs: false,
164
+ lang: nil, #set in post_initialize
165
+ lang_version: nil #set in post_initialize
166
+ })
167
+
168
+ # SSO Config
169
+ @sso = OpenStruct.new({
170
+ enabled: true,
171
+ slo_enabled: true,
172
+ creation_mode: 'real',
173
+ init_path: '/maestrano/auth/saml/init',
174
+ consume_path: '/maestrano/auth/saml/consume',
175
+ idm: nil
176
+ })
177
+
178
+ # WebHooks Config
179
+ @webhook = OpenStruct.new({
180
+ account: OpenStruct.new({
181
+ groups_path: '/maestrano/account/groups/:id',
182
+ group_users_path: '/maestrano/account/groups/:group_id/users/:id',
183
+ })
184
+ })
185
+ end
186
+
187
+ # Force or default certain parameters
188
+ # Used after configure block
189
+ def post_initialize
190
+ self.api.token = "#{self.api.id}:#{self.api.key}"
191
+ self.api.version = Maestrano::VERSION
192
+ self.api.lang = 'ruby'
193
+ self.api.lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
194
+ self.sso.idm ||= self.app.host
195
+ self.sso.slo_enabled &&= self.sso.enabled
196
+ end
197
+
198
+ # Transform legacy parameters into new parameter
199
+ # style
200
+ # Dummy mapping
201
+ def legacy_param_to_new(parameter)
202
+ case parameter.to_s
203
+ when 'user_creation_mode'
204
+ return 'sso.creation_mode'
205
+ when 'verify_ssl_certs'
206
+ return 'api.verify_ssl_certs'
207
+ when 'app_id'
208
+ return 'api.id'
209
+ when /^app_(.*)/i
210
+ return "app.#{$1}"
211
+ when /^api_(.*)/i
212
+ return "api.#{$1}"
213
+ when /^sso_app_(.*)/i
214
+ return "sso.#{$1}"
215
+ when /^sso_(.*)/i
216
+ return "sso.#{$1}"
217
+ else
218
+ return parameter.to_s
219
+ end
220
+ end
221
+
222
+ # Handle legacy parameter assignment
223
+ def method_missing(meth, *args, &block)
224
+ if meth.to_s =~ /^((?:sso|app|api|user)_.*)=$/
225
+ new_meth = self.legacy_param_to_new($1) + '='
226
+ props = new_meth.split('.')
227
+ last_prop = props.pop
228
+ obj = props.inject(self,:send)
229
+ obj.send(last_prop, *args, &block)
230
+ else
231
+ super
232
+ end
233
+ end
234
+
235
+ # Get configuration parameter value
236
+ def param(parameter)
237
+ real_param = self.legacy_param_to_new(parameter)
238
+ props = real_param.split('.')
239
+
240
+ # Either respond to param directly or via properties chaining (e.g: webhook.account.groups_path)
241
+ if self.respond_to?(real_param) || props.inject(self) { |result,elem| result && result.respond_to?(elem) ? result.send(elem) || elem : false }
242
+ last_prop = props.pop
243
+ obj = props.inject(self,:send)
244
+ obj.send(last_prop)
245
+ elsif EVT_CONFIG[@environment.to_s].has_key?(real_param.to_s)
246
+ EVT_CONFIG[@environment.to_s][real_param.to_s]
247
+ else
248
+ raise ArgumentError, "No such configuration parameter: '#{parameter}'"
249
+ end
250
+ end
251
+
252
+ EVT_CONFIG = {
253
+ 'test' => {
254
+ 'api.host' => 'http://api-sandbox.maestrano.io',
255
+ 'api.base' => '/api/v1/',
256
+ 'sso.idp' => 'https://maestrano.com',
257
+ 'sso.name_id_format' => Maestrano::Saml::Settings::NAMEID_PERSISTENT,
258
+ 'sso.x509_fingerprint' => '01:06:15:89:25:7d:78:12:28:a6:69:c7:de:63:ed:74:21:f9:f5:36',
259
+ 'sso.x509_certificate' => "-----BEGIN CERTIFICATE-----\nMIIDezCCAuSgAwIBAgIJAOehBr+YIrhjMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\nVQQGEwJBVTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoT\nEU1hZXN0cmFubyBQdHkgTHRkMRYwFAYDVQQDEw1tYWVzdHJhbm8uY29tMSQwIgYJ\nKoZIhvcNAQkBFhVzdXBwb3J0QG1hZXN0cmFuby5jb20wHhcNMTQwMTA0MDUyMjM5\nWhcNMzMxMjMwMDUyMjM5WjCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEP\nMA0GA1UEBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQG\nA1UEAxMNbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVz\ndHJhbm8uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVkIqo5t5Paflu\nP2zbSbzxn29n6HxKnTcsubycLBEs0jkTkdG7seF1LPqnXl8jFM9NGPiBFkiaR15I\n5w482IW6mC7s8T2CbZEL3qqQEAzztEPnxQg0twswyIZWNyuHYzf9fw0AnohBhGu2\n28EZWaezzT2F333FOVGSsTn1+u6tFwIDAQABo4HuMIHrMB0GA1UdDgQWBBSvrNxo\neHDm9nhKnkdpe0lZjYD1GzCBuwYDVR0jBIGzMIGwgBSvrNxoeHDm9nhKnkdpe0lZ\njYD1G6GBjKSBiTCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE\nBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQGA1UEAxMN\nbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVzdHJhbm8u\nY29tggkA56EGv5giuGMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCc\nMPgV0CpumKRMulOeZwdpnyLQI/NTr3VVHhDDxxCzcB0zlZ2xyDACGnIG2cQJJxfc\n2GcsFnb0BMw48K6TEhAaV92Q7bt1/TYRvprvhxUNMX2N8PHaYELFG2nWfQ4vqxES\nRkjkjqy+H7vir/MOF3rlFjiv5twAbDKYHXDT7v1YCg==\n-----END CERTIFICATE-----"
260
+ },
261
+ 'production' => {
262
+ 'api.host' => 'https://maestrano.com',
263
+ 'api.base' => '/api/v1/',
264
+ 'sso.idp' => 'https://maestrano.com',
265
+ 'sso.name_id_format' => Maestrano::Saml::Settings::NAMEID_PERSISTENT,
266
+ 'sso.x509_fingerprint' => '2f:57:71:e4:40:19:57:37:a6:2c:f0:c5:82:52:2f:2e:41:b7:9d:7e',
267
+ 'sso.x509_certificate' => "-----BEGIN CERTIFICATE-----\nMIIDezCCAuSgAwIBAgIJAPFpcH2rW0pyMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\nVQQGEwJBVTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxGjAYBgNVBAoT\nEU1hZXN0cmFubyBQdHkgTHRkMRYwFAYDVQQDEw1tYWVzdHJhbm8uY29tMSQwIgYJ\nKoZIhvcNAQkBFhVzdXBwb3J0QG1hZXN0cmFuby5jb20wHhcNMTQwMTA0MDUyNDEw\nWhcNMzMxMjMwMDUyNDEwWjCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEP\nMA0GA1UEBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQG\nA1UEAxMNbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVz\ndHJhbm8uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3feNNn2xfEz5/\nQvkBIu2keh9NNhobpre8U4r1qC7h7OeInTldmxGL4cLHw4ZAqKbJVrlFWqNevM5V\nZBkDe4mjuVkK6rYK1ZK7eVk59BicRksVKRmdhXbANk/C5sESUsQv1wLZyrF5Iq8m\na9Oy4oYrIsEF2uHzCouTKM5n+O4DkwIDAQABo4HuMIHrMB0GA1UdDgQWBBSd/X0L\n/Pq+ZkHvItMtLnxMCAMdhjCBuwYDVR0jBIGzMIGwgBSd/X0L/Pq+ZkHvItMtLnxM\nCAMdhqGBjKSBiTCBhjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE\nBxMGU3lkbmV5MRowGAYDVQQKExFNYWVzdHJhbm8gUHR5IEx0ZDEWMBQGA1UEAxMN\nbWFlc3RyYW5vLmNvbTEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBtYWVzdHJhbm8u\nY29tggkA8WlwfatbSnIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQDE\nhe/18oRh8EqIhOl0bPk6BG49AkjhZZezrRJkCFp4dZxaBjwZTddwo8O5KHwkFGdy\nyLiPV326dtvXoKa9RFJvoJiSTQLEn5mO1NzWYnBMLtrDWojOe6Ltvn3x0HVo/iHh\nJShjAn6ZYX43Tjl1YXDd1H9O+7/VgEWAQQ32v8p5lA==\n-----END CERTIFICATE-----"
268
+ }
269
+ }
270
+ end
271
+ end
@@ -0,0 +1,14 @@
1
+ module Maestrano
2
+ module Account
3
+ class Bill < Maestrano::API::Resource
4
+ include Maestrano::API::Operation::List
5
+ include Maestrano::API::Operation::Create
6
+
7
+ def cancel
8
+ response, api_token = Maestrano::API::Operation::Base.request(:delete, url, @api_token)
9
+ refresh_from(response, api_token)
10
+ self
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Maestrano
2
+ module Account
3
+ class RecurringBill < Maestrano::API::Resource
4
+ include Maestrano::API::Operation::List
5
+ include Maestrano::API::Operation::Create
6
+
7
+ def cancel
8
+ response, api_token = Maestrano::API::Operation::Base.request(:delete, url, @api_token)
9
+ refresh_from(response, api_token)
10
+ self
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ module Maestrano
2
+ module API
3
+ module Error
4
+ class AuthenticationError < Maestrano::API::Error::BaseError
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module Maestrano
2
+ module API
3
+ module Error
4
+ class BaseError < StandardError
5
+ attr_reader :message
6
+ attr_reader :http_status
7
+ attr_reader :http_body
8
+ attr_reader :json_body
9
+
10
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
11
+ @message = message
12
+ @http_status = http_status
13
+ @http_body = http_body
14
+ @json_body = json_body
15
+ end
16
+
17
+ def to_s
18
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
19
+ "#{status_string}#{@message}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ module Maestrano
2
+ module API
3
+ module Error
4
+ class ConnectionError < Maestrano::API::Error::BaseError
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ module Maestrano
2
+ module API
3
+ module Error
4
+ class InvalidRequestError < Maestrano::API::Error::BaseError
5
+ attr_accessor :param
6
+
7
+ def initialize(message, param, http_status=nil, http_body=nil, json_body=nil)
8
+ super(message, http_status, http_body, json_body)
9
+ @param = param
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ module Maestrano
2
+ module API
3
+ class ListObject < Maestrano::API::Object
4
+
5
+ def [](k)
6
+ case k
7
+ when String, Symbol
8
+ super
9
+ else
10
+ raise ArgumentError.new("You tried to access the #{k.inspect} index, but ListObject types only support String keys. (HINT: List calls return an object with a 'data' (which is the data array). You likely want to call #data[#{k.inspect}])")
11
+ end
12
+ end
13
+
14
+ def each(&blk)
15
+ self.data.each(&blk)
16
+ end
17
+
18
+ def retrieve(id, api_token=nil)
19
+ api_token ||= @api_token
20
+ response, api_token = Maestrano::API::Operation::Base.request(:get,"#{url}/#{CGI.escape(id)}", api_token)
21
+ Util.convert_to_maestrano_object(response, api_token)
22
+ end
23
+
24
+ def create(params={}, api_token=nil)
25
+ api_token ||= @api_token
26
+ response, api_token = Maestrano::API::Operation::Base.request(:post, url, api_token, params)
27
+ Util.convert_to_maestrano_object(response, api_token)
28
+ end
29
+
30
+ def all(params={}, api_token=nil)
31
+ api_token ||= @api_token
32
+ response, api_token = Maestrano::API::Operation::Base.request(:get, url, api_token, params)
33
+ Util.convert_to_maestrano_object(response, api_token)
34
+ end
35
+ end
36
+ end
37
+ end