Add REST endpoint to confirm emails
Use the new REST endpoint in the UI instead of the old AccountSecurity.validateEmail(...) RPC. AccountSecurity.validateEmail(...) is removed since it is no longer used. Change-Id: I561224e9d9ea31875df2bba838ee53f77f24c55b Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -126,6 +126,32 @@ As result a link:#server-info[ServerInfo] entity is returned.
|
||||
}
|
||||
----
|
||||
|
||||
[[confirm-email]]
|
||||
=== Confirm Email
|
||||
--
|
||||
'PUT /config/server/email.confirm'
|
||||
--
|
||||
|
||||
Confirms that the user owns an email address.
|
||||
|
||||
The email token must be provided in the request body inside
|
||||
an link:#email-confirmation-input[EmailConfirmationInput] entity.
|
||||
|
||||
.Request
|
||||
----
|
||||
PUT /config/server/email.confirm HTTP/1.0
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
|
||||
{
|
||||
"token": "Enim+QNbAo6TV8Hur8WwoUypI6apG7qBPvF+bw==$MTAwMDAwNDp0ZXN0QHRlc3QuZGU="
|
||||
}
|
||||
----
|
||||
|
||||
The response is "`204 No Content`".
|
||||
|
||||
If the token is invalid or if it's the token of another user the
|
||||
request fails and the response is "`422 Unprocessable Entity`".
|
||||
|
||||
|
||||
[[list-caches]]
|
||||
=== List Caches
|
||||
@@ -1132,6 +1158,18 @@ Empty, if accessed anonymously and the download scheme requires
|
||||
authentication.
|
||||
|=================================
|
||||
|
||||
[[email-confirmation-input]]
|
||||
=== EmailConfirmationInput
|
||||
The `EmailConfirmationInput` entity contains information for confirming
|
||||
an email address.
|
||||
|
||||
[options="header",cols="1,6"]
|
||||
|=======================
|
||||
|Field Name |Description
|
||||
|`token` |
|
||||
The token that was sent by mail to a newly registered email address.
|
||||
|=======================
|
||||
|
||||
[[entries-info]]
|
||||
=== EntriesInfo
|
||||
The `EntriesInfo` entity contains information about the entries in a
|
||||
|
@@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2015 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.acceptance.rest.config;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.RestResponse;
|
||||
import com.google.gerrit.server.config.ConfirmEmail;
|
||||
import com.google.gerrit.server.mail.EmailTokenVerifier;
|
||||
import com.google.gerrit.testutil.ConfigSuite;
|
||||
import com.google.gwtjsonrpc.server.SignedToken;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConfirmEmailIT extends AbstractDaemonTest {
|
||||
@ConfigSuite.Default
|
||||
public static Config defaultConfig() {
|
||||
Config cfg = new Config();
|
||||
cfg.setString("auth", null, "registerEmailPrivateKey",
|
||||
SignedToken.generateRandomKey());
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private EmailTokenVerifier emailTokenVerifier;
|
||||
|
||||
@Test
|
||||
public void confirm() throws Exception {
|
||||
ConfirmEmail.Input in = new ConfirmEmail.Input();
|
||||
in.token = emailTokenVerifier.encode(admin.getId(), "new.mail@example.com");
|
||||
RestResponse r = adminSession.put("/config/server/email.confirm", in);
|
||||
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void confirmForOtherUser_UnprocessableEntity() throws Exception {
|
||||
ConfirmEmail.Input in = new ConfirmEmail.Input();
|
||||
in.token = emailTokenVerifier.encode(user.getId(), "new.mail@example.com");
|
||||
RestResponse r = adminSession.put("/config/server/email.confirm", in);
|
||||
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void confirmInvalidToken_UnprocessableEntity() throws Exception {
|
||||
ConfirmEmail.Input in = new ConfirmEmail.Input();
|
||||
in.token = "invalidToken";
|
||||
RestResponse r = adminSession.put("/config/server/email.confirm", in);
|
||||
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
}
|
@@ -47,8 +47,4 @@ public interface AccountSecurity extends RemoteJsonService {
|
||||
@SignInRequired
|
||||
void enterAgreement(String agreementName,
|
||||
AsyncCallback<VoidResult> callback);
|
||||
|
||||
@Audit
|
||||
@SignInRequired
|
||||
void validateEmail(String token, AsyncCallback<VoidResult> callback);
|
||||
}
|
||||
|
@@ -15,10 +15,11 @@
|
||||
package com.google.gerrit.client.account;
|
||||
|
||||
import com.google.gerrit.client.Gerrit;
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.config.ConfigServerApi;
|
||||
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||
import com.google.gerrit.client.ui.AccountScreen;
|
||||
import com.google.gerrit.common.PageLinks;
|
||||
import com.google.gwtjsonrpc.common.VoidResult;
|
||||
|
||||
public class ValidateEmailScreen extends AccountScreen {
|
||||
private final String magicToken;
|
||||
@@ -36,7 +37,7 @@ public class ValidateEmailScreen extends AccountScreen {
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
Util.ACCOUNT_SEC.validateEmail(magicToken,
|
||||
ConfigServerApi.confirmEmail(magicToken,
|
||||
new ScreenLoadCallback<VoidResult>(this) {
|
||||
@Override
|
||||
protected void preDisplay(final VoidResult result) {
|
||||
|
@@ -14,11 +14,13 @@
|
||||
|
||||
package com.google.gerrit.client.config;
|
||||
|
||||
import com.google.gerrit.client.VoidResult;
|
||||
import com.google.gerrit.client.info.AccountPreferencesInfo;
|
||||
import com.google.gerrit.client.info.ServerInfo;
|
||||
import com.google.gerrit.client.info.TopMenuList;
|
||||
import com.google.gerrit.client.rpc.NativeMap;
|
||||
import com.google.gerrit.client.rpc.RestApi;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
|
||||
/**
|
||||
@@ -42,4 +44,21 @@ public class ConfigServerApi {
|
||||
public static void serverInfo(AsyncCallback<ServerInfo> cb) {
|
||||
new RestApi("/config/server/info").get(cb);
|
||||
}
|
||||
|
||||
public static void confirmEmail(String token, AsyncCallback<VoidResult> cb) {
|
||||
EmailConfirmationInput input = EmailConfirmationInput.create();
|
||||
input.setToken(token);
|
||||
new RestApi("/config/server/email.confirm").put(input, cb);
|
||||
}
|
||||
|
||||
private static class EmailConfirmationInput extends JavaScriptObject {
|
||||
final native void setToken(String t) /*-{ this.t = t; }-*/;
|
||||
|
||||
static EmailConfirmationInput create() {
|
||||
return createObject().cast();
|
||||
}
|
||||
|
||||
protected EmailConfirmationInput() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,12 +34,9 @@ import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountByEmailCache;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.account.GroupCache;
|
||||
import com.google.gerrit.server.account.Realm;
|
||||
import com.google.gerrit.server.contact.ContactStore;
|
||||
import com.google.gerrit.server.mail.EmailTokenVerifier;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gwtjsonrpc.common.AsyncCallback;
|
||||
import com.google.gwtjsonrpc.common.VoidResult;
|
||||
@@ -57,10 +54,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
|
||||
private final Realm realm;
|
||||
private final ProjectCache projectCache;
|
||||
private final Provider<IdentifiedUser> user;
|
||||
private final EmailTokenVerifier emailTokenVerifier;
|
||||
private final AccountByEmailCache byEmailCache;
|
||||
private final AccountCache accountCache;
|
||||
private final AccountManager accountManager;
|
||||
private final boolean useContactInfo;
|
||||
|
||||
private final DeleteExternalIds.Factory deleteExternalIdsFactory;
|
||||
@@ -74,9 +69,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
|
||||
AccountSecurityImpl(final Provider<ReviewDb> schema,
|
||||
final Provider<CurrentUser> currentUser, final ContactStore cs,
|
||||
final Realm r, final Provider<IdentifiedUser> u,
|
||||
final EmailTokenVerifier etv, final ProjectCache pc,
|
||||
final ProjectCache pc,
|
||||
final AccountByEmailCache abec, final AccountCache uac,
|
||||
final AccountManager am,
|
||||
final DeleteExternalIds.Factory deleteExternalIdsFactory,
|
||||
final ExternalIdDetailFactory.Factory externalIdDetailFactory,
|
||||
final ChangeHooks hooks, final GroupCache groupCache,
|
||||
@@ -85,11 +79,9 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
|
||||
contactStore = cs;
|
||||
realm = r;
|
||||
user = u;
|
||||
emailTokenVerifier = etv;
|
||||
projectCache = pc;
|
||||
byEmailCache = abec;
|
||||
accountCache = uac;
|
||||
accountManager = am;
|
||||
this.auditService = auditService;
|
||||
|
||||
useContactInfo = contactStore != null && contactStore.isEnabled();
|
||||
@@ -201,22 +193,4 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateEmail(final String tokenString,
|
||||
final AsyncCallback<VoidResult> callback) {
|
||||
try {
|
||||
EmailTokenVerifier.ParsedToken token = emailTokenVerifier.decode(tokenString);
|
||||
Account.Id currentUser = user.get().getAccountId();
|
||||
if (currentUser.equals(token.getAccountId())) {
|
||||
accountManager.link(currentUser, token.toAuthRequest());
|
||||
callback.onSuccess(VoidResult.INSTANCE);
|
||||
} else {
|
||||
throw new EmailTokenVerifier.InvalidTokenException();
|
||||
}
|
||||
} catch (EmailTokenVerifier.InvalidTokenException | OrmException
|
||||
| AccountException e) {
|
||||
callback.onFailure(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,80 @@
|
||||
// Copyright (C) 2015 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.server.config;
|
||||
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.DefaultInput;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.config.ConfirmEmail.Input;
|
||||
import com.google.gerrit.server.mail.EmailTokenVerifier;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
|
||||
public static class Input {
|
||||
@DefaultInput
|
||||
public String token;
|
||||
}
|
||||
|
||||
private final Provider<CurrentUser> self;
|
||||
private final EmailTokenVerifier emailTokenVerifier;
|
||||
private final AccountManager accountManager;
|
||||
|
||||
@Inject
|
||||
public ConfirmEmail(Provider<CurrentUser> self,
|
||||
EmailTokenVerifier emailTokenVerifier,
|
||||
AccountManager accountManager) {
|
||||
this.self = self;
|
||||
this.emailTokenVerifier = emailTokenVerifier;
|
||||
this.accountManager = accountManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<?> apply(ConfigResource rsrc, Input input)
|
||||
throws AuthException, UnprocessableEntityException, AccountException,
|
||||
OrmException {
|
||||
CurrentUser user = self.get();
|
||||
if (!user.isIdentifiedUser()) {
|
||||
throw new AuthException("Authentication required");
|
||||
}
|
||||
|
||||
if (input == null) {
|
||||
input = new Input();
|
||||
}
|
||||
|
||||
try {
|
||||
EmailTokenVerifier.ParsedToken token = emailTokenVerifier.decode(input.token);
|
||||
Account.Id accId = ((IdentifiedUser)user).getAccountId();
|
||||
if (accId.equals(token.getAccountId())) {
|
||||
accountManager.link(accId, token.toAuthRequest());
|
||||
return Response.none();
|
||||
} else {
|
||||
throw new UnprocessableEntityException("invalid token");
|
||||
}
|
||||
} catch (EmailTokenVerifier.InvalidTokenException e) {
|
||||
throw new UnprocessableEntityException("invalid token");
|
||||
}
|
||||
}
|
||||
}
|
@@ -38,5 +38,6 @@ public class Module extends RestApiModule {
|
||||
get(CONFIG_KIND, "info").to(GetServerInfo.class);
|
||||
get(CONFIG_KIND, "preferences").to(GetPreferences.class);
|
||||
put(CONFIG_KIND, "preferences").to(SetPreferences.class);
|
||||
put(CONFIG_KIND, "email.confirm").to(ConfirmEmail.class);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user