hs.hsadmin/hsarback/src/de/hsadmin/mods/user/UnixUserModuleImpl.java

284 lines
9.9 KiB
Java

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.AuthorisationException;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.mods.pac.Pac;
public class UnixUserModuleImpl extends AbstractModuleImpl {
private static final long serialVersionUID = 7480353553685400790L;
public UnixUserModuleImpl() {
}
@Override
public AbstractEntity initialize(AbstractEntity newEntity) throws AuthorisationException {
UnixUser newUnixUser = (UnixUser) super.initialize(newEntity);
newUnixUser.setName(getLoginUser().getPac().getName() + '-');
return newUnixUser;
}
@Override
public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
// do query
UnixUser res = (UnixUser) super.find(entityClass, key);
// check access rights
needsPartialAccessOnPacOf(res, "find");
// return clean result
return res;
}
@Override
public AbstractEntity findByString(Class<? extends AbstractEntity> 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<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) throws HSAdminException {
// do query
if (orderBy == null || orderBy.length() == 0) {
orderBy = "ORDER BY obj.name ASC";
}
List<AbstractEntity> res = super.search(entityClass, condition, orderBy);
List<AbstractEntity> ret = new LinkedList<AbstractEntity>();
// 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 {
EntityManager em = getEntityManager();
// 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(getLoginUser(), "add", newUnixUser, "userId");
}
}
if (userName.length() < 7 || userName.charAt(5) != '-' || userName.lastIndexOf('-') > 5) {
throw new AuthorisationException(getLoginUser(), "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(getLoginUser(), "add", newUnixUser, "userId");
}
if (newUnixUser.getPac() == null || newUnixUser.getPac().getNew()) {
}
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 AND u.pac = :pac");
q.setParameter("userId", newUnixUser.getUserId());
q.setParameter("pac", pac);
List<?> idOfSamePac = q.getResultList();
if (idOfSamePac.size() == 0) {
throw new AuthorisationException(getLoginUser(), "add", newUnixUser, "userId");
}
}
// 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 {
// get the entity from the database
UnixUser detachedUnixUser = (UnixUser) existingEntity;
UnixUser attachedUnixUser = getEntityManager().find(detachedUnixUser.getClass(),
detachedUnixUser.getId());
// authorisation check
needsFullAccessOnUser(attachedUnixUser, "update");
// update fields where the login user has write access
if (attachedUnixUser.getUserId() != detachedUnixUser.getUserId())
throw new AuthorisationException(getLoginUser(), "update",
detachedUnixUser, "id");
attachedUnixUser.setName(detachedUnixUser.getName());
attachedUnixUser.setPassword(detachedUnixUser.getPassword());
if (hasFullAccessOnPacOf(attachedUnixUser))
attachedUnixUser.setComment(detachedUnixUser.getComment());
else if (!attachedUnixUser.getComment().equals(
detachedUnixUser.getComment()))
throw new AuthorisationException(getLoginUser(), "update",
detachedUnixUser, "comment");
if (hasFullAccessOnPacOf(attachedUnixUser))
attachedUnixUser.setHomedir(detachedUnixUser.getHomedir());
else if (!attachedUnixUser.getHomedir().equals(
detachedUnixUser.getHomedir()))
throw new AuthorisationException(getLoginUser(), "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(getLoginUser(), "update",
detachedUnixUser, "shell");
if (attachedUnixUser.isLocked() != detachedUnixUser.isLocked())
throw new AuthorisationException(getLoginUser(), "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(getLoginUser(), "update",
detachedUnixUser, "quota");
}
}
// update entity
return super.update(attachedUnixUser);
}
@Override
public void delete(AbstractEntity existingEntity) throws HSAdminException {
// get the entity from the database
UnixUser detachedUnixUser = (UnixUser) existingEntity;
UnixUser attachedUnixUser = getEntityManager().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);
}
private EntityManager getEntityManager() {
return getTransaction().getEntityManager();
}
// throws an AuthorisationException if the login user has no write acess
// on the pac of the given UnixUser
private boolean hasFullAccessOnPacOf(UnixUser user) {
// only pac admins (same name as pac) and the owner (customer) have
// write access to the pac
boolean isPacAdmin = getLoginUser().getName().equals(
user.getPac().getName());
boolean isCustomer = getLoginUser().getName().equals(
user.getPac().getCustomer().getName());
boolean isHostmaster = getLoginUser().hasHostmasterRole();
return isPacAdmin || isCustomer || isHostmaster;
}
// 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(getLoginUser(), method, user);
}
// throws an AuthorisationException if the login user has no read acess on
// the pac of the given UnixUser
private void needsPartialAccessOnPacOf(UnixUser user, String method)
throws AuthorisationException {
if (!hasFullAccessOnPacOf(user)
&& getLoginUser().getPac().id() != user.getPac().id())
throw new AuthorisationException(getLoginUser(), method, user);
}
// throws an AuthorisationException if the login user has not even partial
// write access on the given UnixUser
private void needsFullAccessOnUser(UnixUser user, String method)
throws AuthorisationException {
// neither pac admin (same name as pac), pac owner (customer) nor the
// user itself?
if (!hasFullAccessOnPacOf(user) && !getLoginUser().sameIdAs(user))
throw new AuthorisationException(getLoginUser(), method, user);
}
// returns true if the given shell is a login shell
private static boolean isLoginShell(String shell) {
// TODO: list of login shells should not be hardcoded
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;
}
}