How to store credentials in Web application to access webservice? - c#

I am working on an application where I need to store a user credentials to access webservice to perform different operations through out user session and finally destroy the credentials.
1.User Enters credentials in Login Screen (Using Forms Authentication)
2. I am Capturing credentials and storing it in session as below:
Webservice webService = new Webservice();
CredentialCache cache = new CredentialCache();
cache.Add(new Uri(webService.Url), // Web service URL
"Negotiate", // Kerberos or NTLM
new NetworkCredential(userName, pwd, domain));
webService.Credentials = cache;
HttpContext.Current.Session["webService"] = webService;
I am not sure whether this is a correct way of doing it or not. As I need this webservice object throughout the session scope I am using above logic.
Please some one suggest me how can I accomplish this.
My application is not a SSL enabled application(Http).

Related

Accessing Azure proxy enterprise app external URL from other registered app using ClientSecret in the background

I have following situation
APP1 : Azure enterprise application running through azure proxy. My external URL is https://xxx.msappproxy.net and internal URL for testing purpose I have put is https://reqres.in
Enterprise App is configured to allow login by any user, now this is all applicable when it runs from UI with specific user login, but as I am running the app from the background, I need to create APP2.
APP2 : I need to create another App which has a permission to access (with admin consent in place) enterprise proxy app (APP1). for that I have configured Client secret in APP2, I can successfully get the token from my App
I believe standard method is to set up client secret in APP2, allow permission to access APP1, get the token passing client secret and access APP2.
Following is my code to retrieve token for APP2 and access APP1 external URL.
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create("7cbb265a-cf6d-xxxx-xx-289bd24d0be0")
.WithClientSecret("1eanye2~.-I_K-69i4B8kahdkjasxxxlnr~3v")
.WithAuthority("https://login.microsoftonline.com/877b6ed6-377f-42d5-ab2e-xxxxxxx")
.Build();
string[] scopes = new string[] { "api://7cbb265a-cf6d-4adf-8ae2-xxxxx/.default" };
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
if(result != null)
{
string Need = result.AccessToken;
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {result.AccessToken}");
//HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await httpClient.GetAsync("https://xxx.msappproxy.net/api/users");
string data = await response.Content.ReadAsStringAsync();
}
All works fine and I get the token for APP2, but when I try to access proxy URL with Authorization, HTTPresponseMessage still ask me to login as in response rather then actual data from https://reqres.in/api/users, I am getting whole Azure AD Authentication html page back asking me to authenticate.
I am not sure if I required anything additional configuration to be in done in either APP1 or APP2.
If you can help or give me some direction ahead making this possible would be greatly appreciated.
Regards,
Hiren.
We can give delegate control to other application (app2) and users will be able to access it through app1. please see the below document for more details.
Delegate permissions.
Kindly check these documents 1 and document 2

Using default credentials to call api in console app

