How can I get a Kerberos ticket with Delphi? - web-services

Are there examples which show how Delphi invokes the Active Directory Kerberos server to request a ticket granting ticket / normal ticket?
Background: the ticket is required for authentification to a web service which exchanges confidential information.
Edit: a short source code example would be very helpful. I have found the JEDI Windows Security Code Library which is very impressing. I am not sure if it contains support for Kerberos.

According to this you should be able to get one with the InitializeSecurityContext windows API call.

First read Kerberizing Applications Using Security Support Provider Interface to get the general idea. InitializeSecurityContext is described as following:
Initiates a security context by
generating a security token that must
be passed to the server. The
application that uses this function is
called an SSPI client.
On msdn, the list of SSPI functions can be found in Authentication Functions.
For actual example code, see Win32 samples's SSPI page. You probably find client.cpp to be useful. Another similar example is GssClient.c. Both code are running it in a loop because the conversation keeps going if SEC_I_CONTINUE_NEEDED is returned.

Related

Using Windows Authentication with cpprestsdk?

Using WinHTTP right now, and looking to switch over to cpprestsdk. I'm looking through the documentation, and I don't see anything about support for NTLM/Negotiate/Kerberos support. Am I missing something? I find it hard to believe that MS wouldn't have supported it, but I don't see any sample code on how you would use it.
The reason we need NTLM/Negotiate/Kerberos support is that we are running our client via RemoteApp, and want our users to only have to login once with their Domain Credentials when starting the app, and not have users prompted to enter passwords a second time.
It seems that Windows authentication is readily build into Casablanca (when used on a Windows machine). Take a look at src/http/client/http_client_winhttp.cpp. There you'll find a function "ChooseAuthScheme". To my understanding this will select the "most secure" authentication scheme that a server supplies. If the server e. g. claims to support both, "BASIC" and "NEGOTIATE", it will prefer and select the latter as the more secure scheme. Thus using Widows authentication should a very easy to use, just don't set any credentials (username/pwd) and try to connect to a server that supports Windows authentication and also announces this in the http "Authenticate" header (otherwise Casablanca will of course not attempt to use Windows authentication).
BUT
I'm also trying to use Windows authentication in Casablanca and I'm currently facing two problems:
Windows authentication sort of works as explained above in my scenario. Bewilderingly however sometimes it does not. This goes as far as that I can connect to a server from machine A with user Foo logged in and I cannot connect from machine B with user Bar logged in at the the very same time and with all machines being in the very same network segment without any router or proxy in between. From a Fiddler log I can see that in case of a failure Casablanca attempts a connect without any authentication and then receives a http 403 unauthorized from the server (which is to be expected and perfectly fine) but afterwards fails to resend the request with the NEGOTIATE in the headers, it simply aborts. On the contrary in the successful case there is a resent with the credentials being a base64 encoded blob (that in fact has binary content and presumably only MS knows what it means). I'm currently unclear about what triggers this, why this happens and how to resolve this. It could well be a bug in Casablanca.
I have a special scenario with a server that has a mixed operation mode where users should be able to connect via BASIC or Windows authentication. Let's not reason about the rationale of the following scenario and best practices, I'm dealing with a TM1 database by IBM and it's just what they implemented. So the users admissible for basic and Windows authentication don't necessarily overlap, one group must authenticate via Windows integrated (let's say domain users) and the other one must use basic authentication (let's say external users). So far I found no way (without patching Casablanca) to clamp the SDK to some mode. If the server announces BASIC and NEGOTIATE it will always switch NEGOTIATE as the more secure mode, making basic authentication inaccessible and effectively locking out the BASIC group. So if you have a similar scenario, this could equally be a problem for you, ChooseAuthScheme() tests several different authentication methods, NEGOTIATE, NTLM, PASSPORT, DIGEST and finally BASIC, in this sequence and will stubbornly select the first one that's supported on both, client and server, discarding all other options.
Casablanca (CpprestSDK) fully supports NTLM authentication. If server rejects request with status code 401/403 and header WWW-Authenticate, library will handle it internally using most secure authentication method. In case of NTLM you could either specify login/password pair, or use automatic logon (Windows), based on calling thread current user token.
However, when I tried using auto-logon feature, it unexpectedly failed on some workstations (case 1 in Don Pedro answer).
Windows version of Cpprest uses WinHTTP internally. When you try to automatically authenticate on the remote server, automatic logon policy takes effect.
The automatic logon (auto-logon) policy determines when it is
acceptable for WinHTTP to include the default credentials in a
request. The default credentials are either the current thread token
or the session token depending on whether WinHTTP is used in
synchronous or asynchronous mode. The thread token is used in
synchronous mode, and the session token is used in asynchronous mode.
These default credentials are often the username and password used to
log on to Microsoft Windows.
Default security level is set to WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM, which allows auto-logon only for intranet servers. Rules governing intranet/internet server classification are defined in the Windows internet options dialog and somewhat murky (at least in our case).
To insure correct auto-login I have lowered security level to WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW using request native handler config:
web::http::client::http_client_config make_config()
{
web::http::client::http_client_config config;
config.set_proxy(web::web_proxy::use_auto_discovery);
if (!m_wsUser.empty()) {
web::credentials cred(m_wsUser, m_wsPass);
config.set_credentials(cred);
}
config.set_nativehandle_options([](web::http::client::native_handle handle) {
DWORD dwOpt = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
WinHttpSetOption(handle, WINHTTP_OPTION_AUTOLOGON_POLICY, &dwOpt, sizeof(dwOpt));
});
return config;
}
In my case this approach was acceptable, because server and clients are always inside organization network boundary. Otherwise this solution is insecure and should not be used.

