We have a scenario where a WCF service is hosted on IIS. The authentication mode is WINDOWS.
We are calling this WCF service from CRM plugin using windows authentication.
While getting the CRM organization instance, we are not getting windows user context.
private OrganizationDetail DiscoverOrganization(Uri discoveryUri, string organizationName, ClientCredentials lclClientCredentials)
{
DiscoveryServiceProxy serviceProxy;
using (serviceProxy = new DiscoveryServiceProxy(discoveryUri, null, lclClientCredentials, null))
{
IDiscoveryService service = serviceProxy;
var orgsRequest = new RetrieveOrganizationRequest()
{
AccessType = EndpointAccessType.Default,
Release = OrganizationRelease.Current,
UniqueName = organizationName
};
var organizations = (RetrieveOrganizationResponse)service.Execute(orgsRequest);
return organizations.Detail;
}
}
We tried setting credentials as below,
lclClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
lclClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
I don't think you can flow the Windows identity of the Dynamics client user to the web service this way. Dynamics plugins execute under one of three Windows accounts:
The account running the Sandbox service (for synchronous plugins registered in the plugin sandbox)
The account running the CRM web application pool (for synchronous plugins registered outside the sandbox)
The account running the Asynchronous service (for asynchronous plugins)
On top of this is layered the Dynamics (systemuser) identity of the client user invoking the plugin, but not the Windows account. The Sandbox and Asynchronous services run in entirely separate processes from the web application, and likely have no way of knowing the Windows identity of the invoking user.
If the web service needs the CRM identity of the invoking user (in order to act as that user in CRM), you will need to:
Pass the GUID of the client systemuser to the web service from the plugin.
Probably also pass some way to identify the CRM organisation to the web service from the plugin, assuming multiple orgs are in use in the deployment.
Authenticate to the web service using some other mechanism, e.g. Basic authentication, so that the service is still assured of being called only from the plugin.
Have the web service configured with connection details for all relevant CRM orgs (rather than use the Discovery service), including its own systemuser account in those orgs.
Edited to add: this could be configured as a non-interactive user, to save on licences.
Grant the web service's systemuser the Dynamics impersonation privilege, so it can act as other users.
When the web service is called:
Retrieve the appropriate connection details from configuration for the passed-in organisation.
Explicitly impersonate (using Dynamics impersonation) the passed-in systemuser GUID.
Related
I have a Web API application and an MVC4 client application on the same web server. They are both configured for Windows Authentication. The client application has impersonation enabled.
When I run the client in Visual Studio, it successfully passes my windows credentials to the Web API.
When I hit the client on the web server, the Web API receives "NT AUTHORITY\NETWORK SERVICE" which I guess is coming from the application pool the client app is running in.
Client passes credentials as follows:
HttpClientHandler handler = new HttpClientHandler()
{
PreAuthenticate = true,
UseDefaultCredentials = true
};
HttpClient client = new HttpClient(handler);
So my question is...do I need delegation here?
The web server is not configured for this in Active Directory - but I thought as the applications are on the same server, that impersonation would be sufficient. I would turn delegation on but I need a system admin to do that - and have all sorts of hoops to jump through - so want to be sure that's what I need.
OK, in short, no - delegation was not required.
It turned out to be an impersonation issue. From what I'd read it sounded like that was what should be required since the applications are on the same server, but even though I thought I had configured it correctly, I was missing a crucial part. I needed to change two settings in aspnet.config:
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
More details here:
https://stackoverflow.com/a/10311823/1230905
I'm having a hard time wrapping my head around some architectural elements to securing a core WCF service that is consumed by many different applications.
Internally, we have an application that allows HR folks to update a peron's details. This is contained in a WPF app. Externally, we have a website that would allow individual people to authenticate (throuh an AD Membership provider) and update their details.
We don't want users to be able to see other user's information (for obvious reasons). But we don't want to host this service inside the same web application that the users would log into. Here is how the architecture would look from a visual studio perspective:
ServiceApplication
WpfApplication
MVCWebApplication
They don't exist inside the same domains, for example, the service application would be hosted at http://www.service1.com/Service.svc and the mvc application would be hosted at http://www.updateyourprofile.com . So a user logs into http://www.updateyourprofile.com and we'd like to hit a Wcf service via JSON. Both the service application, wpf application, and mvc web application would use AD credentials to authenticate. But how do we secure the service so that users who log into the mvc web application can only see their information?
Most of the examples I see say to use the HttpContext.Current.User check inside the service. But since the user authenticated at a different site, how does the cookie transfer? Do you end up having to publish your service inside the same web application that you want to consume so that the cookies travel transparently?
Or is it just not possible to have a centrally located service with disparate applications that use the same authentication store to determine who has access to what on the service?
What you are looking for is some kind of federated authentication system which is used by all the entry points. That is what Windows Identity Foundation can help you to build.
Inside each application, access control would be claims-based, according to the claims embedded in each user's security token issued by the authentication system.
There's an entire book on the subject on MSDN.
I have 2 different applications, one is in Silverlight and another is a web application.
I need single sign-on for both.
Scenario is like: any user logged-in to the Silverlight application then there is a menu in that app to open the other web application in logged-in mode.
Both applications have different databases but the user name and password are same in both.
I am using the WCF services for the silverlight application.
Can anybody suggest a solution?
In my opinion you should use one DB for keep current session's token for each logged user. In this case isn't important where you logged you will take log-in token from this db.
I'm assuming you are using ASP.NET and Forms/other authentication and the Silverlight app is from the same web server.
first look at this link and the Silverlight Business application template from Visual Studio:http://msdn.microsoft.com/en-us/library/ee942449(v=VS.91).aspx
A more manual approach could include writing a WCF service that returns or sets the "UserToken" that you store in session on a successful login.
// the wcf service needs these attributes
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
// a manual approach: successful login, create a webservice method to call from Silverlight to set the authentication
HttpContext.Current.Session.Add("currentUserToken", userToken);
FormsAuthentication.SetAuthCookie(this.EmailAddressUserControl1.EmailAddressTextBox.Text, false);
Forms Authentication will take care of logging you out on ASP.Net requests, but you'll have
to handle session timeouts one service requests yourself.
I'm using custom basic authentication module (http://www.custombasicauth.codeplex.com) for authenticating users in WCF service. I've used a custom membership provider and in the ValidateUser method I've making a db call and returning true if the authentication succeeds. I also created a binding that uses transport security for the WCF service. Everything works fine now the problem is the client want two endpoints to be created for the WCF service and the custom basic authentication should happen for one endpoint not for the other.
Is it really possible to achieve this by using the custom authentication module or I have to try some other ways?
This is not possible when hosting your service in IIS. IIS has authentication scoped per whole virtual directory and your endpoints are exposed on the same service = single resource in single virtual directory. You must either move to self hosting and host service in windows service (you will not need that module anymore) or you must deploy the service again to different virtual directory or web application and change security configuration in each deployment separately (= every endpoint will be in separate deployed service).
I have a web project that has Anonymous access and Integrated Windows authentication enabled. I built a WCF Data Service and since it allows only one authentication, I enabled Integrated authentication on the service. I am able to view the service in browser. However when I try to query the service for any Entity, it gives me Forbidden error. I tried to enable Anonymous access on service too, but it does not work.
Do I need to give it some other access or it is not possible to enable one authentication on the service itself keeping the project virtual directory as Anonymous and Integrated.
Update: I do no have any operations in my Data Service. For the entities, I have already set the "All" permission on all entities.
Only one authentication method is permitted on a WCF Data Service.
If you choose to go the Integrated Security route then you need to set the credentials after constructing the DataServiceContext.
Something like this would work for using the current user's Windows identity.
employeeEntities = new EmployeeDataService.EmployeeEntities(new Uri("http://.../employeedata.svc"));
employeeEntities.Credentials = CredentialCache.DefaultCredentials;