Understanding Wcf Windows Authentication

Understanding WCF Windows Authentication

Can only users who have access (to login) to “SERV1” access the service?

Yes - that's the point of using Windows credentials in a WCF service. Only users which have a domain account in that Active Directory domain (or a separate domain which has a bidirectional full-trust relationship with your domain) will be able to access the service.

Or all users who are able to login to the office network (suing active directory credentials) will be able to consume the service?

The WCF security boundary is the Active Directory Domain - not a particular server.

Is there a way to ensure that only CIO approved applications will be accessing the service, keeping the service as windows authenticated?

How are those "CIO-approved" applications different from others? WCF is accessed by accounts - typically user accounts. You can limit which accounts have access to your service (by e.g. requiring those accounts to be member of a given AD group or something). You cannot really "limit" based on applications (only if those applications use specific application-level accounts to access your WCF service)

Does this authentication check happen for each service operation call or only for the first call?

Depends on your service - if you use a per-call WCF service, then the check happens for each call. If you use a per-session WCF service with "security negotiation" turned on, then the check happens once at the beginning of the session and not anymore until the session ends.

Is there any way the service will be able to know the windows credentials of the user?

Yes - OperationContext.Current.ServiceSecurityContext.WindowsIdentity IS the Windows credentials (the Windows identity) used to call your service. It's a lot more than just the user name.....

How does WCF Windows authentication work without explicitly setting credentials

  1. With your current configuration as you have it on the server and client side the client is sending the creditials that it is running under. Because the credential type is set to Windows that causes the security negotiation to check in Kerberos if you are in a domain or in NTLM if it's a workgroup environment. (More information can be found here.)
  2. To debug the authentication process WCF has an auditing feature that can be enabled. Instructions for adding auditing are here.

Here's the important parts from the auditing MSDN page:

<behaviors>
<behavior name="myAuditBehavior">
<serviceSecurityAudit auditLogLocation="Application"
suppressAuditFailure="false"
serviceAuthorizationAuditLevel="None"
messageAuthenticationAuditLevel="SuccessOrFailure" />
</behavior>
</behaviors>

and adding the behavior to the service:

<service type="[Your service type here]" behaviorConfiguration="myAuditBehavior">

Once auditing is enabled you can see all the authorization activity (success and failure if you configure it that way). This should allow you to validate that your security is setup they way you would like it.

If you happen to need functionality of passing the credentials of the user that is using the ASP.NET web app (this is called Impersonation) the msdn documentation on that is found on this page "Delagation and Impersonation with WCF".

WCF Security Using Windows Authentication

Using existing Windows accounts to authenticate with the service

To do this, you should set the transport clientCredentialType attribute of the binding configuration to Windows.

<bindings>
<wsHttpBinding>
<binding>
<security mode="Message">
<transport clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>

Allow adding of a Service Reference from another project without providing credentials

To do this, create a mex endpoint for your service endpoint.

<services>
<service name="Services.SampleService" behaviorConfiguration="wsDefaultBehavior">
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>

Limiting the users that can call the service

This one is a little more involved. The way I found to secure a service on a per-user basis requires a custom authorization policy. The class that performs the authorization must implement the IAuthorizationPolicy interface. This is the complete code of my authorization class:

namespace Services.SampleService.Authorization
{
/// <summary>
/// Handles the default authorization for access to the service
/// <para>Works in conjunction with the AuthorizedUsersDefault setting</para>
/// </summary>
public class DefaultAuthorization: IAuthorizationPolicy
{

string _Id;

public DefaultAuthorization()
{
this._Id = Guid.NewGuid().ToString();
}

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
bool isAuthorized = false;
try
{
//get the identity of the authenticated user
IIdentity userIdentity = ((IIdentity)((System.Collections.Generic.List<System.Security.Principal.IIdentity>)evaluationContext.Properties["Identities"])[0]);
//verify that the user is authorized to access the service
isAuthorized = Properties.Settings.Default.AuthorizedUsersDefault.Contains(userIdentity.Name, StringComparison.OrdinalIgnoreCase);
if (isAuthorized)
{
//add the authorized identity to the current context
GenericPrincipal principal = new GenericPrincipal(userIdentity, null);
evaluationContext.Properties["Principal"] = principal;
}
}
catch (Exception e)
{
Logging.Log(Severity.Error, "There was an error authorizing a user", e);
isAuthorized = false;
}
return isAuthorized;
}

public ClaimSet Issuer
{
get { return ClaimSet.System; }
}

public string Id
{
get { return this._Id; }
}
}
}

