stormmq-client 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #--
4
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
5
+ # All rights reserved.
6
+ #
7
+ # Please refer to the LICENSE file that accompanies this source
8
+ # for terms of use and redistribution.
9
+ #++
10
+
11
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
12
+
13
+ require 'stormmq/secret_keys'
14
+ require 'stormmq/application'
15
+
16
+ class StormMQ::Application::URLSigner < StormMQ::Application
17
+
18
+ def initialize
19
+ synopsis "--help | --user <userName> --method <HttpMethod> --url <URL>"
20
+ options :help
21
+
22
+ option :names => %w(--user -u),
23
+ :opt_description => "a valid user name, i.e. the user name that you log into the site with",
24
+ :arity => [1,1],
25
+ :opt_found => get_args
26
+
27
+ option :names => %w(--method -m),
28
+ :opt_description => "the HTTP method to use - defaults to 'GET'",
29
+ :arity => [1,1],
30
+ :opt_found => get_args,
31
+ :opt_not_found => 'GET'
32
+
33
+ option :names => %w(--url -a),
34
+ :opt_description => "the URL to be signed",
35
+ :arity => [1,1],
36
+ :opt_found => get_args,
37
+ :opt_not_found => CommandLine::OptionParser::OPT_NOT_FOUND_BUT_REQUIRED
38
+ end
39
+
40
+ def main
41
+ puts self.url.canonicalise_and_sign(opt.user, self.secret_key(opt.user), opt['--method'])
42
+ end
43
+
44
+ def man
45
+ <<-EOM
46
+ NAME
47
+
48
+ #{File.basename(__FILE__)}
49
+
50
+ PURPOSE
51
+
52
+ Use this to experiment with the how signing URLs works if you need
53
+ a reference implementation.
54
+
55
+ USAGE
56
+
57
+ #{File.basename(__FILE__)} --help
58
+ #{File.basename(__FILE__)} --user <userName> --method <HttpMethod> --url <URL>
59
+
60
+ PARAMETERS
61
+
62
+ --user
63
+
64
+ The user name you log in to this site with.
65
+
66
+ --method
67
+
68
+ One of:
69
+
70
+ * GET
71
+ * HEAD
72
+ * OPTIONS
73
+ * PUT
74
+ * DELETE
75
+
76
+ POST is not yet supported.
77
+
78
+ --url
79
+
80
+ The unsigned URL to be signed.
81
+
82
+ --help, -h
83
+
84
+ Displays this help page then quits.
85
+
86
+ RESULT
87
+
88
+ Outputs a signed URL to STDOUT.
89
+
90
+ NOTES
91
+
92
+ Advanced use only - commandline subject to change.
93
+
94
+ COPYRIGHT
95
+
96
+ Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
97
+ All rights reserved.
98
+
99
+ EOM
100
+ end
101
+
102
+ def url
103
+ StormMQ::URL.new(opt.url)
104
+ end
105
+
106
+ def secret_key(user) # :nodoc:
107
+ StormMQ::SecretKeys.key_for(user)
108
+ end
109
+ end
110
+
111
+ StormMQ::Application::URLSigner.run
@@ -0,0 +1,92 @@
1
+ #--
2
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
3
+ # All rights reserved.
4
+ #
5
+ # Please refer to the LICENSE file that accompanies this source
6
+ # for terms of use and redistribution.
7
+ #++
8
+
9
+ require 'mq'
10
+ require 'pp'
11
+
12
+ module StormMQ
13
+
14
+ module AMQPClientImplementation
15
+
16
+ VERSION = '0.0.4'
17
+
18
+ def process_frame frame
19
+ if mq = channels[frame.channel]
20
+ mq.process_frame(frame)
21
+ return
22
+ end
23
+
24
+ case frame
25
+ when Frame::Method
26
+ case method = frame.payload
27
+ when Protocol::Connection::Start
28
+ send Protocol::Connection::StartOk.new(
29
+ {
30
+ :platform => 'Ruby/EventMachine',
31
+ :product => 'StormMQ AMQP',
32
+ :information => 'http://github.com/tonybyrne/StormMQ-Ruby-Client/',
33
+ :version => VERSION
34
+ },
35
+ 'AMQPLAIN',
36
+ {
37
+ :LOGIN => @settings[:user],
38
+ :PASSWORD => @settings[:password]
39
+ },
40
+ 'en_US'
41
+ )
42
+
43
+ when Protocol::Connection::Tune
44
+ send Protocol::Connection::TuneOk.new(
45
+ :channel_max => 0,
46
+ :frame_max => 131072,
47
+ :heartbeat => 0
48
+ )
49
+
50
+ send Protocol::Connection::Open.new(
51
+ :virtual_host => @settings[:vhost],
52
+ :capabilities => '',
53
+ :insist => @settings[:insist]
54
+ )
55
+
56
+ when Protocol::Connection::OpenOk
57
+ succeed(self)
58
+
59
+ when Protocol::Connection::Close
60
+ STDERR.puts "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
61
+
62
+ when Protocol::Connection::CloseOk
63
+ @on_disconnect.call if @on_disconnect
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ module AMQPClient
70
+
71
+ def self.connect(options={})
72
+ AMQP.client = AMQPClientImplementation
73
+ AMQP.connect(
74
+ {
75
+ :vhost => self.vhost_from_options(options),
76
+ :host => 'amqp.stormmq.com',
77
+ :port => 443,
78
+ :ssl => true
79
+ }.merge(options)
80
+ )
81
+ end
82
+
83
+ def self.vhost_from_options(options)
84
+ vhost = "/#{options[:company]}/#{options[:system]}/#{options[:environment]}"
85
+ [:company, :system, :environment].each {|option| options.delete(option)}
86
+ vhost
87
+ end
88
+
89
+ end
90
+
91
+ end
92
+
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
3
+ # All rights reserved.
4
+ #
5
+ # Please refer to the LICENSE file that accompanies this source
6
+ # for terms of use and redistribution.
7
+ #++
8
+
9
+ require 'stormmq/errors'
10
+ require 'stormmq/rest'
11
+ require 'commandline'
12
+ require 'commandline/optionparser'
13
+
14
+ module StormMQ
15
+ class Application < CommandLine::Application_wo_AutoRun
16
+
17
+ def initialize(*args)
18
+ author "Tony Byrne"
19
+ copyright "2010, Tony Byrne & StormMQ. All rights reserved."
20
+ super(*args)
21
+ end
22
+
23
+ def rest_client(user)
24
+ begin
25
+ Rest.new(:user => user)
26
+ rescue Error::SecretKeyNotProvidedError
27
+ raise "Could not find the secret key for user '#{user}' - please ensure it is present in the secret key file"
28
+ end
29
+ end
30
+
31
+ def self_test
32
+ 'Self test ouput goes here'
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ #--
2
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
3
+ # All rights reserved.
4
+ #
5
+ # Please refer to the LICENSE file that accompanies this source
6
+ # for terms of use and redistribution.
7
+ #++
8
+
9
+ module Base64
10
+
11
+ def urlsafe_decode64(str)
12
+ decode64(str.tr("-_", "+/"))
13
+ end
14
+
15
+ def urlsafe_encode64(bin)
16
+ encode64(bin).tr("+/", "-_")
17
+ end
18
+
19
+ end
@@ -0,0 +1,33 @@
1
+ #--
2
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
3
+ # All rights reserved.
4
+ #
5
+ # Please refer to the LICENSE file that accompanies this source
6
+ # for terms of use and redistribution.
7
+ #++
8
+
9
+ module StormMQ
10
+
11
+ module Error
12
+
13
+ class Base < StandardError
14
+ end
15
+
16
+ class LoadSecretKeysError < StormMQ::Error::Base
17
+ end
18
+
19
+ class SecretKeyNotFoundError < StormMQ::Error::Base
20
+ end
21
+
22
+ class SecretKeyNotProvidedError < StormMQ::Error::Base
23
+ end
24
+
25
+ class UserNotProvidedError < StormMQ::Error::Base
26
+ end
27
+
28
+ class InvalidURLError < StormMQ::Error::Base
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,160 @@
1
+ #--
2
+ # Copyright (c) 2010, Tony Byrne & StormMQ Ltd.
3
+ # All rights reserved.
4
+ #
5
+ # Please refer to the LICENSE file that accompanies this source
6
+ # for terms of use and redistribution.
7
+ #++
8
+
9
+ require 'stormmq/url'
10
+ require 'stormmq/errors'
11
+ require 'stormmq/secret_keys'
12
+ require 'json'
13
+ require 'rest_client'
14
+
15
+ module StormMQ
16
+
17
+ API_HOST = ENV['STORMMQ_HOST'] || "api.stormmq.com"
18
+ API = ENV['STORMMQ_API'] || "api"
19
+ API_VERSION = ENV['STORMMQ_API_VERSION'] || "2009-01-01"
20
+
21
+ COMPANIES_PATH = '/companies/'
22
+ CLUSTERS_PATH = '/clusters'
23
+ APIS_PATH = '/'
24
+
25
+ # The Rest class implements the client for StormMQ's RESTful API. The API allows clients to access
26
+ # company, system and environment information.
27
+
28
+ class Rest
29
+
30
+ RestClient.proxy = ENV['http_proxy'] unless ENV['http_proxy'].nil?
31
+
32
+ def initialize(options={})
33
+ unless @user = options.delete(:user)
34
+ raise Error::UserNotProvidedError,
35
+ "could not determine the user name - either provide it via the :user param",
36
+ caller
37
+ end
38
+
39
+ unless @secret_key = options.delete(:secret_key) || self.class.secret_key_from_key_store(@user)
40
+ raise Error::SecretKeyNotProvidedError, "could not determine the secret key for user '#{@user}' - either provide it via the :secret_key param or ensure it is available in the secret key file",
41
+ caller
42
+ end
43
+
44
+ @host = options.delete(:host) || API_HOST
45
+ @api = options.delete(:api) || API
46
+ @version = options.delete(:version) || API_VERSION
47
+
48
+ @url_options = options
49
+ end
50
+
51
+ # Returns an Array of company indentifiers associated with the user.
52
+ def companies
53
+ signed_get(COMPANIES_PATH)
54
+ end
55
+
56
+ # Takes a String containing a valid company identifier and returns a
57
+ # Hash representation of the detailed information stored on the StormMQ
58
+ # system about the company.
59
+ def describe_company(company)
60
+ signed_get(COMPANIES_PATH, escape(company))
61
+ end
62
+
63
+ def systems(company)
64
+ signed_get(COMPANIES_PATH, escape(company), '/')
65
+ end
66
+
67
+ def create_system(company, system, json)
68
+ signed_put(json, COMPANIES_PATH, escape(company), escape(system))
69
+ end
70
+
71
+ def describe_system(company, system)
72
+ signed_get(COMPANIES_PATH, escape(company), escape(system))
73
+ end
74
+
75
+ def delete_system(company, system)
76
+ signed_delete(COMPANIES_PATH, escape(company), escape(system))
77
+ end
78
+
79
+ def clusters(company)
80
+ signed_get(CLUSTERS_PATH, escape(company))
81
+ end
82
+
83
+ def queues(company, system, environment)
84
+ signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'queues/')
85
+ end
86
+
87
+ def bindings(company, system, environment)
88
+ signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'bindings/')
89
+ end
90
+
91
+ def exchanges(company, system, environment)
92
+ signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'exchanges/')
93
+ end
94
+
95
+ def apis
96
+ signed_get(APIS_PATH)
97
+ end
98
+
99
+ def amqp_password(company, system, environment, amqp_user)
100
+ signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'users', escape(amqp_user))
101
+ end
102
+
103
+ def amqp_users(company, system, environment)
104
+ signed_get(COMPANIES_PATH, escape(company), escape(system), escape(environment), 'users/')
105
+ end
106
+
107
+ private
108
+
109
+ def signed_get(*path_args)
110
+ get(build_signed_resource_url(make_normalised_path(*path_args)))
111
+ end
112
+
113
+ def signed_delete(*path_args)
114
+ delete(build_signed_resource_url(make_normalised_path(*path_args), 'DELETE'))
115
+ end
116
+
117
+ def signed_put(payload, *path_args)
118
+ put(build_signed_resource_url(make_normalised_path(*path_args), 'PUT'), payload)
119
+ end
120
+
121
+ def escape(string) # :nodoc:
122
+ StormMQ::URL.escape(string)
123
+ end
124
+
125
+ def get(signed_url) # :nodoc:
126
+ JSON.parse(RestClient.get(signed_url.to_s, {:accept => '*/*'}).to_s)
127
+ end
128
+
129
+ def delete(signed_url) # :nodoc:
130
+ JSON.parse(RestClient.delete(signed_url.to_s).to_s)
131
+ end
132
+
133
+ def put(signed_url, payload) # :nodoc:
134
+ JSON.parse(RestClient.put(signed_url.to_s, payload, {:accept => '*/*', :content_type => 'application/json'}).to_s)
135
+ end
136
+
137
+ def build_signed_resource_url(resource_path='/', method='GET') # :nodoc:
138
+ StormMQ::URL.new(
139
+ {
140
+ :host => @host,
141
+ :scheme => 'https',
142
+ :path => make_normalised_path(@api, @version, resource_path)
143
+ }.merge(@url_options)
144
+ ).canonicalise_and_sign(@user, @secret_key, method)
145
+ end
146
+
147
+ def make_normalised_path(*args) # :nodoc:
148
+ ('/' + args.join('/')).gsub(/\/+/,'/')
149
+ end
150
+
151
+ def self.secret_key_from_key_store(user) # :nodoc:
152
+ begin
153
+ SecretKeys.key_for(user)
154
+ rescue
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ end