Delegate user's credentials from SSAS to WebClient - c#

I'm building a solution that involves SQL Server Analysis Services database (SSAS MD) and an API(all in the same domain). Those two are on separate servers and I'd like to send credentials of a user that log into SSAS (using Windows authentication) to this API. What I do this for is that I developed a C# Assembly that's deployed to SSAS Cube. Assembly queries API like this:
var wc = new WebClient();
wc.Credentials = System.Net.CredentialCache.DefaultCredentials;
wc.Headers["Accept"] = "application/json;odata=nometadata";
System.IO.Stream response = wc.OpenRead(conn);
Data returned is shown in reporting tools that connect to OLAP Cube.
When client connects to OLAP Cube and runs this Assembly, API returns error (401) Unauthorized. Now, it works just fine on 2 occasions:
1) When user accesses OLAP Cube on the server that the Cube is stored on. Therefore it means that there can't be any client servers that connect to the Cube remotely. Seems like credential delegation doesn't work.
2) When adding Assembly to OLAP Cube, it's authorization can be set:
The goal here is to use "Use the credentials of the current user", but if I change it to "Use a specific Windows user name and password" and type in user name and password of a client, it works. Obviously, Assembly will be authorized only as this user and no single sign-on will be present
I've tried this: https://learn.microsoft.com/en-us/sql/analysis-services/instances/configure-analysis-services-for-kerberos-constrained-delegation?view=sql-server-2017 in that I created SPN for SSAS's service account and I enabled delegation on SSAS Server, client server and API server. Funny thing is that after those when I connect to SSAS on SSAS server with SSPI=Kerberos - I get 401 Unauthorized, so I guess I might be doing something wrong. I also tried connecting from Client server to SSAS with Impersonation Level=Delegate (according to https://learn.microsoft.com/en-us/sql/analysis-services/instances/connection-string-properties-analysis-services?view=sql-server-2017) and it doesn't work as well.
To be honest, I'm stumbled. I feel like I missed one, small setting somewhere that's stopping the whole solution from working. Can you please help me out?

Related

Sending e-mail through C#, Exchange and EWS Managed API gives error 407: Request failed - Proxy authentication required. Why?

I am writing a Windows forms application based on C# and the EWS Managed API 2.2.0 (Microsoft.Exchange.WebServices.dll assembly) for a client of mine who works on a company.
The app's logic is simple: My client puts his e-mail address "sender#ABC.domain.com" and the recipient's e-mail address "recipient#contoso.com" and the app sends an HTML-based e-mail to the recipient.
The app must connect to the Exchange Server of my client's company, authenticate my client to Exchange as a Windows domain user (using Windows domain authentication) (client is already logged in Windows with his username "sender" and as this Windows user makes the request) and then, send the E-Mail through his mailbox "sender#ABC.domain.com".
I have wrote the above code so far which seems to be correct, but it gives me this error: "The request failed. The remote server returned an error: (407). Proxy Authentication required"
try{
//Initialize and bound 'service' to the latest known version of Exchange
ExchangeService service = new ExchangeService();
//Use the Windows logged-in user domain account credentials:
//Is this correct / is this enough???
service.UseDefaultCredentials = true;
ServicePointManager.ServerCertificateValidationCallback = myValidationCallBackFunction;
service.AutodiscoverUrl("sender#ABC.domain.com", myRedirectionCallback);
MessageBox.Show("Autodiscover Exchange URL found:" + service.Url.ToString());
//Impersonation test - just in case - but this is not make any difference in the error
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "sender#ABC.domain.com");
//Initialize and set an EmailMessage
EmailMessage message = new EmailMessage(service);
message.Subject = "HelloWorld";
string emailMessageBody = "<!DOCTYPE html><html> ... </html>";
message.Body = new MessageBody(BodyType.HTML, emailMessageBody);
email.ToRecipients.Add("recipient#contoso.com");
message.SendAndSaveCopy();
MessageBox.Show("E-Mail sent successfully");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
My client uses Windows 10. His PC is part of a Windows domain with url "XYZ.domain.com" and his username on Windows is "sender". He also has an Outlook app installed in his PC which connects perfectly to the Exchange Server on his company's network...
I am totally amateur with Windows domain accounts / authentication. Is this a Windows domain authentication problem? Is this an Exchange conection settings problem? Or the problem is in my code in the authentication section (do I have to add something more)?
I found a part of solution by my own!
Now my code works fine.
The problem was in the Proxy Settings in Windows 10 on my client's PC. For some reason he had Manual proxy setup enabled but he didn't know it. When I found it and disabled it, then the e-mail was sent fine.
I'm saying that I found "a part" of solution because:
1) The Outlook 365 works fine with the on premises Exchange Server 2010, even if I have the proxy settings enabled or not. But my app works only with proxy settings disabled. Does anyone know how this is explained? Why Outlook works fine with both ways?
2) If the IT of the company of my client forces him to have always enabled the proxy settings, how can I bypass this error? Do I have to pass somehow the User's credentials (with or without password)? If, yes, then how can I do this with C#?
I think it works fine both ways because your customer has "Don't use the proxy server for local (intranet) addresses" enabled in Windows 10 Proxy Settings. That would explain why the proxy is bypassed when connecting to the on-premise Exchange Server.
It doesn't explain however why that doesn't happen when your app connects to the local Exchange Server (?)
You can configure EWS to use a System.Net.WebProxy like this:
WebProxy myProxy = new WebProxy("http://myproxy", 8080)
{
BypassProxyOnLocal = true,
Credentials = new NetworkCredentials("username", "password)
};
exchangeService.WebProxy = myProxy;
What credentials you use depends on your client's Proxy infrastructure. If it requires a domain account you can set myProxy.UseDefaultCredentials = true to pass in the current user.
Hth

Hosting a C# WebSocket Server on Elastic Beanstalk

I’ve written a WS server from scratch and I’m trying to host it on AWS Elastic Beanstalk service. However, I’ve only figured a way to add it to a web project (that can be hosted on EB) by tacking it on with a thread on startup.cs:
Thread thr = new Thread(() =>
{
var ws = new WebsocketServer();
});
thr.IsBackground = true;
thr.Start();
To my delight and surprise, I was able to successfully test this locally and it works perfectly fine, but when put on EB I am unable to connect to anything (even though I am 99% certain I’m sending requests to the appropriate URL). I’ve tried adding the port I’ve specified but nothing helps.
I’m using a TcpListener initialized like this:
TcpListener server = new TcpListener(IPAddress.Parse(“127.0.0.1”), 443);
server.Start();
And accept clients with a TcpClient like so:
TcpClient client = new TcpClient();
client = server.AcceptTcpClient();
Now based on my experience I assume that the connection is working properly but EB simply does not automatically set it up for public access. Is there any way to do this? Would using the same port as the web app help? (If so, how do I set/see what port it does use?). Since WS is initiated with a HTTP request, is there possibly a way to establish a connection using a Controller method of the format:
[Route("ws")]
[HttpGet]
public async Task<IActionResult> ConnectWS()
{
return await AddClient();
}
I have no Load Balancer set up for the EB environment I'm using.
Lastly, if this is a bad practice or infeasible, is there another AWS service I could use to host the server that’s easy to set up for public connections?
Thank you!
Looking at your code, you need to open up traffic on port 443. Depending on your Elastic Beanstalk configuration ( with load balancer? or without load balancer? update your question with this please ) you are close to getting it to work on AWS.
These high level steps will get you there:
Get a cert. For testing you can install openSSL on your local dev machine and create a self-signed cert. AWS has a guide on how to do this. Note: don't use self-signed certs on your live production system. When your site goes public, obtain a catchy name and a real cert to front your service.
(If no load balancer skip to step 3) Go to Certification Manager in your AWS console. There is a big blue button, Import Certficiate. Click this. Open the server.crt file from step 1 with your favorite text editor and paste the contents in the top box with the label: Certificate body. Then open the privatekey.cer file from step 2 with your favorite text editor and paste the contents in the second box with the label: Certificate private key. Click Review and Import and make sure everything is ok
If you have a load balancer, follow the steps from this AWS guide on how to open up 443 on it.. If you don't have a load balancer and it is just a single instance, its a bit more complicated as you have to do it via configuration files. Follow the steps here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-singleinstance.html
Try it out and reply back if you have updates to your question with more config specifics. I think you are close to working it out and getting it running on AWS.

ASP.NET Core on Azure throw "The client certificate credentials were not recognized"

My setup is similar to this SO post
My ASP.NET Web App connects to a third party service which requires client certificates. Begin a multitenant application, I've a client certificate for each customer, stored inside a database. Skipping the code to retrieve the certificate from database, I do something like this:
HttpClientHandler httpClientHandler = new HttpClientHandler();
X509Certificate2 customerCertificate = new X509Certificate2(certificateFromDatabase, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
httpClientHandler.ClientCertificates.Add(customerCertificate);
httpClientHandler.ServerCertificateCustomValidationCallback += ServerCertificateValidationCallback;
httpClient = new HttpClient(httpClientHandler);
This code works flawlessly on my Windows 10 development PC.
When published to an Azure Web App it fails 20% of time with the following error:
System.Net.Http.HttpRequestException: An error occurred while sending the request. System.Net.Http.WinHttpException: The client certificate credentials were not recognized.
I've written a test method which calls the third party service as fast as it can, switching certificate every time. This one works on my PC, and fails 80% of times on Azure (same error as above).
The solution proposed on the SO post above does not apply to me: I should have to load hundreads of certificates.
To troubleshoot the issue it could be usefull to execute a packet capture.
But, AFAIK, this is not possibile with Azure Web Apps (can be done with Virtual Machines and Network Watcher).

C#/UWP : How to manage certificate errors with HttpClient?

I've developed an UWP app for a client, which uses WebServices that are hosted in its domain.
Until now, the URL WebServices were related to a test server that don't use SSL
But now, the WebServices URL are related to the prod server that use SSL
As I'm a subcontractor, I don't have an AD account, and I need to use the VPN to access to the client's WebServices.
I didn't get any problem to access to the test server, but it's no longer the case with the prod server.
When I try to access to access to the URL through a navigator, I get a security warning message (DLG_FLAGS_INVALID_CA), but I can "force" the navigation to the URL.
But when I call the WebService from the app with HttpCLient, I also get an error (HttpRequestException) and I don't see how I could fix it.
Here are the details of the exception:
HResult = -2147012851
InnerException =
{System.Runtime.InteropServices.COMException (0x80072F0D): Can't find text related to the error code. The certificate authority is invalid or is incorrect at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) ...
Message = "An error occurred while sending the request."
Source = "System.Net.Http"
I've already tried to install handly the certificates on my computer, but this doesn't fix the issue...
Is there another approach?
Edit: add "user" certificate
The client sent me the "user" certificate and I installed it on my computer in "User\Trusted Root Certification Authorities Certificate Store": there is no longer problem from the navigator. However, in the app, the problem is still present.
Is it normal? Do I need to "attach" the certificate to the app? This is not really usefull, as the client's users don't need this problem: it's only me as I'm a subcontractor using the VPN...
Edit: add "computer" certificate
Finally the client sent me the "computer" certificate and I installed it on my computer in "Computer\Trusted Root Certification Authorities Certificate Store": this time I could use the app without problem.
It's good to know that the UWP app and the navigators don't use the same certificate.
The problem has been fixed by installing the "user" and "computer" certificates that has been sent by the client.

Cannot connect to JAMS server other than localshost

I am trying to control/run JAMS from a C# application. Most of the examples I have checked only connect to localhost, but I am trying to connect to a remote server through my program to use JAMSShr assembly.
I current am doing the following, which works great:
JAMS.Server js = JAMS.Server.GetServer("localhost");
I'm trying this to connect to the remote server:
JAMS.Server js = JAMS.Server.GetServer("JAMS_SCHED.PEER1.Company.COM");
I have username and password setup in JAMS.
Make sure their is an entry in host file to resolve your server name to IP address.
Also make sure API versions are compatible with version of JAMS server you are using.They are not very compatible.

Categories

Resources