diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java index 71b6c8132923f4ec118ab20d3d83f26b7a2c6fd2..5c77c13983701491d6b4ef1b432f068c0f141c74 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java @@ -76,6 +76,8 @@ import ch.systemsx.cisd.openbis.generic.shared.util.ServerUtils; */ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> implements IServer { + private final static String ETL_SERVER_USERNAME_PREFIX = "etlserver"; + protected static final class AuthenticatedPersonBasedPrincipalProvider implements IPrincipalProvider { private final PersonPE person; @@ -193,13 +195,13 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp .getSlaveServer(); } - private final RoleAssignmentPE createInstanceAdminRoleAssigment(final PersonPE registrator, - final PersonPE person) + private final RoleAssignmentPE createRoleAssigment(final PersonPE registrator, + final PersonPE person, final RoleCode roleCode) { final RoleAssignmentPE roleAssignmentPE = new RoleAssignmentPE(); roleAssignmentPE.setDatabaseInstance(daoFactory.getHomeDatabaseInstance()); roleAssignmentPE.setRegistrator(registrator); - roleAssignmentPE.setRole(RoleCode.ADMIN); + roleAssignmentPE.setRole(roleCode); person.addRoleAssignment(roleAssignmentPE); return roleAssignmentPE; } @@ -322,7 +324,6 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp final List<PersonPE> persons = daoFactory.getPersonDAO().listPersons(); assert persons.size() > 0 : "At least system user should be in the database"; // If only one user (system user), then this is the first logged user. - final boolean isFirstLoggedUser = (persons.size() == 1); PersonPE person = daoFactory.getPersonDAO().tryFindPersonByUserId(session.getUserName()); final Set<RoleAssignmentPE> roles; if (person == null) @@ -340,27 +341,82 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp { session.setPerson(person); } - if (isFirstLoggedUser) + + if (roles.isEmpty()) { - // If system user does not have any role assignment yet make him database instance - // administrator. - final PersonPE systemUser = getSystemUser(persons); - if (systemUser.getRoleAssignments().isEmpty()) + if (isFirstLoggedUser(person, persons)) + { + grantRoleAtFirstLogin(persons, person, RoleCode.ADMIN); + } else if (isFirstLoggedETLServer(person, persons)) + { + grantRoleAtFirstLogin(persons, person, RoleCode.ETL_SERVER); + } else { - final RoleAssignmentPE roleAssignment = - createInstanceAdminRoleAssigment(systemUser, person); - daoFactory.getRoleAssignmentDAO().createRoleAssignment(roleAssignment); + authenticationLog.info(String.format( + "User '%s' has no role assignments and thus is not permitted to login.", + person.getUserId())); + return null; } - } else if (roles.isEmpty()) - { - authenticationLog.info(String.format( - "User '%s' has no role assignments and thus is not permitted to login.", - person.getUserId())); - return null; } + return asDTO(session); } + private void grantRoleAtFirstLogin(List<PersonPE> persons, PersonPE person, + RoleCode roleCode) + { + final PersonPE systemUser = getSystemUser(persons); + if (systemUser.getRoleAssignments().isEmpty()) + { + final RoleAssignmentPE roleAssignment = + createRoleAssigment(systemUser, person, roleCode); + daoFactory.getRoleAssignmentDAO().createRoleAssignment(roleAssignment); + } + } + + private boolean isFirstLoggedUser(PersonPE newPerson, List<PersonPE> persons) + { + if (isETLServerUserId(newPerson)) + { + return false; + } + + for (PersonPE person : persons) + { + if (person.isSystemUser() || isETLServerUserId(person)) + { + // system & etl users should not receive INSTANCE_ADMIN rights + // upon first login + } else + { + return false; + } + } + return true; + } + + private boolean isFirstLoggedETLServer(PersonPE person, List<PersonPE> persons) + { + if (false == isETLServerUserId(person)) + { + return false; + } + + for (PersonPE existingPerson : persons) + { + if (isETLServerUserId(existingPerson)) + { + return false; + } + } + return true; + } + + private boolean isETLServerUserId(PersonPE person) + { + return person.getUserId().startsWith(ETL_SERVER_USERNAME_PREFIX); + } + private static SessionContextDTO asDTO(Session session) { SessionContextDTO result = new SessionContextDTO(); @@ -377,6 +433,7 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp return result; } + public SessionContextDTO tryGetSession(String sessionToken) { try diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ad04b059e314d75831395605997f1282be0e16b9 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java @@ -0,0 +1,241 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.openbis.generic.server; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.AssertJUnit; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.authentication.ISessionManager; +import ch.systemsx.cisd.authentication.Principal; +import ch.systemsx.cisd.common.spring.IInvocationLoggerContext; +import ch.systemsx.cisd.common.test.RecordingMatcher; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.IPersonDAO; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.IRoleAssignmentDAO; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode; +import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.RoleAssignmentPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.Session; +import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO; + +/** + * @author Kaloyan Enimanev + */ +public class AbstractServerTest extends AssertJUnit +{ + private final String USERNAME = "username"; + + private final String ETL_SERVER = "etlserver"; + + private final String PASSWORD = "password"; + + private final String SESSION_TOKEN = "sessionToken"; + + private Mockery context; + + private AbstractServer<Object> server; + + private ISessionManager<Session> sessionManager; + + private IDAOFactory daoFactory; + + private IPersonDAO personDAO; + + private IRoleAssignmentDAO roleAssigmentDAO; + + @SuppressWarnings( + { "cast", "unchecked" }) + @BeforeMethod + public void beforeMethod() + { + context = new Mockery(); + sessionManager = (ISessionManager<Session>) context.mock(ISessionManager.class); + daoFactory = context.mock(IDAOFactory.class); + personDAO = context.mock(IPersonDAO.class); + roleAssigmentDAO = context.mock(IRoleAssignmentDAO.class); + + server = new AbstractServer<Object>(sessionManager, daoFactory, null) + { + + public Object createLogger(IInvocationLoggerContext loggerContext) + { + return null; + } + + }; + + context.checking(new Expectations() + { + { + allowing(daoFactory).getPersonDAO(); + will(returnValue(personDAO)); + + allowing(daoFactory).getRoleAssignmentDAO(); + will(returnValue(roleAssigmentDAO)); + + allowing(daoFactory).getHomeDatabaseInstance(); + will(returnValue(null)); + } + }); + } + + @AfterMethod + public void afterMethod(Method method) + { + try + { + context.assertIsSatisfied(); + } catch (Error err) + { + fail(method.getName() + ": " + err.getMessage()); + } + } + + @Test + public void testFirstLoggedUserGetsAdminRoleAssignment() + { + prepareLoginExpectations(USERNAME, PASSWORD); + + final RecordingMatcher<RoleAssignmentPE> matcher = new RecordingMatcher<RoleAssignmentPE>(); + context.checking(new Expectations() + { + { + one(personDAO).listPersons(); + List<PersonPE> personsList = + Arrays.asList(createSystemUser(), createUser(ETL_SERVER)); + will(returnValue(personsList)); + + one(roleAssigmentDAO).createRoleAssignment(with(matcher)); + } + }); + SessionContextDTO session = server.tryToAuthenticate(USERNAME, PASSWORD); + assertNotNull(session); + RoleAssignmentPE roleAssigment = matcher.recordedObject(); + assertEquals(USERNAME, roleAssigment.getPerson().getUserId()); + assertEquals(RoleCode.ADMIN, roleAssigment.getRole()); + + } + + @Test + public void testSecondLoggedUserGetsNoRoleAssignment() + { + prepareLoginExpectations(USERNAME, PASSWORD); + + context.checking(new Expectations() + { + { + one(personDAO).listPersons(); + List<PersonPE> personsList = + Arrays.asList(createSystemUser(), createUser("test-admin-user")); + will(returnValue(personsList)); + } + }); + SessionContextDTO session = server.tryToAuthenticate(USERNAME, PASSWORD); + assertNull(session); + } + + @Test + public void testFirstLoggedEtlServerGetsRoleAssignment() + { + prepareLoginExpectations(ETL_SERVER, PASSWORD); + + final RecordingMatcher<RoleAssignmentPE> matcher = new RecordingMatcher<RoleAssignmentPE>(); + context.checking(new Expectations() + { + { + one(personDAO).listPersons(); + List<PersonPE> personsList = + Arrays.asList(createSystemUser(), createUser("admin")); + will(returnValue(personsList)); + + one(roleAssigmentDAO).createRoleAssignment(with(matcher)); + } + }); + SessionContextDTO session = server.tryToAuthenticate(ETL_SERVER, PASSWORD); + assertNotNull(session); + RoleAssignmentPE roleAssigment = matcher.recordedObject(); + assertEquals(ETL_SERVER, roleAssigment.getPerson().getUserId()); + assertEquals(RoleCode.ETL_SERVER, roleAssigment.getRole()); + } + + @Test + public void testSecondLoggedEtlServerGetsNoRoleAssignment() + { + prepareLoginExpectations(ETL_SERVER, PASSWORD); + + context.checking(new Expectations() + { + { + one(personDAO).listPersons(); + List<PersonPE> personsList = + Arrays.asList(createSystemUser(), createUser("etlserver1")); + will(returnValue(personsList)); + } + }); + SessionContextDTO session = server.tryToAuthenticate(ETL_SERVER, PASSWORD); + assertNull(session); + } + + private void prepareLoginExpectations(final String username, final String password) + { + context.checking(new Expectations() + { + { + one(sessionManager).tryToOpenSession(username, password); + will(returnValue(SESSION_TOKEN)); + + Principal principal = + new Principal(username, "firstname", "lastname", "email@email.ch"); + Session session = + new Session(username, SESSION_TOKEN, principal, "localhost", 1); + one(sessionManager).getSession(SESSION_TOKEN); + will(returnValue(session)); + + one(personDAO).tryFindPersonByUserId(username); + will(returnValue(null)); + + PersonPE person = new PersonPE(); + person.setUserId(username); + one(personDAO).createPerson(person); + + allowing(personDAO).tryFindPersonByUserId(PersonPE.SYSTEM_USER_ID); + will(returnValue(createSystemUser())); + } + }); + + } + + private PersonPE createSystemUser() + { + return createUser(PersonPE.SYSTEM_USER_ID); + } + + private PersonPE createUser(String userId) + { + PersonPE result = new PersonPE(); + result.setUserId(userId); + return result; + } +}