Allow winhttp delegation without Active Directory trust

I am developing an application using kerberos authentication in a double-hop scenario : the client is connecting to a server witch needs to use the client's credentials to connect a SQL server.
I already did it using GSoap and GSS-API from kerberos MIT release; but I would have liked to use winHTTP to handle the authentication.
Yet, when I try to use winHTTP with GSOAP WINHTTP PLUGIN (gsoapwinhttp on code.google), the delegation is blocked by the Domain Controller. I want to keep this Active Directory configuration :
When I look at GSS-API kerberos ticket I found several flags allowing delegation such as fowardable or deleg_req_flag :
So my question is : Can I modify the winHTTP flags to have to allow delegation without changing the Domain Controller's configuration ?
Edit :
I'm using the option WINHTTP_AUTH_SCHEME_NEGOTIATE in setCredentials and WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW in setOption to be sure to use Kerberos or NTLM as specified in Microsoft website WinHttpSetCredentials.
Using Fiddler I checked the HTTP connection and it is using Kerberos but I still can't delegate to my next server.
I tried to use almost every possible options of setOption such as WINHTTP_ENABLE_SSL_REVERT_IMPERSONATION or everything that could look like delegation but I have a strange error when using this option :
End of file or no input: message transfer interrupted or timed out (629s recv send delay)
I tried to set a different recv_timeout but still the same error.
.
I've studied this type of kerberos-delegation problem a lot. You are experiencing the Kerberos double-hop problem. In that active-directory configuration screenshot you provided, you must configure delegation; right now delegation is not set. First item to try is open delegation,to do that select the radio button: Trust this computer for delegation to any service (Kerberos only). You set this on the computer account in AD which needs to use the client's credentials to connect a SQL server - not on the domain controller account. If your application is actually running on a domain controller, then that is a known issue and unsupported configuration which won't work - please move application to a member server of the domain.
Regarding those flags allowing delegation such as fowardable or deleg_req_flag shown as being set in the Fiddler trace, I'm not sure why they are shown as set, but they might have been set from the wrong account. From the account of the screenshot you posted, Kerberos delegation is not configured at all.
In your scenario, you must set Kerberos delegation on the computer account which is running the WinHTTP process, in the example shown below, that would be "Server1".
In the Kerberos Delegation properties of that account, you can specify either open delegation (top radio button as I stated above), or constrained delegation to the process on Server2 to which Server1 may forward the user credentials (the Kerberos service tickets).

Making SASL(with GSSAPI) enabled client and server with LDAP+kerberos as authenticator? (Single Sign on SSO sytstem)

I have successfully installed ldap and kerberos. I was also able to make a simple c program with SASL/GSSAPI to search data in my ldapserver?
But I was not find any article (that I can follow easily) on how to use the the single sign on functionality in a client server system? I am not even sure how the communication between client and server happens in SSO.
How would a server know that client is a valid client?
Are there any sample examples/tutorials to make such a system?
Edit:
The server can be as simple as receiving hello from authenticated client. So client should have kerberos ticket and server should verify the ticket if it is valid or not.
I could compile gsspapi program using libs and dll provided by MIT.
the files I needed were gsskrb5.dll,gssapi32.lib,comerr32.lib
These will depend upon the version of kerberos for which they were compiled but I was successful in compiling the example given by mit http://web.mit.edu/macdev/KfM/KerberosFramework/Kerberos5/Tools/GSSExample/ using MinGW gcc compiler after few tweaks.
However I could not communicate successfully using SSPI api by microsoft (that may be due to my lack of knowledge)

Unauthorized HTTP request with Anonymous authentication of SAP PI service

