10

I'm trying to pass a Kerberos ticket onto a webservice through a custom webpart. The webservice is a WCF service, but it is a 3rd party web service that is not claims-aware. The web service doesn't seem like it will allow the SPD web service External Content Type. I was going to create a BCS webpart that will let BCS and SharePoint handle the authentication, but I wasn't sure if that would make a difference.

I have the webpart up and running and working with Classic Mode, but with C2WTS and impersonation, the webpart won't pass the Kerberos Ticket over correctly.

Things I've tried:

  • Setting up the web service in SharePoint Designer as an External Content Type
    • SPD errors - Cannot find any matching endpoint configuration
  • Setting up a classic web authentication
    • Works correctly without C2WTS, but I need this in Claims (its 2013)
  • Basic authentication
    • Works, but need to pass the Kerberos ticket to retain identity.

Here is my code:

public static CreateBinding(string uri){
    BindingElementCollection bec = new BindingElementCollection();
    TransportSecurityBindingElement sbe = TransportSecurityBindingElement.CreateKerberosOverTransportBindingElement();// SecurityBindingElement.CreateKerberosOverTransportBindingElement();
    sbe.IncludeTimestamp = true;
    sbe.AllowInsecureTransport = true;
    sbe.EnableUnsecuredResponse = true;
    bec.Add(sbe);


    if (uri.IndexOf("SOAP") != -1)
    {
        // using the SOAP endpoint
        TextMessageEncodingBindingElement tme = new TextMessageEncodingBindingElement();
        tme.MessageVersion = MessageVersion.Soap11;
        tme.ReaderQuotas.MaxDepth = 1024;
        tme.ReaderQuotas.MaxStringContentLength = 1024 * 1024;
        bec.Add(tme);
    }
    else
    {
        MtomMessageEncodingBindingElement mme = new MtomMessageEncodingBindingElement();
        mme.MessageVersion = MessageVersion.Soap12;
        mme.ReaderQuotas.MaxDepth = 1024;
        mme.ReaderQuotas.MaxStringContentLength = 1024 * 1024;
        mme.MaxBufferSize = 2147483647;

        bec.Add(mme);
    }

    HttpsTransportBindingElement tbe = new HttpsTransportBindingElement();
    tbe.MaxReceivedMessageSize = 2147483647;
//    tbe.RequireClientCertificate = true;
    tbe.MaxBufferSize = 2147483647;

    bec.Add(tbe);

    CustomBinding binding = new CustomBinding(bec);
    binding.ReceiveTimeout = new TimeSpan(TimeSpan.TicksPerDay);    // 100 nanonsecond units, make it 1 day
    binding.SendTimeout = binding.ReceiveTimeout;

    WSHttpBinding custombinding = new WSHttpBinding();
    custombinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
    custombinding.Security.Mode = SecurityMode.TransportWithMessageCredential;
    custombinding.MessageEncoding = WSMessageEncoding.Mtom;


    EndpointIdentity ei = EndpointIdentity.CreateSpnIdentity("HTTP/webservicehost@DOMAIN.COM");

      EndpointAddress endpoint = new EndpointAddress(new Uri(uri), ei);
    port.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
    port.ClientCredentials.Windows.AllowNtlm = false;
    localization = new Localization();
    localization.Timezone = GetTimezone();

    return port;
}

using(WindowsImpersonationContext ctx = winId.Impersonate()){


WebService.Client binding = ConfigureBinding("http://webservicehost.domain.com:3425")

//fetch items using web service methods
}

My options are either to pass the Kerberos using this method, or try to use BCS webpart in order to let it handle authentication, has anyone come across this or have any experience with BCS webpart authentication? Can you set it up to use user's identity in a .NET assembly BCS model?

EDIT: Forgot to mention the errors that I'm getting is from the other side of the webservice: the user is anonymous, or otherwise not authenticated.(paraphrasing)

  • 1
    Since it sounds like you know what you are doing, tis may be a stupid question, but have you made sure to properly follow the c2wts configuration? It sounds like, while trying to set it up, you didn't provide authentication for the Domain Account? support.microsoft.com/kb/2722087 – Brandon C. Jul 4 '14 at 9:01
  • Yes. It has been successfully delegated with Kerberos and constrained delegation, and the c2wts service is passing back a windows identity. Authenticated == true. – Mike Jul 6 '14 at 20:57
  • At first glance this sounds like a double hop problem. Have you investigated this angle at all? – Hutch Jul 7 '14 at 15:17
  • I'm trying to programmatically make the hop. C2WTS has constrained delegation, the web application pool has constrained delegation, web app pool account has the ability to delegate and the Kerberos ticket works fine if it's on classic mode. – Mike Jul 7 '14 at 15:46
  • What account is the c2wts running? is this a multi server farm? – Marco Scheel Jul 9 '14 at 8:12
2
+200

At the end of you code it looks like your code is using the same method to impersonate as in a classic auth app with integrated auth. This is not working in a claims app because the used authenticated using kerberos in the initial handshake (url: _trust/...).

The claims to windows token service is not doing the magic automatically. You have to request a token using your C# code. Take a look at this sample:

http://msdn.microsoft.com/en-us/library/ee517258.aspx

This should give a kick start. Please make sure you understand the difference between kerberos delegation and Kerberos constrained delegation! For constrained delegation you need to set the allow to delegate property on the service account the c2wts is configured to run to delegate the token to the URL of your web service. You need this attribute and the general configuration to use constrained delegation (with protocol transition). The configuration is similar to the one for other SharePoint services leveraging the c2wts.

Check out Steve Peschkas blog bost for detailed instructions: http://blogs.technet.com/b/speschka/archive/2011/08/07/using-saml-claims-sharepoint-wcf-claims-to-windows-token-service-and-constrained-delegation-to-access-sql-server.aspx

  • The winId variable is ambiguous in my post, but it's really requesting the token from c2wts using the S4UClient.UpnLogon(upn) method. This is an interesting article and I'll try to follow this step by step to get this to work properly. – Mike Jul 8 '14 at 15:39
  • Also, yes the I know the difference. It was confusing at first, but c2wts is set to delegate, and according to a MSDN article, the c2wts constrained delegation can be a dummy SPN. – Mike Jul 8 '14 at 15:41
  • 1
    It could be a dummy spn, but never the less the spn has to be set if I'm not remembering the wrong thing :-) – Marco Scheel Jul 8 '14 at 19:45
  • I think this article did the trick, and got my head thinking, but the impersonation wasn't done at a high enough level. The web services' connection needs to be impersonated from Factory/Channel/Connection/Query and so on to ensure the correct user is passing that query to the database for security trimming. – Mike Jul 9 '14 at 19:39
  • Also the KerberosCredentials class from the Web Services Enhancements was used to pick up the Kerberos ticket. – Mike Jul 9 '14 at 20:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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