Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

Is it possible calling a webservice using NTLM authentication from apex? It is a microsoft navision webservice, I tried to do it in java following this guide and it works.

share|improve this question
    
Looking forward to some amazing answers! I had to attack same problem 1 year ago, I ended up quickly hacking together a small proxy in PHP... there must be a better way. –  eyescream Dec 10 '12 at 13:56
    
What have you tried? What isn't working? Does WSDL2Apex generate code, for instance? –  jkraybill Dec 11 '12 at 2:20
add comment

3 Answers

No answers so far... I'll try to summarize what I did without posting actual code (I don't have IP rights to it). Also - I know very little about MicroSoft-y world and I'm not a proper network admin either so don't shout at me if my understanding of certain things is dumbified.

Solution is written in PHP and follows excellent blog entry http://rabaix.net/en/articles/2008/03/13/using-soap-php-with-ntlm-authentication.

Other notable sources include "Freddy's blog" on MSDN (already mentioned by OP). This is the PHP article, you can find Java and C# examples there... hell, even javascript!: http://blogs.msdn.com/b/freddyk/archive/2010/01/19/connecting-to-nav-web-services-from.aspx

Problem

As far as I know it can't be done. The WSDL files from NAV generate into Apex classes just fine (even if the names can be a bit lenghty and you need to rename Update method because it's a reserved keyword... usually I pick UpdateSingle to match UpdateMultiple).

The problem is the NTLM authentication. Salesforce can send "Basic" or "Digest"... What NAV expects is something related to Windows domain, both servers being in same LAN. Which obviously can't be done since Salesforce servers are sitting somewhere else.

The whole thing is tricky to debug because when you access webservice endpoints with Internet Explorer NAV will happily display the WSDL and accept your handcrafted SOAP message if you have any (you can use IE Developer Tools or packet sniffer to see that this "special" authentication is used). Accessed from Firefox / Salesforce / anything that doesn't use some DLLs related to IE - boom, blank page. Originally we thought the packets die somewhere on firewall (I don't remember anymore, I think the damn thing just acts as a black hole, doesn't even return HTTP 401 Unauthorized).

And no, you can't somehow hardcode generated "NTLM key" or use some library on SF side to generate it.

Solution

I quickly hacked a proxy-like page in PHP (on a virtual machine with WAMP stack). It might not have best performance in the world but it works till today and there was no incentive to investigate if "true" proxy solution would be better. I'll keep writing about PHP - since you did your first attempt in Java you might be more comfortable with it.

I've built on Monsieur Rabaix's base with addition of config file where I'd store:

  1. NAV dedicated integration user's username & pass
  2. IP addresses of NAV servers (test & prod)
  3. Salesforce "production"'s instance Id

URL-rewriting flow

Salesforce calls an endpoint (you need to manually edit the class generated from WSDL and add it to Remote Site Settings) similar to

http://proxyPublicAddress/?
org={!UserInfo.getOrganizationId()}&
company=NAV%20Company%201&
page=NameOfPageExposedAsWebservice

Of course you can add more params as you see fit, include some authentication methods... This is the bare minimum. Your proxy needs to make decision whether to send the request to production or test NAV (that's the org), which page or CodeUnit you want to access and in which NAV Company it sits. In apex do not call anything from EncodingUtil class to encode the company name. Simple String encodedName = name.replace(' ', '%20'); is enough.

So let's say your proxy translated it into "local address"

http://192.168.0.10:7047/DynamicsNAV/WS/NAV%20Company%201/Page/NameOfPageExposedAsWebservice

(to all non NAV-developers who happen to read it - NAV is funny and keeps data in separate schemas per each "billing entity". This entity has to be passed as part of webservice endpoint, can't be a part of SOAP payload. Obviously we don't want to generate separate Apex classes per entity so you really need to attack the endpoint variable in the output of wsdl2apex)

Header and payload transfer flow

Simple stuff really, get headers and raw SOAP message from POST data, wrap it in NTLM, get the response and send it back to SF. No need to waste cycles on parsing of this XML in any way, you can add some debug logging if you want during initial testing phase.

<?php
$requestHeaders = getallheaders();
$request = file_get_contents("php://input"); // that's raw POST data

$gateway = new NavGateway($_GET, $request, $requestHeaders); // in $_GET I'll have the URL params like "org". Constructor checks the mandatory params and builds the URL or throws back SOAP Exception
$response = $gateway -> dispatch();
$responseHeaders = $gateway -> soapClient ->__getLastResponseHeaders();

// Send back to SF the HTTP headers from NAV and the response body.
header($responseHeaders);
echo $response;
share|improve this answer
add comment

I was working on a project that required SalesForce to call a service that used NTLM authentication. I ended up writing a client implementation of NTLM in apex that you can re-use. I've hosted it on github here:

https://github.com/natewallace/ApexNTLM

Upload all of the classes into your org and then use the HttpClient class to send messages to your NTLM secured service.

share|improve this answer
add comment

I'm facing the same issue! I have not found a clean and simple solution to this. Also on force.com developer boards http://boards.developerforce.com/t5/Apex-Code-Development/Callout-to-a-SOAP-service-that-uses-NTLM-authentication/td-p/364679 and on stackoverflow http://stackoverflow.com/questions/5558087/soap-ntlm-authorization there are open questions but no solutions.

share|improve this answer
    
This is not an answer, it is a useful comment though. Perhaps you could repost this as a comment on the question –  Daniel Blackhall Dec 11 '12 at 3:45
1  
Sorry for that. I think I can only comment my answer because of my reputation –  Alberto Maianti Dec 12 '12 at 8:14
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.