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;
+    }
+}