riddl 0.99.220 → 0.99.221

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,167 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/oauth2-helper')
2
-
3
- module Riddl
4
- module Utils
5
- module OAuth2
6
-
7
- module UnivieBearer
8
- def self::implementation(client_id, client_secret, access_tokens)
9
- Proc.new do
10
- run CheckAuth, client_id, client_secret, access_tokens if get
11
- end
12
- end
13
-
14
- class CheckAuth < Riddl::Implementation
15
- def response
16
- client_id = @a[0]
17
- client_secret = @a[1]
18
- access_tokens = @a[2]
19
- if @h['AUTHORIZATION']
20
- token = @h['AUTHORIZATION'].sub(/^Bearer /, '')
21
-
22
- data, _, signature = token.rpartition '.'
23
- expected_sign = Riddl::Utils::OAuth2::Helper::sign(client_id + ':' + client_secret, data)
24
-
25
- if !access_tokens.key? token
26
- @status = 403
27
- return Riddl::Parameter::Complex.new('data', 'application/json', {
28
- :error => 'Unknown token'
29
- }.to_json)
30
- elsif signature != expected_sign
31
- @status = 403
32
- return Riddl::Parameter::Complex.new('data', 'application/json', {
33
- :error => 'Invalid token, you bad boy'
34
- }.to_json)
35
- end
36
-
37
- header_claims, payload_claims = data.split('.').map { |v| Base64::urlsafe_decode64 v }
38
- payload_claims = JSON::parse payload_claims
39
-
40
- if header_claims != Riddl::Utils::OAuth2::Helper::header
41
- @status = 401
42
- return Riddl::Parameter::Complex.new('data', 'application/json', {
43
- :error => 'Invalid header claims'
44
- }.to_json)
45
- elsif payload_claims['exp'] <= Time.now.to_i
46
- @status = 403
47
- return Riddl::Parameter::Complex.new('data', 'application/json', {
48
- :error => 'Expired token'
49
- }.to_json)
50
- elsif !payload_claims['aud'].split(',').map(&:strip).include? client_id
51
- # XXX: ein token für mehrere clients gültig? lookup?
52
- @status = 403
53
- return Riddl::Parameter::Complex.new('data', 'application/json', {
54
- :error => 'Token is not valid for this application'
55
- }.to_json)
56
- end
57
-
58
- @headers << Riddl::Header.new('AUTHORIZATION_BEARER', access_tokens[token])
59
- end
60
-
61
- @p
62
- end
63
- end
64
- end
65
-
66
- module UnivieApp
67
- def self::implementation(client_id, client_secret, access_tokens, refresh_tokens)
68
- Proc.new do
69
- on resource 'verify' do
70
- run VerifyIdentity, access_tokens, refresh_tokens, client_id, client_secret if post 'verify_in'
71
- end
72
- on resource 'token' do
73
- run RefreshToken, access_tokens, refresh_tokens, client_id, client_secret if post 'refresh_token_in'
74
- end
75
- on resource 'revoke' do
76
- run RevokeTokenFlow, access_tokens, refresh_tokens if get 'revoke_token_in'
77
- run RevokeUserFlow, access_tokens, refresh_tokens if get 'revoke_user_in'
78
- end
79
- end
80
- end
81
-
82
- class VerifyIdentity < Riddl::Implementation
83
- def response
84
- code = Base64::urlsafe_decode64 @p[0].value
85
- access_tokens = @a[0]
86
- refresh_tokens = @a[1]
87
- client_id = @a[2]
88
- client_secret = @a[3]
89
-
90
- client_pass = "#{client_id}:#{client_secret}"
91
- user_id, decrypted = Riddl::Utils::OAuth2::Helper::decrypt_with_shared_secret(code, client_pass).split(':', 2)
92
- token, refresh_token = Riddl::Utils::OAuth2::Helper::generate_optimistic_token(client_id, client_pass)
93
- access_tokens[token] = user_id
94
- refresh_tokens[refresh_token] = token
95
-
96
- json_response = {
97
- :access_token => token,
98
- :refresh_token => refresh_token,
99
- :code => Base64.urlsafe_encode64(decrypted)
100
- }.to_json
101
-
102
- Riddl::Parameter::Complex.new('data', 'application/json', json_response)
103
- end
104
- end
105
-
106
- class RevokeTokenFlow < Riddl::Implementation
107
- def response
108
- token = @p[0].value
109
- access_tokens = @a[0]
110
- refresh_tokens = @a[1]
111
-
112
- access_tokens.delete(token)
113
- refresh_tokens.delete_by_value(token)
114
- end
115
- end
116
-
117
- class RevokeUserFlow < Riddl::Implementation
118
- def response
119
- user_id = @p[0].value
120
- access_tokens = @a[0]
121
- refresh_tokens = @a[1]
122
-
123
- token = access_tokens.delete_by_value user_id
124
- refresh_tokens.delete_by_value token
125
- end
126
- end
127
-
128
- class RefreshToken < Riddl::Implementation
129
- def response
130
- refresh_token = @p[1].value
131
- access_tokens = @a[0]
132
- refresh_tokens = @a[1]
133
- client_id = @a[2]
134
- client_secret = @a[3]
135
-
136
- token, _ = refresh_token.split '.'
137
- token_data = JSON::parse(Base64::urlsafe_decode64 token)
138
-
139
- if token_data['iss'] != client_id
140
- @status = 401
141
- return Riddl::Parameter::Complex.new('data', 'application/json', {
142
- :error => 'Token must be refreshed by issuer.'
143
- }.to_json)
144
- elsif refresh_tokens[refresh_token].nil? || token_data['exp'] <= Time.now.to_i
145
- @status = 403
146
- puts "i dont know #{refresh_token}", "#{refresh_tokens[refresh_token]}"
147
- return Riddl::Parameter::Complex.new('data', 'application/json', {
148
- :error => 'Invalid refresh token.'
149
- }.to_json)
150
- end
151
-
152
- old_token = refresh_tokens[refresh_token]
153
- user = access_tokens.delete old_token
154
-
155
- token = Riddl::Utils::OAuth2::Helper::generate_access_token(client_id, client_id + ':' + client_secret)
156
-
157
- refresh_tokens[refresh_token] = token
158
- access_tokens[token] = user
159
-
160
- Riddl::Parameter::Complex.new('data', 'application/json', { :token => token }.to_json)
161
- end
162
- end
163
- end
164
-
165
- end
166
- end
167
- end
@@ -1,479 +0,0 @@
1
- module Riddl
2
- module Utils
3
- module Properties
4
-
5
- VERSION_MAJOR = 1
6
- VERSION_MINOR = 0
7
- PROPERTIES_SCHEMA_XSL_RNG = "#{File.dirname(__FILE__)}/../ns/common-patterns/properties/#{VERSION_MAJOR}.#{VERSION_MINOR}/properties.schema.xsl"
8
-
9
- def self::implementation(backend,handler=nil,details=:production)
10
- unless handler.nil? || (handler.is_a? Riddl::Utils::Properties::HandlerBase)
11
- raise "handler not a subclass of HandlerBase"
12
- end
13
- Proc.new do
14
- run Riddl::Utils::Properties::All, backend, handler if get '*'
15
- run Riddl::Utils::Properties::Query, backend, handler if get 'query'
16
- on resource 'schema' do
17
- run Riddl::Utils::Properties::Schema, backend if get
18
- on resource 'rng' do
19
- run Riddl::Utils::Properties::RngSchema, backend if get
20
- end
21
- end
22
- on resource 'values' do
23
- run Riddl::Utils::Properties::Properties, backend, handler if get
24
- run Riddl::Utils::Properties::AddProperty, backend, handler if post 'property'
25
- run Riddl::Utils::Properties::AddProperties, backend, handler if put 'properties'
26
- on resource do
27
- run Riddl::Utils::Properties::GetContent, backend, handler if get
28
- run Riddl::Utils::Properties::DelContent, backend, handler if delete
29
- run Riddl::Utils::Properties::AddContent, backend, handler if post 'addcontent'
30
- run Riddl::Utils::Properties::UpdContent, backend, handler if put 'updcontent'
31
- on resource do
32
- run Riddl::Utils::Properties::GetContent, backend, handler if get
33
- run Riddl::Utils::Properties::DelContent, backend, handler if delete
34
- run Riddl::Utils::Properties::UpdContent, backend, handler if put 'updcontent'
35
- on resource do
36
- run Riddl::Utils::Properties::GetContent, backend, handler if get
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
-
44
- # Overloadable and Backends
45
- class HandlerBase #{{{
46
- def initialize(data)
47
- @data = data
48
- @property = nil
49
- end
50
- def property(p)
51
- @property = p
52
- self
53
- end
54
- def create; end
55
- def read; end
56
- def update; end
57
- def delete; end
58
- end #}}}
59
-
60
- class Backend #{{{
61
- attr_reader :schema, :data, :rng
62
-
63
- def initialize(schema,target,init=nil)
64
- @target = target.gsub(/^\/+/,'/')
65
- @schemas = {}
66
- @rngs = {}
67
-
68
- if schema.is_a? Hash
69
- schema.each { |k,v| add_schema k, v }
70
- elsif schema.is_a? String
71
- add_schema 'default', schema
72
- end
73
- raise "no schemas provided" if @schemas.length == 0
74
- @schema = @schemas.first[1]
75
- @rng = @rngs.first[1]
76
-
77
- FileUtils::mkdir_p(File::dirname(@target)) unless File.exists?(@target)
78
- FileUtils::cp init, @target if init and not File.exists?(@target)
79
-
80
- raise "properties file not found" unless File.exists?(@target)
81
- @data = XML::Smart.open_unprotected(@target)
82
- @data.register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
83
- @mutex = Mutex.new
84
- end
85
-
86
- def activate_schema(name)
87
- if @schemas[name]
88
- @schema = @schemas[name]
89
- @rng = @rngs[name]
90
- true
91
- else
92
- false
93
- end
94
- end
95
-
96
- def add_schema(key,name)
97
- raise "schema file not found" unless File.exists?(name)
98
- @schemas[key] = XML::Smart.open_unprotected(name.gsub(/^\/+/,'/'))
99
- @schemas[key].register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
100
- if !File::exists?(Riddl::Utils::Properties::PROPERTIES_SCHEMA_XSL_RNG)
101
- raise "properties schema transformation file not found"
102
- end
103
- @rngs[key] = @schemas[key].transform_with(XML::Smart.open_unprotected(Riddl::Utils::Properties::PROPERTIES_SCHEMA_XSL_RNG))
104
- end
105
- private :add_schema
106
-
107
- def modifiable?(property)
108
- @schema.find("boolean(/p:properties/p:#{property}[@modifiable='true'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}[@modifiable='true'])")
109
- end
110
- def valid_state?(property,current,new)
111
- @schema.find("boolean(/p:properties/p:#{property}/p:#{current}/p:#{new}[@putable='true'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}/p:#{current}/p:#{new}[@putable='true'])")
112
- end
113
- def is_state?(property)
114
- @schema.find("boolean(/p:properties/p:#{property}[@type='state'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}[@type='state'])")
115
- end
116
- def init_state?(property,new)
117
- @schema.find("boolean(/p:properties/p:#{property}/p:#{new}[position()=1])") || schema.find("boolean(/p:properties/p:optional/p:#{property}/p:#{new}[position()=1])")
118
- end
119
- def property_type(property)
120
- exis = @schema.find("/p:properties/*[name()='#{property}']|/p:properties/p:optional/*[name()='#{property}']")
121
- exis.any? ? exis.first.attributes['type'].to_sym : nil
122
- end
123
-
124
- def modify(&block)
125
- tdoc = @data.root.to_doc
126
- tdoc.register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
127
- @mutex.synchronize do
128
- block.call tdoc
129
- if tdoc.validate_against(@rng){|err| puts err.message }
130
- block.call @data
131
- @data.save_as(@target)
132
- true
133
- else
134
- false
135
- end
136
- end
137
- end
138
- end #}}}
139
-
140
- # Just reading
141
- class All < Riddl::Implementation #{{{
142
- def response
143
- backend = @a[0]
144
- handler = @a[1]
145
- EM.defer{handler.read} unless handler.nil?
146
- return Riddl::Parameter::Complex.new("document","text/xml",backend.data.to_s)
147
- end
148
- end #}}}
149
-
150
- class Properties < Riddl::Implementation #{{{
151
- def response
152
- backend = @a[0]
153
- handler = @a[1]
154
- EM.defer{handler.read} unless handler.nil?
155
-
156
- ret = XML::Smart.string("<properties xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
157
- backend.schema.find("/p:properties/*[name()!='optional']|/p:properties/p:optional/*").each do |r|
158
- ret.root.add("property",r.qname.to_s)
159
- end
160
- return Riddl::Parameter::Complex.new("keys","text/xml",ret.to_s)
161
- end
162
- end #}}}
163
-
164
- class Query < Riddl::Implementation #{{{
165
- def response
166
- backend = @a[0]
167
- handler = @a[1]
168
- EM.defer{handler.read} unless handler.nil?
169
- query = (@p[0].value.to_s.strip.empty? ? '*' : @p[0].value)
170
-
171
- begin
172
- e = backend.data.find(query)
173
- rescue => e
174
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>").to_s
175
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
176
- end
177
- if e.class == XML::Smart::Dom::NodeSet
178
- if e.any?
179
- prop = XML::Smart::string("<value xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
180
- prop.root.add(e)
181
- else
182
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>").to_s
183
- end
184
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
185
- else
186
- return Riddl::Parameter::Simple.new("value",e.to_s)
187
- end
188
- end
189
- end #}}}
190
-
191
- class RngSchema < Riddl::Implementation #{{{
192
- def response
193
- backend = @a[0]
194
- Riddl::Parameter::Complex.new("document-schema","text/xml",backend.rng.to_s)
195
- end
196
- end #}}}
197
-
198
- class Schema < Riddl::Implementation #{{{
199
- def response
200
- backend = @a[0]
201
- return Riddl::Parameter::Complex.new("document-schema","text/xml",backend.schema.to_s)
202
- end
203
- end #}}}
204
-
205
- class GetContent < Riddl::Implementation #{{{
206
- def response
207
- backend = @a[0]
208
- handler = @a[1]
209
-
210
- EM.defer{handler.property(@r[1]).read} unless handler.nil?
211
-
212
- if ret = extract_values(backend,@r[1],Riddl::Protocols::Utils::unescape(@r[2..-1].join('/')))
213
- ret
214
- else
215
- @status = 404
216
- end
217
- end
218
-
219
- def extract_values(backend,property,minor=nil)
220
- case backend.property_type(property)
221
- when :complex
222
- res = backend.data.find("/p:properties/*[name()=\"#{property}\"]#{minor == '' ? '' : "/p:#{minor}"}")
223
- if res.any?
224
- prop = XML::Smart::string("<value xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
225
- if res.length == 1
226
- prop.root.add(res.first.children)
227
- else
228
- prop.root.add(res)
229
- end
230
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
231
- else
232
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
233
- end
234
- when :simple, :state
235
- res = backend.data.find("string(/p:properties/*[name()=\"#{property}\"]#{minor})")
236
- return Riddl::Parameter::Simple.new("value",res.to_s)
237
- when :arbitrary
238
- res = backend.data.find("/p:properties/*[name()=\"#{property}\"]")
239
- if res.any?
240
- c = res.first.children
241
- if c.length == 1 && c.first.class == XML::Smart::Dom::Element
242
- return Riddl::Parameter::Complex.new("content","text/xml",c.first.dump)
243
- else
244
- return Riddl::Parameter::Complex.new("content","text/plain",c.first.to_s)
245
- end
246
- else
247
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
248
- return Riddl::Parameter::Complex.new("content","text/xml",prop.to_s)
249
- end
250
- end
251
- nil
252
- end
253
- private :extract_values
254
-
255
- end #}}}
256
-
257
- # Modifiable
258
- class AddProperty < Riddl::Implementation #{{{
259
- def response
260
- backend = @a[0]
261
- handler = @a[1]
262
-
263
- property = @p[0].value
264
- ct = @p[1]
265
- value = ct.name == 'value' ? ct.value : nil
266
- content = ct.name == 'content' ? ct.value : nil
267
-
268
- unless backend.modifiable?(property)
269
- @status = 500
270
- return # change properties.schema
271
- end
272
-
273
- path = "/p:properties/*[name()=\"#{property}\"]"
274
- nodes = backend.data.find(path)
275
- if nodes.any?
276
- @status = 404
277
- return # this property does not exist
278
- end
279
-
280
- if backend.is_state?(property)
281
- unless backend.init_state?(property,value)
282
- @status = 404
283
- return # not a valid state from here on
284
- end
285
- end
286
-
287
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
288
- backend.modify do |doc|
289
- ele = doc.root.add property
290
- if value.nil?
291
- ele.add newstuff
292
- else
293
- ele.text = newstuff
294
- end
295
- end || begin
296
- @status = 400
297
- return # bad request
298
- end
299
-
300
- EM.defer{handler.property(property).create} unless handler.nil?
301
- return
302
- end
303
- end #}}}
304
-
305
- class AddProperties < Riddl::Implementation #{{{
306
- def response
307
- backend = @a[0]
308
- handler = @a[1]
309
-
310
- 0.upto(@p.length/2-1) do |i|
311
- property = @p[i*2].value
312
- ct = @p[i*2+1]
313
- value = ct.name == 'value' ? ct.value : nil
314
- content = ct.name == 'content' ? ct.value : nil
315
-
316
- unless backend.modifiable?(property)
317
- @status = 500
318
- return # change properties.schema
319
- end
320
-
321
- path = "/p:properties/*[name()=\"#{property}\"]"
322
- nodes = backend.data.find(path)
323
- if nodes.empty?
324
- @status = 404
325
- return # this property does not exist
326
- end
327
-
328
- if backend.is_state?(property)
329
- unless backend.valid_state?(property,nodes.first.to_s,value)
330
- @status = 404
331
- return # not a valid state from here on
332
- end
333
- end
334
-
335
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
336
- backend.modify do |doc|
337
- nodes = doc.find(path)
338
- nods = nodes.map{|ele| ele.children.delete_all!; ele}
339
- nods.each do |ele|
340
- if value.nil?
341
- ele.add newstuff
342
- else
343
- ele.text = newstuff
344
- end
345
- end
346
- end || begin
347
- @status = 400
348
- return # bad request
349
- end
350
-
351
- end
352
- EM.defer do
353
- 0.upto(@p.length/2-1) do |i|
354
- property = @p[i*2].value
355
- handler.property(property).create
356
- end
357
- end unless handler.nil?
358
- return
359
- end
360
- end #}}}
361
-
362
- class AddContent < Riddl::Implementation #{{{
363
- def response
364
- backend = @a[0]
365
- handler = @a[1]
366
-
367
- property = @r[1]
368
- value = @p.detect{|p| p.name == 'value'}.value
369
-
370
- unless backend.modifiable?(property)
371
- @status = 500
372
- return # change properties.schema
373
- end
374
-
375
- path = "/p:properties/p:#{property}"
376
- node = backend.data.find(path)
377
- if node.empty?
378
- @status = 404
379
- return # this property does not exist
380
- end
381
-
382
- newstuff = XML::Smart.string(value)
383
- backend.modify do |doc|
384
- node = doc.find(path)
385
- node.first.add newstuff.root
386
- end || begin
387
- @status = 400
388
- return # bad request
389
- end
390
-
391
- EM.defer{handler.property(property).create} unless handler.nil?
392
- end
393
- end #}}}
394
-
395
- class DelContent < Riddl::Implementation #{{{
396
- def response
397
- backend = @a[0]
398
- handler = @a[1]
399
-
400
- property = @r[1]
401
- minor = Riddl::Protocols::Utils::unescape(@r[2])
402
-
403
- unless backend.modifiable?(property)
404
- @status = 500
405
- return # change properties.schema
406
- end
407
-
408
- path = "/p:properties/*[name()=\"#{property}\"]#{minor.nil? ? '' : "/p:#{minor}"}"
409
- nodes = backend.data.find(path)
410
- if nodes.empty?
411
- @status = 404
412
- return # this property does not exist
413
- end
414
-
415
- backend.modify do |doc|
416
- doc.find(path).delete_all!
417
- end || begin
418
- @status = 400
419
- return # bad request
420
- end
421
-
422
- EM.defer{handler.property(property).delete} unless handler.nil?
423
- return
424
- end
425
- end #}}}
426
-
427
- class UpdContent < Riddl::Implementation #{{{
428
- def response
429
- backend = @a[0]
430
- handler = @a[1]
431
-
432
- property = @r[1]
433
- value = @p.detect{|p| p.name == 'value'}; value = value.nil? ? value : value.value
434
- content = @p.detect{|p| p.name == 'content'}; content = content.nil? ? content : content.value
435
- minor = @r[2]
436
-
437
- unless backend.modifiable?(property)
438
- @status = 500
439
- return # change properties.schema
440
- end
441
-
442
- path = "/p:properties/*[name()=\"#{property}\"]#{minor.nil? ? '' : "/p:#{minor}"}"
443
- nodes = backend.data.find(path)
444
- if nodes.empty?
445
- @status = 404
446
- return # this property does not exist
447
- end
448
-
449
- if backend.is_state?(property)
450
- unless backend.valid_state?(property,nodes.first.to_s,value)
451
- @status = 404
452
- return # not a valid state from here on
453
- end
454
- end
455
-
456
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
457
- backend.modify do |doc|
458
- nodes = doc.root.find(path)
459
- nods = nodes.map{|ele| ele.children.delete_all!; ele}
460
- nods.each do |ele|
461
- if value.nil?
462
- ele.add newstuff
463
- else
464
- ele.text = newstuff
465
- end
466
- end
467
- end || begin
468
- @status = 400
469
- return # bad request
470
- end
471
-
472
- EM.defer{handler.property(property).update} unless handler.nil?
473
- return
474
- end
475
- end #}}}
476
-
477
- end
478
- end
479
- end