Remove auth token based REST API support
This never turned into a real implementation. Drop it and
look at other ways to do authentication.
Change-Id: I404c834e5e9d0d61248d28471785d825c136f3ad
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
index 650cacd..35aea60 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/rpc/RestApi.java
@@ -44,11 +44,9 @@
private class MyRequestCallback<T extends JavaScriptObject> implements
RequestCallback {
- private final boolean wasGet;
private final AsyncCallback<T> cb;
- public MyRequestCallback(boolean wasGet, AsyncCallback<T> cb) {
- this.wasGet = wasGet;
+ MyRequestCallback(AsyncCallback<T> cb) {
this.cb = cb;
}
@@ -79,11 +77,6 @@
}
json = json.substring(JSON_MAGIC.length());
- if (wasGet && json.startsWith("{\"_authkey\":")) {
- RestApi.this.resendPost(cb, json);
- return;
- }
-
T data;
try {
// javac generics bug
@@ -168,7 +161,7 @@
public <T extends JavaScriptObject> void send(final AsyncCallback<T> cb) {
RequestBuilder req = new RequestBuilder(RequestBuilder.GET, url.toString());
req.setHeader("Accept", JsonConstants.JSON_TYPE);
- req.setCallback(new MyRequestCallback<T>(true, cb));
+ req.setCallback(new MyRequestCallback<T>(cb));
try {
RpcStatus.INSTANCE.onRpcStart();
req.send();
@@ -178,21 +171,6 @@
}
}
- private <T extends JavaScriptObject> void resendPost(
- final AsyncCallback<T> cb, String token) {
- RequestBuilder req = new RequestBuilder(RequestBuilder.POST, url.toString());
- req.setHeader("Accept", JsonConstants.JSON_TYPE);
- req.setHeader("Content-Type", JsonConstants.JSON_TYPE);
- req.setRequestData(token);
- req.setCallback(new MyRequestCallback<T>(false, cb));
- try {
- req.send();
- } catch (RequestException e) {
- RpcStatus.INSTANCE.onRpcComplete();
- cb.onFailure(e);
- }
- }
-
private static boolean isJsonBody(Response res) {
return isContentType(res, JsonConstants.JSON_TYPE);
}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RestTokenVerifier.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RestTokenVerifier.java
deleted file mode 100644
index 783ebc7..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RestTokenVerifier.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd;
-
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.mail.RegisterNewEmailSender;
-
-/** Verifies the token sent by {@link RegisterNewEmailSender}. */
-public interface RestTokenVerifier {
- /**
- * Construct a token to verify a REST PUT request.
- *
- * @param user the caller that wants to make a PUT request
- * @param url the URL being requested
- * @return an unforgeable string to send to the user as the body of a GET
- * request. Presenting the string in a follow-up POST request provides
- * proof the user has the ability to read messages sent to thier
- * browser and they likely aren't making the request via XSRF.
- */
- public String sign(Account.Id user, String url);
-
- /**
- * Decode a token previously created.
- *
- * @param user the user making the verify request.
- * @param url the url user is attempting to access.
- * @param token the string created by sign.
- * @throws InvalidTokenException the token is invalid, expired, malformed,
- * etc.
- */
- public void verify(Account.Id user, String url, String token)
- throws InvalidTokenException;
-
- /** Exception thrown when a token does not parse correctly. */
- public static class InvalidTokenException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public InvalidTokenException() {
- super("Invalid token");
- }
-
- public InvalidTokenException(Throwable cause) {
- super("Invalid token", cause);
- }
- }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/SignedTokenRestTokenVerifier.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/SignedTokenRestTokenVerifier.java
deleted file mode 100644
index 83d6caa..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/SignedTokenRestTokenVerifier.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd;
-
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.config.AuthConfig;
-import com.google.gwtjsonrpc.server.SignedToken;
-import com.google.gwtjsonrpc.server.ValidToken;
-import com.google.gwtjsonrpc.server.XsrfException;
-import com.google.inject.AbstractModule;
-import com.google.inject.Inject;
-
-import org.eclipse.jgit.util.Base64;
-
-import java.io.UnsupportedEncodingException;
-
-/** Verifies the token sent by {@link RestApiServlet}. */
-public class SignedTokenRestTokenVerifier implements RestTokenVerifier {
- private final SignedToken restToken;
-
- public static class Module extends AbstractModule {
- @Override
- protected void configure() {
- bind(RestTokenVerifier.class).to(SignedTokenRestTokenVerifier.class);
- }
- }
-
- @Inject
- SignedTokenRestTokenVerifier(AuthConfig config) {
- restToken = config.getRestToken();
- }
-
- @Override
- public String sign(Account.Id user, String url) {
- try {
- String payload = String.format("%s:%s", user, url);
- byte[] utf8 = payload.getBytes("UTF-8");
- String base64 = Base64.encodeBytes(utf8);
- return restToken.newToken(base64);
- } catch (XsrfException e) {
- throw new IllegalArgumentException(e);
- } catch (UnsupportedEncodingException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- @Override
- public void verify(Account.Id user, String url, String tokenString)
- throws InvalidTokenException {
- ValidToken token;
- try {
- token = restToken.checkToken(tokenString, null);
- } catch (XsrfException err) {
- throw new InvalidTokenException(err);
- }
- if (token == null || token.getData() == null || token.getData().isEmpty()) {
- throw new InvalidTokenException();
- }
-
- String payload;
- try {
- payload = new String(Base64.decode(token.getData()), "UTF-8");
- } catch (UnsupportedEncodingException err) {
- throw new InvalidTokenException(err);
- }
-
- int colonPos = payload.indexOf(':');
- if (colonPos == -1) {
- throw new InvalidTokenException();
- }
-
- Account.Id tokenUser;
- try {
- tokenUser = Account.Id.parse(payload.substring(0, colonPos));
- } catch (IllegalArgumentException err) {
- throw new InvalidTokenException(err);
- }
-
- String tokenUrl = payload.substring(colonPos+1);
-
- if (!tokenUser.equals(user) || !tokenUrl.equals(url)) {
- throw new InvalidTokenException();
- }
- }
-}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/TokenVerifiedRestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/TokenVerifiedRestApiServlet.java
deleted file mode 100644
index 98a1b57..0000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/TokenVerifiedRestApiServlet.java
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd;
-
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Maps;
-import com.google.gerrit.httpd.RestTokenVerifier.InvalidTokenException;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.OutputFormat;
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonParser;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.Enumeration;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
-
-public abstract class TokenVerifiedRestApiServlet extends RestApiServlet {
- private static final long serialVersionUID = 1L;
- private static final String FORM_ENCODED = "application/x-www-form-urlencoded";
- private static final String UTF_8 = "UTF-8";
- private static final String AUTHKEY_NAME = "_authkey";
- private static final String AUTHKEY_HEADER = "X-authkey";
-
- private final Gson gson;
- private final Provider<CurrentUser> userProvider;
- private final RestTokenVerifier verifier;
-
- @Inject
- protected TokenVerifiedRestApiServlet(Provider<CurrentUser> userProvider,
- RestTokenVerifier verifier) {
- super(userProvider);
- this.gson = OutputFormat.JSON_COMPACT.newGson();
- this.userProvider = userProvider;
- this.verifier = verifier;
- }
-
- /**
- * Process the (possibly state changing) request.
- *
- * @param req incoming HTTP request.
- * @param res outgoing response.
- * @param requestData JSON object representing the HTTP request parameters.
- * Null if the request body was not supplied in JSON format.
- * @throws IOException
- * @throws ServletException
- */
- protected abstract void doRequest(HttpServletRequest req,
- HttpServletResponse res,
- @Nullable JsonObject requestData) throws IOException, ServletException;
-
- @Override
- protected final void doGet(HttpServletRequest req, HttpServletResponse res)
- throws ServletException, IOException {
- CurrentUser user = userProvider.get();
- if (!(user instanceof IdentifiedUser)) {
- sendError(res, SC_UNAUTHORIZED, "API requires authentication");
- return;
- }
-
- TokenInfo info = new TokenInfo();
- info._authkey = verifier.sign(
- ((IdentifiedUser) user).getAccountId(),
- computeUrl(req));
-
- ByteArrayOutputStream buf = new ByteArrayOutputStream();
- String type;
- buf.write(JSON_MAGIC);
- if (acceptsJson(req)) {
- type = JSON_TYPE;
- buf.write(gson.toJson(info).getBytes(UTF_8));
- } else {
- type = FORM_ENCODED;
- buf.write(String.format("%s=%s",
- AUTHKEY_NAME,
- URLEncoder.encode(info._authkey, UTF_8)).getBytes(UTF_8));
- }
-
- res.setContentType(type);
- res.setCharacterEncoding(UTF_8);
- res.setHeader("Content-Disposition", "attachment");
- send(req, res, buf.toByteArray());
- }
-
- @Override
- protected final void doPost(HttpServletRequest req, HttpServletResponse res)
- throws IOException, ServletException {
- CurrentUser user = userProvider.get();
- if (!(user instanceof IdentifiedUser)) {
- sendError(res, SC_UNAUTHORIZED, "API requires authentication");
- return;
- }
-
- ParsedBody body;
- if (JSON_TYPE.equals(req.getContentType())) {
- body = parseJson(req, res);
- } else if (FORM_ENCODED.equals(req.getContentType())) {
- body = parseForm(req, res);
- } else {
- sendError(res, SC_BAD_REQUEST, String.format(
- "Expected Content-Type: %s or %s",
- JSON_TYPE, FORM_ENCODED));
- return;
- }
-
- if (body == null) {
- return;
- }
-
- if (Strings.isNullOrEmpty(body._authkey)) {
- String h = req.getHeader(AUTHKEY_HEADER);
- if (Strings.isNullOrEmpty(h)) {
- sendError(res, SC_BAD_REQUEST, String.format(
- "Expected %s in request body or %s in HTTP headers",
- AUTHKEY_NAME, AUTHKEY_HEADER));
- return;
- }
- body._authkey = URLDecoder.decode(h, UTF_8);
- }
-
- try {
- verifier.verify(
- ((IdentifiedUser) user).getAccountId(),
- computeUrl(req),
- body._authkey);
- } catch (InvalidTokenException err) {
- sendError(res, SC_BAD_REQUEST,
- String.format("Invalid or expired %s", AUTHKEY_NAME));
- return;
- }
-
- doRequest(body.req, res, body.json);
- }
-
- private static ParsedBody parseJson(HttpServletRequest req,
- HttpServletResponse res) throws IOException {
- try {
- JsonElement element = new JsonParser().parse(req.getReader());
- if (!element.isJsonObject()) {
- sendError(res, SC_BAD_REQUEST, "Expected JSON object in request body");
- return null;
- }
-
- ParsedBody body = new ParsedBody();
- body.req = req;
- body.json = (JsonObject) element;
- JsonElement authKey = body.json.remove(AUTHKEY_NAME);
- if (authKey != null
- && authKey.isJsonPrimitive()
- && authKey.getAsJsonPrimitive().isString()) {
- body._authkey = authKey.getAsString();
- }
- return body;
- } catch (JsonParseException e) {
- sendError(res, SC_BAD_REQUEST, "Invalid JSON object in request body");
- return null;
- }
- }
-
- private static ParsedBody parseForm(HttpServletRequest req,
- HttpServletResponse res) throws IOException {
- ParsedBody body = new ParsedBody();
- body.req = new WrappedRequest(req);
- body._authkey = req.getParameter(AUTHKEY_NAME);
- return body;
- }
-
- private static String computeUrl(HttpServletRequest req) {
- StringBuffer url = req.getRequestURL();
- String qs = req.getQueryString();
- if (!Strings.isNullOrEmpty(qs)) {
- url.append('?').append(qs);
- }
- return url.toString();
- }
-
- private static class TokenInfo {
- String _authkey;
- }
-
- private static class ParsedBody {
- HttpServletRequest req;
- String _authkey;
- JsonObject json;
- }
-
- private static class WrappedRequest extends HttpServletRequestWrapper {
- @SuppressWarnings("rawtypes")
- private Map parameters;
-
- WrappedRequest(HttpServletRequest req) {
- super(req);
- }
-
- @Override
- public String getParameter(String name) {
- if (AUTHKEY_NAME.equals(name)) {
- return null;
- }
- return super.getParameter(name);
- }
-
- @Override
- public String[] getParameterValues(String name) {
- if (AUTHKEY_NAME.equals(name)) {
- return null;
- }
- return super.getParameterValues(name);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Override
- public Map getParameterMap() {
- Map m = parameters;
- if (m == null) {
- m = super.getParameterMap();
- if (m.containsKey(AUTHKEY_NAME)) {
- m = Maps.newHashMap(m);
- m.remove(AUTHKEY_NAME);
- }
- parameters = m;
- }
- return m;
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Override
- public Enumeration getParameterNames() {
- return Iterators.asEnumeration(getParameterMap().keySet().iterator());
- }
- }
-}
-
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index c164d48..7d27482 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -22,7 +22,6 @@
import com.google.gerrit.httpd.GitOverHttpModule;
import com.google.gerrit.httpd.HttpCanonicalWebUrlProvider;
import com.google.gerrit.httpd.RequestContextFilter;
-import com.google.gerrit.httpd.SignedTokenRestTokenVerifier;
import com.google.gerrit.httpd.WebModule;
import com.google.gerrit.httpd.WebSshGlueModule;
import com.google.gerrit.httpd.auth.openid.OpenIdModule;
@@ -295,7 +294,6 @@
modules.add(new DefaultCacheFactory.Module());
modules.add(new SmtpEmailSender.Module());
modules.add(new SignedTokenEmailTokenVerifier.Module());
- modules.add(new SignedTokenRestTokenVerifier.Module());
modules.add(new PluginModule());
if (httpd) {
modules.add(new CanonicalWebUrlModule() {
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index b352d4f..6dab0d3 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -231,7 +231,6 @@
modules.add(new DefaultCacheFactory.Module());
modules.add(new SmtpEmailSender.Module());
modules.add(new SignedTokenEmailTokenVerifier.Module());
- modules.add(new SignedTokenRestTokenVerifier.Module());
modules.add(new PluginModule());
modules.add(new CanonicalWebUrlModule() {
@Override