diff --git a/src/nginxconfig.ejs b/src/nginxconfig.ejs index 861e130df..8cda1c02b 100644 --- a/src/nginxconfig.ejs +++ b/src/nginxconfig.ejs @@ -258,6 +258,9 @@ server { } location @proxy-auth-login { + if ($http_user_agent ~* "docker-client") { + return 401; + } return 302 /login?redirect=$request_uri; } diff --git a/src/proxyauth.js b/src/proxyauth.js index deb29b304..2192b39ad 100644 --- a/src/proxyauth.js +++ b/src/proxyauth.js @@ -99,9 +99,23 @@ function loginPage(req, res, next) { }); } -// called by nginx to authorize any protected route +// someday this can be more sophisticated and check for a real browser +function isBrowser(req) { + const userAgent = req.get('user-agent'); + if (!userAgent) return false; + + return !userAgent.toLowerCase().includes('docker-client'); +} + +// called by nginx to authorize any protected route. this route must return only 2xx or 401/403 (http://nginx.org/en/docs/http/ngx_http_auth_request_module.html) function auth(req, res, next) { - if (!req.user) return next(new HttpError(401, 'Unauthorized')); + if (!req.user) { + if (isBrowser(req)) return next(new HttpError(401, 'Unauthorized')); + + // the header has to be generated here and cannot be set in nginx config - https://forum.nginx.org/read.php?2,171461,171469#msg-171469 + res.set('www-authenticate', 'Basic realm="Cloudron"'); + return next(new HttpError(401, 'Unauthorized')); + } // user is already authenticated, refresh cookie const token = jwt.sign({ user: req.user }, TOKEN_SECRET, { expiresIn: `${EXPIRY_DAYS}d` });