allow cors on subdomain with reverse proxy in nginx - asp.net-core

As per the MS doc, I need to set up a reverse proxy for my web api. The below is the nginx config with cors & reverse proxy settings:
server {
listen 80;
listen [::]:80;
server_name api.ZZZ.com;
set $cors '';
location / {
if ($http_origin ~ '^https?://(localhost|www\.ZZZ\.com|www\.ZZZ\.com|ZZZ\.com)') {
set $cors 'true';
}
if ($cors = 'true') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,Width,X-Requested-With' always;
# required to be able to read Authorization header in frontend
add_header 'Access-Control-Expose-Headers' 'Authorization' always;
}
if ($request_method = 'OPTIONS') {
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
I also have the following in my startup.cs:
services.AddCors(options =>
{
options.AddPolicy(corsName, builder =>
{
builder.WithOrigins("http://www.ZZZ.com", "http://ZZZ.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
and later:
app.userCors(corsName);
But I am still getting the below CORS error:
Access to XMLHttpRequest at 'http://api.ZZZ.com/YYY' from origin 'http://www.ZZZ.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Please help!

Can you try with SetIsOriginAllowedToAllowWildcardSubdomains configuration and adding wildcard subdomain? like this.
In the ConfigureServices method.
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.SetIsOriginAllowedToAllowWildcardSubdomains()
.WithOrigins("https://*.example.com","https://example.com")
.AllowAnyMethod()
.AllowCredentials()
.AllowAnyHeader()
.Build()
);
});
And in the Configure method
app.UseCors("CorsPolicy");

Related

It is not clear how the CORS policy works for NGINX and ASP.NET Core

Good day. On an Ubuntu 20.04 server, nginx is installed and a daemonized asp.net core web api project is running (serves as a back-end). On the back-end, I enabled the CORS policy and allowed full access to the server, that is, all requests from all origins must go through. However, the requests fail, referring to the CORS policy. Is it possible that the cloud network does not pass? Please tell me what's the matter.
My Program.cs:
`
var builder = WebApplication.CreateBuilder(args);
string connection = builder.Configuration.GetConnectionString("DatabaseConnection");
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(connection));
builder.Services.AddHttpContextAccessor();
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "Standard Authorization header using the Bearer scheme (\"bearer {token}\")",
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
options.OperationFilter<SecurityRequirementsOperationFilter>();
});
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8
.GetBytes(builder.Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
builder.Services.AddCors(options => options.AddPolicy(name: "NgOrigins",
policy =>
{
policy.WithOrigins("http://[website adress what i need]", "http://localhost:8080", "http://[website ip adress]", "http://[website ip adress]:7000").AllowAnyMethod().AllowAnyHeader();
}));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors("NgOrigins");
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
`
My current config for back-end:
server {
listen 81;
server_name [server domain name];
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Cont> #
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Cont> add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Cont> add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
I tried adding special add-ons to /etc/nginx/sites-enabled/default and /etc/nginx/sites-aviable/default after location (default in this case is the back-end configuration of the project):
`
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
`

CORS block only localhost request

I have a problem with my server developed in EXPRESS and hosted on NGINX.
I use passport.js for user authentication, even if I don't think this is the problem, and when I try to login from localhost I get an error while if I run it by uploading it to my domain I don't get it wrong and it works correctly, so I think it's a CORS problem blocking localhost requests.
NGINX default
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name api.mysite.com www.api.mysite.com;
location / {
proxy_pass https://localhost:3007; #whatever port your app runs on
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
if ($http_origin ~* (^https?://([^/]+\.)*(mysite)\.com$)) {
set $cors "true";
}
if ($http_origin ~* (^http?://([^/]+\.)*(localhost:3006))) {
set $cors "true";
}
if ($http_origin ~* (^https?://([^/]+\.)*(192.168.1.21:3006))) {
set $cors "true";
}
# Nginx doesn't support nested If statements. This is where things get slightly nasty.
# Determine the HTTP request method used
if ($request_method = 'OPTIONS') {
set $cors "${cors}options";
}
if ($request_method = 'GET') {
set $cors "${cors}get";
}
if ($request_method = 'POST') {
set $cors "${cors}post";
}
if ($cors = "true") {
# Catch all incase there's a request method we're not dealing with properly
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
if ($cors = "trueget") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($cors = "trueoptions") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($cors = "truepost") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
serverDev.js
const sessionParser = session({
saveUninitialized: false,
secret: 'secret',
resave: false,
cookie: {expires: 43200000, secure: false }
})
var privateKey = fs.readFileSync('ssl-cert/privkey.pem', 'utf8');
var certificate = fs.readFileSync('ssl-cert/fullchain.pem', 'utf8');
var credentials = { key: privateKey, cert: certificate };
var httpsServer = https.createServer(credentials,app);
routes.js
app.post('/Login', passport.authenticate('local-login', {
successRedirect : '/Profile',
failureRedirect : '/Login',
failureFlash : false
}),
function(req, res) {
if (req.body.remember) {
req.session.cookie.maxAge = 1000 * 60 * 3;
} else {
req.session.cookie.expires = false;
}
res.redirect('/Login');
});
app.get('/Profile', isLoggedIn, todoList.profile);
function isLoggedIn(req, res, next) {
console.log("isLoggedIn",req.isAuthenticated()) <--- THIS IS THE PROBLEM IN LOCALHOST RETURN ALWAYS FALSE
if (req.isAuthenticated())
return next();
res.redirect('/Login');
}
passport.js
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("use `Users`");
connection.query("SELECT * FROM Accounts WHERE id = ? ",[id], function(err, rows){
if (err){
return done(err);
}
var user = rows[0];
done(err, user);
});
});
If anyone else had this problem I solved it by configuring the 'express-session' in this way
var session = require('express-session');
const sessionParser = session({
secret: 'your-secret',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'none',
maxAge: 1000 * 60 * 60 * 12 // milliseconds * seconds * minutes * hours
}
})

Nginx reverse proxy using auth_request module and external authentication API - error 404

I am trying to configure nginx as a reverse proxy to protect another server (kibana) using an external authentication API.
This is the url that should log me into kibana dashboard - http://127.0.0.1/kibana_proxy?username=my.user&password=test67
Once the authentication done (i.e. https status 200), nginx is throwing a 404 error. But the error log has this -
2018/10/18 13:33:52 [error] 10718#0: *19 open()
"/usr/share/nginx/html/app/kibana" failed (2: No such file or
directory), client: 127.0.0.1, server: _, request: "GET /app/kibana
HTTP/1.1", host: "127.0.0.1", referrer:
"http://127.0.0.1/kibana_proxy/?username=my.user&password=test67"
This is my nginx conf file -
server {
listen *:80;
server_name _;
location = /auth {
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
proxy_pass http://127.0.0.1:8080/auth?$query;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location /kibana_proxy/ {
proxy_pass http://127.0.0.1:5601/;
auth_request /auth;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
Whenever you are using Restricting Access with HTTP Basic Authentication then you should use the following url pattern to access the restricted url
http://username:password#example.com/
It is not possible to pass username and password via query parameters in standard HTTP auth.
Update:
I feel your nginx settings needs some update. You should rewrite the url to remove the /kibana_proxy/:
location /kibana_proxy/
{
rewrite ^/kibana_proxy/(.*) /$1 break;
proxy_pass http://localhost:5200;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
For those seeking answer - here's the nginx server conf that solved the issue for me -
server {
listen *:80;
server_name 127.0.0.1;
location = /auth {
set $query '';
if ($request_uri ~* "[^\?]+\?(.*)$") {
set $query $1;
}
# add_header X-debug-message "Parameters being passed $is_args$args" always;
proxy_pass http://127.0.0.1:8080/auth?$query;
}
location /kibana/ {
rewrite ^/kibana/(.*) /$1 break;
proxy_pass http://127.0.0.1:5601;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
auth_request /auth;
}
location ~ (/app/|/app/kibana|/bundles/|/kibana4|/status|/plugins|/ui/|/api/|/monitoring/|/elasticsearch/) {
proxy_pass http://127.0.0.1:5601;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
rewrite /kibana4/(.*)$ /$1 break;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

Nginx proxy pass 404 error - CORS

I have configured a proxy_pass for an JAVA web service to enable cross origin. I can send a post request using the web service URL http://10.1.200.156:8080/ClientService/passwordReset/, but http://10.1.200.156/ClientService/passwordReset/ gives a 404 error. And client application gives, Response for preflight is invalid (redirect).
After searching the web I added proxy_set_header Host $http_host; to the Nginx configuration, but still no luck. Below, the Nginx configuration. Please help.
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name euca-172-16-10-214.eucalyptus.internal;
location /ClientService/passwordReset/ {
proxy_pass http://10.1.200.156:8080/ClientService/passwordReset/;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
#add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
}
}
You shouldn't include the URI when you're proxying. Try the following:
proxy_pass http://10.1.200.156:‌​8080;

nginx won't restart with my config file

Restarting nginx :
# service nginx start
Starting nginx: nginx: [emerg] duplicate upstream "api" in /etc/nginx/sites-enabled/default:1
nginx: configuration file /etc/nginx/nginx.conf test failed
This is the config file :
upstream api{
least_conn;
server 127.0.0.1:5001 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5002 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5003 max_fails=2 fail_timeout=15s;
server 127.0.0.1:5004 max_fails=2 fail_timeout=15s;
}
server {
listen 192.168.10.33:80;
allow 192.168.0.0/20;
allow 127.0.0.1/32;
deny all;
server_name api api.my.intranet;
location ^~ (/images/|/css/|/javascripts/) {
root /var/www/myapi/public/;
expires 30m;
}
# serve all other stuff from appserver
location / {
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://api/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
}
}
server {
listen 175.30.33.14:80;
server_name api.my.com;
return 301 https://api.my.com$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /etc/ssl/certs/my.com.2014.chain;
ssl_certificate_key /etc/ssl/private/my.com.2014.key;
server_tokens off;
server_name api api.my.com api.my.intranet;
location ^~ (/images/|/css/|/javascripts/) {
root /var/www/myapi/public/;
expires 30d;
}
# serve all other stuff from appserver
location / {
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://api/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
}
location /v2 {
rewrite ^/v2/(.*) /$1 break;
if ($http_origin ~ (.*\.my\.intranet|.*\.my\.com) ) {
add_header 'Access-Control-Allow-Origin' $http_origin;
}
# add_header 'Access-Control-Allow-Origin' '*';
expires off;
proxy_pass http://192.168.10.8:3000/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Do you see any problem ?
a backup file: defuault.backup was in the same folder which created a conflict !