AWS Api Gateway Web Socket Post to $default forbidden - c#

I'm trying to get my lambda to post to my aws web socket api and I am getting a Forbidden error message on the post. I have the following setup:
A public api configured using proxy+ to point to a lambda that handles all my routes.
A public web socket api that calls the above lambda.
I am testing out connectivity and my lambda correctly receives the $connect, $default and $disconnect events from the web socket api. I am trying to send a test message back to the client on open but receive the Forbidden error on the Post command.
My code is here:
public async Task<ITrWebsocketsContext> SendMessageAsync(UserDefinition userDefinition, string message)
{
var connectionIds = GetConnectionIds(userDefinition);
if (connectionIds != null)
{
foreach (var connectionId in connectionIds)
{
try
{
Console.WriteLine($"Sending to {connectionId}");
var response = await PostAsync($"https://{suppliedServiceUrl}/#connections/{connectionId}", message);
Console.WriteLine($"Sent to {connectionId}: {response}");
}
catch (ForbiddenException ex)
{
Console.WriteLine($"Exception: {SerialisableException.Serialise(ex)}");
}
catch (AmazonServiceException ex)
{
Console.WriteLine($"Exception: {SerialisableException.Serialise(ex)}");
RemoveConnection(connectionId);
}
catch (Exception ex)
{
throw;
}
}
}
return this;
}
The call to PostAsync fails.
I think this is a VPC issue as the Lambda is behind a VPC. The VPC is configured with 2 private subnets and 1 public one, with an Internet Gateway. The lambda can access the internet, so the VPC seems to be setup correctly. I also have an endpoint pointing to execute api in my region.
Any ideas on where to go? Do I need a VPC link configured for my lambda to connect to my AWS web sockets api?

Related

How to wait for all clients to answer to a request?

