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