Merge "Bug 508815 - Fixed org unit exists check" into develop
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESAuthorizationService.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESAuthorizationService.java
index 0169791..df2e7b7 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESAuthorizationService.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/DefaultESAuthorizationService.java
@@ -13,6 +13,7 @@
 
 import java.util.ArrayList;
 import java.util.EnumMap;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -295,34 +296,48 @@
 			return true;
 		}
 
-		for (final Role role : roles) {
+		final Iterable<ProjectAdminRole> projectAdminRoles = Iterables.filter(roles, ProjectAdminRole.class);
 
-			if (!ProjectAdminRole.class.isInstance(role)) {
-				continue;
-			}
+		final Iterator<ProjectAdminRole> iterator = projectAdminRoles.iterator();
 
-			if (!ServerConfiguration.isProjectAdminPrivileg(privileg)) {
+		if (iterator.hasNext()) {
+			/* if at least one project admin role, perform validity checks */
+			if (!isProjectAdminPrivileg(privileg)) {
 				throw new AccessControlException(Messages.AccessControlImpl_PARole_Missing_Privilege);
 			}
-
 			if (globalProjectId == null) {
 				return false;
 			}
+		}
 
-			final ProjectAdminRole projectAdminRole = ProjectAdminRole.class.cast(role);
-			final ProjectId projectId = APIUtil.toInternal(ProjectId.class, globalProjectId);
+		final ProjectId projectId = APIUtil.toInternal(ProjectId.class, globalProjectId);
 
-			if (!projectAdminRole.canAdministrate(projectId)) {
-				throw new AccessControlException(Messages.AccessControlImpl_PARole_Missing_Privilege);
+		while (iterator.hasNext()) {
+			final ProjectAdminRole projectAdminRole = iterator.next();
+
+			if (projectAdminRole.canAdministrate(projectId)) {
+				/* return false, because no server admin. no exception because still valid */
+				return false;
 			}
 
-			return false;
+			if (!iterator.hasNext()) {
+				/* no project admin role allows this operation -> throw exception */
+				throw new AccessControlException(Messages.AccessControlImpl_PARole_Missing_Privilege);
+			}
 		}
 
 		throw new AccessControlException(Messages.AccessControlImpl_Insufficient_Rights);
 	}
 
 	/**
+	 * @param privileg the {@link ESProjectAdminPrivileges}
+	 * @return <code>true</code> if a project admin has the required privileges, <code>false</code> otherwise
+	 */
+	protected boolean isProjectAdminPrivileg(ESProjectAdminPrivileges privileg) {
+		return ServerConfiguration.isProjectAdminPrivileg(privileg);
+	}
+
+	/**
 	 *
 	 * {@inheritDoc}
 	 *
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/EMFStoreSessions.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/EMFStoreSessions.java
index 10de2b4..6c4db15 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/EMFStoreSessions.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/EMFStoreSessions.java
@@ -38,6 +38,7 @@
 		for (final Entry<SessionId, ACUserContainer> entry : sessionUserMap.entrySet()) {
 			final ACUserContainer container = entry.getValue();
 			if (container.getRawUser().getId().equals(userId)) {
+				container.active();
 				return entry.getKey().toAPI();
 			}
 		}
diff --git a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/ACUserContainer.java b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/ACUserContainer.java
index 9068354..898ea65 100644
--- a/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/ACUserContainer.java
+++ b/bundles/org.eclipse.emf.emfstore.server/src/org/eclipse/emf/emfstore/internal/server/accesscontrol/authentication/ACUserContainer.java
@@ -79,7 +79,10 @@
 		}
 	}
 
-	private void active() {
+	/**
+	 * Update timestamp when user was last active.
+	 */
+	public void active() {
 		lastActive = System.currentTimeMillis();
 	}
 }
\ No newline at end of file
diff --git a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
index c54a7a4..585b97e 100644
--- a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
+++ b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/AllAccessControlTests.java
@@ -42,7 +42,8 @@
 	AdminEMFStoreTests.class,
 	AddInitialParticipantTest.class,
 	AutoCreateACUserTestTest.class,
-	DefaultESPasswordHashGeneratorTests.class
+	DefaultESPasswordHashGeneratorTests.class,
+	DefaultESAuthorizationServiceTests.class
 
 })
 public class AllAccessControlTests {
diff --git a/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESAuthorizationServiceTests.java b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESAuthorizationServiceTests.java
new file mode 100644
index 0000000..921bc68
--- /dev/null
+++ b/tests/org.eclipse.emf.emfstore.server.test/src/org/eclipse/emf/emfstore/server/accesscontrol/test/DefaultESAuthorizationServiceTests.java
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2017 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Johannes Faltermeier - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.server.accesscontrol.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.emf.emfstore.client.test.common.mocks.DAOFacadeMock;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.DefaultESAuthorizationService;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.DefaultESOrgUnitResolverService;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.Messages;
+import org.eclipse.emf.emfstore.internal.server.accesscontrol.authentication.ACUserContainer;
+import org.eclipse.emf.emfstore.internal.server.exceptions.AccessControlException;
+import org.eclipse.emf.emfstore.internal.server.exceptions.SessionTimedOutException;
+import org.eclipse.emf.emfstore.internal.server.impl.api.ESOrgUnitProviderImpl;
+import org.eclipse.emf.emfstore.internal.server.model.ModelFactory;
+import org.eclipse.emf.emfstore.internal.server.model.ProjectId;
+import org.eclipse.emf.emfstore.internal.server.model.SessionId;
+import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACGroup;
+import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACUser;
+import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.AccesscontrolFactory;
+import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.roles.Role;
+import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.roles.RolesFactory;
+import org.eclipse.emf.emfstore.internal.server.model.impl.ProjectIdImpl;
+import org.eclipse.emf.emfstore.internal.server.model.impl.SessionIdImpl;
+import org.eclipse.emf.emfstore.internal.server.model.impl.api.ESOrgUnitRepositoryImpl;
+import org.eclipse.emf.emfstore.server.auth.ESOrgUnitResolver;
+import org.eclipse.emf.emfstore.server.auth.ESProjectAdminPrivileges;
+import org.eclipse.emf.emfstore.server.auth.ESSessions;
+import org.eclipse.emf.emfstore.server.model.ESOrgUnitProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link DefaultESAuthorizationService}.
+ */
+@SuppressWarnings("restriction")
+public class DefaultESAuthorizationServiceTests {
+
+	private TestSession sessions;
+	private DAOFacadeMock acDAOFacade;
+	private ESOrgUnitRepositoryImpl orgUnitRepository;
+	private ESOrgUnitProviderImpl orgUnitProvider;
+	private DefaultESOrgUnitResolverService orgUnitResolver;
+	private SessionIdImpl sessionId;
+	private ProjectIdImpl projectId;
+
+	@Before
+	public void before() {
+		sessions = new TestSession();
+
+		acDAOFacade = new DAOFacadeMock();
+		orgUnitRepository = new ESOrgUnitRepositoryImpl(acDAOFacade);
+		orgUnitProvider = new ESOrgUnitProviderImpl(orgUnitRepository);
+
+		orgUnitResolver = new DefaultESOrgUnitResolverService();
+		orgUnitResolver.init(orgUnitProvider);
+
+		sessionId = (SessionIdImpl) ModelFactory.eINSTANCE.createSessionId();
+		projectId = (ProjectIdImpl) ModelFactory.eINSTANCE.createProjectId();
+	}
+
+	@Test(expected = SessionTimedOutException.class)
+	public void testCheckProjectAdminAccessInvalidUserSession() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* act */
+		try {
+			defaultESAuthorizationService.checkProjectAdminAccess(
+				sessionId.toAPI(),
+				projectId.toAPI(),
+				ESProjectAdminPrivileges.AssignRoleToOrgUnit);
+		}
+
+		/* assert */
+		catch (final SessionTimedOutException ex) {
+			assertEquals(Messages.AccessControlImpl_SessionID_Unknown, ex.getMessage());
+			throw ex;
+		}
+	}
+
+	@Test
+	public void testCheckProjectAdminAccessServerAdminDirect() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(RolesFactory.eINSTANCE.createServerAdmin());
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		assertTrue(defaultESAuthorizationService.checkProjectAdminAccess(
+			sessionId.toAPI(),
+			projectId.toAPI(),
+			ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+
+	}
+
+	@Test
+	public void testCheckProjectAdminAccessServerAdminViaGroup() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+		group.getRoles().add(RolesFactory.eINSTANCE.createServerAdmin());
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		assertTrue(defaultESAuthorizationService.checkProjectAdminAccess(
+			sessionId.toAPI(),
+			projectId.toAPI(),
+			ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+	}
+
+	@Test(expected = AccessControlException.class)
+	public void testCheckProjectAdminAccessNotProjectAdmin() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		try {
+			defaultESAuthorizationService.checkProjectAdminAccess(
+				sessionId.toAPI(),
+				projectId.toAPI(),
+				ESProjectAdminPrivileges.AssignRoleToOrgUnit);
+		}
+		/* assert */
+		catch (final AccessControlException ex) {
+			assertEquals(Messages.AccessControlImpl_Insufficient_Rights, ex.getMessage());
+			throw ex;
+		}
+	}
+
+	@Test(expected = AccessControlException.class)
+	public void testCheckProjectAdminAccessInvalidPrivileg() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver, Collections.singleton(ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(projectAdminRole(projectId));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		try {
+			defaultESAuthorizationService.checkProjectAdminAccess(
+				sessionId.toAPI(),
+				projectId.toAPI(),
+				ESProjectAdminPrivileges.AssignRoleToOrgUnit);
+		}
+		/* assert */
+		catch (final AccessControlException ex) {
+			assertEquals(Messages.AccessControlImpl_PARole_Missing_Privilege, ex.getMessage());
+			throw ex;
+		}
+	}
+
+	@Test
+	public void testCheckProjectAdminAccessNoProjectId() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(projectAdminRole(projectId));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		assertFalse(defaultESAuthorizationService.checkProjectAdminAccess(
+			sessionId.toAPI(),
+			null,
+			ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+	}
+
+	@Test(expected = AccessControlException.class)
+	public void testCheckProjectAdminAccessCannotAdministrate() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(projectAdminRole(ModelFactory.eINSTANCE.createProjectId()));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+		group.getRoles().add(projectAdminRole(ModelFactory.eINSTANCE.createProjectId()));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		try {
+			defaultESAuthorizationService.checkProjectAdminAccess(
+				sessionId.toAPI(),
+				projectId.toAPI(),
+				ESProjectAdminPrivileges.AssignRoleToOrgUnit);
+		} catch (final AccessControlException ex) {
+			assertEquals(Messages.AccessControlImpl_PARole_Missing_Privilege, ex.getMessage());
+			throw ex;
+		}
+	}
+
+	@Test
+	public void testCheckProjectAdminAccessCanAdministrateByUser() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(projectAdminRole(projectId));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+		group.getRoles().add(projectAdminRole(ModelFactory.eINSTANCE.createProjectId()));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		assertFalse(defaultESAuthorizationService.checkProjectAdminAccess(
+			sessionId.toAPI(),
+			projectId.toAPI(),
+			ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+	}
+
+	@Test
+	public void testCheckProjectAdminAccessCanAdministrateByGroup() throws AccessControlException {
+		/* setup */
+		final DefaultESAuthorizationService defaultESAuthorizationService = createServiceUnderTest(sessions,
+			orgUnitProvider, orgUnitResolver);
+
+		/* setup user */
+		final ACUser user = AccesscontrolFactory.eINSTANCE.createACUser();
+		acDAOFacade.add(user);
+		user.getRoles().add(writerRole(projectId));
+		user.getRoles().add(projectAdminRole(ModelFactory.eINSTANCE.createProjectId()));
+
+		final ACGroup group = AccesscontrolFactory.eINSTANCE.createACGroup();
+		acDAOFacade.add(group);
+		group.getMembers().add(user);
+		group.getRoles().add(readerRole(projectId));
+		group.getRoles().add(projectAdminRole(projectId));
+
+		sessions.addUser(user, sessionId);
+
+		/* act */
+		assertFalse(defaultESAuthorizationService.checkProjectAdminAccess(
+			sessionId.toAPI(),
+			projectId.toAPI(),
+			ESProjectAdminPrivileges.AssignRoleToOrgUnit));
+	}
+
+	private static Role projectAdminRole(ProjectId projectId) {
+		return addProjectToRole(projectId, RolesFactory.eINSTANCE.createProjectAdminRole());
+	}
+
+	private static Role readerRole(ProjectId projectId) {
+		return addProjectToRole(projectId, RolesFactory.eINSTANCE.createReaderRole());
+	}
+
+	private static Role writerRole(ProjectId projectId) {
+		return addProjectToRole(projectId, RolesFactory.eINSTANCE.createWriterRole());
+	}
+
+	private static Role addProjectToRole(ProjectId projectId, final Role role) {
+		role.getProjects().add(projectId);
+		return role;
+	}
+
+	private static DefaultESAuthorizationService createServiceUnderTest(
+		final ESSessions sessions,
+		final ESOrgUnitProvider orgUnitProvider,
+		final ESOrgUnitResolver orgUnitResolver) {
+		return createServiceUnderTest(
+			sessions,
+			orgUnitProvider,
+			orgUnitResolver,
+			Collections.<ESProjectAdminPrivileges> emptySet());
+	}
+
+	private static DefaultESAuthorizationService createServiceUnderTest(
+		final ESSessions sessions,
+		final ESOrgUnitProvider orgUnitProvider,
+		final ESOrgUnitResolver orgUnitResolver,
+		final Set<ESProjectAdminPrivileges> invalidPrivileges) {
+		final DefaultESAuthorizationService defaultESAuthorizationService = new DefaultESAuthorizationService() {
+
+			@Override
+			protected boolean isProjectAdminPrivileg(ESProjectAdminPrivileges privileg) {
+				return !invalidPrivileges.contains(privileg);
+			}
+		};
+		defaultESAuthorizationService.init(sessions, orgUnitResolver, orgUnitProvider);
+		return defaultESAuthorizationService;
+	}
+
+	private static class TestSession extends ESSessions {
+		public void addUser(ACUser user, SessionId sessionId) {
+			sessionUserMap.put(
+				sessionId,
+				new ACUserContainer(user));
+		}
+	}
+
+}