package de.hsadmin.mods.user; import java.util.LinkedList; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.Query; import de.hsadmin.core.model.AbstractEntity; import de.hsadmin.core.model.AbstractModuleImpl; import de.hsadmin.core.model.AuthorisationException; import de.hsadmin.core.model.HSAdminException; import de.hsadmin.core.model.Transaction; import de.hsadmin.hostsharing.BasePacType; import de.hsadmin.hostsharing.MultiOption; import de.hsadmin.mods.pac.Pac; public class UnixUserModuleImpl extends AbstractModuleImpl { public UnixUserModuleImpl() { } @Override public AbstractEntity initialize(AbstractEntity newEntity) throws AuthorisationException { UnixUser newUnixUser = (UnixUser) super.initialize(newEntity); newUnixUser.setName(getTransaction().getLoginUser().getPac().getName() + '-'); return newUnixUser; } @Override public AbstractEntity find(Class entityClass, Object key) throws HSAdminException { UnixUser res = (UnixUser) super.find(entityClass, key); needsPartialAccessOnPacOf(res, "find"); return res; } @Override public AbstractEntity findByString(Class entityClass, String key) throws HSAdminException { // do query UnixUser res = (UnixUser) super.findByString(entityClass, key); // return directly (checking rights already done in search within // findByString) return res; } @Override public List search(Class entityClass, String condition, String orderBy) throws HSAdminException { // do query if (orderBy == null || orderBy.length() == 0) { orderBy = "ORDER BY obj.name ASC"; } List res = super.search(entityClass, condition, orderBy); List ret = new LinkedList(); // remove entities where login user has no access rights if (res != null) { for (AbstractEntity entity : res) { try { UnixUser returnedUnixUser = (UnixUser) entity; needsPartialAccessOnPacOf(returnedUnixUser, "search"); ret.add(returnedUnixUser); } catch (AuthorisationException exc) { } // ignore } } // return clean result return ret; } @Override public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException { Transaction transaction = getTransaction(); EntityManager em = transaction.getEntityManager(); UnixUser loginUser = transaction.getLoginUser(); // only allow pac which matches the username (TODO: hard coded // Hostsharing convention) UnixUser newUnixUser = (UnixUser) newEntity; // validation of username and password String name = newUnixUser.getName(); if (name == null) { throw new HSAdminException("username is required"); } String userName = name.toLowerCase().trim(); for (char c : userName.toCharArray()) { if (!(Character.isLetterOrDigit(c) || c == '.' || c == '-' || c == '_')) { throw new AuthorisationException(loginUser, "add", newUnixUser, "userId"); } } if (userName.length() < 7 || userName.charAt(5) != '-' || userName.lastIndexOf('-') > 5) { throw new AuthorisationException(loginUser, "add", newUnixUser, "userId"); } String passWord = newUnixUser.getPassword(); if (passWord == null || passWord.length() == 0) { throw new HSAdminException("password is required"); } if (passWord.indexOf(':') >= 0) { throw new AuthorisationException(loginUser, "add", newUnixUser, "userId"); } Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName"); qPac.setParameter("pacName", userName.substring(0, 5)); Object singleResult = qPac.getSingleResult(); Pac pac = (Pac) singleResult; newUnixUser.setName(userName); newUnixUser.setHomedir("/home/pacs/" + userName.substring(0, 5) + "/users/" + userName.substring(6)); // no appropriate uid? if (newUnixUser.getUserId() < 1000) { // determine next free uid long nUID = 20000; Query qUID = em.createQuery("SELECT MAX(u.userId) FROM UnixUsers u"); Long maxUid = (Long) qUID.getSingleResult(); if (maxUid >= nUID) nUID = maxUid + 1; newUnixUser.setUserId(nUID); } else { // given uid belongs to same pac? Query q = em.createQuery("SELECT u.userId FROM UnixUsers u WHERE u.userId = :userId"); q.setParameter("userId", newUnixUser.getUserId()); List idExists = q.getResultList(); q = em.createQuery("SELECT u.userId FROM UnixUsers u WHERE u.userId = :userId AND u.pac = :pac"); q.setParameter("userId", newUnixUser.getUserId()); q.setParameter("pac", pac); List idOfSamePac = q.getResultList(); if (idOfSamePac.isEmpty() && !idExists.isEmpty()) { throw new AuthorisationException(loginUser, "add", newUnixUser, "userId"); } } //TODO: Needs better implementation String pacType = pac.getBasepac().getName(); if (!pacType.equals(BasePacType.PAC_WEB) && !pacType.equals(BasePacType.PAC_DW) && !pacType.equals(BasePacType.PAC_SW)) { throw new HSAdminException("not allowed for this packet type"); } //TODO: Needs better implementation Query qUnixUsers = em.createQuery("SELECT obj FROM UnixUsers obj WHERE obj.id = :pacId"); qUnixUsers.setParameter("pacId", pac.getId()); if (qUnixUsers.getResultList().size() >= MultiOption.UNIXUSERS_PER_OPTION * pac.getQuantityByComponentName("MULTI")) { throw new HSAdminException("included unix users exceeded"); } // don't move this up, it will update the new entity still with wrong // userid! newUnixUser.setPac(pac); newUnixUser.init(); // authorisation check needsFullAccessOnPacOf(newUnixUser, "add"); // add new entity return super.add(newEntity); } @Override public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException { Transaction transaction = getTransaction(); UnixUser loginUser = transaction.getLoginUser(); EntityManager em = transaction.getEntityManager(); UnixUser detachedUnixUser = (UnixUser) existingEntity; UnixUser attachedUnixUser = em.find(detachedUnixUser.getClass(), detachedUnixUser.getId()); needsFullAccessOnUser(attachedUnixUser, "update"); if (attachedUnixUser.getUserId() != detachedUnixUser.getUserId()) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "id"); } if (!attachedUnixUser.getName().equals(detachedUnixUser.getName())) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "name"); } attachedUnixUser.setPassword(detachedUnixUser.getPassword()); if (hasFullAccessOnPacOf(attachedUnixUser)) { attachedUnixUser.setComment(detachedUnixUser.getComment()); attachedUnixUser.setHomedir(detachedUnixUser.getHomedir()); } else { if (!attachedUnixUser.getComment().equals(detachedUnixUser.getComment())) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "comment"); } if (!attachedUnixUser.getHomedir().equals(detachedUnixUser.getHomedir())) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "homedir"); } } if (!attachedUnixUser.getShell().equals(detachedUnixUser.getShell())) if (hasFullAccessOnPacOf(attachedUnixUser) || isLoginShell(attachedUnixUser.getShell()) || !isLoginShell(detachedUnixUser.getShell())) attachedUnixUser.setShell(detachedUnixUser.getShell()); else throw new AuthorisationException(loginUser, "update", detachedUnixUser, "shell"); if (attachedUnixUser.isLocked() != detachedUnixUser.isLocked()) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "locked"); } if (detachedUnixUser.getQuotaSoftlimit() != null) { if (hasFullAccessOnPacOf(attachedUnixUser)) { attachedUnixUser.setQuotaSoftlimit(detachedUnixUser.getQuotaSoftlimit()); if (detachedUnixUser.getQuotaHardlimit() != null) { attachedUnixUser.setQuotaHardlimit(detachedUnixUser.getQuotaHardlimit()); } } else { Integer oldQuota = attachedUnixUser.getQuotaSoftlimit(); Integer newQuota = detachedUnixUser.getQuotaSoftlimit(); if (oldQuota != newQuota && !oldQuota.equals(newQuota)) { throw new AuthorisationException(loginUser, "update", detachedUnixUser, "quota"); } } } return super.update(attachedUnixUser); } @Override public void delete(AbstractEntity existingEntity) throws HSAdminException { // get the entity from the database EntityManager entityManager = getTransaction().getEntityManager(); UnixUser detachedUnixUser = (UnixUser) existingEntity; UnixUser attachedUnixUser = entityManager.find(detachedUnixUser.getClass(), detachedUnixUser.getId()); // authorisation check if (attachedUnixUser.getName().length() < 7) { throw new AuthorisationException(attachedUnixUser, "delete"); } needsFullAccessOnPacOf(attachedUnixUser, "delete"); // delete entity super.delete(attachedUnixUser); } // throws an AuthorisationException if the login user has no write acess // on the pac of the given UnixUser private boolean hasFullAccessOnPacOf(UnixUser user) { UnixUser loginUser = getTransaction().getLoginUser(); String loginUserName = loginUser.getName(); return loginUser.hasHostmasterRole() || loginUserName.equals(user.getPac().getName()) || loginUserName.equals(user.getPac().getCustomer().getName()); } // throws an AuthorisationException if the login user has no write acess // on the pac of the given UnixUser private void needsFullAccessOnPacOf(UnixUser user, String method) throws AuthorisationException { if (!hasFullAccessOnPacOf(user)) throw new AuthorisationException(getTransaction().getLoginUser(), method, user); } private void needsPartialAccessOnPacOf(UnixUser user, String method) throws AuthorisationException { UnixUser loginUser = getTransaction().getLoginUser(); if (!hasFullAccessOnPacOf(user) && loginUser.getPac().id() != user.getPac().id()) { throw new AuthorisationException(loginUser, method, user); } } private void needsFullAccessOnUser(UnixUser user, String method) throws AuthorisationException { UnixUser loginUser = getTransaction().getLoginUser(); if (!hasFullAccessOnPacOf(user) && !loginUser.sameIdAs(user)) { throw new AuthorisationException(loginUser, method, user); } } private static boolean isLoginShell(String shell) { if (shell.equals("/bin/sh")) return true; if (shell.equals("/bin/bash")) return true; if (shell.equals("/bin/csh")) return true; if (shell.equals("/bin/tcsh")) return true; if (shell.equals("/bin/zsh")) return true; if (shell.equals("/bin/ksh")) return true; return false; } }