I made an application that access CRM's web service. The problem is, when I deployed the dll into Sharepoint server, it returned error 401 unauthorized. Apparently the System.Net.CredentialCache.DefaultCredentials didn't work (my suspicion). Here's the code.
CrmSdk.CrmAuthenticationToken token = new CrmSdk.CrmAuthenticationToken();
token.AuthenticationType = AuthenticationType.AD;
token.OrganizationName = ORGANIZATION_NAME;
CrmService service = new CrmService();
service.Url = "http://crmserver:5555/mscrmservices/2007/crmservice.asmx";
service.CrmAuthenticationTokenValue = token;
service.PreAuthenticate = true;
service.Credentials = System.Net.CredentialCache.DefaultCredentials;
It goes vice-versa.
When I made application that access Sharepoint's webservice (coding the plugin) and deployed it to CRM server. It couldn't access the Sharepoint's web service. Unauthorized error. Here is the code:
Lists listService = new Lists();
listService.PreAuthenticate = true;
listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
listService.Url = "http://sharepointserver/webname/_vti_bin/Lists.asmx";
My CRM server and Sharepoint server are in the same domain.
For both code, if I changed the credentials part into something like this then deploy it on server, it can run.
service.Credentials = new NetworkCredential("username", "password", "domain");
Still, I don't want to do this because it reveals user's password in the code. May anyone help me?
The IIS in both server doesn't allow Anonymous Access and it uses Integrated Windows Authentication.
Thank you
From my local computer, I can access the CRM web services or Sharepoint web services. I guess I'm authorized because the DefaultCredentials sent my credentials that its password is saved in the "Stored Username and Password" (Control Panel > User Accounts > tab Advanced > Manage Passwords)
This way, I don't have to type:
service.Credentials = new NetworkCredential("username", "password", "domain");
and my DefaultCredentials from my local comp is authorized to access the web services.
I tried to implement this on the Sharepoint server that access CRM web services. and..tadaa..it won't work. hahaha..
can we inject credentials to DefaultCredentials in server?
the last thing I want to do is to hardcode the useraccount (like the code above)
Could be that you need to be running Kerberos for authentication, but cannot be sure and it is a pain to setup just to check.
Have you verified that the default credentials are the same as those when you explicitly state them? It could be that the default credentails are those of another account that you wouldn't expect.
EDIT #1: Per the remarks for the DefaultCredentials property on MSDN:
DefaultCredentials represents the
system credentials for the current
security context in which the
application is running. For a
client-side application, these are
usually the Windows credentials (user
name, password, and domain) of the
user running the application. For
ASP.NET applications, the default
credentials are the user credentials
of the logged-in user, or the user
being impersonated.
You'll also want to ensure that the user accessing the CRM page (making the call to the SharePoint web service) can access the web service with their credentials and vice versa. If they can then it would seem more likely that some kind of impersonation is happening.
Edit #2: Assuming that you have access to both the CRM and SharePoint server you might take a peak into both the application and system logs. One or both should likely indicate a failed login and indicate which account attempted to access the resource (in this case the web services).
By using DefaultCredentials means the ASP.NET worker process or IIS worker process will take the credential of the user who run the IIS Application Pool.
so if your Dynamics CRM Application Pool is run under a user account Custom-CRM-Domain\JohnDoe, that means it will take the privileges under user account Custom-CRM-Domain\JohnDoe.
Please check the user account who run the application pool of the CRM\Sharepoint Application IIS Web application.
These are the steps to check the Application Pool:
Open the website -> Right Click -> Choose Properties
Select the Home Directory tab
Notice the Application Pool name at the dropdownlist below
Now, go to the Application Pools folder
Try to find the Application Pool name which has been listed in the step 3 -> Right Click and choose Properties
Select the "Identity" tab and you will find the user account who run the application pool
Hope this helps.
service.Credentials = System.Net.CredentialsCache.DefaultNetworkCredentials;
Try that.
Not familiar with Sharepoint, but can't you just store the connection information in a configuration and use built in tools for securing your web.config? Thats what I do.
https://web.archive.org/web/20211029043331/https://aspnet.4guysfromrolla.com/articles/021506-1.aspx
to be able use defaultcredentials, the user in active directory must be defined both in SharePoint and CRM and have enough privileges to do what you are doing with code.
And try to use sdk (crm have helper classes) instead of service definitions.
For fixing this issue you need to know first which user is running the App pool as the others said and if you need to use CredentialCache.DefaultCredentials then you have to add the user lets say svcadmin or the like into "Secondary site collection administrator" by running SharePoint central administration application . By that SP allows to the user which the credential has been passed through to access the things it needs.
Related
I work for a large company with an intranet and Windows AD logins for everyone. We have a number of internal SQL Server databases which allow us to log in using Windows authentication, one of which I'm trying to connect to through an ASP.NET Core application. I can connect to this database through SQL Server Management Studio and query the tables fine.
I've followed the tutorial for an ASP.NET Core app using an existing database as closely as I possibly could, and created a single model class to test with to see if I could read data from the database. When debugging with IIS Express in Visual Studio, I can read data from the database when accessing the auto-generated controller and views.
Everything seems fine when debugging, but when publishing to IIS, I receive the following error:
SqlException: Login failed for user '<DOMAIN>\<COMPUTERNAME>$'.
Where domain is my domain and computername is my computer's name. This is expected, since my computer itself doesn't have access to the database. But it shouldn't be trying to connect using that system account (with the dollar sign), it should be trying to connect with my windows account: <DOMAIN>\<USERNAME>.
What's weirder, the app does seem to recognize my Windows credentials in some capacity - when I access the home page, I get the familiar "Hello, <DOMAIN>\<USERNAME>!" message in the nav bar. So the Windows credentials are definitely getting passed through to the app, but for some reason not getting passed through when trying to connect to the database through DbContext.
Am I missing something obvious here?
My Code
I started with Visual Studio's ASP.NET Core Web Application template.
In launchSettings.json, I have:
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:60686",
"sslPort": 44336
}
},
In appsettings.json, I have:
"ConnectionStrings": {
"MyDB": "Server=<servername>;Database=<dbname>;Trusted_Connection=True;"
},
In Startup.cs, I have the following line in ConfigureServices
services.AddDbContext<MyContext>(options => {
options.UseSqlServer(Configuration.GetConnectionString("MyDB"));
});
And from there, I have scaffolded an MVC controller with views using Entity Framework.
IIS has Windows authentication set to Yes and anonymous authentication set to No. My application pool is set to No Managed Code with ApplicationPoolIdentity.
Edit: The problem
To state the actual problem I'm trying to solve, I have a SQL Server database on a remote intranet server which allows access to a subset of the whole company via Windows authentication. If I want to create an ASP.NET application to provide an API to that database, hosted by IIS, what's the best way to do this? Assuming:
I don't want to have to manage permissions myself or have to duplicate them in some way
The people who have access to the database directly should have access to the API, the people who don't should not.
If they're accessing it from within the intranet while logged in to Windows, they shouldn't have to log in again.
I assumed I could just pass their windows credentials from IIS through the app to SQL server but I'm starting to wonder if that's actually the case.
After learning more about .NET and what Windows auth actually does on IIS, I'm going to say that what I was trying to do is not recommended. There is a difference between passing windows credentials to a .NET app in order to read from them, vs. actually executing a secondary process as that user. The latter case is what I was trying to do, but instead should set up my app pool in IIS with a user who can log in to the database, and use the windows credentials to verify against the list of users who have access.
You are using Entity-Framework for SqlServer and EF is using ADO.NET SqlClient. Therefore Trusted_Connection=yes; does not work.
Add Integrated Security=true; instead and it should be fixed.
Here some resources to read about it
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-string-syntax
Not to dig up an old thread, but this is a function that should work as long as Identity Impersonate = True is set. Here's some stuff being worked on.
GitHub Doc
I'll add my answer because this is how I fixed this issue.
The reason a "$"-sign is added to the login name/user must have something to do with the IIS that the application is being hosted on.
I'm not an expert on any of this, so I can't really go in-depth, but I've added the IIS user to the Logins and then it works.
USE [master]
GO
CREATE LOGIN [IIS APPPOOL\'name'] FROM WINDOWS WITH DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english]
GO
ALTER SERVER ROLE [sysadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [securityadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [serveradmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [setupadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [processadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [diskadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [dbcreator] ADD MEMBER [IIS APPPOOL\'name']
GO
ALTER SERVER ROLE [bulkadmin] ADD MEMBER [IIS APPPOOL\'name']
GO
You have to change 'name' to your IIS hosted application name. So for example if you app/site's name in ISS is "My-Backend-App" you should do:
CREATE LOGIN [IIS APPPOOL\My-Backend-App] FROM WINDOWS ...
So all the names should be "My-Backend-App".
When adding this user to the logins, my backend application could access & create the DB, create tables, access data etc...
SIDENOTE: I've used the Windows Event logger to find out this was my issue. My application just crashed, said a "500.30" error but no real information given.
You can access the "Event Viewer" application from Windows Search. Then you can go to "Applications" and there are all application errors/crashes that occured on your machine, and in this case also the reason why. It said it couldn't find user "myUser$" while trying to login to SQL, but the Windows Authentication user was "myUser". So for some reason it added a "$"-sign and couldn't log in. My fix above fixes this issue and you can login etc.
I am attempting to create an ASP.NET (.NET 3.5) website to connect to our Exchange 2010 server through Exchange Web Services, I am able to connect to EWS when I define the username, password and domain to authenticate with but I would like, if possible, to not include login details in my code.
In IIS I have enabled Integrated Windows Authentication for the site, in web.config of the site I have <authentication mode="Windows"/>.
The following code is what I have been woking with:
svc.UseDefaultCredentials = True
svc.Credentials = New WebCredentials()
svc.Url = New Uri(svcURL)
With the above code I am receiving the message:
When making a request as an account that does not have a mailbox, you
must specify the mailbox primary SMTP address for any distinguished
folder Ids.
When I attempt to use svc.Credentials = CredentialCache.DefaultNetworkCredentials (in place of svc.Credentials = New WebCredentials()) I receive the error message:
Unable to cast object of type 'System.Net.SystemNetworkCredential' to
type 'Microsoft.Exchange.WebServices.Data.ExchangeCredentials'.
As mentioned, the only thing that has worked is to define the user credentials to authenticate to by hardcoding user login details, which I would rather not do: svc.Credentials = New WebCredentials("username","password","domain")
Has anyone been able to authenticate to EWS using the credentials of the current logged in user in an ASP.NET website?
By default it is not possible to delegate a user's credentials from one server (the server on which you are hosting your ASP.NET site) to another (your Exchange server). This is known as a "server hop" and Windows will prevent it by default as a security measure.
You have a couple of options to work around this:
Using Kerberos: When Kerberos is enabled it makes it possible to delegate user credentials between servers when using Windows authentication. I do not know the exact details on how to set up Kerberos as I am only a humble developer but maybe your system administrator can assist you. AFAIK, you need to set up your ASP.NET server to allow user delegation.
Setting the user identity of your IIS application pool: If Kerberos is not an option, you may change the identity of the application pool that your ASP.NET site is running under. First define a new application pool in IIS manager. Then go to the Advanced Settings dialog for that application pool and set the identity to a domain user that is allowed to access your Exchange server. More info on the application pool identity here: http://technet.microsoft.com/en-us/library/cc771170(v=WS.10).aspx.
Setting the <identity> element: If you for some reason cannot change the application pool, you may try impersonation of your ASP.NET web site using the <identity> element in your web.config file. ASP.NET gives you the option of storing the credentials in the registry so that you do not have to put them directly in your web.config file. More info here: http://msdn.microsoft.com/en-us/library/72wdk8cc(v=vs.90).aspx
Using the <appSettings> ellement and encryption: The last option I can think of is to simply put the credentials in your web.config file as normal <appSettings> and then encrypt the entire <appSettings> section. You would then simply read the appSettings from your code using the AppSettingsReader class. .NET allows you to encrypt sections of the web.config file out of the box and you can read the settings without event noticing that the section is encrypted. .NET takes care of decrypting for you. More info here: http://msdn.microsoft.com/en-us/library/zhhddkxy.aspx
I have an ASP.NET application that uses Forms Authentication.
I need to call the Sharepoint search.asmx web service to retrieve a list of files from the network satisfying the search criteria (there's a good reason for me doing this outside of Sharepoint)
I'm not sure of the security information I need to pass the search.asmx. I've tried:
queryService.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials
queryService.ClientCredentials.Windows.AllowedImpersonationLevel = Security.Principal.TokenImpersonationLevel.Impersonation
-which works in my development environment as my user has access to the File Shares Sharepoint is accessing. What I can't understand, and can't infer from debugging or event viewers, etc. is what credentials are passed in the above code once I deploy this code on a server.
Will it pass the windows credentials of the user who opened the IE window prior to using forms authentication. Will it pass the credentials of the account that is running the asp.net components i.e. the account of the AppPool I'm running in, or will it pass something else?
I can't seem to get Sharepoint to return any files and I guess it's because the credentials being passed don't have access to the File Share.
Thanks
Andy
To get this working quickly you can access the SharePoint webservices with your username & password. This isn't the best solution long term obviously.
Set the Credentials property on the SharePoint webservice proxy to your username & password:
spProxy.Credentials = new NetworkCredential("username", "password", "domain");
You'll need to make sure the credentials property is set before you call the webservice.
I'm not a SharePoint expert (I've only used it as a developer), but I believe it only uses Windows authentication to secure the webservices. So forms authentication isn't going to help you out here if you want to access the webservices as the logged in user (unless you're validating the username & password manually with LDAP). ASP.NET Impersonation & Delegation only makes sense if you are using Windows authentication.
As stated by pseudocoder you might want to setup a special account to access SharePoint from the web server.
In my previous questions I was asking how to use windows authentication within my application. That is now working, users can login with there account but I have one database access scenario I can't find anything on.
Basically I will have several servers and here is the problem.
On some servers they will have Windows Authentication accounts for the SQL Server database server, so using impersonate their credentials should be used. But I notice its a global setting in the web.config (not per connection) and it one case I want to use the applications (IIS or ASP) Windows Authentication account rather than the users. (Access to my configuration database)
How could I achieve this?
Web Application is ASP.NET MVC hosted on Server 2003/2008 IIS 6/7/7.5 with clients being Windows XP and above. Using SQL Server Express/Standard 2005/2008 mixed.
Impersonation is on a site wide basis, or you can manually turn it on. What you can't do is manually turn it off I'm afraid, nor can it be done via the connection strings.
So basically turn impersonation off, then wrap the database calls when impersonation is needed like so:
using System.Security.Principal;
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = null;
try
{
ctx = winId.Impersonate();
// Do your thing
}
catch
{
}
finally
{
if (ctx != null)
ctx.Undo();
}
The MSDN P&P guide to asp.net impersonation has more.
You'll have to set up delegation on your network so that the ASP.NET servers can impersonate users on the Sql server machines. This assumes your servers are on an Active Directory controlled network (not workgroups) and that the sql servers are on different machines than your web servers.
You would configure delegation for those database server machines where you want the users to be impersonated and don't configure it for those server machines that you want the ASP.NET worker process account to be the account accessing the server.
If you can't do this, you can turn off windows/mixed authentication on the Sql Server instances you wish to prevent delegation on, and then manually configure the Sql Server account to connect with in the connection string within web.config.
Use domain controller - so it could propagate same credentials for single user across entire domain.
The second trick for workgroups - create same account of impersonation (with exactly same login and password) on both servers (ASP and SQLServer). Don't forget to grant this permission on SQLServer.
I have installed Microsoft Search Server 2008 Express on a Windows 2003 server and created a search content source (our corporate website) for testing. I can search this source just fine from the Search Centre.
From an ASP.NET web application I am trying to query the provided web service as described here
I am using impersonation settings in the web.config to specify the user account the request runs under but I cannot find out how to set up that user in the Search Server to allow it to make the query.
<authentication mode="Windows"/>
<identity impersonate="true" userName="MyDomain\MyUser" password="myPassword" />
If I use my own network credentials I get the results back, as I am set up with Full Control permissions in the Search Server instance, but when I use an alternate domain account for this (MyDomain\QueryUser) I get this error:
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> Attempted to perform an unauthorized operation.
I have added the user to the server in Search Server > Site Settings > Permissions > Add Users and have given the account Full Control but it still cannot use the webservice. Is there a setting somewhere I am missing?
**EDIT
Ok, I have tried Gordon's suggestion and using the credentials the Sharepoint application is using makes the error go away. Also, adding the second domain user to the local Administrators group on the server makes the error go away.
What permissions are these changes granting the webservice? Do I have to resort to using these work arounds or can I give my domain user appropriate permissions in Sharepoint somewhere?
the key to access the Search webservice of MOSS is
1) to authenticate properly
2) to force the MOSS webservice to use that identity
for the first part check if all properties are properly assigned for your networkcredential, i usually provide these:
NetworkCredential credentials = new NetworkCredential(userName, password, domain);
service.PreAuthenticate = true;
service.Url = your_ws_fullurl;
service.UseDefaultCredentials = false;
service.useDefaultCredentialsSetExplicitly = true;
service.Credentials = credentials;
for the second part one solution is to remove the IUSR (IIS anonymous user) the right to access the /_vti_bin/Search.asmx file with IIS (got to the /_vti_bin/ folder, right click to file security properties), this way MOSS will retrieve the credentials provided in the credential cache and you won't have the "unauthorized operation" message