I have a .WSDL file from our client company, for which I need to use to call a web service. Their system is SAP (SAP PI). My application is a C# .NET 3.5 client developed in VS 2008. I added a Service Reference in Visual Studio using their provided .WSDL file. This created a reference class for me to use to call their service, and set up several bindings in the app.config file for me.
I did not change anything in the app.config file, but did create code to call their web service. However, when I call their webservice, I receive the following exception:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="SAP NetWeaver Application Server ..."'.
(I modified slightly the string used in the 'Basic realm' section so as to not give it out.)
Did the app.config not get built correctly from the WSDL? Am I supposed to modify the app.config file somehow?
Things I've tried:
changed authenticationScheme in app.config from Anonymous to Basic
(as well as all the other authentication types)
changed realm string in app.config to match the realm in the exception message
set username/pw fields in the ClientCredentials.Username object in my code
Any pointers or help would be appreciated.
Edit: After some more investigation, I found that Visual Studio has several warnings about the extension element Policy and Policy assertions:
Custom tool warning: The optional WSDL extension element 'Policy'
from namespace 'http://schemas.xmlsoap.org/ws/2004/09/policy' was not
handled.
Custom tool warning: The following Policy Assertions were not Imported:
XPath://wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:rfc:functions']/wsdl:binding[#name='Binding_FieldValidation']
Assertions: ...
I wasnt able to find out if this was related or not to my current issue with the authentication scheme. It does seem to be related, but I havent been able to find any solutions to getting these policy warnings resolved either. It seems WCF doesnt handle the statements in the wsdl very well.
Most SAP services dont support anonymous.
So pass some form of authentication data with the call.
User and password / X.509 Ticket...
If you are sending auth data with the call the try this
Ask the SAP guy to regenerate the WSDL with
No SAP assertions, No policy, SOAP 1.1.
You can also try and edit the WSDL by hand to remove the extra guff...
As a starting point, I'd verify that you can call the service successfully with the provided username and password. Use something like SoapUI to test that everything works correctly - just create a new project, import the WSDL provided by SAP PI, set the username and password and execute the call. You'll probably get some form of exception with an empty payload, but at least that'll verify that the username and password are correct.
Once you've verified that's working, check that your application is calling the service correctly and that the http basic authentication headers are being sent. You can confirm this by using a network monitoring tool and checking that the http request is being generated correctly. Something like netcat for Windows can do it - just make it listen to a port on your local machine and then specify localhost and the port as your SOAP endpoint.
Once you've verified both of those are correct, your call should succeed.
There must be the Basic authentication header missing or something wrong
with the credentials.
SAP PI always defaults to Basic Authentication if a Service is published via it's SOAP Adapter. I would investigate if WCF really does send out that header (e.g. Point your client endpoint to TCP Gateway and let TCP Gateway point to the SAP PI Endpoint from the WSDL).
About the Warnings: AFAIK the WSDL generated by SAP PI will always contain these Policy Tags, you can't really ommit it. What you can do is simply throw them out as they are not really validated

MonoTouch support for accessing Mono.Security.Protocol.Ntlm.NtlmFlags

We use NTLM auth to access an ASP.net web services from our MonoTouch app and everything works fine.
One of our customers uses the same app and the NTLM auth fails from our app but works from the iPad's Safari browser.
Looking at the packet flow from the customer, the server does not return NTLMSSP_CHALLENGE, when our app sends NTLMSSP_NEGOTIATE message.
Looking the differences between our app's NTLMSSP_NEGOTIATE message and iPad's Safari same message
Our MT app sets the NTLM flags to 0xb203 and Safari sets this to 0x88207.
The NegotiateNtlm2Key is set to 0 in our app and 1 in Safari
Our app also sends the calling workstation domain and name fields whereas Safari send both as null.
The client's server is Windows Server 2003 and they also use Kerberos as their main authentication scheme and fall back on NTLM.
Would setting the NegotiateNtlm2Key flags in Mono.Security.Protocol.Ntlm.NtlmFlags help?
NTLMv2 Session and NTLMv2 Authentication has now been implemented in Mono (mono/master commit 45745e5).
See this article for a description of the different NTLM versions.
By default, Mono now uses NTLMv2 Session Authentication whenever the server supports it and falls back to LM & NTLM otherwise.
The default behavior can be configured by using the new Mono.Security.Protocol.Ntlm.Type3Message.DefaultAuthLevel property in Mono.Security.dll (see Type3Message.cs and NtlmAuthLevel.cs in mcs/class/Mono.Security/Mono.Security.Protocol.Ntlm).
This is similar to the Lan Manager Authentication Level in Windows.
Update 01/26/13
There has been an issue with Microsoft Server 2008 RC2 not accepting the domain name that it sent back in the Type 2 Message's Target Name (or Domain Name from the Target Info block).
Therefore, we are now using the domain name from the NetworkCredential to allow the user to specify the desired domain. This is also the domain name that's initially being sent to the server in the Type 1 Message.
Simply setting flags ? Maybe but IMHO that's quite unlikely.
That code base was written in 2003 (and updated in 2004) and I'm pretty sure that I (as the author of the low-level code) did not have access to a Windows 2003 server or a Kerberos-enabled domain at that time.
The amount of required change, for a fallback, might not be too large (but I would not bet 5$ on that ;-) if you already have the environment to test it. I'm 100% positive that the Mono project would be happy to receive patches to enable this. You can also fill a bug report (priority enhancement) to ask for this feature at http://bugzilla.xamarin.com
An alternative is to use the iOS API, which I assume Safari is using, to communicate with the ASP.NET web service and deserialize the data yourself. Hard to say which options is more complex.