280 lines
9.7 KiB
Java
280 lines
9.7 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.Entity;
|
||
|
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 Entity initialize(Entity newEntity) throws AuthorisationException {
|
||
|
UnixUser newUnixUser = (UnixUser) super.initialize(newEntity);
|
||
|
newUnixUser.setName(getLoginUser().getPac().getName() + '-');
|
||
|
return newUnixUser;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Entity find(Class<? extends Entity> 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 Entity findByString(Class<? extends Entity> 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<Entity> search(Class<? extends Entity> entityClass, String condition, String orderBy) throws HSAdminException {
|
||
|
// do query
|
||
|
if (orderBy == null || orderBy.length() == 0) {
|
||
|
orderBy = "ORDER BY obj.name ASC";
|
||
|
}
|
||
|
List<Entity> res = super.search(entityClass, condition, orderBy);
|
||
|
List<Entity> ret = new LinkedList<Entity>();
|
||
|
|
||
|
// remove entities where login user has no access rights
|
||
|
if (res != null) {
|
||
|
for (Entity entity : res) {
|
||
|
try {
|
||
|
UnixUser returnedUnixUser = (UnixUser) entity;
|
||
|
needsPartialAccessOnPacOf(returnedUnixUser, "search");
|
||
|
ret.add(returnedUnixUser);
|
||
|
} catch (AuthorisationException exc) {
|
||
|
} // ignore
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// return clean result
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Entity add(Entity 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");
|
||
|
}
|
||
|
Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName");
|
||
|
qPac.setParameter("pacName", userName.substring(0, 5));
|
||
|
Pac pac = (Pac) qPac.getSingleResult();
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
private EntityManager getEntityManager() {
|
||
|
return getTransaction().getEntityManager();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Entity update(Entity 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(Entity 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);
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
}
|