rack-webmoney 0.0.2

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.
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/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ = Rack::Webmoney
2
+
3
+ === Usage
4
+
5
+ You trigger an Webmoney request similar to HTTP authentication. From your app,
6
+ return a "401 Unauthorized" and a "WWW-Authenticate" header with the identifier you would like to validate.
7
+
8
+ On competition, the Webmoney response is automatically verified and assigned to
9
+ <tt>env["rack.webmoney.response"]</tt>.
10
+
11
+ === Rails 3 Example
12
+
13
+ application.rb
14
+
15
+ ...
16
+ config.middleware.insert_before(Warden::Manager, Rack::Webmoney,
17
+ :credentials => {:site_rid => 'your_site_rid', :site_holder_wmid => 'your_site_holder_wmid'},
18
+ :mode => Rails.env)
19
+ ...
20
+
21
+ === Rack Example
22
+
23
+ MyApp = lambda { |env|
24
+ if resp = env["rack.webmoney.response"]
25
+ case resp.status
26
+ when :successful
27
+ ...
28
+ else
29
+ ...
30
+ else
31
+ [401, {"WWW-Authenticate" => 'Webmoney"}, []]
32
+ end
33
+ }
34
+
35
+ use Rack::Webmoney, :credentials => {:site_rid => 'your_site_rid', :site_holder_wmid => 'your_site_holder_wmid'}, :mode => "development_OR_test_FOR_TESTING"
36
+ run MyApp
37
+
38
+ === Sinatra Example
39
+
40
+ # Session needs to be before Rack::OpenID
41
+ use Rack::Session::Cookie
42
+
43
+ require 'rack/webmoney'
44
+ use Rack::Webmoney, :credentials => {:site_rid => 'your_site_rid', :site_holder_wmid => 'your_site_holder_wmid'}, :mode => "development_OR_test_FOR_TESTING"
45
+
46
+ get '/login' do
47
+ erb :login
48
+ end
49
+
50
+ post '/login' do
51
+ if resp = request.env["rack.webmoney.response"]
52
+ if resp.status == :successful
53
+ "Welcome: #{resp.display_identifier}"
54
+ else
55
+ "#{resp.status}: #{resp.message}"
56
+ end
57
+ else
58
+ headers 'WWW-Authenticate' => Rack::Webmoney.build_header({})
59
+ throw :halt, [401, 'got webmoney?']
60
+ end
61
+ end
62
+
63
+ use_in_file_templates!
64
+
65
+ __END__
66
+
67
+ @@ login
68
+ <form action="/login" method="post">
69
+ <p>
70
+ <input style="display:none;" name="auth_provider" type="text" value="webmoney"/>
71
+ </p>
72
+
73
+ <p>
74
+ <input name="commit" type="submit" value="Sign in" />
75
+ </p>
76
+ </form>
77
+
78
+
79
+ == Thank for inspiration goes to:
80
+
81
+ rack-openid[http://github.com/josh/rack-openid.git]
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rack-webmoney"
8
+ gem.summary = 'Rack Webmoney authentication'
9
+ gem.description = %q{Rack webmoney authentication}
10
+ gem.email = ['eagle.anton@gmail.com', 'eagle.alex@gmail.com']
11
+ gem.homepage = "http://github.com/SkyEagle/rack-webmoney"
12
+ gem.authors = ['Anton Orel', 'Alexander Orel']
13
+ gem.add_dependency(%q<rack>, ">= 1.2.1")
14
+ gem.add_dependency(%q<savon>, ">= 0.7.9")
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/test_*.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "rack-webmoney #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,253 @@
1
+ #encoding: utf-8
2
+ require 'rack/request'
3
+ require 'rack/utils'
4
+
5
+ require "savon"
6
+
7
+ module Rack #:nodoc:
8
+ # A Rack middleware that provides a more HTTPish API around Webmoney authentication
9
+ #
10
+ # You trigger an Webmoney request similar to HTTP authentication.
11
+ # From your app, return a "401 Unauthorized" and a "WWW-Authenticate"
12
+ # header with the identifier you would like to validate.
13
+ #
14
+ # On competition, the Webmoney response is automatically verified and
15
+ # assigned to <tt>env["rack.webmoney.response"]</tt>.
16
+ class Webmoney
17
+ class Response
18
+ ERROR_MESSAGES = {
19
+ # -2 raised network error
20
+ :server_not_available => "Sorry, the Webmoney Login server is not available",
21
+ # -1
22
+ :internal_error => "Webmoney Login server internal error",
23
+ # 1
24
+ :invalid_arguments => "Invalid arguments",
25
+ # 2
26
+ :ticket_invalid => "Sorry, invalid authorization ticket",
27
+ # 3
28
+ :ticket_expired => "Sorry, authorization ticket expired",
29
+ # 4
30
+ :user_not_found => "Sorry, user not found",
31
+ # 5
32
+ :holder_not_found => "The holder of a site not found",
33
+ # 6
34
+ :website_not_found => "Website Not Found",
35
+ # 7
36
+ :url_not_found => "This url is not found, or does not belong to the site",
37
+ # 8
38
+ :settings_not_found => "Security Settings for the site could not be found",
39
+ # 9
40
+ :invalid_password => "Access service is not authorized. Invalid password.",
41
+ # 10
42
+ :not_trusted => "Attempting to gain access to the site, which does not accept you as a trustee",
43
+ # 11
44
+ :pwd_access_blocked => "Password access to the service blocked",
45
+ # 12
46
+ :user_blocked => "The user is temporarily blocked. Probably made the selection Ticket",
47
+ # 201
48
+ :ip_differs => "Ip address in the request differs from the address, which was an authorized user"
49
+ }
50
+
51
+ def initialize(code, info)
52
+ @code = code
53
+ @info = info
54
+ end
55
+
56
+ def status
57
+ @code
58
+ end
59
+
60
+ def successful?
61
+ @code == :successful
62
+ end
63
+
64
+ def unsuccessful?
65
+ ERROR_MESSAGES.keys.include?(@code)
66
+ end
67
+
68
+ def message
69
+ ERROR_MESSAGES[@code]
70
+ end
71
+
72
+ def wmid
73
+ @info[:wmid]
74
+ end
75
+ end
76
+
77
+ #SOAP driver setup
78
+ #@@driver = SOAP::WSDLDriverFactory.new('https://login.wmtransfer.com/ws/Security.asmx?WSDL').create_rpc_driver
79
+ #@@driver.options['protocol.http.ssl_config.verify_mode'] = OpenSSL::SSL::VERIFY_PEER
80
+
81
+ #
82
+ # Helper method for building the "WWW-Authenticate" header value.
83
+ #
84
+ # Rack::Webmoney.build_header(:site_rid => "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
85
+ # #=> Webmoney site_rid="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
86
+ def self.build_header(params = {})
87
+ 'Webmoney ' + params.map { |key, value|
88
+ if value.is_a?(Array)
89
+ "#{key}=\"#{value.join(',')}\""
90
+ else
91
+ "#{key}=\"#{value}\""
92
+ end
93
+ }.join(', ')
94
+ end
95
+
96
+ # Helper method for parsing "WWW-Authenticate" header values into
97
+ # a hash.
98
+ #
99
+ # Rack::Webmoney.parse_header("Webmoney site_rid="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
100
+ # #=> {:site_rid => "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
101
+ def self.parse_header(str)
102
+ params = {}
103
+ if str =~ AUTHENTICATE_REGEXP
104
+ str = str.gsub(/#{AUTHENTICATE_REGEXP}\s+/, '')
105
+ str.split(', ').each { |pair|
106
+ key, *value = pair.split('=')
107
+ value = value.join('=')
108
+ value.gsub!(/^\"/, '').gsub!(/\"$/, "")
109
+ value = value.split(',')
110
+ params[key] = value.length > 1 ? value : value.first
111
+ }
112
+ end
113
+ params
114
+ end
115
+
116
+ #class TimeoutResponse #:nodoc:
117
+ #include ::OpenID::Consumer::Response
118
+ #STATUS = :failure
119
+ #end
120
+
121
+ #class MissingResponse #:nodoc:
122
+ #include ::OpenID::Consumer::Response
123
+ #STATUS = :missing
124
+ #end
125
+
126
+ # :stopdoc:
127
+
128
+ HTTP_METHODS = %w(GET HEAD PUT POST DELETE OPTIONS)
129
+
130
+ RESPONSE = "rack.webmoney.response"
131
+ AUTHENTICATE_HEADER = "WWW-Authenticate"
132
+ AUTHENTICATE_REGEXP = /^Webmoney/
133
+
134
+ URL_FIELD_SELECTOR = lambda { |field| field.to_s =~ %r{^https://} }
135
+
136
+ attr_reader :credentials, :mode
137
+
138
+ # :startdoc:
139
+
140
+ # Initialize middleware with application
141
+ #
142
+ # use Rack::Webmoney, :credentials => {:site_holder_wmid => 'your_site_holder_wmid', :site_rid => 'your_site_rid'}, :mode => Rails.env
143
+ #
144
+ def initialize(app, opts ={})
145
+ @app = app
146
+ @credentials = opts[:credentials]
147
+ @mode = opts[:mode]
148
+ end
149
+
150
+ # Standard Rack +call+ dispatch that accepts an +env+ and
151
+ # returns a <tt>[status, header, body]</tt> response.
152
+ def call(env)
153
+ req = Rack::Request.new(env)
154
+ if req.params["WmLogin_WMID"]
155
+ complete_authentication(env)
156
+ end
157
+
158
+ status, headers, body = @app.call(env)
159
+
160
+ qs = headers[AUTHENTICATE_HEADER]
161
+ if status.to_i == 401 && qs && qs.match(AUTHENTICATE_REGEXP)
162
+ begin_authentication(env, qs)
163
+ else
164
+ [status, headers, body]
165
+ end
166
+ end
167
+
168
+ private
169
+ def begin_authentication(env, qs)
170
+ req = Rack::Request.new(env)
171
+ params = self.class.parse_header(qs)
172
+ session = env["rack.session"]
173
+
174
+ raise RuntimeError, "Rack::Webmoney requires a session" unless session
175
+
176
+ redirect_to "https://login.wmtransfer.com/GateKeeper.aspx?RID=#{credentials[:site_rid]}"
177
+ end
178
+
179
+ def complete_authentication(env)
180
+ req = Rack::Request.new(env)
181
+ session = env["rack.session"]
182
+
183
+ unless session
184
+ raise RuntimeError, "Rack::Webmoney requires a session"
185
+ end
186
+
187
+ wminfo =
188
+ { :ticket => req.params["WmLogin_Ticket"],
189
+ :url_id => req.params["WmLogin_UrlID"],
190
+ :expires => req.params["WmLogin_Expires"],
191
+ :auth_type => req.params["WmLogin_AuthType"],
192
+ :last_access => req.params["WmLogin_LastAccess"],
193
+ :created => req.params["WmLogin_Created"],
194
+ :wmid => req.params["WmLogin_WMID"],
195
+ :user_ip => req.params["WmLogin_UserAddress"] }
196
+
197
+ # work around for local development
198
+ ip_to_check = %w(development test).include?(mode) ? wminfo[:user_ip] : req.ip
199
+
200
+ check_req_params = {
201
+ :SiteHolderWMID => credentials[:site_holder_wmid],
202
+ :wmId => wminfo[:wmid],
203
+ :ticket => wminfo[:ticket],
204
+ :urlId => wminfo[:url_id],
205
+ :authType => wminfo[:auth_type],
206
+ :userAddress => ip_to_check
207
+ }
208
+
209
+ begin
210
+ soap_client = Savon::Client.new "https://login.wmtransfer.com"
211
+ response = soap_client.authorize! do |soap| # (!) disable WSDL
212
+ soap.namespace = "https://login.wmtransfer.com/ws/Security.asmx?WSDL"
213
+ soap.body = check_req_params
214
+ end.to_hash['authorizeResult'].to_i
215
+ rescue Exception => msg
216
+ response = -2
217
+ end
218
+
219
+ status = case response
220
+ when 0 then :successful
221
+ when -2 then :server_not_available
222
+ when -1 then :internal_error
223
+ when 1 then :invalid_arguments
224
+ when 2 then :ticket_invalid
225
+ when 3 then :ticket_expired
226
+ when 4 then :user_not_found
227
+ when 5 then :holder_not_found
228
+ when 6 then :website_not_found
229
+ when 7 then :url_not_found
230
+ when 8 then :settings_not_found
231
+ when 9 then :invalid_password
232
+ when 10 then :not_trusted
233
+ when 11 then :pwd_access_blocked
234
+ when 12 then :user_blocked
235
+ when 201 then :ip_differs
236
+ else
237
+ "Unknown response code(#{response})"
238
+ end
239
+
240
+ env[RESPONSE] = Response.new(status, wminfo)
241
+
242
+ req.params['authenticity_token'] = session['_csrf_token']
243
+ end
244
+
245
+ def redirect_to(url)
246
+ [303, {"Content-Type" => "text/html", "Location" => url}, []]
247
+ end
248
+
249
+ def logger
250
+ @logger ||= Rails.logger if defined?(Rails)
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,49 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rack-webmoney}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Anton Orel", "Alexander Orel"]
12
+ s.date = %q{2010-09-01}
13
+ s.description = %q{Rack webmoney authentication}
14
+ s.email = ["eagle.anton@gmail.com", "eagle.alex@gmail.com"]
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "Gemfile",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/rack/webmoney.rb",
25
+ "rack-webmoney.gemspec"
26
+ ]
27
+ s.homepage = %q{http://github.com/SkyEagle/rack-webmoney}
28
+ s.rdoc_options = ["--charset=UTF-8"]
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = %q{1.3.7}
31
+ s.summary = %q{Rack Webmoney authentication}
32
+
33
+ if s.respond_to? :specification_version then
34
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
35
+ s.specification_version = 3
36
+
37
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
38
+ s.add_runtime_dependency(%q<rack>, [">= 1.2.1"])
39
+ s.add_runtime_dependency(%q<savon>, [">= 0.7.9"])
40
+ else
41
+ s.add_dependency(%q<rack>, [">= 1.2.1"])
42
+ s.add_dependency(%q<savon>, [">= 0.7.9"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<rack>, [">= 1.2.1"])
46
+ s.add_dependency(%q<savon>, [">= 0.7.9"])
47
+ end
48
+ end
49
+
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-webmoney
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Anton Orel
13
+ - Alexander Orel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-09-01 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 1
31
+ - 2
32
+ - 1
33
+ version: 1.2.1
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: savon
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 0
46
+ - 7
47
+ - 9
48
+ version: 0.7.9
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ description: Rack webmoney authentication
52
+ email:
53
+ - eagle.anton@gmail.com
54
+ - eagle.alex@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - README.rdoc
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - README.rdoc
65
+ - Rakefile
66
+ - VERSION
67
+ - lib/rack/webmoney.rb
68
+ - rack-webmoney.gemspec
69
+ has_rdoc: true
70
+ homepage: http://github.com/SkyEagle/rack-webmoney
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --charset=UTF-8
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.7
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Rack Webmoney authentication
101
+ test_files: []
102
+