I'm trying to call a Web API 2 method that requires auth from a console app running on my desktop where I have authorization, but I'm getting 401 Unathorized. I know I have authorization because when I make the same call from a web browser it works fine. So a browser can get my default login id/pw to send to the API but .NET's WebClient can't? That seems insane. There has to be a way to do this without entering my id/pw into the console app.
The below is what I'm using in a console app and it's not working.
This is using Windows Auth as it's intranet stuff.
This throws an exception "The remote server returned an error: (401) Unauthorized."
using(var c = new WebClient())
{
c.UseDefaultCredentials = true;
string value = c.DownloadString("http://localhost:62659/api/Store/GetData");
}
I also tried the below and when I mouse over DefaultNetworkCredentials the username/pw are blank strings. Why wouldn't .NET be able to figure this out?
using(var c = new WebClient())
{
var creds = new CredentialCache();
var uri = new Uri("http://localhost:62659/api/Store/GetData");
creds.Add(uri, "ntlm", System.Net.CredentialCache.DefaultNetworkCredentials);
c.Credentials = creds;
string value = c.DownloadString(uri);
}
It is likely that you do not have your credential information stored within Windows Credential Manager. You can access that via Control Panel > Credential Manager. From there you can add whatever credential you need. CredentialCache.DefaultCredentials and CredentialCache.DefaultNetworkCredentials contains the login credentials of the currently logged-in or impersonated user. If what you are connecting to requires different credentials then these will not work. You will need to add those credentials to the Credential Manager in Windows.
The reason you are connecting fine within Chrome is that Chrome will store credentials within itself that you have designated to save.
Login credentials being used as functional ids can be set to never expire, or it will need to be added to a list of monthly/yearly maintenance items to update the password for those accounts.
You would also want to handle bad login information within your application. If this is an automated task, have it email or otherwise notify someone that the credentials need to be updated.
If a user runs this, you could simply prompt the current user to provide a new password, which you can use to update the stored credentials right then.
Another option would be to set the user running the application as a user on the receiving end using those same credentials. That way the entire process is tied to the user(s) that will be running the application.
Using DefaultCredentials should work to use Windows Auth from console application. As long as you have the appropriate authorization header that your web api is looking for. Same with my comment I recommend testing the api call using Postman so that you can troubleshoot and check what you are missing.
Regarding the credentials as blank, this is maybe because you are using DefaultNetworkCredentials.
Try this:
using(var c = new WebClient())
{
var uri = new Uri("http://localhost:62659/api/Store/GetData");
c.Credentials = System.Net.CredentialCache.DefaultCredentials;
string value = c.DownloadString(uri);
}
If you want to use NetworkCredential you should be inputting network credentials like so:
c.Credentials = new NetworkCredential(username, password, domain);
I created this type of console application and used it as a service and I can tell you that this should work. You should just need to troubleshoot and bits by bits get the real problem.

Infopath COM object authentication failure using Web Service

So I have a windows forms application that loads an infopath form(.xml) from a sharepoint library, and does some processing to it. I created an exe out of it and I just supply a sharepoint library url to it through cmd and it pulls up the form.
I also have a web service which runs on an IIS server that calls the exe and displays infomartion for specific users. Now the problem is when I call the exe from then web service, it kept on asking for a login prompt. So i figured the web service must be running as a System account, and i supplied credentals through a number of ways
WebRequest request = WebRequest.Create(sharepoint_url);
request.Credentials = CredentialCache.DefaultNetworkCredentials;
or
request.Credentials = new NetworkCredential("","");
I also tried System.Net.CredentialCache mycache = new System.Net.CredentialCache();
mycache.Add(formUrlName, "Basic", new System.Net.NetworkCredential("", "")); and
request.Credentials = mycache;
But all the time i got an exception being thrown....Infopath cannot open this frm...the signature on this form is not from a trusted publisher.
Then I tried loading my project along with the web service and creating a new form ( Form form2 = new Form()), but doing the authentication procedure first. Now I get a http 401 unauthorized error.
(I use FormControl.Open(url) to open the form fromm the sharepoint library)
What am i doing wrong?
UPDATE:
I checked with the admin of the sharepoint library...apparently, the credentials are not being received at all. I dont know if they are not being sent properly or whether sharepoint is just dropping the credentials and not accepting it.

Windows Form calls Web Service but needs to impersonate a different Windows user

