/*******************************************************************************
* Copyright (c) 2013, 2014 Lectorius, Inc.
* Authors:
* Vijay Pandurangan (vijayp@mitro.co)
* Evan Jones (ej@mitro.co)
* Adam Hilss (ahilss@mitro.co)
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can contact the authors at inbound@mitro.co.
*******************************************************************************/
package co.mitro.core.servlets;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import co.mitro.core.accesscontrol.AuthenticatedDB;
import co.mitro.core.exceptions.MitroServletException;
import co.mitro.core.exceptions.SendableException;
import co.mitro.core.exceptions.UserVisibleException;
import co.mitro.core.server.data.DBGroup;
import co.mitro.core.server.data.RPC;
import co.mitro.core.server.data.RPC.CreateOrganizationRequest;
import co.mitro.core.server.data.RPC.CreateOrganizationRequest.PrivateGroupKeys;
import co.mitro.core.server.data.RPC.CreateOrganizationResponse;
import co.mitro.core.servlets.MitroServlet.MitroRequestContext;
import com.google.common.collect.ImmutableMap;
public class CreateOrganizationTest extends MemoryDBFixture {
private CreateOrganizationRequest request;
private CreateOrganization servlet;
private AuthenticatedDB db;
@SuppressWarnings("deprecation")
@Before
public void setUp() {
servlet = new CreateOrganization(managerFactory, keyFactory);
request = new CreateOrganizationRequest();
request.name = "hello";
request.publicKey = "org public key";
request.adminEncryptedKeys = new HashMap<>();
request.adminEncryptedKeys.put(testIdentity.getName(), "org key for user");
request.memberGroupKeys = new HashMap<>();
addMemberToRequest(testIdentity.getName());
db = AuthenticatedDB.deprecatedNew(manager, testIdentity);
}
private void addMemberToRequest(String identityEmail) {
PrivateGroupKeys keys = new PrivateGroupKeys();
keys.publicKey = "public key for group";
keys.keyEncryptedForUser = "group key for user";
keys.keyEncryptedForOrganization = "group key for org";
request.memberGroupKeys.put(identityEmail, keys);
}
private void expectMessage(String substring) {
String errorMessage = CreateOrganization.validateRequest(request);
assertThat(errorMessage, containsString(substring));
}
@Test
public void requestErrorMessage() {
// empty request = not valid
request = new RPC.CreateOrganizationRequest();
expectMessage("name cannot be empty");
request.name = "";
expectMessage("name cannot be empty");
request.name = "hello";
expectMessage("publicKey cannot be empty");
request.publicKey = "";
expectMessage("publicKey cannot be empty");
request.publicKey = "pubkey";
expectMessage("adminEncryptedKeys cannot be empty");
request.adminEncryptedKeys = new HashMap<>();
expectMessage("adminEncryptedKeys cannot be empty");
request.adminEncryptedKeys.put("identity", "fake key");
expectMessage("memberGroupKeys cannot be empty");
request.memberGroupKeys = new HashMap<>();
expectMessage("memberGroupKeys cannot be empty");
request.memberGroupKeys.put("identity2", null);
expectMessage("each admin must be a member");
request.memberGroupKeys.put("identity", null);
assertEquals(null, CreateOrganization.validateRequest(request));
}
@Test
public void createOrg() throws Exception {
assertEquals(0, db.getOrganizations().size());
request.name = "";
expectExceptionType(SendableException.class, "name cannot be empty");
assertEquals(1, manager.auditDao.countOf()); // audit log rollback
request.name = "org";
makeRequest();
assertEquals(2, manager.auditDao.countOf());
Set<DBGroup> orgs = db.getOrganizations();
assertEquals(1, orgs.size());
DBGroup g = orgs.iterator().next();
assertEquals("org", g.getName());
assertEquals(DBGroup.Type.TOP_LEVEL_ORGANIZATION, g.getType());
manager.commitTransaction();
// execute the request again: duplicate organization error
expectException("duplicate organization name");
// create a different org with this user as a member
request.name = "second org";
request.adminEncryptedKeys.clear();
request.adminEncryptedKeys.put(testIdentity2.getName(), "admin keys for testIdentity2");
addMemberToRequest(testIdentity2.getName());
addMemberToRequest(testIdentity.getName());
// users can now be in more than one organization
servlet.processCommand(new MitroRequestContext(
testIdentity2, gson.toJson(request), manager, null));
}
@Test
public void createOrgWithAdditionalMembers() throws Exception {
// add testIdentity2 as a member
addMemberToRequest(testIdentity2.getName());
makeRequest();
assertEquals(1, db.getOrganizations().size());
@SuppressWarnings("deprecation")
AuthenticatedDB db2 = AuthenticatedDB.deprecatedNew(manager, testIdentity2);
assertEquals(1, db2.getOrganizations().size());
}
@Test
public void createOrgBadMembers() throws Exception {
// add a non-existent user as a member
addMemberToRequest("bad@example.com");
expectException("acl must apply to exactly one identity or group");
}
@Test
public void createOrgRequestorNotAdmin() throws Exception {
// make testIdentity2 an admin instead of testIdentity; must fail
request.adminEncryptedKeys = ImmutableMap.of(testIdentity2.getName(), "private key");
request.memberGroupKeys.put(
testIdentity2.getName(), request.memberGroupKeys.get(testIdentity.getName()));
expectException("does not have permission to modify group");
}
private void expectException(String errorSubstring) throws IOException, SQLException {
expectExceptionType(MitroServletException.class, errorSubstring);
}
private <T> void expectExceptionType(
Class<T> exceptionClass, String errorSubstring) throws IOException, SQLException {
try {
makeRequest();
fail("expected exception");
} catch (MitroServletException e) {
assertThat(e, instanceOf(exceptionClass));
assertThat(e.getMessage(), containsString(errorSubstring));
} finally {
manager.rollbackTransaction();
}
}
public CreateOrganizationResponse makeRequest()
throws IOException, SQLException, MitroServletException {
CreateOrganizationResponse response = (CreateOrganizationResponse) servlet.processCommand(
new MitroRequestContext(testIdentity, gson.toJson(request), manager, null));
return response;
}
}