I'm working on a corporate ASP.NET Core application that needs to reach out to a cloud resource (Elastic APM).
Unfortunately, our corporate proxy is swatting down the request before it can complete. It's not my code that making the requests but code within a NuGet package, so I can't easily change how it's making the connection.
I'm hoping to use middleware to inject the proxy details before it goes out the door. I've tried this below, but it doesn't seem to be working:
services.AddHttpClient<HttpClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
{
Proxy = new WebProxy(new Uri("http://proxy.mycompany.com:8080"), true, new string[]{}, CredentialCache.DefaultCredentials)
});
Long-term, I am going to whitelist the cloud resource. But as I prototype this solution, I'd prefer not to go through that red tape...
Related
I am currently writing an integration test for a websocket connection. I want to test a ClientWebSocket connection against a server instantiated by Microsoft.AspNetCore.Mvc.Testing. This does not seem to work. Does anybody have an idea how to get this to work?
My setup is as follows:
I have an API application, which offers some normal http endpoints and one websocket
I have some application code, which establishes a websocket connection
I have integration tests, which instantiate the API application using Microsoft.AspNetCore.Mvc.Testing and use my application code against it
I general am following https://learn.microsoft.com/de-de/aspnet/core/test/integration-tests?view=aspnetcore-6.0 . This works great for normal HTTP(S) endpoints. My Code looks like this:
_application = new WebApplicationFactory<Program>().WithWebHostBuilder(builder => { });
//HttpClient for http endpoints
_client = _application.CreateClient();
The WebSocket endpoint is created as described here: https://learn.microsoft.com/de-de/aspnet/core/fundamentals/websockets?view=aspnetcore-6.0
app.Use(async (context, next) =>
{
if (context.Request.Path == "/"+nameof(TestModel.WebsocketEvent))
{
if (context.WebSockets.IsWebSocketRequest)
{
TestModel.Instance.WebsocketEvent = await context.WebSockets.AcceptWebSocketAsync();
await ListenForClose(TestModel.Instance.WebsocketEvent);
}
}
}
For the connection to the endpoint I am using ClientWebsocket in the code I want to test.
var ws = new ClientWebSocket();
await ws.ConnectAsync(_href, cancellation);
When I run my API application manually and execute my code against that instance, everything works as expected. The WebSocket connection is established.
When I try to run it with Microsoft.AspNetCore.Mvc.Testing I get an exception that the server refused the connection.
To some degree it makes sense to me, since the ClientWebSocket is not using anything generated by the WebApplicationFactory.(e.g. _application.Server.CreateWebSocketClient.
On the other Hand I do want to use ClientWebSocket in my code and not inject the WebSocketClient of Microsoft.AspNetCore.Mvc.Testing into my production code. In Contrast to http where I actually get a regular HttpClient which I am fine with to inject.
Does anybody have an idea, how I can make the integration test working with ClientWebSocket?
Is there the possiblity to reuse the server Microsoft.AspNetCore.Mvc.Testing starts for requests other than what the WebApplicationFactory generates?
Is Microsoft.AspNetCore.Mvc.Testing running the API application at all as a server? Or is there some black magic in the background?
What I checked so far:
_href is correct
_application.Server.BaseAddress does not seem to have an impact
What I want to do is simply not possible. The answer of the following thread pushed me in the right direction.
Inject HttpClient from WebApplicationFactory
This matches the official documentation if you know what you are looking for:https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
Hence I can only access the instance of my Web API application using what WebApplicationFactory offers me.
I can't access the instance of the Web API application over my local network.
Thanks to everybody taking the time to read and think about my question.
I've written a C# app that performs web requests via the System.Net.Http.HttpClient (e.g. client.GetAsync(uri);). Compiling and executing it with the .Net runtime, all these calls are successful. However, compiling and running with Mono, they fail with exceptions ("IOException Authentication or decryption failed").
However, switching to a network that doesn't go through the proxy resolves the issue. So in conclusion, it's not a certificate or whatever issue, but just the issue of the proxy.
Same applies for the tlstest tool: Fails miserably with the proxy, works fine without it.
How do I configure mono to use the proxy settings / use the system proxy settings?
Can you try setting the proxy in HttpClient? You can set proxy credentials if necessary.
WebProxy proxy = new WebProxy("proxyaddress", port);
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = proxy
};
HttpClient client = new HttpClient(handler);
Try to use modernhttpclient component. This library brings the latest platform-specific networking libraries to Xamarin applications via a custom HttpClient handler which can handle for you this kind of issues.
I have a web application which is a mesh of a few different servers and 1 server is the front-end server which handles all request external incoming requests.
So some of these request will have to be passed along to different servers and ideally the only thing I want to change is the host and Uri fields of these request. Is there a way to map an entire incoming request to a new outgoing request and just change a few fields?
I tried something like this:
// some controller
public HttpResponseMessage get()
{
return this.Request.Rewrite("192.168.10.13/api/action");
}
//extension method Rewrite
public static HttpResponseMessage Rewrite(this HttpRequestMessage requestIn, string Uri) {
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpRequestMessage requestOut = new HttpRequestMessage(requestIn.Method, Uri);
requestOut.Content = requestIn.Content;
var headerCollection = requestIn.Headers.ToDictionary(x => x.Key, y => y.Value);
foreach (var i in headerCollection)
{
requestOut.Headers.Add(i.Key, i.Value);
}
return httpClient.SendAsync(requestOut).Result;
}
The issue I am having is that this has a whole slew of issues. If the request is a get Content shouldn't be set. THe headers are incorrect since it also copies things like host which shouldn't be touched afterwards etc.
Is there an easier way to do something like this?
I had to do this in C# code for a Silverlight solution once. It was not pretty.
What you're wanting is called reverse proxying and application request routing.
First, reverse proxy solutions... they're relatively simple.
Here's Scott Forsyth and Carlos Aguilar Mares guides for creating a reverse proxy using web.config under IIS.
Here's a module some dude named Paul Johnston wrote if you don't like the normal solution. All of these focus on IIS.
Non-IIS reverse proxies are more common for load balancing. Typically they're Apache based or proprietary hardware. They vary from free to expensive as balls. Forgive the slang.
To maintain consistency for the client's perspective you may need more than just a reverse proxy configuration. So before you go down the pure reverse proxy route... there's some considerations.
The servers likely need to share Machine Keys to synchronize view state and other stuff, and share the Session Store too.
If that's not consistent enough, you may want to implement session stickiness through Application Request Routing (look for Server Affinity), such that a given session cookie (or IP address, or maybe have it generate a token cookie) maps the user to the same server on every request.
I also wrote a simple but powerful reverse proxy for asp.net / web api. It does exactly what you need.
You can find it here:
https://github.com/SharpTools/SharpReverseProxy
Just add to your project via nuget and you're good to go. You can even modify on the fly the request, the response, or deny a forwarding due to authentication failure.
Take a look at the source code, it's really easy to implement :)
I would like to authenticate users of my servicestack.net rest services using basic auth over HTTPS.
Can anyone explain how the https portion of this would work or point me in the right direction? Is it the responsibility of the client to ensure the calls are made over https? Do I need to do anything involving SSL Certificates to enable this?
This service will most likely live on AppHarbor if that matters.
EDIT
Can anyone cite specific examples of how to accomplish this in service stack. I think that I would be having all of the services in my api require HTTPS. Would I be able to accomplish this using request filters?
You will need to have an SSL Certificate purchased and installed to handle https (you should be able to get one from your domain name provider, which you will then need to install on your hosting server). The service clients will generally be allowed to connect by any method they choose. It will be your responsibility to stop the request and generate an error message to the client if they attempt to connect by http, instead of allowing them access.
You can validate whether they are on http or https by checking the Request.Url.Scheme property in your REST Service API. Typically, a request for http on a service that requires https will return an HTTP 403 (forbidden) status code. If you have access to IIS, you can force HTTPS easily without doing any coding: http://www.sslshopper.com/iis7-redirect-http-to-https.html
If you don't need on all services the following at the top of any service that needs the security does the job:
if (!Request.IsSecureConnection)
{
throw new HttpError(HttpStatusCode.Forbidden,"403","HTTPS ONLY");
}
However it's better to this as a filter attribute: https://github.com/ServiceStack/ServiceStack/wiki/Filter-attributes
If you want it globally, you could apply your attribute to a shared BaseService or better use a global filter: https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filters
...Like this:
this.GlobalRequestFilters.Add((req, res, dto) =>
{
if (!req.IsSecureConnection)
{
res.StatusCode = (int)HttpStatusCode.Forbidden;
res.Close();
}
});
If you want one that redirects to https rather than reject request then you could base it on this: http://weblogs.asp.net/dwahlin/requiring-ssl-for-asp-net-mvc-controllers
I am using a WCF service client generated by slsvcutil form Silverlight toolkit version 4. I've also tried version 3 with the same problems. When I use a client instance running on http with no user credentials it runs without problems. But I need to switch to https for productive servers and send user credentials that are hardcoded for my application. I use the following code for that:
var binding = new BasicHttpBinding (BasicHttpSecurityMode.TransportCredentialOnly);
var endpoint = new EndpointAddress (AppSettings.FlareEndPoint);
_service = new TopicAnalystAPIClient(binding, endpoint);
_service.ClientCredentials.UserName.UserName = "xxx";
_service.ClientCredentials.UserName.Password = "xxx";
When I call a method on that service pointing to http with no authentication it works. When I use the this code against http/https with the credential I get "There was an error on processing web request: Status code 401(Unauthorized): Unauthorized" exception. I've checked that the credentials are correct, I am able to open the service reference in my browser. I've also tried several combinations of http/https and SecurityMode value. I've also tried it on four different servers always with the same result.
What can be the problem?
A lot of permutations are possible. BasicHttpSecurityMode.TransportCredentialOnly should be usable without SSL [1] using HTTP itself. This means the server will send one (or more) authentication method(s) to the client (e.g. basic, digest, ntlm) and Mono (including MonoTouch) should be providing support for the most of them.
It is possible that the linker (if used) removes one of them. In that case you could try building and testing without linking (or skip linking of System.Net.dll).
It's also possible that the authentication method that the serve insist on is not supported. You could find which one is used by running a network trace (e.g. wireshark) or, maybe, it will show up in more details in the server log (along with the 401 error).
[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode%28v=vs.95%29.aspx