I have an ASP.NET core WebApi project which also uses SignalR to communicate with clients. This app has an action that is called by a third-party service and requires that all clients currently connected should send some info back.
The SignalR infrastructure is already being used between the server and clients, so I added this particular action:
public async Task<ActionResult> GetClientInfo()
{
await hubContext.Clients.All.GetClientInfo();
//var infos...
return Ok(infos);
}
So basically, this is what should happen:
The third-party service calls the action
The server asks all clients to send their info
The server returns OK with all the client info
Is it possible to somehow wait and make sure that all clients sent their info before returning OK?
I implemented the code as suggested like this:
public async Task<ActionResult> GetClientInfo()
{
try
{
var tasks = new List<Task<IEnumerable<ClientInfo>>>();
foreach (var client in cache.Clients.Values)
{
tasks.Add(Task.Run(async () =>
{
return await hubContext.Clients.Client(client.Id).GetClientInfo();
}));
}
var list = await Task.WhenAll(tasks);
return Ok(list);
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
cache is MemoryCache implementation that is available throughout the whole app and is based on code similar to this SO answer.

Client IP Listing and Blocking in SignalR

In Asp.net (core) .net 5, on the SignalR side, how can we list (receive) client IPs and block or allow certain IP's connections and requests by IP?
In my research, I saw that only Azure SingalR was mentioned.
How can we tell SignalR Hub to request Client IPs and accept (whitelist) or block (blacklist) public connection requests from specific IPs by coding in the application?
Is it possible ?
In SignalR you can get the ip of the user with the HttpContext.
public class AppHub : Hub
{
public string Ip => Context.GetHttpContext().Connection.RemoteIpAddress.ToString();
public override async Task OnConnectedAsync()
{
if (Ip == "::1")
{
await Clients.All.SendAsync("ReceiveMessage", "Server", "Welcome to the server!");
}
else
{
throw new Exception("You are not allowed to connect to this server!");
}
await base.OnConnectedAsync();
}
}
Another solution would be to create a hub filter wich you can find the documentation here :
https://learn.microsoft.com/en-us/aspnet/core/signalr/hub-filters?view=aspnetcore-6.0

Azure does not display custom error message for hosted .net core API

I have the following API endpoint:
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Authenticate([FromBody] LoginViewModel credentials)
{
try
{
var result = await _facade.SomeMethodThatFailsAndThrowsCustomCode4001(credentials);
return Ok(result);
}
catch (CustomException cEx)
{
return StatusCode(4001, new { Message = cEx.FriendlyMessage ?? "" }); //Message = Our custom user friendly message
}
}
When hosted on external server through IIS, these messages were returned perfectly. When hosted on Azure, the messages are not showing, and this is the response received:
{
"Message": ""
}
I have read about Policies allowed in on-error, but this means I will need to register my .Net Core API with the API management in Azure, and not sure if this is necessary.
What would be required to be configured to allow our custom messages returned through our API hosted in Azure?
You should read RFC doc about HTTP Status Codes.
1xx: Informational - Request received, continuing process
2xx: Success - The action was successfully received, understood, and accepted
3xx: Redirection - Further action must be taken in order to complete the request
4xx: Client Error - The request contains bad syntax or cannot be fulfilled
5xx: Server Error - The server failed to fulfill an apparently valid request
First, after testing, the upper limit of the usable range of StatusCode is 999. When StatusCode >999, errors will be reported all the time.
Second, you also can handle custom status code in Startup.cs.
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseStatusCodePages(async context =>
{
if (context.HttpContext.Response.StatusCode == 401)
{
await context.HttpContext.Response.WriteAsync("Custom Unauthorized request");
}
});
//other middlewars
Related Post:
1. How can I return custom error message for error status code 401 in .Net Core?
2. How to return a specific status code and no contents from Controller?

How to get something from server using SignalR

I need to create method, which can request to server and return answer. But if I use SignalR, I can run server's method and server will run client's method. But how I can create something like this template?
public Response Request()
{
//???
}
if I use SignalR, I can run server's method and server will run client's method.
If you'd like to invoke hub method from .NET client application in c#, you can refer to the following code snippet.
try
{
HubConnection connection = new HubConnectionBuilder()
.WithUrl("http://localhost:61262/chatHub")
.Build();
await connection.StartAsync();
var mes = "hello";
await connection.InvokeAsync("SendMessage", "Consloe Client", mes);
// await connection.StopAsync();
}
catch (Exception ex)
{
Console.WriteLine("Can not communicate with server now, please retry later.");
}
Hub method
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Besides, to setup Hub and client, please refer to the following articles.
Use hubs in SignalR for ASP.NET Core
ASP.NET Core SignalR .NET Client

Call Web API from MVC Controller Hanging Up

I've tried many different approaches for the past couple of hours, but my method call is hanging up the thread.
Here is my Web API code, which works fine when making AJAX call from the MVC client, but I'm trying to test calling from the server:
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
Below is my MVC controller code and model code:
public async Task<ActionResult> TestApi()
{
try
{
var result = await VoipModels.GetValues();
return MVCUtils.JsonContent(result);
}
catch (Exception ex)
{
return MVCUtils.HandleError(ex);
}
}
...
public static async Task<string[]> GetValues()
{
string[] result = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44305/api/");
//THIS IS THE LINE THAT HANGS UP - I'VE TRIED MANY VARIATIONS
var response = await client.GetAsync("values", HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
result = await response.Content.ReadAsAsync<string[]>();
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
return result;
}
I've used this format successfully when calling a separate, 3rd party API. I've run out of examples to try from my couple of hours of Googling.
What am I doing wrong here?
Check your port number. Based on your code, you have "hard coded" the port "http://localhost:44305/api/" which may likely be incorrect, you should convert that to grab it from the host
configuration instead.
Check your local machine's firewall. Make sure that your local machine's firewall is allowing connections to the port assigned.
Check your protocol. Ensure that you are using http or https appropriately in your request URL.
As a special note, there are very rare cases / exception cases that you would want to have a web API server call itself. Doing so, is rather inefficient design as it will consume resources for no gain (such a generating request and response).

Categories