I inherited a large .NET server application which contains code that is supposed to connect to a Sharepoint server. I know this code worked when the original developer wrote it, and it still works on the client's production machine, but fails with an authentication error ("The sign-in name or password does not match one in the Microsoft account system") when I run it on my workstation for development.
The Sharepoint code uses a WebClient. The relevant lines are these:
var client = new WebClient();
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = GetSharePointCredentials();
The function "GetSharePointCredentials" returns an instance of ICredentials that is constructed from a username and a password. I know the username and password are correct, because I can go to the Sharepoint site in a web browser and log in with them.
I tried saying client.UseDefaultCredentials = true, but I didn't really expect it to work since my workstation is not signed on to any Windows domain that is associated with the Sharepoint server.
I do notice that the Sharepoint web application does a two-factor authentication when I log in that way (it sends a text message to the phone number of the account, which I have access to) and I suspect this might be part of the problem, although I think the X-FORMS_BASED_AUTH_ACCEPTED header is supposed to allow it to work without the phone number verification.
Unfortunately I am not the administrator of the Sharepoint instance or the domain, so I can't directly view or change their configuration, although I could ask someone for help if necessary.
Thanks,
Frank
Turns out my code was fine, but my IP address was being blocked by a firewall rule.
Related
I have a C# .net core web app published to Azure and I'm having trouble downloading a report from SSRS (URL based report - hit the URL, SSRS generates the report, app downloads it to memory and serves it to the user for download). It's a multi-layer application with multiple different people managing these different layers. Also, nobody else has ever used SSRS in this way, all our previous SSRS reports have been scheduled reports, so none of us know exactly how this works. But it does, "It works on my machine."
These are the pieces:
Web app deployed on Azure
Azure SQL Database
SSRS is running on-prem
I don't control any of these, just the code. If I open the report on the SSRS site, it pulls the data in from the database just fine. If I run the app from my computer, it goes out to SSRS and runs the report, which pulls the data from the database and generates the report and feeds it back to me no problem. After publishing to Azure, I no longer get a valid file back (unreadable content, file is only 3KB when it should be about 20KB). But I do get a file back, so I assume that means SSRS permissions are fine. And since SSRS can access the database and generate the report if I run it directly in the SSRS interface, I assume the connection to the database from SSRS is fine. We don't know which layer to look into to troubleshoot this.
Here are a few things I've tried to see if I could reproduce when I'm running on my machine and their results:
Remove access to SSRS for my account - no file is downloaded and I get a 500 error
Changed database creds to be incorrect - no file is downloaded and I get a 500 error
Removed WebClient.Credentials = DefaultCredentials from the C# app - no file is downloaded and I get a 500 error
I can't reproduce downloading the report with "unreadable content" when running on my machine. I don't know who to tell they need to look into something deeper. At this point, everyone tells me that "It should work." I've included my method that handles the report download to see if there's anything there that can be changed.
public FileStreamResult GetReport(string reportAddress)
{
var net = new WebClient();
net.Credentials = CredentialCache.DefaultCredentials; //I feel like this could be related, as it's likely different when running on Azure but SSRS still gives me a file instead of a 500 error like when we removed SSRS access for my account to test while running on my machine
var data = net.DownloadData(reportAddress);
var content = new MemoryStream(data);
var contentType = "APPLICATION/octet-stream";
return new FileStreamResult(content, contentType);
}
Any idea on where to look?
Method execution:
return GetReport("http://server/ReportServer/?/ReportsRoot/ProjectFolder/ReportName&Param1=P1Value&rs:Command=Render&rs:format=wordopenxml");
As stated in remarks from documentation of CredentialCache.DefaultCredentials:
The DefaultCredentials property applies only to NTLM, negotiate, and Kerberos-based authentication.
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.
When running on your machine, that I assume is in the same domain of SSRS, DefaultCredentials are passing your domain user authentication, because the app is running under your authentication/authorization context, and your code is passing that authentication information in the request, making everything work.
When running on Azure, obviously the code has a local user, not your domain user, breaking the auth chain.
I'd suggest you to investigate ways to use your domain user (or even better an ad hoc user for your app) to create non-default credentials and pass them to the request, it should work.
Maybe investigate the possibility to federate your AD Domain with your Azure subscription (not an expert, but should be possible to join Azure AD whit on premise one).
I have created an ASP.NET website that has to access Active Directory on another server and change users passwords. The problem is that I need to authenticate with existing AD account and I cannot send AD user's password in plaintext when communicating with the Active Directory server. How do I communicate with AD server from ASP.NET website, so that connection is secure? My AD server supports LDAP protocol, but I do not know how to enforce communication with LDAP via a secure channel.
ASP.NET Website --------------LDAP/another protocol (secure)------------> AD Server
Fairly simple, you need to do two things :
Configure your Active Directory instance to accept connections over LDAPS, or port 636. You'll need a certificate (it can be self-signed) to set that up.
Update your LDAP authorization code to use this the new connection. This shouldn't be anything more than changing the server to "ldaps://{{IP OR DNS}}", and ensuring you're setting SessionOptions.SecureSocketLayer = true;
If you want to verify that it's working properly, Wireshark the traffic leaving your ASP.Net site that's going over port 636, and you should notice it's now heavily encrypted, and impossible to discern anything meaningful from.
I've done a ton of this stuff over the years, so I've had a few other questions surrounding this that should also help you out :
Set callback for System.DirectoryServices.DirectoryEntry to handle self-signed SSL certificate?
(This contains a full implementation of LDAPS)
Custom Multi-factor Active Directory Authentication
(This is a much more simple example, but would work perfectly fine for your purposes)
I have made a webform that inserts work items to a tfs 2010server. On the tfs server I need to be able to see which user created the work item. If I run the webform code locally on my machine this works, because my machine is logged in to my user on the tfs server. But after deploying the code on a server I get a (401) unauthorized error message if I don't hardcode in my credentials like this
TfsConfigurationServer configurationServer = new TfsConfigurationServer(configurationServerUri, new NetworkCredential(user, pwd, domain));
(Locally the code below works)
TfsConfigurationServer configurationServer = new TfsConfigurationServer(configurationServerUri);
Is it possible to tell the webserver which user is logged into the machine accessing the webform, or is it any way I can prompt the user for username/password when he/she submits the webform?
thx for any help!
There are several things you need to do and approach this issue
First most likely you have anonymous authentication allowed for your website. Meaning users can access your site without any restrictions and wont need to provide any information. Webserver doesn't know who they are. This will need to be disabled as by your question you need their info. You web app will try to connect to tfs under the webservers identity - either the dedicated account running the application pool or computer account.
http://technet.microsoft.com/en-us/library/cc770966(v=ws.10).aspx
The most simplest method is to enable basic authentication for your website, this will request users to provide username and password, downside is this method transmits data in base64 plain text, as such you channel must be secure
http://technet.microsoft.com/en-us/library/cc772009(v=ws.10).aspx
Forms authentication will allow you to use custom form to collect login info from users, and validate it yourself but works much like basic authentication
http://technet.microsoft.com/en-us/library/cc753252(v=ws.10).aspx
If clients are users in your domain and application is used in intranet the best option is to use Windows authentication, it will try to automatically get users identity from domain, and will issue popup if that fails. Depending how your servers are setup getting this to work may be as easy as enabling it (tfs and your app on the same server) or require configuring your domain controllers for kerberous.
http://technet.microsoft.com/en-us/library/cc754628(v=ws.10).aspx
Once users are in have been authenticated you must make the webserver impersonate them when your code calls tfs. Complexity again depends on your setup.
http://technet.microsoft.com/en-us/library/cc730708(v=ws.10).aspx
Alternativly you can use tfs impersonation to get similar result, this can be also used if for example you dont have users in tfs for each user connecting but instead want to impersonate and ClientCompany, Project or Team account
http://blogs.msdn.com/b/paulking/archive/2010/11/04/using-the-new-tfs-2010-impersonation-apis.aspx
I'm working on a recently created server that was built to house a migrated version of SSRS, from SSRS 05 to 08.
Previously, we had no issues with connectivity from the IIS server to the SSRS server via the report viewer control and we did not supply credentials at that time. Now, when we try to use the viewer we get back; "The request failed with HTTP status 401: Unauthorized."
Obviously that is a new issue that we have never had before even though we never used credentials in the first place. So that is my first question... The new server is sitting in the same "place" as the old one. IP, Domain, Subnet is the same. Users have been set up the same, and the SSRS configuration appears to be the same. What could be the difference that is causing the error?
Also, i've been doing some testing, and I realized that I can access that server and get the reports in that environment by pointing my dev environment running in visual studio 2008 to that server without using credentials. I'm assuming by not setting the report viewer objects serverreport.reportservercredentials to something and leaving that property as a null value that it is using something else? possibly my windows user credentials? to access the reporting server. (That would be my second question.)
And finally. I decided to bite the bullet and implement credentials on the report viewer. When i create the credentials for the local user on the ssrs server that was created for this purpose, and is also listed in the report manager as a browser, i get the request failed error. My third question is; Is there something that I'm not thinking of for this type of implementation?
Please let me know if there are any questions or things that i need to clarify with in my post.
I ended up going down a different route.
There were two issues... first. the application on the web server was running as a local user. And the old SSRS server was set up to accept anonymous users.
To remedy this, I had our net work guys create a new domain account. I then changed the app pool identity for the application to use that domain account, and gave it list and write permissions on the temp folder and added it to the correct groups in windows.
I then gave that domain user browse ability on the reporting server.
this worked for 2.0+ apps... now i just need to figgure out what folders the user needs access to for the 1.1 apps.
(ps... i also found that the domain user actually works when i pass credentials via the report viewer control in .net.)
I have an asp.NET webapplication running in our datacenter in which we want the customer to logon with single sign-on. This would be very easy if we could use the IIS integrated security. However we can't do this. We don't have a trust to the domain controller of the customer. ANd we want to website to be available to the general internet. Only when people are connecting from within the clients network they should automatically login.
What we have is a list of domain accounts and a way to query the DC via LDAP in asp.net code. When anonymous access is allowed in IIS, IIS never challenges the browser for credentials. And thus our application never gets the users credentials.
Is there a way to force the browser into sending the credentials (and thus be able to use single sign-on) with IIS accepting anonymous request.
Update:
I tried sending 401: unauthorized, www-authenticate: NTLM headers by myself. What happens next (as Fiddler tells me) is that IIS takes complete control and handles the complete chain of request. As I understand from various sources is that IIS takes the username, sends a challenge back to the browser. The browser returns with encrypted reponse and IIS connects to the domain controller to authenticate the user with this response.
However in my scenario IIS is in a different windows domain than the clients and have no way to authenticate the users. For that reason building a seperate site with windows authenticaion enabaled isn't going to work either.
For now I have to options left which I'm researching:
Creating a domain trust between our hosting domain and the clients domain (our IT department isn'tto happy with this)
Using a NTML proxy to forward the IIS authentication requests to the clients domain controller (we have a VPN connection available to connect via LDAP)
What you're asking for is called mixed mode authentication. I've recently used a two entry-point mechanism from Paul Glavich and it works perfectly. I guess it's the most elegant solution for this problem.
Not sure that you'll easily get this to work. Unlike basic where the 401 challenge happens in-band of the user request - such that the creds appear in the headers, NTLM handshakes are done on a separate port - then forced onto the thread context by unmanaged code.
You tried pulling apart the ASP.NET NTLM module in VS2008 (or reflector) to see what it does to extract the creds?
Not really an answer - sorry...
This solution is about forms authentication, but it details the 401 issue.
The solution was simply to attach a
handler to the Application's
EndRequest event by putting the
following in Global.asax:
protected void Application_EndRequest(object sender, EventArgs e) {
if (Context.Items["Send401"] != null)
{
Response.StatusCode = 401;
Response.StatusDescription = "Unauthorized";
} }
Then, in order to trigger this code, all you have to do is put a
Context.Items["Send401"] = true;
Edit:
I've used this method with Anonymous and Integrated turned on to get the user's domain credentials. I'm not sure if it'll work in your situation, but I thought I was worth a shot.