5

Objective: I am trying to build Proof Of Concept client app to implement Single Sign On by using SSPI. I am new to C# and I am getting confused.

What I know and have done so far: All users are part of Active Directory domain, so I know Kerberos is being used for authentication during login. All I need to do at this point is to get service token from Kerberos so I can pass it to the service resource instead of username and password (correct me if I am wrong). I have been provided Service Principle Name (SPN) and password that has been registered with Kerberos for the service.

I was hoping not to use Platform Invocation Services to call SSPI functions, but I will if I have to. I read through ".NET Remoting Authentication and Authorization Sample - Part I" and used Microsoft.Samples.Security.SSPI for testing. I also tried using C#/.Net Interface To The Win32 SSPI Authentication API.

So far, I can get user/client credentials, build client security context. But how do I request a Service Ticket for a given SPN?

I would appreciate your help and guidance. Please be specific if you can and let me know if you have any questions.

Furkat Kholmatov
  • 338
  • 1
  • 3
  • 8
  • Link to ".NET Remoting Authentication and Authorization Sample - Part I" is "https://msdn.microsoft.com/en-us/library/ms973911.aspx" I can't add more than two links in the main body of question right now – Furkat Kholmatov Jun 14 '16 at 17:18
  • What is the wire protocol you are going to speak? Custom or standard? – Michael-O Jun 14 '16 at 17:27
  • Standard. We are not using any custom protocols. – Furkat Kholmatov Jun 14 '16 at 17:49
  • Which wire protocol? Please provide more details. – Michael-O Jun 14 '16 at 18:22
  • I guess I am not sure what you mean or how it matters. I will be using TCP/UDP as a transport layer. User is authenticated using Windows so they should already have a TGT available. How do I get the current active TGT and request Ticket for specific service. I am not sure how the wire protocol matters. Could you explain please? – Furkat Kholmatov Jun 14 '16 at 18:53
  • have you already read this: http://stackoverflow.com/questions/17241365/client-server-authentication-using-sspi? – Michael-O Jun 14 '16 at 19:33
  • I have. I am using advice of accepted answer, wrapper created by antiduh is the second link in my question. Unfortunately I cant comment there due to my almost nonexistent reputation. – Furkat Kholmatov Jun 14 '16 at 22:41
  • I can authenticate user and get TGT (server token) but I am lost on how to get specific ticket for the remote service using this TGT. I am missing something. – Furkat Kholmatov Jun 14 '16 at 22:47

2 Answers2

3

You can use below to get the token by giving the SPN

  public String getToken(string userName)
    {
     using (var domainContext = new PrincipalContext(ContextType.Domain, "domain"))
        {
          using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
            {
                Console.WriteLine("User Principale name" + UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName);
                string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName;
                KerberosSecurityTokenProvider k1 = new KerberosSecurityTokenProvider(spn, System.Security.Principal.TokenImpersonationLevel.Impersonation, new System.Net.NetworkCredential(userName, "password", "domain"));
                KerberosRequestorSecurityToken T1 = k1.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
                string sret = Convert.ToBase64String(T1.GetRequest());
                Console.WriteLine("=====sret========" + sret);
                return sret;
            }
        }

    }
Hasanthi
  • 1,251
  • 3
  • 14
  • 30
  • Thank You for the answer, could you please elaborate on the following? With Kerberos there are 3 main steps that need to occur. First is authenticating client and getting Ticket Granting Ticket. Second is requesting a ticket for a Service using the Ticket Granting Ticket and the third is having the service validate the ticket that the client requested for it. With the code sample above I am confused because the username variable is used for foundUser and spn. Can you elaborate on answer and specify which is truly client user and service user please? – Furkat Kholmatov Jun 15 '16 at 14:51
  • Hi, the above code states how you can obtain a ticket for a given spn. Here the user name is the logon name of the AD user and by using the method it will create the spn as logon name@domain. By using that spn you can generate the ticket. I am also doing the same kind of task and I'm following C#/.Net Interface To The Win32 SSPI Authentication API. I could also get the TGT by using nsspi and searching for a way to get SGT :) – Hasanthi Jun 15 '16 at 16:13
  • 2
    For everyone that copies the above code please note that `spn` in it's current form is not useful. The point of `spn` is to indicate which *service* you want to prove your authentication to, and getting a ticket to an spn of yourself provides very little value. Your spn value is likely wrong if it's in the form of `user@realm` and instead should be `foo/service.domain` or `foo/service.domain@realm` – Steve Apr 11 '19 at 22:23
  • are there any downsides of this approach compared to using SSPI? – neelesh bodgal Jul 30 '21 at 09:03
3

Code provided by Hasanthi worked perfectly for my need and I didn't have to use SSPI. I was asking wrong questions but I learned a lot about Kerberos and SSPI. Here is my code in a nutshell:

AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
var domain = Domain.GetCurrentDomain().ToString();

using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
{
    string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, serviceName).UserPrincipalName;
    KerberosSecurityTokenProvider tokenProvider = new KerberosSecurityTokenProvider(spn, System.Security.Principal.TokenImpersonationLevel.Impersonation, CredentialCache.DefaultNetworkCredentials);
    KerberosRequestorSecurityToken securityToken = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
    string serviceToken = Convert.ToBase64String(securityToken.GetRequest());
}
Furkat Kholmatov
  • 338
  • 1
  • 3
  • 8
  • Do you know how to go backwards and get the user principal name from the 'serviceToken'? Is this even possible? – Scott Lin Jul 20 '16 at 00:32
  • I didn't implement server side but it is possible. I believe user principal name is included in service token and in order to decrypt it you would need to get the key from Kerberos server that issued the token. – Furkat Kholmatov Jul 21 '16 at 21:36
  • @FurkatKholmatov could you give an example what is the "serviceName"? I'm trying to similarly request a ticket for a service with the current network credentials, but within an impersonated context (delegation). I'm confused about why you are getting a UPN and then use it as an SPN, as for me it worked (without delegation) simply by setting the spn to e.g. "HTTP/myservice.domain.com" when initializing the TokenProvider. Could you elaborate on your use-case? It might help me debug mine :) – valorl Aug 21 '18 at 12:06
  • @valorl - this was a while back and I can't remember the details. I think for some reason we were allowing client's network administrator to name their own SPN and provide it to the user if they allowed Single Sign On. I think "serviceName" was that SPN entered by the user. – Furkat Kholmatov Aug 24 '18 at 16:31
  • 1
    How do you verify this service token? – Travis Rivera Dec 09 '21 at 22:07