canned_soap 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +62 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/canned_soap.gemspec +29 -0
- data/docker-compose.yml +9 -0
- data/example.rb +26 -0
- data/lib/canned_soap/client.rb +83 -0
- data/lib/canned_soap/soap/soap.rb +86 -0
- data/lib/canned_soap/soap/soap_action.rb +9 -0
- data/lib/canned_soap/soap/soap_parameter.rb +17 -0
- data/lib/canned_soap/version.rb +3 -0
- data/lib/canned_soap/wcf_handler.rb +102 -0
- data/lib/canned_soap/web/security_protocol.rb +10 -0
- data/lib/canned_soap/web/web_request_handler.rb +88 -0
- data/lib/canned_soap/wsdl/wsdl.rb +7 -0
- data/lib/canned_soap/wsdl/wsdl_parser.rb +151 -0
- data/lib/canned_soap.rb +5 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 23355d1c2e66be1f8577a68e8015eab0a1ea1169
|
4
|
+
data.tar.gz: 859ff7e1c8ff6b1cc0386e0173579e54d040c66e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37fa359b99059c40aef433b40d7cf83aecc2a8ec5a6125296349a442b1087f10422a2ae860e6c672a943e49a6ed1c0b379d1cda672b271ec023faab59cca55b4
|
7
|
+
data.tar.gz: 638c52370ac7199be8143812d5fb1541d4ec604d06203743912b08f81486ed853c56062e0ebe23cff14fa4600599d220a05a66670a4effe9b0452e9f991a61a0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Canned
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#CannedSoap
|
2
|
+
|
3
|
+
A rewrite version of the [ruby2soap](https://github.com/ericman93/ruby2soap) gem.
|
4
|
+
|
5
|
+
##Motivation
|
6
|
+
The original gem has a lot of bugs and don't work on Linux environments. I started to maintain an old gem that uses this gem, so I started to maintain this gem too.
|
7
|
+
|
8
|
+
#Ruby2Soap Doc
|
9
|
+
I started this project when I needed to call a WCF method which required cookies on init. Unfortunalty, I could not find any gem that will help me so, so I implemented it myself.
|
10
|
+
|
11
|
+
While working I noticed that I need more features - authentication, for example.
|
12
|
+
|
13
|
+
Please post any bugs, questions and feature requests using the 'Issues' page.
|
14
|
+
|
15
|
+
Thank you,
|
16
|
+
Eric
|
17
|
+
|
18
|
+
|
19
|
+
##Examples
|
20
|
+
|
21
|
+
###Initialize the handler
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
handler = WcfHandler.new('http://www.webservicex.net/CurrencyConvertor.asmx')
|
25
|
+
```
|
26
|
+
|
27
|
+
###Simple objects
|
28
|
+
```ruby
|
29
|
+
handler.ConversionRate(:FromCurrency => 'ILS', :ToCurrency => 'GBP')
|
30
|
+
```
|
31
|
+
|
32
|
+
###Statefull
|
33
|
+
```ruby
|
34
|
+
handler.Init(:userName => 'ericman93')
|
35
|
+
handler.IncreaseScore() #the cookies saved automaticly
|
36
|
+
```
|
37
|
+
|
38
|
+
###Complex type
|
39
|
+
```ruby
|
40
|
+
handler = WcfHandler.new('http://localhost:1659/Service1.svc')
|
41
|
+
res = handler.GetDataUsingDataContract(:composite => {:BoolValue => true,:StringValue => "ruby2soap"})
|
42
|
+
```
|
43
|
+
|
44
|
+
##Result
|
45
|
+
The object that the soap service function returns is actually a HTTP response with 'result' function that returns the actual value.
|
46
|
+
If the value is a complex object, then it would be represented as a hash
|
47
|
+
|
48
|
+
|
49
|
+
##Authentication
|
50
|
+
Available authentications
|
51
|
+
1. NTLM
|
52
|
+
2. Basic
|
53
|
+
3. Digest
|
54
|
+
|
55
|
+
###NTLM Auth
|
56
|
+
```ruby
|
57
|
+
handler.ConversionRate({:FromCurrency => 'ILS', :ToCurrency => 'GBP'},SecutryProtocol::NTLM,'user','password')
|
58
|
+
```
|
59
|
+
###With domain
|
60
|
+
```ruby
|
61
|
+
handler.ConversionRate({:FromCurrency => 'ILS', :ToCurrency => 'GBP'},SecutryProtocol::NTLM,'user','password','domain')
|
62
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "canned_soap"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/canned_soap.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "canned_soap/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "canned_soap"
|
8
|
+
spec.version = CannedSoap::VERSION
|
9
|
+
spec.authors = ["Gustavo Canedo"]
|
10
|
+
spec.email = ["gknedo@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "Communication between ruby and soap services"
|
13
|
+
spec.homepage = 'https://github.com/gknedo/canned_soap'
|
14
|
+
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_dependency "xml-simple", "~> 1.0"
|
28
|
+
spec.add_dependency "httpi", "~> 2.0"
|
29
|
+
end
|
data/docker-compose.yml
ADDED
data/example.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ruby2soap'
|
2
|
+
|
3
|
+
def complex_object_example
|
4
|
+
handler = CannedSoap::Client.new('http://localhost:1659/Service1.svc')
|
5
|
+
res = handler.GetDataUsingDataContract(composite: {
|
6
|
+
BoolValue: true,
|
7
|
+
StringValue: "canned"
|
8
|
+
})
|
9
|
+
res.result['StringValue']
|
10
|
+
end
|
11
|
+
|
12
|
+
def cookie_state_full_example
|
13
|
+
handler = CannedSoap::Client.new('http://localhost:1659/Service1.svc')
|
14
|
+
handler.Init(userName: 'ericman93')
|
15
|
+
handler.IncreaseScore()
|
16
|
+
end
|
17
|
+
|
18
|
+
def few_params_example
|
19
|
+
handler = CannedSoap::Client.new('http://www.webservicex.net/CurrencyConvertor.asmx')
|
20
|
+
handler.ConversionRate(FromCurrency: 'ILS', ToCurrency: 'GBP').result
|
21
|
+
end
|
22
|
+
|
23
|
+
def ntlm_example
|
24
|
+
handler = CannedSoap::Client.new('http://localhost:1659/Service1.svc')
|
25
|
+
handler.AddPoints({points: 6}, CannedSoap::Web::SecutryProtocol::NTLM, 'user', 'password', 'domain')
|
26
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Handle the requests to the service
|
2
|
+
module CannedSoap
|
3
|
+
class Client
|
4
|
+
# C'tor.
|
5
|
+
# Parse the wsdl and create a method to each WCF/WebService method
|
6
|
+
# Params:
|
7
|
+
# +service_url+:: the url of your service
|
8
|
+
# +save_cookeis+:: should save cookies of the result
|
9
|
+
def initialize(service_url,save_cookeis = true)
|
10
|
+
HTTPI.log = false
|
11
|
+
@cookies = []
|
12
|
+
@save_cookeis = save_cookeis
|
13
|
+
|
14
|
+
@uri = URI("#{service_url}")
|
15
|
+
|
16
|
+
wsdl = WsdlParser.parse(service_url)
|
17
|
+
@service_address = wsdl.location_address
|
18
|
+
|
19
|
+
wsdl.actions.each do |action|
|
20
|
+
define_wcf_action(action)
|
21
|
+
end
|
22
|
+
|
23
|
+
# maybe create class for each service and the function will be there
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the the current cookie set
|
27
|
+
def cookies
|
28
|
+
@cookies
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
# Define a method to the +Ruby2Soap+ object base on the method from the WSDL
|
33
|
+
# Params:
|
34
|
+
# +action+:: +SoapAction+ that have all the info about the method from the WSDL
|
35
|
+
def define_wcf_action(action)
|
36
|
+
self.class.send(:define_method ,action.name) do |data=nil,*args|
|
37
|
+
body = build_body(action, data)
|
38
|
+
|
39
|
+
res = send_wcf_action(action.soap_action,body,*args)
|
40
|
+
(@cookies << res.headers["Set-Cookie"]) if @save_cookeis
|
41
|
+
|
42
|
+
result = get_wcf_response(res,action.name)
|
43
|
+
res.singleton_class.send(:define_method,:result) do
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
#if(res.code == '401') # not autorized
|
48
|
+
# (raise "Please use ntlm") if res['WWW-Authenticate'].include?('NTLM')
|
49
|
+
#end
|
50
|
+
|
51
|
+
res
|
52
|
+
end
|
53
|
+
|
54
|
+
#create new method that takes the data and user and password and user ntlm
|
55
|
+
end
|
56
|
+
|
57
|
+
# Call to wcf method
|
58
|
+
# Params:
|
59
|
+
# +soap_action+:: the value of the SOAPAction header
|
60
|
+
# +body+:: the body of the HTTP request
|
61
|
+
# +args+:: metadata that indicate wich autountication to use
|
62
|
+
def send_wcf_action(soap_action,body,*args)
|
63
|
+
#req = Net::HTTP::Post.new(@uri.path)
|
64
|
+
#req = Net::HTTP::Post.new(@service_address)
|
65
|
+
|
66
|
+
#req["SOAPAction"] = soap_action
|
67
|
+
#req["Content-Type"] = "text/xml; charset=utf-8"
|
68
|
+
#req["Cookie"] = @cookies.join(',') unless @cookies.empty?
|
69
|
+
#req.body = body
|
70
|
+
|
71
|
+
yield(req) if block_given?
|
72
|
+
|
73
|
+
#get_web_response(req,@uri,*args)
|
74
|
+
# "Cookie" => (@cookies.join(',') unless @cookies.empty?)
|
75
|
+
cookies = @cookies.empty? ? "" : @cookies.join(',')
|
76
|
+
send_message_to_wcf(@service_address,
|
77
|
+
{"SOAPAction" => soap_action,
|
78
|
+
"Content-Type" => "text/xml; charset=utf-8",
|
79
|
+
"Cookie" => cookies},
|
80
|
+
body, *args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'canned_soap/soap/soap_action'
|
2
|
+
require 'canned_soap/soap/soap_parameter'
|
3
|
+
require 'xmlsimple'
|
4
|
+
|
5
|
+
module CannedSoap::Soap
|
6
|
+
# Covert the data to hash
|
7
|
+
# Params:
|
8
|
+
# +object+:: the object to covert to hash
|
9
|
+
def data_to_arr(object)
|
10
|
+
return '' if object.nil?
|
11
|
+
return [object] unless object.is_a? Hash
|
12
|
+
|
13
|
+
params = {}
|
14
|
+
object.each do |key,value|
|
15
|
+
params["#{@name_space}:#{key}"] = data_to_arr(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
params
|
19
|
+
end
|
20
|
+
|
21
|
+
# Build the body that need to be send to the service when calling the soap action and return the result
|
22
|
+
# Params :
|
23
|
+
# +action+:: +SoapAction+ object that keep all the data about the soap action
|
24
|
+
# +data+:: the user data that he want to send to the server
|
25
|
+
def build_body(action , data)
|
26
|
+
@name_space = 'a'
|
27
|
+
body = {
|
28
|
+
'soap:Envelope' => {
|
29
|
+
'xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
30
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
31
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
32
|
+
'soap:Body' => {
|
33
|
+
"#{action.name}" => {
|
34
|
+
"xmlns" => WsdlParser.target_namespace
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
if(!data.nil?)
|
41
|
+
data.each do |key, value|
|
42
|
+
build_param(body['soap:Envelope']['soap:Body']["#{action.name}"],action,key,value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
XmlSimple.xml_out(body, 'RootName' => nil)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parse the server response to hash that the user will work eith
|
50
|
+
# Params:
|
51
|
+
# +res+:: +HTTPI::Response+ object that represent the response from the server
|
52
|
+
# +action_name+:: the name of the action that the response is belongs to
|
53
|
+
def get_wcf_response(res,action_name)
|
54
|
+
#res.error?
|
55
|
+
if res.code.to_i >= 400
|
56
|
+
'error please see body'
|
57
|
+
else
|
58
|
+
result = XmlSimple.xml_in(res.body)['Body'].first["#{action_name}Response"].first["#{action_name}Result"].first
|
59
|
+
if result.class == Hash
|
60
|
+
# I dont want to return the result xml attributes
|
61
|
+
result.select!{|k,v| v.class == Array}
|
62
|
+
end
|
63
|
+
|
64
|
+
result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Adds to the action element in the +Hash+ and add the user send data to the hash
|
69
|
+
# Params:
|
70
|
+
# +action_element+:: the action element in the hash of the body
|
71
|
+
# +action+:: +SoapAction+ object that keep all the data about the soap action
|
72
|
+
# +key+:: the name of the parameter
|
73
|
+
# +value+:: the value of the parameter
|
74
|
+
def build_param(action_element,action,key,value)
|
75
|
+
if(action.parameters.nil?)
|
76
|
+
action_element["#{key}"] = ((value.is_a? Hash) ? data_to_arr(value) : [value])
|
77
|
+
else
|
78
|
+
current_param = action.parameters.select{|p| p.name.upcase == key.to_s.upcase}.first
|
79
|
+
action_element["#{key}"] = ((value.is_a? Hash) ? data_to_arr(value) : [value])
|
80
|
+
|
81
|
+
if current_param && current_param.namespace
|
82
|
+
action_element["#{key}"].merge!("xmlns:#{@name_space}" => current_param.namespace)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CannedSoap::Soap
|
2
|
+
class SoapParamter
|
3
|
+
attr_accessor :name, :nullable, :type, :namespace
|
4
|
+
|
5
|
+
# Gets the xml element of the paramter and parse it to a +SoapParamter+ object
|
6
|
+
# Params:
|
7
|
+
# +param_element+:: +Hash+ that represent the xml element of the paramter
|
8
|
+
def self.parse(param_element)
|
9
|
+
param = SoapParamter.new
|
10
|
+
param.name = param_element['name']
|
11
|
+
param.type = param_element['type'].split(':').last
|
12
|
+
yield param if block_given?
|
13
|
+
|
14
|
+
param
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'xmlsimple'
|
3
|
+
require 'canned_soap/wsdl/wsdl'
|
4
|
+
include Wsdl
|
5
|
+
#require 'soap/soap'
|
6
|
+
#include Soap
|
7
|
+
#include WebRequestHandler
|
8
|
+
#require_relative 'wsdl.rb'
|
9
|
+
#require_relative 'wsdl_parser.rb'
|
10
|
+
#require_relative 'soap.rb'
|
11
|
+
#include WsdlParser
|
12
|
+
#include Soap
|
13
|
+
|
14
|
+
#Dir["lib/*.rb"].each {|file|
|
15
|
+
# require file
|
16
|
+
# #require_relative file# if file != 'wcf_handler'
|
17
|
+
# #include file.gsub('.rb','')
|
18
|
+
#}
|
19
|
+
|
20
|
+
# Handle the requests to the service
|
21
|
+
module CannedSoap
|
22
|
+
class WcfHandler
|
23
|
+
# C'tor.
|
24
|
+
# Parse the wsdl and create a method to each WCF/WebService method
|
25
|
+
# Params:
|
26
|
+
# +service_url+:: the url of your service
|
27
|
+
# +save_cookeis+:: should save cookies of the result
|
28
|
+
def initialize(service_url,save_cookeis = true)
|
29
|
+
HTTPI.log = false
|
30
|
+
@cookies = []
|
31
|
+
@save_cookeis = save_cookeis
|
32
|
+
|
33
|
+
@uri = URI("#{service_url}")
|
34
|
+
|
35
|
+
wsdl = Wsdl::WsdlParser.parse(service_url)
|
36
|
+
@service_address = wsdl.location_address
|
37
|
+
|
38
|
+
wsdl.actions.each do |action|
|
39
|
+
define_wcf_action(action)
|
40
|
+
end
|
41
|
+
|
42
|
+
# maybe create class for each service and the function will be there
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the the current cookie set
|
46
|
+
def cookies
|
47
|
+
@cookies
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
# Define a method to the +WcfHandler+ object base on the method from the WSDL
|
52
|
+
# Params:
|
53
|
+
# +action+:: +SoapAction+ that have all the info about the method from the WSDL
|
54
|
+
def define_wcf_action(action)
|
55
|
+
self.class.send(:define_method ,action.name) do |data=nil,*args|
|
56
|
+
body = build_body(action, data)
|
57
|
+
|
58
|
+
res = send_wcf_action(action.soap_action,body,*args)
|
59
|
+
(@cookies << res.headers["Set-Cookie"]) if @save_cookeis
|
60
|
+
|
61
|
+
result = get_wcf_response(res,action.name)
|
62
|
+
res.singleton_class.send(:define_method,:result) do
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
#if(res.code == '401') # not autorized
|
67
|
+
# (raise "Please use ntlm") if res['WWW-Authenticate'].include?('NTLM')
|
68
|
+
#end
|
69
|
+
|
70
|
+
res
|
71
|
+
end
|
72
|
+
|
73
|
+
#create new method that takes the data and user and password and user ntlm
|
74
|
+
end
|
75
|
+
|
76
|
+
# Call to wcf method
|
77
|
+
# Params:
|
78
|
+
# +soap_action+:: the value of the SOAPAction header
|
79
|
+
# +body+:: the body of the HTTP request
|
80
|
+
# +args+:: metadata that indicate wich autountication to use
|
81
|
+
def send_wcf_action(soap_action,body,*args)
|
82
|
+
#req = Net::HTTP::Post.new(@uri.path)
|
83
|
+
#req = Net::HTTP::Post.new(@service_address)
|
84
|
+
|
85
|
+
#req["SOAPAction"] = soap_action
|
86
|
+
#req["Content-Type"] = "text/xml; charset=utf-8"
|
87
|
+
#req["Cookie"] = @cookies.join(',') unless @cookies.empty?
|
88
|
+
#req.body = body
|
89
|
+
|
90
|
+
yield(req) if block_given?
|
91
|
+
|
92
|
+
#get_web_response(req,@uri,*args)
|
93
|
+
# "Cookie" => (@cookies.join(',') unless @cookies.empty?)
|
94
|
+
cookies = @cookies.empty? ? "" : @cookies.join(',')
|
95
|
+
send_message_to_wcf(@service_address,
|
96
|
+
{"SOAPAction" => soap_action,
|
97
|
+
"Content-Type" => "text/xml; charset=utf-8",
|
98
|
+
"Cookie" => cookies},
|
99
|
+
body, *args)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'httpi'
|
2
|
+
require 'canned_soap/web/security_protocol'
|
3
|
+
|
4
|
+
# Handle all the communication to the service
|
5
|
+
module CannedSoap::Web
|
6
|
+
# Send Http get rquest to a url and return his result via +HTTPI+
|
7
|
+
# Params:
|
8
|
+
# +url+:: the url to send the request to
|
9
|
+
# +headers+:: hash that keeps the headers that need to be send to the service
|
10
|
+
def get_web_response(url,headers)
|
11
|
+
request = HTTPI::Request.new(url)
|
12
|
+
|
13
|
+
request.headers = headers
|
14
|
+
response = HTTPI.get(request)
|
15
|
+
|
16
|
+
response
|
17
|
+
end
|
18
|
+
|
19
|
+
# Send http request to the service
|
20
|
+
# Params:
|
21
|
+
# +url+:: the url to send the request to
|
22
|
+
# +headers+:: hash that keeps the headers that need to be send to the service
|
23
|
+
# +body+:: the body of the HTTP request
|
24
|
+
# +args+:: metadata that indicate wich autountication to use
|
25
|
+
def send_message_to_wcf(url,headers,body,*args)
|
26
|
+
request = HTTPI::Request.new(url)
|
27
|
+
request.headers = headers
|
28
|
+
request.body = body
|
29
|
+
|
30
|
+
#TODO: change to user self.send('use_'+)
|
31
|
+
case args.first
|
32
|
+
when SecurityProtocol::NTLM
|
33
|
+
use_ntlm(request,*args)
|
34
|
+
when SecurityProtocol::GGS_API
|
35
|
+
use_kerberos(request)
|
36
|
+
when SecurityProtocol::BASIC
|
37
|
+
use_basic(request,*args)
|
38
|
+
when SecurityProtocol::DIGEST
|
39
|
+
use_digest(request,*args)
|
40
|
+
end
|
41
|
+
|
42
|
+
response = HTTPI.post(request)
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
# Use ntlm auth in the request
|
48
|
+
# Params:
|
49
|
+
# +request+:: +HTTPI::Request+ request
|
50
|
+
# +args+:: keep the data that need to be uses for the NTLM auth
|
51
|
+
def use_ntlm(request,*args)
|
52
|
+
# the first is the security name
|
53
|
+
user = args[1]
|
54
|
+
password = args[2]
|
55
|
+
domain = args[3]
|
56
|
+
|
57
|
+
request.auth.ntlm(user,password,domain)# if request.auth.ntlm?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Use kerberos auth in the request
|
61
|
+
# Params:
|
62
|
+
# +request+:: +HTTPI::Request+ request
|
63
|
+
def use_kerberos(request)
|
64
|
+
request.auth.gssnegotiate
|
65
|
+
end
|
66
|
+
|
67
|
+
# Use basic auth in the request
|
68
|
+
# Params:
|
69
|
+
# +request+:: +HTTPI::Request+ request
|
70
|
+
# +args+:: keep the data that need to be uses for the basic auth
|
71
|
+
def use_basic(request,*args)
|
72
|
+
user = args[1]
|
73
|
+
password = args[2]
|
74
|
+
|
75
|
+
request.auth.basic(user,password)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Use digest auth in the request
|
79
|
+
# Params:
|
80
|
+
# +request+:: +HTTPI::Request+ request
|
81
|
+
# +args+:: keep the data that need to be uses for the digest auth
|
82
|
+
def use_digest(request,*args)
|
83
|
+
user = args[1]
|
84
|
+
password = args[2]
|
85
|
+
|
86
|
+
request.auth.digest(user,password)
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'xmlsimple'
|
2
|
+
require 'canned_soap/soap/soap'
|
3
|
+
require 'canned_soap/web/web_request_handler'
|
4
|
+
include CannedSoap::Soap
|
5
|
+
include CannedSoap::Web
|
6
|
+
|
7
|
+
module CannedSoap::Wsdl
|
8
|
+
class WsdlParser
|
9
|
+
# Parse the service wsdl to a +Wsdl+ object
|
10
|
+
# Params :
|
11
|
+
# +service+:: the url of the service
|
12
|
+
def self.parse(service)
|
13
|
+
@service = service
|
14
|
+
wsdl_xml = get_serivce_data('wsdl')
|
15
|
+
doc = XmlSimple.xml_in(wsdl_xml)
|
16
|
+
|
17
|
+
res = Wsdl.new
|
18
|
+
res.actions = get_soap_actions(doc)
|
19
|
+
res.location_address = get_location_address(doc)
|
20
|
+
res.target_namespace = doc['targetNamespace']
|
21
|
+
|
22
|
+
res
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the target namespace of the last wsdl parser.
|
26
|
+
# TODO: Remove this method and user tel +Wsdl+ it self to get the target namespace
|
27
|
+
def self.target_namespace
|
28
|
+
@@target_namespace
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
# Return the service data for specified extension (wsdl, xsd=xsd0, etc)
|
33
|
+
# Params:
|
34
|
+
# +extension+:: the extension the query the service with (wsdl, xsd=xsd0, etc)
|
35
|
+
def self.get_serivce_data(extension)
|
36
|
+
uri = URI("#{@service}")
|
37
|
+
|
38
|
+
res = get_web_response("#{@service}?#{extension}",
|
39
|
+
{"Accept" => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
40
|
+
"Accept-Encoding" => 'gzip,deflate,sdch'})
|
41
|
+
res.body
|
42
|
+
end
|
43
|
+
|
44
|
+
# ???
|
45
|
+
def self.get_action_datacontact(action_name)
|
46
|
+
if @xsd_namespace.nil?
|
47
|
+
xsd0 = get_serivce_data('xsd=xsd0')
|
48
|
+
doc = XmlSimple.xml_in(xsd0)
|
49
|
+
|
50
|
+
import = doc['import']
|
51
|
+
@xsd_namespace = (import.first['namespace'] unless import.nil?)
|
52
|
+
end
|
53
|
+
|
54
|
+
@xsd_namespace
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return list of +SoapAction+
|
58
|
+
# Params:
|
59
|
+
# +doc+:: +Hash+ that represent the wsdl xml
|
60
|
+
def self.get_soap_actions(doc)
|
61
|
+
result = []
|
62
|
+
|
63
|
+
@@target_namespace = doc['targetNamespace']
|
64
|
+
should_read_from_xsd = !doc['types'].first['schema'].first['import'].nil?
|
65
|
+
|
66
|
+
binding = doc['binding'].first
|
67
|
+
binding['operation'].each do |opp|
|
68
|
+
action = SoapAction.new
|
69
|
+
|
70
|
+
action.name = opp['name']
|
71
|
+
action.soap_action = opp['operation'].first['soapAction']
|
72
|
+
action.parameters = get_action_params(action.name, doc, should_read_from_xsd)
|
73
|
+
|
74
|
+
result << action
|
75
|
+
end
|
76
|
+
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return the location address of the service
|
81
|
+
# Params:
|
82
|
+
# +doc+:: +Hash+ that represent the wsdl xml
|
83
|
+
def self.get_location_address(doc)
|
84
|
+
service = doc['service']
|
85
|
+
location = service.first['port'].first['address'].first['location']
|
86
|
+
|
87
|
+
location
|
88
|
+
end
|
89
|
+
|
90
|
+
# Return the parameters that the soap actiop requires as list of +SoapParamter+ objects
|
91
|
+
# Params :
|
92
|
+
# +action_name+:: the name of the soap action
|
93
|
+
# +doc+:: hash the represent the WSDL
|
94
|
+
# +should_read_from_xsd+:: boolean that indicates whether it should read the parameters from the wsdl or imported xsd
|
95
|
+
def self.get_action_params(action_name,doc,should_read_from_xsd)
|
96
|
+
if(should_read_from_xsd)
|
97
|
+
get_action_params_from_xsd(action_name)
|
98
|
+
else
|
99
|
+
get_action_params_from_wsdl(action_name,doc)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Parse the soap action element in the wsdl and return the parameters that the soap actiop requires as list of +SoapParamter+ objects
|
104
|
+
# Params:
|
105
|
+
# +action_name+:: the name of the soap action
|
106
|
+
# +doc+:: hash the represent the WSDL
|
107
|
+
def self.get_action_params_from_wsdl(action_name, doc)
|
108
|
+
#puts opp['input'].first
|
109
|
+
if @schema.nil?
|
110
|
+
@schema = doc['types'].first['schema'].first
|
111
|
+
end
|
112
|
+
|
113
|
+
action_element = @schema['element'].select{|e| e['name'] == action_name}.first
|
114
|
+
action_params_elements = action_element['complexType'].first['sequence'].first['element']
|
115
|
+
|
116
|
+
action_params_elements.map do |element|
|
117
|
+
SoapParamter.parse(element) do |param|
|
118
|
+
param.nullable = ['minOccurs'] == 0
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Parse the imported xsd and return the parameters that the soap actiop requires as list of +SoapParamter+ objects
|
124
|
+
# Params:
|
125
|
+
# +action_name+:: the name of the soap action
|
126
|
+
def self.get_action_params_from_xsd(action_name)
|
127
|
+
if @elements.nil?
|
128
|
+
#@elements = {}
|
129
|
+
xsd0 = get_serivce_data('xsd=xsd0')
|
130
|
+
doc = XmlSimple.xml_in(xsd0)
|
131
|
+
|
132
|
+
@elements = doc['element']
|
133
|
+
|
134
|
+
# the page dose not have imported shceme
|
135
|
+
return nil if @elements.nil?
|
136
|
+
end
|
137
|
+
|
138
|
+
element = @elements.select{|e| e['name'] == action_name}.first
|
139
|
+
sequence = element['complexType'].first['sequence'].first
|
140
|
+
|
141
|
+
return [] if sequence['element'].nil?
|
142
|
+
sequence['element'].map do |e|
|
143
|
+
SoapParamter.parse(e) do |param|
|
144
|
+
param.nullable = e['nillable']
|
145
|
+
namespace_element = e.select{|key,value| key.match(/xmlns(.*)/)}.first
|
146
|
+
(param.namespace = namespace_element[1]) unless namespace_element.nil?
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
data/lib/canned_soap.rb
ADDED
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: canned_soap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gustavo Canedo
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: xml-simple
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: httpi
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- gknedo@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bin/console
|
98
|
+
- bin/setup
|
99
|
+
- canned_soap.gemspec
|
100
|
+
- docker-compose.yml
|
101
|
+
- example.rb
|
102
|
+
- lib/canned_soap.rb
|
103
|
+
- lib/canned_soap/client.rb
|
104
|
+
- lib/canned_soap/soap/soap.rb
|
105
|
+
- lib/canned_soap/soap/soap_action.rb
|
106
|
+
- lib/canned_soap/soap/soap_parameter.rb
|
107
|
+
- lib/canned_soap/version.rb
|
108
|
+
- lib/canned_soap/wcf_handler.rb
|
109
|
+
- lib/canned_soap/web/security_protocol.rb
|
110
|
+
- lib/canned_soap/web/web_request_handler.rb
|
111
|
+
- lib/canned_soap/wsdl/wsdl.rb
|
112
|
+
- lib/canned_soap/wsdl/wsdl_parser.rb
|
113
|
+
homepage: https://github.com/gknedo/canned_soap
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.6.12
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Communication between ruby and soap services
|
137
|
+
test_files: []
|