I have a Windows Form app (4.0) that calls a Web Service (WCF) but needs to impersonate a different user than who is currently logged inot the machine. How can that be done? Right now the Web Service is failing to return records because the user does not have the rights. I need to use a different user for the Web Service call.
From my app where I do this:
NetworkCredential credentials = new NetworkCredential(user, pw, userDomain);
// This is the client generated by the WCF Service Reference
AppClient appClient = new AppClient();
appClient.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
appClient.ClientCredentials.Windows.ClientCredential = credentials;
appClient.MyWcfServiceCall();
Now calls to the WCF service will be done under the credentials supplied. Your WCF Service methods must be decorated to allow impersonation as such:
[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
or
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
depending on your needs.
From within the WCF Service, you have the following info about the logged on user:
OperationContext.Current.ServiceSecurityContext
Thread.CurrentPrincipal.IsInRole(roleName)
Thread.CurrentPrincipal.Identity
You can also look into LogonUser() for other methods of impersonation: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_impersonatingusinglogonuser
HTH!
James

Domain.GetDomain(...) fails when called from a web service

I have the following code in a class that is called from a web service:
NetworkCredential credentials = new NetworkCredential("user", "password");
connection = new LdapConnection("domain");
connection.Bind(credentials);
DirectoryContext directoryContext =
new DirectoryContext(DirectoryContextType.Domain, "domain");
// This call returns a domain object with unreadable properties
Domain domain = Domain.GetDomain(directoryContext);
If I instantiate the class directly, all is well, I have a valid domain object that I can work with. If I go through the web service, the domain object is created, but most of the properties throw exceptions, e.g.:
'domain.Children' threw an exception of type ActiveDirectoryOperationException
I have impersonation enabled and am explicitly setting the credentials before calling the web service. Examining Thread.CurrentPrincipal.Identity.Name on the web service side shows the username of the credentials I've explicitly set.
If I look at Request.LogonUserIdentity, I have the following properties:
Name: "domain\\username" (is correct)
ImpersonationLevel: Impersonation
IsAnonymous: false
IsAuthenticated: true
AuthenticationType: NTLM
Anonymous access is disabled (enabling it makes no difference), and 'Basic Authentication' and 'Integrated Windows Authentication' are both checked. The web service is running under IIS 5.1 on my development box.
The code that calls the web service, resulting in a failed call to Domain.GetDomain():
MyServiceProxy proxy = new MyServiceProxy ();
CredentialCache credCache = new CredentialCache();
NetworkCredential netCred = new NetworkCredential(user, password, domain);
credCache.Add(new Uri(proxy.Url), "Ntlm", netCred);
proxy.Credentials = credCache;
proxy.MethodCall();
The code that calls directly and succeeds:
MyService myService = new MyService();
myService.MethodCall();
Any ideas why calls to Active Directory would fail when made in the context of a web service? And again, the call doesn't fail per se... it returns a domain object with unreadable properties.
Thanks in advance!
When you do...
NetworkCredential credentials = new NetworkCredential("user", "password");
connection = new LdapConnection("domain");
connection.Bind(credentials);
DirectoryContext directoryContext =
new DirectoryContext(DirectoryContextType.Domain, "domain");
// This call returns a domain object with unreadable properties
Domain domain = Domain.GetDomain(directoryContext);
...you're in fact just creating a (System.DirectoryServices.Protocols).LdapConnection with specific NetworkCredentials and you validate your "user" and "password" credentials against that. But then you don't use the connection-object anymore; instead you create a new entirely unrelated (System.DirectoryServices.ActiveDirectory).DirectoryContext-object.
And because you're not using a constructor where you're explicitly specifying a username and a password the DirectoryContext-object will get using the credentials of the user running the Application Pool (in IIS 6+, in IIS 5.1 the application will, if memory serves me right, always be a/the local system account - IUSR_XXX - which won't be able to access Active Directory because it's not a domain account).
The different credentials that are used when you're running your code in an IIS-environment versus just testing using a console application (where you're running code as the logged in/interactive user) is a common cause of problems in programming Directory Services.
Try using the constructor where you specify a username and password for the DirectoryContext-object.
As far as impersonation is concerned you might have better luck by using this code-snippet...
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
...taken from KB306158: How to implement impersonation in an ASP.NET application.
In the end, I converted this to a WCF service hosted in IIS, and the impersonation is fine. I'd love to know what the problem was, but I had to move forward, and a WCF service is a better solution overall, anyway. Thanks for the help, though!

Categories