The "magic" happens in the Evaluate method. In my case, the list of authorized users is maintained in a Properties.Settings variable (of type ArrayOfString) named AuthorizedUsersDefault. This way, I can maintain the user list without having to redeploy the entire project.

And then, to use this authorization policy on a per-service basis, set the following in the ServiceBehaviors node:

<behaviors>
<serviceBehaviors>
<behavior name="wsDefaultBehavior">
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Services.SampleService.Authorization.DefaultAuthorization, MyAssemblyName" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>

Active Directory usage in WCF Windows authentication

If anyone interested, this is what I've found.

If you set your client credentials type to Windows, WCF uses something called Windows SSPI for Windows authentication.

Windows SSPI makes either Kerberos or CLDAP requests to domain controller. Example:

Kerberos: AS-REQ request

CLDAP:

searchRequest(..) "<ROOT>"

(&(&(&(&(&(&(DnsDomain=...)(Host=...))(User=...))(AAC=...))(DomainGuid=...))(NtVer=...))(DnsHostName=...))

Both can be observed using Wireshark (look for Kerberos5 or CLDAP protocol requests)

Windows Authentication using WCF and Self Hosting

Within the configuration for your client, you'll need to add an additional element within your 'endpoint' element to specify the principal that the service is running under. Here is an example:

<identity>
<servicePrincipalName value="user@mydomain.com" />
</identity>

This should allow for proper authentication to occur when establishing a channel between your client and host. If the service is being run under a different account, you will need to adjust the value accordingly (i.e. if it is running as a windows service using the system account, it would be similar to 'host/mymachine.mydomain.com').

Calling a WCF service using Windows Auth from a Windows Store App

Turns out that the issue was a result of me hosting the service (for testing) on my laptop and calling it using 'localhost'.

I've deployed the same service to another server on our domain and updated the endpoint address in the app and it all worked just fine.

Looks like there's a restriction on windows store app calling services on localhost

Not quite sure why this is working fine if I provide the credentials explicitly and does not if I just carry the logged on user though..

WCF and Windows authentication

You should grant access permission in the SQL Server for the NT AUTHORITY\NETWORK SERVICE account if you use local SQL Server or for DomainName\AspNetServer$ (where AspNetServer is the name of the server where IIS7 are running). For details see for example the last section of http://msdn.microsoft.com/en-us/library/ff647402.aspx.

UPDATED: First of all you should don't forget to configure virtual directory of IIS to switch on "Windows Authentication" and switch off "Anonymous Authentication".

I am not sure that basicHttpBinding is the best choice for you. You wrote almost nothing about your WCF service so I can't recommend you a way. Look at http://msdn.microsoft.com/en-us/library/ms734769.aspx for example to see which ways you can choose.

To access a local DB you can use user impersonation. It can be implemented either generally per WFC call or you can do temporary impersonation before accessing of DB. (see http://www.danrigsby.com/blog/index.php/2008/04/17/impersonate-a-clients-identity-in-wcf/ for example for details).

The main problem is that there are no best way to access database from a service. If you choose impersonation for example. It can looks like nice because inside of database one sees from which user the request come. But in a lot of real situation the usage of impersonation not really solve a problem, but only forward it. Who should administrate permission inside of the database? With respect of which tool one should grant permission to users. Who makes user administration in your corporation? Do one only user administration inside of Active Directory or do one also administration of SQL Server databases? So because of existing processes in your corporation the user impersonation could be not the best choice.

There are a lot of different scenarios to access DB from WCF. For example in the last project which I implemented I wrote a WCF service which has a lot of methods. Inside of every method direct at the beginning of the method I used Microsoft Authorization Manager API to verify whether the user has permission for the corresponding operation or not. One used Authorization Manager Snap-In to grant permission to user through assigning it to some application role. And for accessing to the database I used one user account (like NT AUTHORITY\NETWORK SERVICE in your case). Nevertheless the solution was secure and one had a tool for the user administration which corresponds to business requirements.

I have too less information about you environment and business requirements to give you one recommendation. I want only explain that you probably need to make a security concept of your solution based on different possibilities which you have.



Related Topics



Leave a reply



Submit