Display error when HTTP authentication isn't configured

Its a common installation failure to set auth.type = HTTP, but
then not configure the reverse proxy server or servlet container
to actually perform the user authentication.

Help the new administrator out by telling them what might be wrong,
and display an example Apache configuration block they can use to
get things working.

Change-Id: I8523bdd80be74cd7ce3b8f94c91cdd3a6cab3853
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce 2010-05-11 13:16:52 -07:00
parent 7dcb1e925f
commit f13d3d6861
2 changed files with 125 additions and 4 deletions

View File

@ -15,6 +15,7 @@
package com.google.gerrit.httpd.auth.container;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
@ -29,11 +30,16 @@ import com.google.inject.Singleton;
import org.eclipse.jgit.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.IOException;
import javax.annotation.Nullable;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -79,11 +85,35 @@ class HttpLoginServlet extends HttpServlet {
return;
}
rsp.setHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
rsp.setHeader("Pragma", "no-cache");
rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
final String user = getRemoteUser(req);
if (user == null || "".equals(user)) {
log.error("Unable to authenticate user by " + loginHeader
+ " request header. Check container or server configuration.");
rsp.sendError(HttpServletResponse.SC_FORBIDDEN);
final Document doc = HtmlDomUtil.parseFile( //
HttpLoginServlet.class, "ConfigurationError.html");
replace(doc, "loginHeader", loginHeader);
replace(doc, "ServerName", req.getServerName());
replace(doc, "ServerPort", ":" + req.getServerPort());
replace(doc, "ContextPath", req.getContextPath());
final byte[] bin = HtmlDomUtil.toUTF8(doc);
rsp.setStatus(HttpServletResponse.SC_FORBIDDEN);
rsp.setContentType("text/html");
rsp.setCharacterEncoding("UTF-8");
rsp.setContentLength(bin.length);
final ServletOutputStream out = rsp.getOutputStream();
try {
out.write(bin);
} finally {
out.flush();
out.close();
}
return;
}
@ -107,12 +137,32 @@ class HttpLoginServlet extends HttpServlet {
rdr.append(token);
webSession.get().login(arsp, false);
rsp.setHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");
rsp.setHeader("Pragma", "no-cache");
rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
rsp.sendRedirect(rdr.toString());
}
private void replace(Document doc, String name, String value) {
Element e = HtmlDomUtil.find(doc, name);
if (e != null) {
e.setTextContent(value);
} else {
replaceByClass(doc, name, value);
}
}
private void replaceByClass(Node parent, String name, String value) {
final NodeList list = parent.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
final Node n = list.item(i);
if (n instanceof Element) {
final Element e = (Element) n;
if (name.equals(e.getAttribute("class"))) {
e.setTextContent(value);
}
}
replaceByClass(n, name, value);
}
}
private String getToken(final HttpServletRequest req) {
String token = req.getPathInfo();
if (token != null && token.startsWith("/")) {

View File

@ -0,0 +1,71 @@
<html>
<head>
<title>Configuration Error - Gerrit Code Review</title>
<style>
.check_msg {
background: orange;
padding: 20px;
width: 25em;
}
.apache_config {
font-size: small;
border: 1px dotted black;
width: 40em;
margin-left: 5em;
padding: 1em;
}
.apache_auth {
background: lightgrey;
}
#loginHeader {
font-weight: bold;
background: lightgrey;
padding-left: 5px;
padding-right: 5px;
}
</style>
</head>
<body>
<h1>Configuration Error</h1>
<div class='check_msg'>
<b>Check the HTTP server's authentication settings.</b>
</div>
<p>
The HTTP server did not provide the username in the
<span id='loginHeader'>HEADER</span> header when it
forwarded the request to Gerrit Code Review.
</p>
<p>
If the HTTP server is Apache HTTPd, check the proxy
configuration includes an authorization directive with
the proper location, ensuring it ends with '/':
</p>
<pre class='apache_config'>
&lt;VirtualHost <span class='ServerName'>review.example.com</span><span class='ServerPort'>:80</span>&gt;
ServerName <span class='ServerName'>review.example.com</span>
ProxyRequests Off
ProxyVia Off
ProxyPreserveHost On
&lt;Proxy *&gt;
Order deny,allow
Allow from all
&lt;/Proxy&gt;
<div class='apache_auth'> &lt;Location <span class='ContextPath'>/r</span>/login/&gt;
AuthType Basic
AuthName "Gerrit Code Review"
Require valid-user
...
&lt;/Location&gt;</div>
ProxyPass <span class='ContextPath'>/r</span>/ http://...<span class='ContextPath'>/r</span>/
&lt;/VirtualHost&gt;
</pre>
</body>
</html>