nakamura 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/nakamura.rb ADDED
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env ruby
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'cgi'
5
+ require 'rubygems'
6
+ require 'json'
7
+ require 'yaml'
8
+ require 'nakamura/users'
9
+ require 'logger'
10
+
11
+ class String
12
+ def base64_decode
13
+ unpack('m').first
14
+ end
15
+
16
+ def base64_encode
17
+ [self].pack('m').chop
18
+ end
19
+ end
20
+
21
+
22
+ class Hash
23
+
24
+ def dump
25
+ return keys.collect{|k| "#{k} => #{self[k]}"}.join(", ")
26
+ end
27
+
28
+ end
29
+
30
+ ## Fix array handling
31
+ module Net::HTTPHeader
32
+ def set_form_data(params, sep = '&')
33
+ self.body = params.map {|k, v| encode_kvpair(k, v) }.flatten.join(sep)
34
+ self.content_type = 'application/x-www-form-urlencoded'
35
+ end
36
+
37
+
38
+ def initialize_http_header(initheader)
39
+ @header = { "Referer" => ["/dev/integrationtests"] }
40
+ return unless initheader
41
+ initheader.each do |key, value|
42
+ warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
43
+ @header[key.downcase] = [value.strip]
44
+ end
45
+ end
46
+
47
+ def encode_kvpair(k, vs)
48
+ if vs.nil? or vs == '' then
49
+ "#{urlencode(k)}="
50
+ else
51
+ Array(vs).map {|v| "#{urlencode(k)}=#{urlencode(v.to_s)}" }
52
+ end
53
+ end
54
+ end
55
+
56
+ class WrappedCurlResponse
57
+
58
+ def initialize(response)
59
+ @response = response
60
+ end
61
+
62
+ def code
63
+ return @response.response_code
64
+ end
65
+
66
+ def message
67
+ return @response.response_code
68
+ end
69
+
70
+ def body
71
+ return @response.body_str
72
+ end
73
+
74
+ end
75
+
76
+ module SlingInterface
77
+
78
+ class Sling
79
+
80
+ attr_accessor :log, :trustedauth
81
+
82
+ def initialize(server="http://localhost:8080/", trustedauth=false)
83
+ @server = server
84
+ @serveruri = URI.parse(server)
85
+ @user = SlingUsers::User.admin_user()
86
+ @trustedauth = trustedauth
87
+ @cookies = Hash.new()
88
+ @loggedin = false
89
+ @log = Logger.new(STDOUT)
90
+ @log.level = Logger::WARN
91
+ end
92
+
93
+ def dump_response(response)
94
+ @log.info "Response: #{response.code} #{response.message}"
95
+ @log.debug "#{response.body}"
96
+ end
97
+
98
+ def switch_user(user)
99
+ @log.info "Switched user to #{user}"
100
+ @cookies = Hash.new()
101
+ @user = user
102
+ if ( @trustedauth )
103
+ @loggedin = false
104
+ end
105
+ end
106
+
107
+
108
+ def text_to_multipart(key,value)
109
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n" +
110
+ "\r\n" +
111
+ "#{value}\r\n"
112
+ end
113
+
114
+ def file_to_multipart(key,filename,mime_type,content)
115
+ if ( filename != nil )
116
+ return "Content-Disposition: form-data; name=\"*\"; filename=\"#{filename}\"\r\n" +
117
+ "Content-Transfer-Encoding: binary\r\n" +
118
+ "Content-Type: #{mime_type}\r\n" +
119
+ "\r\n" +
120
+ "#{content}\r\n"
121
+ else
122
+ return "Content-Disposition: form-data; name=\"jcr:content\"\r\n" +
123
+ "Content-Transfer-Encoding: binary\r\n" +
124
+ "Content-Type: #{mime_type}\r\n" +
125
+ "\r\n" +
126
+ "#{content}\r\n"
127
+ end
128
+
129
+ end
130
+
131
+ def execute_file_post(path, fieldname, filename, data, content_type)
132
+ uri = URI.parse(path)
133
+ fileTypeHint = "Content-Disposition: form-data; name=\"*@TypeHint\"\r\n\r\n" +
134
+ "nt:file\r\n"
135
+
136
+ params = [fileTypeHint,file_to_multipart(fieldname, filename, content_type, data)]
137
+ boundary = '349832898984244898448024464570528145'
138
+ post_body = params.collect {|p| '--' + boundary + "\r\n" + p}.join('') + "--" + boundary + "--\r\n"
139
+ req = Net::HTTP::Post.new(uri.path)
140
+ req.set_content_type("multipart/form-data", {"boundary" => boundary})
141
+ req.body = post_body
142
+ res = sendRequest(uri, req)
143
+ dump_response(res)
144
+ return res
145
+ end
146
+
147
+ def createHttp(uri)
148
+ http = Net::HTTP.new(uri.host, uri.port)
149
+ if (uri.scheme == 'https')
150
+ http.use_ssl = true
151
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
152
+ end
153
+ return http
154
+ end
155
+
156
+ def sendRequest(uri, req)
157
+ # Not all browsers take port number into account when setting cookies.
158
+ isSlingReq = uri.host && (uri.host == @serveruri.host)
159
+ if (isSlingReq)
160
+ if ( @trustedauth )
161
+ if ( ! @loggedin )
162
+ do_login()
163
+ end
164
+ else
165
+ @user.do_request_auth(req)
166
+ end
167
+ set_cookies(req)
168
+ else
169
+ @log.warn("Path #{uri} is not a Sling URL, not sending state")
170
+ end
171
+ res = createHttp(uri).start { |http| http.request(req ) }
172
+ save_cookies(res) if (isSlingReq)
173
+ return res
174
+ end
175
+
176
+ def delete_file(path)
177
+ uri = URI.parse(path)
178
+ req = Net::HTTP::Delete.new(uri.path)
179
+ res = sendRequest(uri, req)
180
+ dump_response(res)
181
+ return res
182
+ end
183
+
184
+ def execute_put_file(path, data)
185
+ @log.debug "URL: #{path}"
186
+ @log.debug("PUTFILE: #{path} (as '#{@user.name}')")
187
+ uri = URI.parse(path)
188
+ req = Net::HTTP::Put.new(uri.path)
189
+ req.body = data
190
+ res = sendRequest(uri, req)
191
+ dump_response(res)
192
+ return res
193
+ end
194
+
195
+ def execute_post(path, post_params={})
196
+ # We always post with utf-8
197
+ if ( post_params["_charset_"] == nil)
198
+ post_params["_charset_"] = "utf-8"
199
+ end
200
+ @log.debug("POST: #{path} (as '#{@user.name}')\n\tparams: #{post_params.dump}")
201
+ uri = URI.parse(path)
202
+ req = Net::HTTP::Post.new(uri.path)
203
+ req.set_form_data(post_params)
204
+ res = sendRequest(uri, req)
205
+ dump_response(res)
206
+ return res
207
+ end
208
+
209
+ def execute_get(path, query_params=nil)
210
+ if (query_params != nil)
211
+ param_string = query_params.collect { |k,v|
212
+ val = case v
213
+ when String then
214
+ v
215
+ when Numeric then
216
+ v.to_s
217
+ else
218
+ v.to_json
219
+ end
220
+ CGI.escape(k) + "=" + CGI.escape(val)
221
+ }.join("&")
222
+ path = "#{path}?#{param_string}"
223
+ end
224
+ @log.debug "URL: #{path}"
225
+ uri = URI.parse(path)
226
+ path = uri.path
227
+ path = path + "?" + uri.query if uri.query
228
+ @log.debug("GET: #{path} (as '#{@user.name}')")
229
+ req = Net::HTTP::Get.new(path)
230
+ res = sendRequest(uri, req)
231
+ res = followRedirects(res)
232
+ dump_response(res)
233
+ return res
234
+ end
235
+
236
+ def followRedirects(res)
237
+ lastlocation = ''
238
+ while (res.header['location'] && res.header['location'] != lastlocation)
239
+ lastlocation = res.header['location']
240
+ uri = URI.parse(res.header['location'])
241
+ @log.info("Redirecting to #{uri}")
242
+ req = Net::HTTP::Get.new(uri.request_uri())
243
+ res = sendRequest(uri, req)
244
+ end
245
+ return res
246
+ end
247
+
248
+ def set_cookies(req)
249
+ req["Cookie"] = @cookies.values * ", "
250
+ @log.debug("Cookie is #{req["Cookie"]}")
251
+ end
252
+
253
+ def save_cookies(res)
254
+ if ( res["Set-Cookie"] )
255
+ setcookie = res.get_fields('Set-Cookie')
256
+ @log.debug("Set-Cookie header #{setcookie} ")
257
+ setcookie.each do |cookieitem|
258
+ cookie = cookieitem.split(/;/)[0]
259
+ cookiename = cookie.split(/=/)[0]
260
+ value = cookie.split(/=/)[1]
261
+ cookievalue = "#{cookiename}=#{value}"
262
+ if ( @cookies[cookiename] != cookievalue )
263
+ @cookies[cookiename] = cookievalue
264
+ @log.info("New Cookie Value #{@cookies.values * "' "} ")
265
+ else
266
+ @log.debug("No Change to Cookie #{@cookies}")
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ def do_login()
273
+ path = url_for("/system/sling/formlogin")
274
+ req = Net::HTTP::Post.new(path)
275
+ uri = URI.parse(path)
276
+ req.set_form_data({ "sakaiauth:un" => @user.name, "sakaiauth:pw" => @user.password, "sakaiauth:login" => 1 })
277
+ res = createHttp(uri).start{ |http| http.request(req) }
278
+ if ( res.code == "200" )
279
+ save_cookies(res)
280
+ @log.info("Login Ok, cookie was {#@cookies}")
281
+ @loggedin = true
282
+ else
283
+ @log.info("Failed to perform login, got "+res.code+" response code")
284
+ end
285
+ end
286
+
287
+ def url_for(path)
288
+ if (path.slice(0,1) == '/')
289
+ path = path[1..-1]
290
+ end
291
+ return "#{@server}#{path}"
292
+ end
293
+
294
+ def update_properties(principal, props)
295
+ principal.update_properties(self, props)
296
+ end
297
+
298
+ def delete_node(path)
299
+ result = execute_post(url_for(path), ":operation" => "delete")
300
+ end
301
+
302
+ def create_file_node(path, fieldname, filename, data, content_type="text/plain")
303
+ result = execute_file_post(url_for(path), fieldname, filename, data, content_type)
304
+ end
305
+
306
+ def create_node(path, params)
307
+ result = execute_post(url_for(path), params)
308
+ end
309
+
310
+ def get_user()
311
+ return @user
312
+ end
313
+
314
+ def get_node_props_json(path)
315
+ @log.debug "Getting props for path: #{path}"
316
+ result = execute_get(url_for("#{path}.json"))
317
+ if ( result.code == "200" )
318
+ return result.body
319
+ end
320
+ @log.info("Failed to get properties for "+path+" cause "+result.code+"\n"+result.body)
321
+ return "{}"
322
+ end
323
+
324
+ def get_node_props(path)
325
+ return JSON.parse(get_node_props_json(path))
326
+ end
327
+
328
+ def update_node_props(path, props)
329
+ return execute_post(url_for(path), props)
330
+ end
331
+
332
+ def get_node_acl_json(path)
333
+ return execute_get(url_for("#{path}.acl.json")).body
334
+ end
335
+
336
+ def get_node_ruleacl_json(path)
337
+ return execute_get(url_for("#{path}.ruleacl.json")).body
338
+ end
339
+
340
+ def get_node_acl(path)
341
+ return JSON.parse(get_node_acl_json(path))
342
+ end
343
+
344
+ def get_node_ruleacl(path)
345
+ return JSON.parse(get_node_ruleacl_json(path))
346
+ end
347
+
348
+ def set_node_acl_entries(path, principal, privs)
349
+ @log.info "Setting node acl for: #{principal} to #{privs.dump}"
350
+ res = execute_post(url_for("#{path}.modifyAce.html"),
351
+ { "principalId" => principal.name }.update(
352
+ privs.keys.inject(Hash.new) do |n,k|
353
+ n.update("privilege@#{k}" => privs[k])
354
+ end))
355
+ return res
356
+ end
357
+
358
+ def set_node_acl_rule_entries(path, principal, privs, props)
359
+ @log.info "Setting node acl for: #{principal} to #{privs.dump}"
360
+ props["principalId"] = principal.name
361
+ res = execute_post(url_for("#{path}.modifyRuleAce.html"),
362
+ props.update(
363
+ privs.keys.inject(Hash.new) do |n,k|
364
+ n.update("privilege@#{k}" => privs[k])
365
+ end))
366
+ return res
367
+ end
368
+
369
+ def delete_node_acl_entries(path, principal)
370
+ res = execute_post(url_for("#{path}.deleteAce.html"), {
371
+ ":applyTo" => principal
372
+ })
373
+ end
374
+
375
+ def clear_acl(path)
376
+ acl = JSON.parse(get_node_acl_json(path))
377
+ acl.keys.each { |p| delete_node_acl_entries(path, p) }
378
+ end
379
+
380
+ def save_node(path)
381
+ res = execute_post(url_for("#{path}.save.json"), {})
382
+ if (res.code == "200")
383
+ return JSON.parse(res.body)["versionName"]
384
+ end
385
+ return nil
386
+ end
387
+
388
+ def versions(path)
389
+ return get_node_props("#{path}.versions")["versions"].keys
390
+ end
391
+
392
+ def version(path, version, extension)
393
+ return execute_get(url_for("#{path}.version.,#{version},.#{extension}"))
394
+ end
395
+
396
+ end
397
+
398
+ end
399
+
400
+ if __FILE__ == $0
401
+ @log.info "Sling test"
402
+ s = SlingInterface::Sling.new("http://localhost:8080/", false)
403
+ um = SlingUsers::UserManager.new(s)
404
+ um.create_group(10)
405
+ user = um.create_test_user(10)
406
+ s.create_node("fish", { "foo" => "bar", "baz" => "jim" })
407
+ @log.info s.get_node_props_json("fish")
408
+ @log.info s.get_node_acl_json("fish")
409
+
410
+ s.set_node_acl_entries("fish", user, { "jcr:write" => "granted" })
411
+ @log.info s.get_node_acl_json("fish")
412
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nakamura
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sakai Project
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-30 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Ruby library for interacting with Sakai Nakamura. Provides convenience
15
+ methods for adding users and groups and other similar tasks.
16
+ email: oae-dev@collab.sakaiproject.org
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/nakamura/test.rb
22
+ - lib/nakamura/authz.rb
23
+ - lib/nakamura/full_group_creator.rb
24
+ - lib/nakamura/users.rb
25
+ - lib/nakamura/contacts.rb
26
+ - lib/nakamura/message.rb
27
+ - lib/nakamura/search.rb
28
+ - lib/nakamura/file.rb
29
+ - lib/nakamura.rb
30
+ homepage: http://sakaiproject.org
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements:
49
+ - none
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.6
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Ruby library for interacting with Sakai Nakamura.
55
+ test_files: []