Support creating new users in DEVELOPMENT_BECOME_ANY_ACCOUNT
Under development mode it can be useful to construct a new user account anytime, without needing to manually inject records in the database or switch temporarily to LDAP or OpenID methods. Because we don't really have an external identity for the user we given them a random one via the JRE's UUID generator. New account creation should be infrequent enough in development to never run into a collision. Change-Id: Id15ddc34ef7bfa5cea6d12c435cb09b8443c77fd Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -14,10 +14,16 @@
|
||||
|
||||
package com.google.gerrit.httpd.auth.become;
|
||||
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gerrit.httpd.HtmlDomUtil;
|
||||
import com.google.gerrit.httpd.WebSession;
|
||||
import com.google.gerrit.reviewdb.Account;
|
||||
import com.google.gerrit.reviewdb.AccountExternalId;
|
||||
import com.google.gerrit.reviewdb.ReviewDb;
|
||||
import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.account.AuthRequest;
|
||||
import com.google.gerrit.server.account.AuthResult;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.gerrit.server.config.Nullable;
|
||||
import com.google.gwtorm.client.OrmException;
|
||||
@@ -33,8 +39,8 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
@@ -49,16 +55,19 @@ public class BecomeAnyAccountLoginServlet extends HttpServlet {
|
||||
private final SchemaFactory<ReviewDb> schema;
|
||||
private final Provider<WebSession> webSession;
|
||||
private final Provider<String> urlProvider;
|
||||
private final AccountManager accountManager;
|
||||
private final byte[] raw;
|
||||
|
||||
@Inject
|
||||
BecomeAnyAccountLoginServlet(final Provider<WebSession> ws,
|
||||
final SchemaFactory<ReviewDb> sf,
|
||||
final @CanonicalWebUrl @Nullable Provider<String> up,
|
||||
final ServletContext servletContext) throws IOException {
|
||||
final AccountManager am, final ServletContext servletContext)
|
||||
throws IOException {
|
||||
webSession = ws;
|
||||
schema = sf;
|
||||
urlProvider = up;
|
||||
accountManager = am;
|
||||
|
||||
final String pageName = "BecomeAnyAccount.html";
|
||||
final Document doc = HtmlDomUtil.parseFile(getClass(), pageName);
|
||||
@@ -87,15 +96,18 @@ public class BecomeAnyAccountLoginServlet extends HttpServlet {
|
||||
rsp.setHeader("Pragma", "no-cache");
|
||||
rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
|
||||
|
||||
final List<Account> accounts;
|
||||
if (req.getParameter("ssh_user_name") != null) {
|
||||
accounts = bySshUserName(rsp, req.getParameter("ssh_user_name"));
|
||||
final AuthResult res;
|
||||
if ("create_account".equals(req.getParameter("action"))) {
|
||||
res = create();
|
||||
|
||||
} else if (req.getParameter("ssh_user_name") != null) {
|
||||
res = bySshUserName(rsp, req.getParameter("ssh_user_name"));
|
||||
|
||||
} else if (req.getParameter("preferred_email") != null) {
|
||||
accounts = byPreferredEmail(rsp, req.getParameter("preferred_email"));
|
||||
res = byPreferredEmail(rsp, req.getParameter("preferred_email"));
|
||||
|
||||
} else if (req.getParameter("account_id") != null) {
|
||||
accounts = byAccountId(rsp, req.getParameter("account_id"));
|
||||
res = byAccountId(rsp, req.getParameter("account_id"));
|
||||
|
||||
} else {
|
||||
rsp.setContentType("text/html");
|
||||
@@ -110,10 +122,17 @@ public class BecomeAnyAccountLoginServlet extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
|
||||
if (accounts.size() == 1) {
|
||||
final Account account = accounts.get(0);
|
||||
webSession.get().login(account.getId(), false);
|
||||
rsp.sendRedirect(urlProvider.get());
|
||||
if (res != null) {
|
||||
webSession.get().login(res.getAccountId(), false);
|
||||
final StringBuilder rdr = new StringBuilder();
|
||||
rdr.append(urlProvider.get());
|
||||
rdr.append('#');
|
||||
if (res.isNew()) {
|
||||
rdr.append(PageLinks.REGISTER);
|
||||
rdr.append(',');
|
||||
}
|
||||
rdr.append(PageLinks.MINE);
|
||||
rsp.sendRedirect(rdr.toString());
|
||||
|
||||
} else {
|
||||
rsp.setContentType("text/html");
|
||||
@@ -128,58 +147,69 @@ public class BecomeAnyAccountLoginServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private List<Account> bySshUserName(final HttpServletResponse rsp,
|
||||
private AuthResult auth(final Account account) {
|
||||
return account != null ? new AuthResult(account.getId(), false) : null;
|
||||
}
|
||||
|
||||
private AuthResult bySshUserName(final HttpServletResponse rsp,
|
||||
final String userName) {
|
||||
try {
|
||||
final ReviewDb db = schema.open();
|
||||
try {
|
||||
final Account account = db.accounts().bySshUserName(userName);
|
||||
return account != null ? Collections.<Account> singletonList(account)
|
||||
: Collections.<Account> emptyList();
|
||||
return auth(db.accounts().bySshUserName(userName));
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch (OrmException e) {
|
||||
getServletContext().log("cannot query database", e);
|
||||
return Collections.<Account> emptyList();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Account> byPreferredEmail(final HttpServletResponse rsp,
|
||||
private AuthResult byPreferredEmail(final HttpServletResponse rsp,
|
||||
final String email) {
|
||||
try {
|
||||
final ReviewDb db = schema.open();
|
||||
try {
|
||||
return db.accounts().byPreferredEmail(email).toList();
|
||||
List<Account> matches = db.accounts().byPreferredEmail(email).toList();
|
||||
return matches.size() == 1 ? auth(matches.get(0)) : null;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch (OrmException e) {
|
||||
getServletContext().log("cannot query database", e);
|
||||
return Collections.<Account> emptyList();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Account> byAccountId(final HttpServletResponse rsp,
|
||||
private AuthResult byAccountId(final HttpServletResponse rsp,
|
||||
final String idStr) {
|
||||
final Account.Id id;
|
||||
try {
|
||||
id = Account.Id.parse(idStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return Collections.<Account> emptyList();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final ReviewDb db = schema.open();
|
||||
try {
|
||||
final Account account = db.accounts().get(id);
|
||||
return account != null ? Collections.<Account> singletonList(account)
|
||||
: Collections.<Account> emptyList();
|
||||
return auth(db.accounts().get(id));
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
} catch (OrmException e) {
|
||||
getServletContext().log("cannot query database", e);
|
||||
return Collections.<Account> emptyList();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private AuthResult create() {
|
||||
String fakeId = AccountExternalId.SCHEME_UUID + UUID.randomUUID();
|
||||
try {
|
||||
return accountManager.authenticate(new AuthRequest(fakeId));
|
||||
} catch (AccountException e) {
|
||||
getServletContext().log("cannot create new account", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,22 +31,44 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form method="GET">
|
||||
<b>ssh_user_name:</b>
|
||||
<input type="text" size="30" name="ssh_user_name" />
|
||||
<input type="submit" value="Become Account" />
|
||||
</form>
|
||||
<h2>Sign In</h2>
|
||||
<table border="0">
|
||||
<tr>
|
||||
<th>SSH Username:</th>
|
||||
<td>
|
||||
<form method="GET">
|
||||
<input type="text" size="30" name="ssh_user_name" />
|
||||
<input type="submit" value="Become Account" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<form method="GET">
|
||||
<b>preferred_email:</b>
|
||||
<input type="text" size="30" name="preferred_email" />
|
||||
<input type="submit" value="Become Account" />
|
||||
</form>
|
||||
<tr>
|
||||
<th>Email Address:</th>
|
||||
<td>
|
||||
<form method="GET">
|
||||
<input type="text" size="30" name="preferred_email" />
|
||||
<input type="submit" value="Become Account" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<form method="GET">
|
||||
<b>account_id:</b>
|
||||
<input type="text" size="12" name="account_id" />
|
||||
<input type="submit" value="Become Account" />
|
||||
<tr>
|
||||
<th>Account ID:</th>
|
||||
<td>
|
||||
<form method="GET">
|
||||
<input type="text" size="12" name="account_id" />
|
||||
<input type="submit" value="Become Account" />
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
<h2>Register</h2>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="create_account" />
|
||||
<input type="submit" value="New Account" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Collection;
|
||||
/** Association of an external account identifier to a local {@link Account}. */
|
||||
public final class AccountExternalId {
|
||||
public static final String SCHEME_GERRIT = "gerrit:";
|
||||
public static final String SCHEME_UUID = "uuid:";
|
||||
public static final String SCHEME_MAILTO = "mailto:";
|
||||
public static final String LEGACY_GAE = "Google Account ";
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public class AuthResult {
|
||||
private final Account.Id accountId;
|
||||
private final boolean isNew;
|
||||
|
||||
AuthResult(final Account.Id accountId, final boolean isNew) {
|
||||
public AuthResult(final Account.Id accountId, final boolean isNew) {
|
||||
this.accountId = accountId;
|
||||
this.isNew = isNew;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,13 @@ public class AuthConfig {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (id.isScheme(AccountExternalId.SCHEME_UUID)) {
|
||||
// UUID identities are absolutely meaningless and cannot be
|
||||
// constructed through any normal login process we use.
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
for (final String p : trusted) {
|
||||
if (matches(p, id)) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user