tags:

views:

887

answers:

2

I have a WCF Web Service which is consuming by C# client application. I’m also having 4 groups stored in Active Directory. Client application should connect this web service by passing login credentials.

Requirement:

  1. Restrict web service functionality based on windows user credential’s group stored in AD (Active Directory)
  2. Pass specific user credentials from the client application to this web service

Question:

How to authenticate or validate logged in user on connecting to this web service, which event handler function will be invoked to validate logged in user credentials.

If anybody knows about this then please do let me know

+1  A: 

You need to two keep concepts apart:

  • AUTHENTICATION is the process of determining who it is that's calling you, and making sure he really is who he claims to be; this can be done using username/password, Windows credentials (he had already authenticated himself to his Windows box through logging on), or by requiring the caller to have some information (certificate)

  • AUTHORIZATION is the process - once you know who is calling you, to determine what that caller can do (or what he cannot do)

In order to use Active Directory groups, you need to use a security mode in WCF that supports Windows credentials. The easiest is to use Windows credentials from the beginning, which is the default for wsHttpBinding and netTcpBinding - in this case, the caller will always pass along his Windows credentials with every call, and you can inspect those on the server side by looking at the ServiceSecurityContext.Current.WindowsIdentity:

WindowsIdentity caller = ServiceSecurityContext.Current.WindowsIdentity;

This works well in an Intranet scenario - everyone is behind a corporate firewall and authenticated on their machines anyway. In order to enable this, just use wsHttp or netTcp binding (I'd recommend netTcp in this case).

The other slightly more complicated case is when you have your client present a X.509 certificate, and you then map that on the server side to an existing AD user in your network. That's rather advanced, however.

Once your caller is authenticated, e.g. you know who is calling, you can use the regular role-based security model to limit privileges. Just add [PrincipalPermission(....)] attributes to your methods that you want to protect, and if the user doesn't match any of those requirements, a security exception will the thrown and the method will not be executed.

    [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
    [PrincipalPermission(SecurityAction.Demand, Name = "JohnDoe")]
    public string SayHello(string caller)
    {
     ......
    }

You can have multiple of those "PrincipalPermission" attributes, and they're matched together in an "OR"-fashion - if any one of them matches the current caller, he'll be allowed to make the call.

Check out page 4 of this article Fundamentals of WCF Security for more details on how to use role-based security.

Marc

marc_s
Thanks arc, Let me try your proposed solution. Many Thanks again.
Lalit Sharma
This is great, thanks. Solved me a lot of work. How do you catch the SecurityException that is thrown, however? It seems to be thrown before the method is called but doesn't get propagated up the callstack...
trendl
It's thrown to the client - the client needs to deal with that.
marc_s
A: 

But How can I fetch Windows Group Name belongs to Logged in User in Web Service? I'm trying this code but unbale to get User Password in Webservice to run this code.

List<string> fullAccessUserGroups = new List<string>();
fullAccessUserGroups.Add("WindowsGroup1");

//Checking domain
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "My Domain"))
{
   if (ServiceSecurityContext.Current.WindowsIdentity.IsAnonymous == true)
   {
      error = String.Empty;
      return true;
   }

   try
   {
      if (principalContext.ValidateCredentials(username, password))
      {
         string username = String/ServiceSecurityContext.Current.WindowsIdentity.Name;

         using (UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, username))
         {
             var gpList = user.GetAuthorizationGroups();

             foreach (GroupPrincipal gp in gpList)
             {
                 if (user.IsMemberOf(gp))
                 {
                     foreach (string fullAccessGroups in fullAccessUserGroups)
                     {
                        if (fullAccessGroups == null)
                        {
                           continue;
                        }

                        if (fullAccessGroups.CompareTo(gp.Name) == 0)
                        {
                           error = String.Empty;
                           return true;
                        }
                     }
                  }
               }
            }
         }
      }
      catch (Exception e)
      {
         return false;
      }
} //end using PrincipalContext}
Lalit Sharma
But not sure that this the right code to fetch windows group of logged in user in WCF web service. Please help
Lalit Sharma
you will **NEVER** be able to read a user's Windows password!
marc_s
You dont' need to do all this checking yourself - just add the PrincipalPermission attributes on your methods - that's all **you** need to do, the rest is handled by WCF
marc_s