1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
=pod
=head1 NAME
SOAP::WSDL::Manual::Cookbook - SOAP::WSDL recipes
=head2 Accessing HTTPS webservices
You need Crypt::SSLeay installed to access HTTPS webservices.
=head2 Accessing protected web services
Passing a username and password, or a client certificate and key, to the
transport layer is highly dependent on the transport backend. The descriptions
below are for HTTP(S) transport using LWP::UserAgent
=head3 Accessing HTTP(S) webservices with basic/digest authentication
When using SOAP::WSDL::Transport::HTTP (SOAP::Lite not installed), add a
method called "get_basic_credentials" to SOAP::WSDL::Transport::HTTP:
*SOAP::WSDL::Transport::HTTP::get_basic_credentials = sub {
return ($user, $password);
};
When using SOAP::Transport::HTTP (SOAP::Lite is installed), do the same to
this backend:
*SOAP::Transport::HTTP::Client::get_basic_credentials = sub {
return ($user, $password);
};
=head3 Accessing HTTP(S) webservices protected by NTLM authentication
If you want to connect to a windows server using some Windows Domain Login, please
consider using Kerberos instead of the (older) NTLM mechanism - see below.
Kerberos and NTLM are (currently) mutually exclusive - when LWP::Authen::Negotiate
is installed, it will always be queried (and will always raise an error), even
if you don't want to use it. See http://rt.cpan.org/Public/Bug/Display.html?id=32826
for details.
You need the L<NTLM|NTLM> distribution installed to access webservices protected
by NTLM authentication. More specifically, you need the Authen::NTLM module
from this distribution. Note that this is different from the Authen::NTML
distribution by Yee Man Chan also available from CPAN.
Your user credentials usually need to include the windows domain or the
windows hostname like this:
testdomain\testuser
or
\\testhost\testuser
Besides passing user credentials as when accessing a web service protected
by basic or digest authentication, you also need to enforce connection
keep_alive on the transport backens.
To do so, pass a I<proxy> argument to the new() method of the generated
class. This unfortunately means that you have to set the endpoint URL, too:
my $interface = MyInterfaces::SERVICE_NAME::PORT_NAME->new({
proxy => [ $url, keep_alive => 1 ]
});
You may, of course, decide to just hack the generated class. Be advised that
subclassing might be a more appropriate solution - re-generating overwrites
changes in interface classes.
=head3 Accessing HTTP(S) webservices protected by NTLMv2
There are different variants of NTLM, and by default Authen::NTLM uses the v1 variant.
NTLM is a connection-based handshake authentication protocol, which requires
three or more requests on the same connection:
Request POST
Response 401 Unauthorized
WWW-Authenticate: NTLM
Request Authorization: NTLM <base64-encoded type-1-message>
Response 401 Unauthorized
WWW-Authenticate: NTLM <base64-encoded type-2-message>
Request Authorization: NTLM <base64-encoded type-3-message>
Response 200 Ok
If you try to access a NTLMv2 protected web service and switch on LWP::Debug by
saying
use LWP::Debug qw(+);
you should see at least two lines containing something like
Authorization NTLM TlRMTVNTUAABAAAAB7IAAAAAAAAAAAAAAwADACAAAABmb28=
...
Authorization NTLM TlRMTVNTUAABAAAAB7IAAAAAAAAAAAAAAw ... much longer ... ADACAAAABmb28=
If you're talking to a Server using NTLMv2 exclusively, you will only the first line
in the debug output, and then an error.
To explicitly enable NTLMv2, do the following in your client:
use Authen::NTLM;
ntlmv2(1);
This globally enables the use of NTLMv2. Note that this is a global setting: All
clients running in the same perl interpreter will be affected. This can
cause unexpected issues when running under mod_perl.
=head3 Accessing webservices protected by HTTP Kerberos Authentication
Use the L<LWP::Authen::Negotiate|LWP::Authen::Negotiate> plugin from CPAN. You
need to set up GSSAPI to perform the Kerberos authentication, though. How to do
this is implementation specific (MIT or Heimdahl). See your Kerberos/GSSAPI
documentation for details.
(Newer) Windows Web Services usually allow one to use both the Negotiate (Kerberos)
and NTLM authentication scheme.
=head3 Accessing HTTPS webservices protected by certificate authentication
You need Crypt::SSLeay installed to access HTTPS webservices.
See L<Crypt::SSLeay> on how to configure client certificate authentication.
=head1 XML OUTPUT
=head2 Outputting namespaces as prefixes
Q: I need to interface with a SOAP server which doesn't accept the following
format:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<getElement xmlns="http://services.company.com/">
<elementId>12345</elementId>
</getElement>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Instead, it requires this:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns2="http://services.company.com/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns2:getElement>
<ns2:elementId>12345</ns2:elementId>
</ns2:getElement>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
How do I do this using SOAP::WSDL?
A: The following steps are necessary to achieve this result:
First, you would need to write a new serializer, which is quite easy, as it
just creates the envelope and calls ->serialize_qualified() on $header and
$body to fill them in. The new serializer has to declare all namespace
prefixes used, the rest is just the same as the original XSD serializer.
Second, you'd need to overwrite the start_tag method in
L<SOAP::WSDL::XSD::Typelib::Element|SOAP::WSDL::XSD::Typelib::Element> to use
the appropriate prefixes for the body elements.
In contrast to the original method, it would probably look up the appropriate
prefix from some data set in the serializer class, so this could be the
appropriate place to load SOAP::WSDL::XSD::Typelib::Element and override the
method.
Something like this should do (without the handling of specialties like empty
or nil elements):
%PREFIX_OF = { 'http://services.company.com/' => 'ns2' };
*SOAP::WSDL::XSD::Typelib::Element::start_tag = sub {
# use prefix instead of xmlns attribute and copy the rest from
# SOAP::WSDL::XSD::Typelib::Element::start_tag
my $prefix = $PREFIX_OF{ $_[0]->get_xmlns() };
my $name = $_[1]->{ name } || $self->__get_name();
return "<$prefix:$name>";
}
=head1 Skipping unknown XML elements - "lax" XML processing
SOAP::WSDL's default serializer
L<SOAP::WSDL::Deserializer::XSD|SOAP::WSDL::Deserializer::XSD> is a "strict"
XML processor in the sense that it throws an exception on encountering unknown
XML elements.
L<SOAP::WSDL::Deserializer::XSD|SOAP::WSDL::Deserializer::XSD> allows
switching off the stric XML processing by passing the C<strict =E<gt> 0>
option.
=head2 Disabling strict XML processing in a Client
Pass the following as C<deserializer_args>:
{ strict => 0 }
Example: The generated SOAP client is assumed to be "MyInterface::Test".
use MyInterface::Test;
my $soap = MyInterface::Test->new({
deserializer_args => { strict => 0 }
});
my $result = $soap->SomeMethod();
=head2 Disabling strict XML processing in a CGI based server
You have to set the deserializer in the transport class explicitly to
a L<SOAP::WSDL::Deserializer|SOAP::WSDL::Deserializer> object with the
C<strict> option set to 0.
Example: The generated SOAP server is assumed to be "MyServer::Test".
use strict;
use MyServer::Test;
use SOAP::WSDL::Deserializer::XSD;
my $soap = MyServer::Test->new({
transport_class => 'SOAP::WSDL::Server::CGI',
dispatch_to => 'main',
});
$soap->get_transport()->set_deserializer(
SOAP::WSDL::Deserializer::XSD->new({ strict => 0 })
);
$soap->handle();
=head2 Disabling strict XML processing in a mod_perl based server
Sorry, this is not implemented yet - you'll have to write your own handler
class based on L<SOAP::WSDL::Server::Mod_Perl2|SOAP::WSDL::Server::Mod_Perl2>.
=head1 Changing the encoding of a SOAP request
SOAP::WSDL uses utf-8 per default: utf-8
is the de-facto standard for webservice ommunication.
However, you can change the encoding the transport layer announces by calling
C<set_encoding($encoding)> on a client object.
You probably have to write your own serializer class too, because the default
serializer has the utf-8 encoding hardcoded in the envelope.
Just look into SOAP::WSDL::Serializer on how to do that.
Don't forget to register your serializer at the serializer factory
SOAP::WSDL::Factory::Serializer.
=head1 LICENSE AND COPYRIGHT
Copyright 2008, 2009 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself.
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 583 $
$LastChangedBy: kutterma $
$Id: $
$HeadURL: $
=cut
|