EDIT I THINK THE ISSUE MUST BE MY BACK END CODE url configurations, e.g. look at this: webBuilder.UseUrls("http://*:5002")
(I since changed to webBuilder.UseUrls("https://*:5002")
although not working. surely the port 5002 has to match up with my listener????
Here it all is:
program.cs:
namespace Vepo.Web
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("http://*:5002");
});
}
}
Startup.cs:
namespace Vepo.Web
{
public class Startup
{
private class CustomTransformer : HttpTransformer
{
public override async ValueTask TransformRequestAsync(HttpContext httpContext,
HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
{
// Copy all request headers
await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
// Customize the query string:
var queryContext = new QueryTransformContext(httpContext.Request);
// Assign the custom uri. Be careful about extra slashes when concatenating here. RequestUtilities.MakeDestinationAddress is a safe default.
proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("https://maps.googleapis.com/maps/api", httpContext.Request.Path, queryContext.QueryString);
// Suppress the original request header, use the one from the destination Uri.
proxyRequest.Headers.Host = null;
}
}
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Env = env;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment Env { get; }
public void ConfigureServices(IServiceCollection services)
{
services
.AddDbContext<VepoContext>(opt =>
{
opt
.UseNpgsql(
Configuration
.GetConnectionString("DefaultConnection"),
o => o.UseNetTopologySuite()
)
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.LogTo(Console.WriteLine);
});
services.AddHttpContextAccessor();
services.AddHttpForwarder();
services.AddTransient<UserResolverService>();
services.AddTransient<ExtendedVepoContext>();
services.AddControllers().AddJsonOptions(opt =>
{
opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
opt.JsonSerializerOptions.Converters.Add(new GeoJsonConverterFactory());
});
services.AddControllers(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).AddNewtonsoftJson(x =>
{
x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
x.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
}).AddJsonOptions(opt =>
{
opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
if (Env.IsDevelopment())
{
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("firebase_admin_sdk_development.json"),
},
"vepo-dev-e5b8a"
);
}
if (Env.IsQa())
{
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("firebase_admin_sdk_qa.json"),
},
"vepo-qa");
}
var claims = new Dictionary<string, object>
{
{ ClaimTypes.Role, "User" }
};
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = Configuration["FirebaseAuthority"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = Configuration["FirebaseAuthority"],
ValidateAudience = true,
ValidAudience = Configuration["FirebaseProjectId"],
ValidateLifetime = true
};
});
services.AddMvc().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
});
services.AddScoped(typeof(IGroceryItmEstsRepository), typeof(GroceryItmEstsRepository));
services.AddScoped(typeof(IAllVgnItmEstsRepository), typeof(AllVgnItmEstsRepository));
services.AddScoped(typeof(IEventItmEstsRepository), typeof(EventItmEstsRepository));
services.AddScoped(typeof(IFashionItmEstsRepository), typeof(FashionItmEstsRepository));
services.AddScoped(typeof(IRecipeItmEstsRepository), typeof(RecipeItmEstsRepository));
services.AddScoped(typeof(IGroceryStoreItmEstsRepository), typeof(GroceryStoreItmEstsRepository));
services.AddScoped(typeof(IRestaurantItmEstsRepository), typeof(RestaurantItmEstsRepository));
services.AddScoped(typeof(IUsersRepository), typeof(UsersRepository));
services.AddScoped(typeof(IBookMarksRepository), typeof(BookMarksRepository));
services.AddScoped(typeof(IGroceryItmsRepository), typeof(GroceryItmsRepository));
services.AddScoped(typeof(IEventItmsRepository), typeof(EventItmsRepository));
services.AddScoped(typeof(IFashionItmsRepository), typeof(FashionItmsRepository));
services.AddScoped(typeof(IRecipeItmsRepository), typeof(RecipeItmsRepository));
services.AddScoped(typeof(IGroceryStoreItmsRepository), typeof(GroceryStoreItmsRepository));
services.AddScoped(typeof(IRestaurantItmsRepository), typeof(RestaurantItmsRepository));
services.AddScoped(typeof(IMenuItmsRepository), typeof(MenuItmsRepository));
services.AddScoped<IUsersService, UsersService>();
services.AddScoped<IBookMarksService, BookMarksService>();
services.AddScoped<IMenuItmEstsService, MenuItmEstsService>();
services.AddScoped<IGroceryStoreItmEstsService, GroceryStoreItmEstsService>();
services.AddScoped<IRestaurantItmEstsService, RestaurantItmEstsService>();
services.AddScoped<IEventItmEstsService, EventItmEstsService>();
services.AddScoped<IFashionItmEstsService, FashionItmEstsService>();
services.AddScoped<IRecipeItmEstsService, RecipeItmEstsService>();
services.AddScoped<IGroceryItmEstsService, GroceryItmEstsService>();
services.AddScoped<IAllVgnItmEstsService, AllVgnItmEstsService>();
services.AddScoped<IMenuItmsService, MenuItmsService>();
services.AddScoped<IGroceryStoreItmsService, GroceryStoreItmsService>();
services.AddScoped<IRestaurantItmsService, RestaurantItmsService>();
services.AddScoped<IEventItmsService, EventItmsService>();
services.AddScoped<IFashionItmsService, FashionItmsService>();
services.AddScoped<IRecipeItmsService, RecipeItmsService>();
services.AddScoped<IGroceryItmsService, GroceryItmsService>();
services.AddScoped(typeof(IMenuItmEstsRepository), typeof(MenuItmEstsRepository));
services.AddScoped<ISearchService, SearchService>(serviceProvider =>
{
return new SearchService(
Configuration["openSearchEndpoint"],
Configuration["openSearchUsername"],
Configuration["openSearchPassword"],
Configuration["openSearchIndexName"]);
});
var x = Configuration["openSearchEndpoint"];
services.AddScoped<IGroceryItmsSearchIndexService, GroceryItmsSearchIndexService>();
services.AddScoped<IRecipeItmsSearchIndexService, RecipeItmsSearchIndexService>();
services.AddScoped<IEventItmsSearchIndexService, EventItmsSearchIndexService>();
services.AddScoped<IFashionItmsSearchIndexService, FashionItmsSearchIndexService>();
services.AddScoped<IMenuItmsSearchIndexService, MenuItmsSearchIndexService>();
services.AddScoped<IRestaurantItmsSearchIndexService, RestaurantItmsSearchIndexService>();
services.AddScoped<IGroceryStoreItmsSearchIndexService, GroceryStoreItmsSearchIndexService>();
services.AddScoped<IAllVgnItmsSearchIndexService, AllVgnItmsSearchIndexService>();
services.AddAutoMapper(
typeof(EstProfile),
typeof(VgnItmEstProfile),
typeof(VgnItmProfile),
typeof(EventItmEstProfile),
typeof(EventItmProfile),
typeof(FashionItmEstProfile),
typeof(FashionItmProfile),
typeof(RecipeItmEstProfile),
typeof(RecipeItmProfile),
typeof(GroceryItmEstProfile),
typeof(GroceryItmProfile),
typeof(GroceryStoreItmEstProfile),
typeof(GroceryStoreItmProfile),
typeof(RestaurantItmEstProfile),
typeof(RestaurantItmProfile),
typeof(MenuItmEstProfile),
typeof(MenuItmProfile));
services.AddSwaggerGen();
}
[Obsolete]
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
VepoContext context,
IGroceryItmsSearchIndexService searchIndexService,
IHttpForwarder forwarder//,
/*ILogger logger*/)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(options =>
{
options.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite();
app.UseAuthentication();
app.UseAuthorization();
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
});
var transformer = new CustomTransformer(); // or HttpTransformer.Default;
var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
RequestDelegate googleMapsApi = async httpContext =>
{
var error = await forwarder.SendAsync(httpContext, "https://maps.googleapis.com/maps/api/",
httpClient, requestConfig, transformer);
// Check if the operation was successful
if (error != ForwarderError.None)
{
var errorFeature = httpContext.GetForwarderErrorFeature();
var exception = errorFeature.Exception;
}
};
endpoints.Map("/place/{**catch-all}", googleMapsApi);
endpoints.Map("/geocode/{**catch-all}", googleMapsApi);
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Test1 Api v1");
});
searchIndexService.ReIndex(context, SearchIndexes.All);
}
}
public static class HostEnvironmentExtensions
{
public static bool IsQa(this IHostEnvironment hostingEnvironment)
{
return hostingEnvironment.IsEnvironment("Qa");
}
}
}
EDIT: Once my server is HTTPS, does it mean my front end on localhost has to be served via https to talk to it? As mine is http://localhost:62650
I'm trying to make my single instance Elastic Beanstalk environment for my asp.net core back end hosted on Linux use HTTPS via converting to being load balanced and having a certificate.
However, when I try to hit the endpoint from my front end, it stays pending and then fails after my 200-second timeout in my front end. These requests take 2 seconds with a single instance un-load-balanced elastic beanstalk.
When I change it back to single instance, not load balanced, it works again.
It is currently reachable from my front end (when the front end is hosted on HTTP at http://localhost:57276/) and the beanstalk back end is at http://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:5002. But I am getting a blocked mixed content issue when I host the front end on HTTPS which I need to do. So I need to go from this http://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:5002 to https://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:5002 OR into a completely different url that uses HTTPS like https://vepo-qa.com.
I have created a domain in Route 53 for vepo-qa.com and a certificate in the AWS Certificate Manager console, valid for the domain vepo-qa.com and *.vepo-qa.com, and it is issued. Here are the route 53 records:
In order to use my certificate, I have converted my Elastic Beanstalk environment from single instance to load balanced and added an HTTPS listener based on the recommended settings for the docs:
If my URL was http://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:**5002** do I need to have 5002 as one of the ports in the listener? My back-end code has this which only allows port 5002 webBuilder.UseUrls("http://*:5002");
should I be adding other ports that are already in my listener to this back-end line of code?
Is simply assigning the certificate to the listener enough to make the server capable of HTTPS protocol, or do I need to enter a private key into my back-end code base or add config files like these?
.ebextensions/
securelistener-alb.config:
option_settings:
aws:elbv2:listener:443:
ListenerEnabled: 'true'
https-instance-securitygroup.config:
Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 443
FromPort: 443
CidrIp: 0.0.0.0/0
sg-ingressfromlb.config:
Resources:
sslSecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
IpProtocol: tcp
ToPort: 1000
FromPort: 1000
SourceSecurityGroupName: {"Fn::GetAtt" : ["AWSEBLoadBalancer" , "SourceSecurityGroup.GroupName"]}
Am I supposed to change my URL in the front-end app HTTP request from
http://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:5002
to
https://vepo-qa-env.eba-xxx.ap-southeast-2.elasticbeanstalk.com:5002
or to
And if so, do I need to somehow let my elastic beanstalk environment know about https://vepo-qa.com?
Here are some of my AWS configurations in case they are relevant:
EDIT btw I also tried an AWS expert and it didn't get my app https requests working from my front end. So maybe it is a .net issue. I asked about the asp.net parts of this question over here, where I seem to have made progress because I am now hitting my back end at https://vepo-qa.com from the front end at a firebase https address and getting a CORS error.