HSAdmin Backend Domains, E-Mail, Datenbanken
Peter Hormanns
2011-08-12 888b109f9edc1c0bf9b6131decfeefd9e3b09f49
find module implementations by annotation
26 files modified
895 ■■■■■ changed files
hsarback/src/de/hsadmin/core/model/AbstractModuleImpl.java 479 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/core/model/EntitySessionHelper.java 32 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/core/model/SecureDefaultModuleImpl.java 35 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/cust/Customer.java 11 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/cust/CustomerModuleImpl.java 20 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/Database.java 20 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/DatabaseUser.java 10 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlDatabase.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseModuleImpl.java 14 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlUser.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/MySqlUserModuleImpl.java 10 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlDatabase.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseModuleImpl.java 13 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlUser.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/db/PgSqlUserModuleImpl.java 8 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/dom/Domain.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/dom/DomainModuleImpl.java 19 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAddress.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAddressModuleImpl.java 12 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAlias.java 13 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/email/EMailAliasModuleImpl.java 10 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/Pac.java 2 ●●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/pac/PacModuleImpl.java 4 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/user/UnixUser.java 29 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/mods/user/UnixUserModuleImpl.java 120 ●●●●● patch | view | raw | blame | history
hsarback/test/de/hsadmin/remote/RemoteTest.java 22 ●●●● patch | view | raw | blame | history
hsarback/src/de/hsadmin/core/model/AbstractModuleImpl.java
@@ -1,13 +1,13 @@
package de.hsadmin.core.model;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.hsadmin.core.qserv.EntityProcessorFactory;
import de.hsadmin.core.qserv.Processor;
@@ -21,21 +21,183 @@
 */
public abstract class AbstractModuleImpl implements ModuleInterface {
    
    private static Log log = LogFactory.getLog(AbstractModuleImpl.class);
    private UnixUser loginUser;
    private Transaction transaction;
    public void construct(Transaction tx) {
        transaction = tx;
    }
    public Transaction getTransaction() {
        return transaction;
    }
    public AbstractEntity initialize(AbstractEntity newEntity)
            throws AuthorisationException {
        newEntity.initialize(transaction.getEntityManager(), transaction.getLoginUser());
        return newEntity;
    }
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        UnixUser loginUser = transaction.getLoginUser();
        EntityManager entityManager = transaction.getEntityManager();
        newEntity.complete(entityManager, loginUser);
        entityManager.persist(newEntity);
        if (!newEntity.isWriteAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        EntityProcessorFactory procFact = createProcessorFactory(newEntity.getClass());
        if (procFact != null) {
            Processor proc = procFact.createCreateProcessor(entityManager, newEntity);
            queueProcessor(proc, loginUser, newEntity, "hinzugefuegt");
        }
        return newEntity;
    }
    public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
        AbstractEntity entity = transaction.getEntityManager().find(entityClass, key);
        UnixUser loginUser = transaction.getLoginUser();
        if (!entity.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", entity);
        }
        return entity;
    }
    public AbstractEntity findByString(Class<? extends AbstractEntity> entityClass, String key) throws HSAdminException {
        Method method = null;
        try {
            method = entityClass.getDeclaredMethod("createQueryFromStringKey", String.class);
        } catch (SecurityException e) {
            throw new HSAdminException(e);
        } catch (NoSuchMethodException e) {
            method = null;
        }
        AbstractEntity entity = null;
        if (method == null) {
            entity = transaction.getEntityManager().find(entityClass, key);
        }
        else {
            String query = null;
            try {
                query = (String) method.invoke(null, key);
            } catch (Exception e) {
                throw new HSAdminException(e);
            }
            List<AbstractEntity> result = search(entityClass, query, null);
            if (result.size() > 1) throw new NonUniqueResultException();
            if (result.size() == 0) return null;
            entity = result.get(0);
        }
        return entity;
    }
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) throws HSAdminException {
        UnixUser loginUser = transaction.getLoginUser();
        condition = restrict(entityClass, loginUser, condition);
        Entity entityAnnot = entityClass.getAnnotation(Entity.class);
        String queryString = "SELECT obj FROM " + entityAnnot.name() + " obj";
        if (condition != null && condition.length() > 0) {
            queryString += " WHERE " + condition;
        }
        if (condition != null && condition.contains("AND (FALSE)")) {
            return new LinkedList<AbstractEntity>();
        }
        if (orderBy != null) {
            queryString += " ";
            queryString += orderBy;
        }
        EntityManager entityManager = transaction.getEntityManager();
        entityManager.clear();
        Query query = entityManager.createQuery(queryString);
        query.setParameter("loginUser", loginUser);
        query.setParameter("loginUserName", loginUser.getName());
        query.setParameter("loginUserPac", loginUser.getPac());
        try {
            List<?> res = query.getResultList();
            List<AbstractEntity> ret = new LinkedList<AbstractEntity>();
            // remove entities where login user has no access rights
            for (Object entity : res) {
                if (entity instanceof AbstractEntity) {
                    AbstractEntity returnedEntity = (AbstractEntity) entity;
                    if (returnedEntity.isReadAllowedFor(transaction.getLoginUser())) {
                        ret.add(returnedEntity);
                    }
                }
            }
            return ret;
        } catch (Exception ex) {
            throw new HSAdminException(ex);
        }
    }
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        UnixUser loginUser = transaction.getLoginUser();
        existingEntity = existingEntity.merge(transaction.getEntityManager(), loginUser);
        if (!existingEntity.isWriteAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "update", existingEntity);
        }
        EntityProcessorFactory procFact = createProcessorFactory(existingEntity.getClass());
        if (procFact != null) {
            Processor proc = procFact.createUpdateProcessor(transaction.getEntityManager(), existingEntity);
            queueProcessor(proc, loginUser, existingEntity, "aktualisiert");
        }
        return existingEntity;
    }
    public void delete(AbstractEntity existingEntity) throws HSAdminException {
        UnixUser loginUser = transaction.getLoginUser();
        EntityManager entityManager = transaction.getEntityManager();
        existingEntity = entityManager.find(existingEntity.getClass(), existingEntity.id());
        if (!existingEntity.isWriteAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", existingEntity);
        }
        entityManager.remove(existingEntity);
        EntityProcessorFactory procFact = createProcessorFactory(existingEntity.getClass());
        if (procFact != null) {
            Processor proc = procFact.createDeleteProcessor(entityManager, existingEntity);
            queueProcessor(proc, loginUser, existingEntity, "geloescht");
        }
    }
    protected EntityProcessorFactory createProcessorFactory(Class<? extends AbstractEntity> entityClass)
            throws HSAdminException {
        String procFactName = entityClass.getCanonicalName() + "ProcessorFactory";
        Class<?> procFactClass = null;
        EntityProcessorFactory procFact = null;
        try {
            procFactClass = Class.forName(procFactName);
            if (procFactClass != null) {
                procFact = (EntityProcessorFactory) procFactClass.newInstance();
            }
        } catch (ClassNotFoundException e) {
            // no processor defined
        } catch (InstantiationException e) {
            throw new HSAdminException(e);
        } catch (IllegalAccessException e) {
            throw new HSAdminException(e);
        }
        return procFact;
    }
    protected void queueProcessor(Processor proc, UnixUser user, AbstractEntity entity, String action) {
        EntityInfo entityInfo = entity.getClass().getAnnotation(EntityInfo.class);
        String entityTypeName = entityInfo != null ? entityInfo.name() : entity.getClass().getSimpleName();
        StringBuilder details = new StringBuilder();
        String title = entityTypeName + " (" + entity.createStringKey() + ") " + action;
        QueueTask task = new QueueTask(user, title, details.toString(), proc);
        transaction.getEntityManager().persist(task);
        transaction.enqueue(entity.getHiveName(), task);
    }
    public String toString(StackTraceElement[] stackTrace) {
        StringBuilder stack = new StringBuilder();
        for (StackTraceElement e : stackTrace) {
            stack.append(e.getFileName() + ":" + e.getLineNumber() + "\n");
        }
        return stack.toString();
    }
    /**
     *  apply access restriction to JPA-QL condition.
     * @param entityClass
     * @param loginUser
     * @param condition
     * @return
     */
    private String restrict(Class<?> entityClass, UnixUser loginUser, String condition) {
        String restriction = AbstractEntity.restriction(entityClass, loginUser);
@@ -46,302 +208,5 @@
        else
            condition = restriction;
        return condition;
    }
    public Transaction getTransaction() {
        return transaction;
    }
    public AbstractEntity initialize(AbstractEntity newEntity)
            throws AuthorisationException {
        newEntity.initialize(transaction.getEntityManager(), getLoginUser());
        return newEntity;
    }
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        // get the user who is logged in
        UnixUser loginUser = getLoginUser();
        // create record in database
        log.debug("merging?");
        newEntity.complete(transaction.getEntityManager(), loginUser);
        try {
            transaction.getEntityManager().persist(newEntity);
        } catch (Throwable exc) {
            log.error("exception: " + exc);
        } finally {
            log.debug("finally");
        }
        log.debug("merged");
        // check rights
        if (!newEntity.isWriteAllowedFor(loginUser))
            throw new AuthorisationException(loginUser, "add", newEntity);
        // generically create the processor
        EntityProcessorFactory procFact = createProcessorFactory(newEntity.getClass());
        if (procFact == null) {
            log.debug("no procFact found :-(");
            return newEntity;
        }
        log.debug("procFact found :-)");
        Processor proc = procFact.createCreateProcessor(transaction.getEntityManager(), newEntity);
        // queue the processor
        queueProcessor(proc, loginUser, newEntity, "hinzugefuegt");
        // return the added entity
        return newEntity;
    }
    public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
        AbstractEntity entity = transaction.getEntityManager().find(entityClass, key);
        // check rights
        UnixUser loginUser = getLoginUser();
        if (!entity.isReadAllowedFor(loginUser))
            throw new AuthorisationException(loginUser, "add", entity);
        return entity;
    }
    public AbstractEntity findByString(Class<? extends AbstractEntity> entityClass, String key) throws HSAdminException {
        // find a static method which creates the query
        java.lang.reflect.Method method = null;
        try {
            method = entityClass.getDeclaredMethod("createQueryFromStringKey", String.class);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            method = null;
        }
        AbstractEntity entity;
        if (method == null)
            entity = transaction.getEntityManager().find(entityClass, key);
        else {
            // get the query expression from the static method (query part after
            // WHERE)
            String query;
            try {
                query = (String) method.invoke(null, key);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            // perform the query
            List<AbstractEntity> result = search(entityClass, query, null);
            if (result.size() > 1)
                throw new javax.persistence.NonUniqueResultException();
            if (result.size() == 0)
                return null;
            entity = result.get(0);
            // this was maybe thought as a fallback
            // but is wrong when the above result is empty due to accessibility
            // entity = em.find(entityClass, key);
        }
        // return (checking rights already done in search)
        return entity;
    }
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) throws HSAdminException {
        // restrict query
        UnixUser loginUser = getLoginUser();
        condition = restrict(entityClass, loginUser, condition);
        // get the entities name (query part from FROM to WHERE)
        // TODO: beware SQL injections!!!
        javax.persistence.Entity entityAnnot = entityClass.getAnnotation(javax.persistence.Entity.class);
        String queryString = "SELECT obj FROM " + entityAnnot.name() + " obj";
        if (condition != null && condition.length() > 0)
            queryString += " WHERE " + condition;
        // Fix problem with queries WHERE .. AND (FALSE) -- pe
        if (condition != null && condition.contains("AND (FALSE)")) {
            return new LinkedList<AbstractEntity>();
        }
        if (orderBy != null) {
            queryString += " ";
            queryString += orderBy;
        }
        // set parameters
        EntityManager entityManager = transaction.getEntityManager();
        entityManager.clear();
        Query query = entityManager.createQuery(queryString);
        setQueryParameter(query, queryString, "loginUser", loginUser);
        setQueryParameter(query, queryString, "loginUserName", loginUser.getName());
        setQueryParameter(query, queryString, "loginUserPac", loginUser.getPac());
        // do query
        try {
            List<?> res = query.getResultList();
            List<AbstractEntity> ret = new LinkedList<AbstractEntity>();
            // remove entities where login user has no access rights
            for (Object entity : res) {
                if (entity instanceof AbstractEntity) {
                    AbstractEntity returnedEntity = (AbstractEntity) entity;
                    if (returnedEntity.isReadAllowedFor(getLoginUser())) {
                        ret.add(returnedEntity);
                    }
                }
            }
            // return clean result
            return ret;
        } catch (Exception ex) {
            throw new HSAdminException(ex);
        }
    }
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        // get the user who is logged in
        UnixUser loginUser = getLoginUser();
        // update record in database
        log.debug("merging:");
        try {
            existingEntity = existingEntity.merge(transaction.getEntityManager(), loginUser);
        } catch (Throwable exc) {
            log.error("exception: " + exc);
            throw new RuntimeException(exc);
        } finally {
            log.debug("finally");
        }
        log.debug("merged!");
        // check rights
        if (!existingEntity.isWriteAllowedFor(loginUser))
            throw new AuthorisationException(loginUser, "update",
                    existingEntity);
        // generically create the processor
        EntityProcessorFactory procFact =
            createProcessorFactory(existingEntity.getClass());
        if (procFact != null) {
            log.debug("creating processor");
            Processor proc = procFact.createUpdateProcessor(transaction.getEntityManager(), existingEntity);
            // queue the processor
            queueProcessor(proc, loginUser, existingEntity, "aktualisiert");
        }
        // return the merged entity
        return existingEntity;
    }
    public void delete(AbstractEntity existingEntity) throws HSAdminException {
        // get the user who is logged in
        UnixUser user = getLoginUser();
        // re-attach the entity
        log.debug("merging:");
        try {
            existingEntity = transaction.getEntityManager().find(existingEntity.getClass(), existingEntity.id());
        } catch (Throwable exc) {
            log.error("exception: " + exc);
            throw new RuntimeException(exc);
        } finally {
            log.debug("finally");
        }
        log.debug("merged!");
        // check rights
        if (!existingEntity.isWriteAllowedFor(loginUser))
            throw new AuthorisationException(loginUser, "add", existingEntity);
        // delete record in database
        log.debug("deleting:");
        try {
            transaction.getEntityManager().remove(existingEntity);
        } catch (Throwable exc) {
            log.error("exception: " + exc);
        } finally {
            log.debug("finally");
        }
        log.debug("deleted!");
        // generically create the processor
        EntityProcessorFactory procFact = createProcessorFactory(existingEntity.getClass());
        if (procFact == null) {
            log.debug("no procFact found :-(");
            return;
        }
        log.debug("procFact found :-)");
        Processor proc = procFact.createDeleteProcessor(transaction.getEntityManager(), existingEntity);
        // queue the processor
        queueProcessor(proc, user, existingEntity, "geloescht");
    }
    public EntityProcessorFactory createProcessorFactory(Class<? extends AbstractEntity> entityClass) {
        try {
            String procFactName = entityClass.getCanonicalName()
                    + "ProcessorFactory";
            Class<?> procFactClass = Class.forName(procFactName);
            if (procFactClass == null)
                return null;
            Object procFact = procFactClass.newInstance();
            return (EntityProcessorFactory) procFact;
        } catch (Exception exc) {
            log.error("exception creating instance: " + exc);
            return null;
        }
    }
    /**
     *  get current login user from session context.
     * @return
     */
    public UnixUser getLoginUser() {
        if (loginUser == null) {
            loginUser = transaction.getLoginUser();
        }
        return loginUser;
    }
    public void queueProcessor(Processor proc, UnixUser user, AbstractEntity entity, String action) {
        log.debug("queueing processor for user " + user.getId() + "/"
                + user.getUserId() + "/" + user.getName());
        EntityInfo entityInfo =
            entity.getClass().getAnnotation(EntityInfo.class);
        String entityTypeName =
            entityInfo != null ? entityInfo.name() : entity.getClass().getSimpleName();
        StringBuilder details = new StringBuilder();
        // TODO: add properties of entity to details
        String title =
            entityTypeName + " (" + entity.createStringKey() + ") " + action;
        QueueTask task = new QueueTask(user, title, details.toString(), proc);
        transaction.getEntityManager().persist(task);
        transaction.enqueue(entity.getHiveName(), task);
        log.debug("processor queued");
    }
    public String toString(StackTraceElement[] stackTrace) {
        StringBuilder stack = new StringBuilder();
        for (StackTraceElement e : stackTrace)
            stack.append(e.getFileName() + ":" + e.getLineNumber() + "\n");
        return stack.toString();
    }
    public static void setQueryParameter(Query query, String queryString,
            String argName, Object argValue) {
        int argLen = argName.length();
        int iMax = queryString.length();
        int i = 0;
        while ((i = queryString.indexOf(argName, i)) >= 0) {
            if ((i + argLen) >= iMax || queryString.charAt(i + argLen) < 'A') {
                query.setParameter(argName, argValue);
                break;
            }
            ++i;
        }
    }
}
hsarback/src/de/hsadmin/core/model/EntitySessionHelper.java
@@ -17,17 +17,9 @@
        // get in instance
        AbstractModuleImpl impl = null;
        try {
            // determine wrapper class
            ModuleImpl wrapperAnnot = entityClass.getAnnotation(ModuleImpl.class);
            Class<?> wrapperClass = null;
            if (wrapperAnnot != null) {
                wrapperClass = wrapperAnnot.value();
            } else {
                wrapperClass = Class.forName(entityClass.getCanonicalName() + "ModuleImpl");
            }
            Class<?> wrapperClass = determineModuleImpl(entityClass);
            // instantiate wrapper
            impl = (AbstractModuleImpl) wrapperClass.newInstance();
            impl.construct(tx);
            impl = instantiateModuleImpl(tx, wrapperClass);
        } catch (ClassNotFoundException exc) {
            log.info("entity class '"
                            + entityClass.getCanonicalName()
@@ -40,4 +32,24 @@
        return impl;
    }
    private static AbstractModuleImpl instantiateModuleImpl(Transaction tx, Class<?> wrapperClass)
            throws InstantiationException, IllegalAccessException {
        AbstractModuleImpl impl;
        impl = (AbstractModuleImpl) wrapperClass.newInstance();
        impl.construct(tx);
        return impl;
    }
    private static Class<?> determineModuleImpl(Class<? extends AbstractEntity> entityClass)
            throws ClassNotFoundException {
        ModuleImpl wrapperAnnot = entityClass.getAnnotation(ModuleImpl.class);
        Class<?> wrapperClass = null;
        if (wrapperAnnot != null) {
            wrapperClass = wrapperAnnot.value();
        } else {
            wrapperClass = Class.forName(entityClass.getCanonicalName() + "ModuleImpl");
        }
        return wrapperClass;
    }
}
hsarback/src/de/hsadmin/core/model/SecureDefaultModuleImpl.java
@@ -3,6 +3,10 @@
import java.util.LinkedList;
import java.util.List;
import javax.persistence.EntityManager;
import de.hsadmin.mods.user.UnixUser;
/**
 *  allows access only for hostmasters, used as fallback wrapper.
 */
@@ -15,26 +19,29 @@
    @Override
    public AbstractEntity find(Class<? extends AbstractEntity> entityClass, Object key) throws HSAdminException {
        Transaction transaction = getTransaction();
        AbstractEntity entity = super.find(entityClass, key);
        if (entity != null && !entity.isReadAllowedFor(getLoginUser()))
            throw new AuthorisationException(getLoginUser(), "find");
        if (entity != null && !entity.isReadAllowedFor(transaction.getLoginUser()))
            throw new AuthorisationException(transaction.getLoginUser(), "find");
        return entity;
    }
    @Override
    public AbstractEntity findByString(Class<? extends AbstractEntity> entityClass, String key) throws HSAdminException {
        Transaction transaction = getTransaction();
        AbstractEntity entity = super.findByString(entityClass, key);
        if (entity != null && !entity.isReadAllowedFor(getLoginUser()))
            throw new AuthorisationException(getLoginUser(), "findByString");
        if (entity != null && !entity.isReadAllowedFor(transaction.getLoginUser()))
            throw new AuthorisationException(transaction.getLoginUser(), "findByString");
        return entity;
    }
    @Override
    public List<AbstractEntity> search(Class<? extends AbstractEntity> entityClass, String condition, String orderBy) 
            throws HSAdminException {
        Transaction transaction = getTransaction();
        // restrict query to entities where the loginUser could have rights on
        SearchFilter filterAnnot;
        if (!getLoginUser().hasHostmasterRole()
        if (!transaction.getLoginUser().hasHostmasterRole()
                && (filterAnnot = getSecurityFilterAnnotation(entityClass)) != null) {
            String securityCondition = filterAnnot.value();
            if (condition != null && condition.length() > 0)
@@ -52,7 +59,7 @@
        if (res != null) {
            for (AbstractEntity entity : res) {
                AbstractEntity returnedEntity = entity;
                if (returnedEntity.isReadAllowedFor(getLoginUser()))
                if (returnedEntity.isReadAllowedFor(transaction.getLoginUser()))
                    ret.add(returnedEntity);
            }
        }
@@ -88,15 +95,13 @@
    @Override
    public void delete(AbstractEntity detachedEntity) throws HSAdminException {
        // get the entity from the database
        AbstractEntity attachedEntity = getTransaction().getEntityManager().find(detachedEntity.getClass(),
                detachedEntity.id());
        // does the login user have the right to delete?
        if (!attachedEntity.isWriteAllowedFor(getLoginUser()))
            throw new AuthorisationException(getLoginUser(), "delete",
                    detachedEntity);
        Transaction transaction = getTransaction();
        EntityManager entityManager = transaction.getEntityManager();
        UnixUser loginUser = transaction.getLoginUser();
        AbstractEntity attachedEntity = entityManager.find(detachedEntity.getClass(), detachedEntity.id());
        if (!attachedEntity.isWriteAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "delete", detachedEntity);
        }
        super.delete(attachedEntity);
    }
hsarback/src/de/hsadmin/mods/cust/Customer.java
@@ -22,12 +22,15 @@
import javax.persistence.Temporal;
import javax.persistence.Transient;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@Entity(name = "Customers")
@Table(name = "business_partner")
public class Customer extends de.hsadmin.core.model.AbstractEntity implements Serializable {
@ModuleImpl(de.hsadmin.mods.cust.CustomerModuleImpl.class)
public class Customer extends AbstractEntity implements Serializable {
    private static final long serialVersionUID = -7450594652238392616L;
@@ -253,17 +256,11 @@
        return null; // TODO: no access yet
    }
    /**
     * determines whether the given user has full read access on all merged fields of this entity
     */
    @Override
    public boolean isReadAllowedFor(UnixUser loginUser) {
        return loginUser.hasCustomerRoleFor(this);
    }
    /**
     * determines whether the given user has full write access on all merged fields of this entity
     */
    @Override
    public boolean isWriteAllowedFor(UnixUser loginUser) {
        return loginUser.hasCustomerRoleFor(this);
hsarback/src/de/hsadmin/mods/cust/CustomerModuleImpl.java
@@ -9,6 +9,7 @@
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.GenericModuleImpl;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.Transaction;
import de.hsadmin.core.util.TextUtil;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -17,8 +18,9 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        if (!getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        Transaction transaction = getTransaction();
        if (!transaction.getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(transaction.getLoginUser(), "add", newEntity);
        }
        Customer newCustomer = (Customer) newEntity;
        assertNotNull("membercode", newCustomer.getName());
@@ -62,16 +64,18 @@
    @Override
    public AbstractEntity update(AbstractEntity existingEntity)
            throws HSAdminException {
        if (!getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(getLoginUser(), "update", existingEntity);
        Transaction transaction = getTransaction();
        if (!transaction.getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(transaction.getLoginUser(), "update", existingEntity);
        }
        return super.update(existingEntity);
    }
    @Override
    public void delete(AbstractEntity existingEntity) throws HSAdminException {
        if (!getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(getLoginUser(), "delete", existingEntity);
        Transaction transaction = getTransaction();
        if (!transaction.getLoginUser().hasHostmasterRole()) {
            throw new AuthorisationException(transaction.getLoginUser(), "delete", existingEntity);
        }
        Customer cust = (Customer) existingEntity;
        
@@ -81,13 +85,13 @@
        Date memberUntil = cust.getMemberUntil();
        if (memberSince != null) {
            if (memberUntil == null || memberUntil.after(new Date())) {
                throw new AuthorisationException(getLoginUser(), "delete", existingEntity);
                throw new AuthorisationException(transaction.getLoginUser(), "delete", existingEntity);
            }
        }
        // keine Pakete mehr!
        Set<Pac> pacs = cust.getPacs();
        if (pacs != null && pacs.size() > 0) {
            throw new AuthorisationException(getLoginUser(), "delete", existingEntity);
            throw new AuthorisationException(transaction.getLoginUser(), "delete", existingEntity);
        }
        
        GenericModuleImpl helper = new GenericModuleImpl(getTransaction());
hsarback/src/de/hsadmin/mods/db/Database.java
@@ -22,7 +22,6 @@
import javax.persistence.Table;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@@ -84,29 +83,20 @@
    public void complete(EntityManager em, UnixUser loginUser) {
        if (pac == null && name != null && name.length() > 0) {
            if (name.length() < 7 || name.charAt(5) != '_') {
                throw new SecurityException("database name '" + name
                        + "' not allowed");
                throw new SecurityException("database name '" + name + "' not allowed");
            }
            // TODO: it's ugly having this code here, needs refactoring
            String pacName = name.substring(0, 5);
            try {
                // get the entities name (query part from FROM to WHERE)
                Entity entityAnnot = Pac.class.getAnnotation(Entity.class);
                String queryString = "SELECT obj FROM " + entityAnnot.name() + " obj WHERE "
                        + Pac.createQueryFromStringKey(pacName);
                // set parameters
                Query query = em.createQuery(queryString);
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUser", loginUser);
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUserName", loginUser.getName());
                AbstractModuleImpl.setQueryParameter(query,
                        queryString, "loginUserPac", loginUser.getPac());
                query.setParameter("loginUser", loginUser);
                query.setParameter("loginUserName", loginUser.getName());
                query.setParameter("loginUserPac", loginUser.getPac());
                pac = (Pac) query.getSingleResult();
            } catch (NoResultException exc) {
                throw new SecurityException("packet '" + pacName
                        + "' not found or access denied");
                throw new SecurityException("packet '" + pacName + "' not found or access denied");
            }
        }
    }
hsarback/src/de/hsadmin/mods/db/DatabaseUser.java
@@ -23,7 +23,6 @@
import javax.persistence.Transient;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -87,12 +86,9 @@
                // set parameters
                Query query = em.createQuery(queryString);
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUser", loginUser);
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUserName", loginUser.getName());
                AbstractModuleImpl.setQueryParameter(query, queryString,
                        "loginUserPac", loginUser.getPac());
                query.setParameter("loginUser", loginUser);
                query.setParameter("loginUserName", loginUser.getName());
                query.setParameter("loginUserPac", loginUser.getPac());
                pac = (Pac) query.getSingleResult();
            } catch (NoResultException exc) {
                throw new SecurityException("packet '" + pacName
hsarback/src/de/hsadmin/mods/db/MySqlDatabase.java
@@ -6,6 +6,7 @@
import javax.persistence.Entity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@@ -14,6 +15,7 @@
@EntityInfo(name = "MySQL Datenbank")
@SearchFilter("obj.instance = 'mysql' AND (" + "    obj.pac = :loginUserPac OR "
        + "    obj.pac.customer.memberCode = :loginUserName )")
@ModuleImpl(de.hsadmin.mods.db.MySqlDatabaseModuleImpl.class)
public class MySqlDatabase extends Database implements Serializable {
    
    private static final long serialVersionUID = 2862112440807946042L;
hsarback/src/de/hsadmin/mods/db/MySqlDatabaseModuleImpl.java
@@ -9,6 +9,7 @@
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.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -25,26 +26,29 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        Transaction transaction = getTransaction();
        UnixUser loginUser = transaction.getLoginUser();
        MySqlDatabase database = (MySqlDatabase) newEntity;
        String name = database.getName();
        if (name.length() < 7 || name.charAt(5) != '_') {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        EntityManager em = getTransaction().getEntityManager();
        Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName");
        qPac.setParameter("pacName", name.substring(0, 5));
        Object singleResult = qPac.getSingleResult();
        Pac pac = (Pac) singleResult;
        if (pac == null || !pac.isReadAllowedFor(getLoginUser())) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        if (pac == null || !pac.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        return super.add(newEntity);
    }
    
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        EntityManager em = getTransaction().getEntityManager();
        UnixUser unixUser = getLoginUser();
        Transaction transaction = getTransaction();
        EntityManager em = transaction.getEntityManager();
        UnixUser unixUser = transaction.getLoginUser();
        MySqlDatabase detachtedDB = (MySqlDatabase) existingEntity;
        MySqlDatabase attachedDB = em.find(MySqlDatabase.class, detachtedDB.getId());
        if (!attachedDB.getName().equals(detachtedDB.getName())) {
hsarback/src/de/hsadmin/mods/db/MySqlUser.java
@@ -6,6 +6,7 @@
import javax.persistence.Entity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@@ -15,6 +16,7 @@
@SearchFilter("obj.instance = 'mysql' AND ("
        + "    obj.pac = :loginUserPac OR "
        + "    obj.pac.customer.memberCode = :loginUserName )")
@ModuleImpl(de.hsadmin.mods.db.MySqlUserModuleImpl.class)
public class MySqlUser extends DatabaseUser implements Serializable {
    
    private static final long serialVersionUID = 6218494776881999478L;
hsarback/src/de/hsadmin/mods/db/MySqlUserModuleImpl.java
@@ -9,16 +9,20 @@
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.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
public class MySqlUserModuleImpl extends AbstractModuleImpl {
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        Transaction transaction = getTransaction();
        UnixUser loginUser = transaction.getLoginUser();
        MySqlUser user = (MySqlUser) newEntity;
        String name = user.getName();
        if (name.length() < 7 || name.charAt(5) != '_') {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        if (name.length() > 16) {
            throw new HSAdminException("mysql database name max. length is 16 characters");
@@ -28,8 +32,8 @@
        qPac.setParameter("pacName", name.substring(0, 5));
        Object singleResult = qPac.getSingleResult();
        Pac pac = (Pac) singleResult;
        if (pac == null || !pac.isReadAllowedFor(getLoginUser())) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        if (pac == null || !pac.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        return super.add(newEntity);
    }
hsarback/src/de/hsadmin/mods/db/PgSqlDatabase.java
@@ -6,6 +6,7 @@
import javax.persistence.Entity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@@ -15,6 +16,7 @@
@SearchFilter("obj.instance = 'pgsql' AND (" 
        + "    obj.pac = :loginUserPac OR "
        + "    obj.pac.customer.memberCode = :loginUserName )")
@ModuleImpl(de.hsadmin.mods.db.PgSqlDatabaseModuleImpl.class)
public class PgSqlDatabase extends Database implements Serializable {
    
    private static final long serialVersionUID = 6688358817554938015L;
hsarback/src/de/hsadmin/mods/db/PgSqlDatabaseModuleImpl.java
@@ -9,6 +9,7 @@
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.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -24,26 +25,28 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        UnixUser loginUser = getTransaction().getLoginUser();
        PgSqlDatabase database = (PgSqlDatabase) newEntity;
        String name = database.getName();
        if (name.length() < 7 || name.charAt(5) != '_') {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        EntityManager em = getTransaction().getEntityManager();
        Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName");
        qPac.setParameter("pacName", name.substring(0, 5));
        Object singleResult = qPac.getSingleResult();
        Pac pac = (Pac) singleResult;
        if (pac == null || !pac.isReadAllowedFor(getLoginUser())) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        if (pac == null || !pac.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        return super.add(newEntity);
    }
    
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        EntityManager em = getTransaction().getEntityManager();
        UnixUser unixUser = getLoginUser();
        Transaction transaction = getTransaction();
        EntityManager em = transaction.getEntityManager();
        UnixUser unixUser = transaction.getLoginUser();
        MySqlDatabase detachtedDB = (MySqlDatabase) existingEntity;
        MySqlDatabase attachedDB = em.find(MySqlDatabase.class, detachtedDB.getId());
        if (!attachedDB.getName().equals(detachtedDB.getName())) {
hsarback/src/de/hsadmin/mods/db/PgSqlUser.java
@@ -6,6 +6,7 @@
import javax.persistence.Entity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
@@ -14,6 +15,7 @@
@EntityInfo(name = "PostgreSQL Konto")
@SearchFilter("obj.instance = 'pgsql' AND (" + "    obj.pac = :loginUserPac OR "
        + "    obj.pac.customer.memberCode = :loginUserName )")
@ModuleImpl(de.hsadmin.mods.db.PgSqlUserModuleImpl.class)
public class PgSqlUser extends DatabaseUser implements Serializable {
    private static final long serialVersionUID = -1097602753310286629L;
hsarback/src/de/hsadmin/mods/db/PgSqlUserModuleImpl.java
@@ -10,23 +10,25 @@
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
public class PgSqlUserModuleImpl extends AbstractModuleImpl {
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        UnixUser loginUser = getTransaction().getLoginUser();
        PgSqlUser user = (PgSqlUser) newEntity;
        String name = user.getName();
        if (name.length() < 7 || name.charAt(5) != '_') {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        EntityManager em = getTransaction().getEntityManager();
        Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName");
        qPac.setParameter("pacName", name.substring(0, 5));
        Object singleResult = qPac.getSingleResult();
        Pac pac = (Pac) singleResult;
        if (pac == null || !pac.isReadAllowedFor(getLoginUser())) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        if (pac == null || !pac.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        return super.add(newEntity);
    }
hsarback/src/de/hsadmin/mods/dom/Domain.java
@@ -18,11 +18,13 @@
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.mods.user.UnixUser;
@Entity(name = "Domains")
@Table(name = "domain")
@SequenceGenerator(name = "DomainsSeqGen", sequenceName = "domain_domain_id_seq")
@ModuleImpl(de.hsadmin.mods.dom.DomainModuleImpl.class)
public class Domain extends AbstractEntity {
    @Id
hsarback/src/de/hsadmin/mods/dom/DomainModuleImpl.java
@@ -7,9 +7,9 @@
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.AbstractEntity;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.util.DNSCheck;
import de.hsadmin.mods.dom.Domain.Status;
@@ -23,7 +23,7 @@
    public AbstractEntity initialize(AbstractEntity newEntity) throws AuthorisationException {
        AbstractEntity newDom = super.initialize(newEntity);
        if (newDom instanceof Domain) {
            ((Domain) newDom).setUser(getLoginUser());
            ((Domain) newDom).setUser(getTransaction().getLoginUser());
            return newDom;
        }
        return null;
@@ -94,7 +94,7 @@
        }
        EntityManager em = getTransaction().getEntityManager();
        UnixUser loginUser = getLoginUser();
        UnixUser loginUser = getTransaction().getLoginUser();
        if (!loginUser.hasHostmasterRole()) {
            // search for domains superior to dom
            Query domainQuery = em.createQuery("SELECT d FROM Domains d WHERE d.name = :domainName");
@@ -158,7 +158,7 @@
            dom.setUser((UnixUser) query.getSingleResult());
        }
        needsWriteAccessOn(existingEntity, "update");
        throw new AuthorisationException(getLoginUser(), "update", existingEntity);
        throw new AuthorisationException(getTransaction().getLoginUser(), "update", existingEntity);
    }
    @Override
@@ -177,25 +177,26 @@
    }
    private void needsReadAccessOn(AbstractEntity ent, String method) throws AuthorisationException {
        UnixUser loginUser = getTransaction().getLoginUser();
        if (ent instanceof Domain) {
            Domain dom = (Domain) ent;
            String aLoginUserName = getLoginUser().getName();
            String aLoginUserName = loginUser.getName();
            UnixUser domUser = dom.getUser();
            Pac domPac = domUser.getPac();
            boolean isDomAdmin = aLoginUserName.equals(domUser.getName());
            boolean isPacAdmin = aLoginUserName.equals(domPac.getName());
            boolean isCustomer = aLoginUserName.equals(domPac.getCustomer().getName());
            boolean isHostmaster = getLoginUser().hasHostmasterRole();
            boolean isHostmaster = loginUser.hasHostmasterRole();
            if (!isDomAdmin && !isPacAdmin && !isCustomer && !isHostmaster) {
                throw new AuthorisationException(getLoginUser(), method, dom);
                throw new AuthorisationException(loginUser, method, dom);
            }
        } else {
            throw new AuthorisationException(getLoginUser(), method, ent);
            throw new AuthorisationException(loginUser, method, ent);
        }
    }
    private void needsWriteAccessOn(AbstractEntity ent, String method) throws AuthorisationException {
        UnixUser loginUser = getLoginUser();
        UnixUser loginUser = getTransaction().getLoginUser();
        if (ent instanceof Domain) {
            Domain dom = (Domain) ent;
            String aLoginUserName = loginUser.getName();
hsarback/src/de/hsadmin/mods/email/EMailAddress.java
@@ -20,6 +20,7 @@
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.dom.Domain;
import de.hsadmin.mods.user.UnixUser;
@@ -34,6 +35,7 @@
@SearchFilter("domain.user = :loginUser OR "
        + "domain.user.pac = :loginUserPac OR "
        + "domain.user.pac.customer.name = :loginUserName")
@ModuleImpl(de.hsadmin.mods.email.EMailAddressModuleImpl.class)
public class EMailAddress extends AbstractEntity implements Serializable {
    
    private static final long serialVersionUID = -2265500181746604429L;
hsarback/src/de/hsadmin/mods/email/EMailAddressModuleImpl.java
@@ -9,7 +9,9 @@
import de.hsadmin.core.model.AuthorisationException;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.Transaction;
import de.hsadmin.mods.dom.Domain;
import de.hsadmin.mods.user.UnixUser;
public class EMailAddressModuleImpl extends AbstractModuleImpl {
@@ -46,23 +48,25 @@
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        Transaction transaction = getTransaction();
        UnixUser loginUser = transaction.getLoginUser();
        EMailAddress detachedAddr = (EMailAddress) existingEntity;
        EntityManager em = getTransaction().getEntityManager();
        EntityManager em = transaction.getEntityManager();
        EMailAddress attachedAddr = em.find(EMailAddress.class, detachedAddr.getId());
        String domain = detachedAddr.getDomain().getName();
        if (domain != null && !domain.equals(attachedAddr.getDomain().getName())) {
            detachedAddr.setDomain(attachedAddr.getDomain());
            throw new AuthorisationException(getLoginUser(), "update", detachedAddr, "domain");
            throw new AuthorisationException(loginUser, "update", detachedAddr, "domain");
        }
        String subdomain = detachedAddr.getSubdomain();
        if (subdomain != null && !subdomain.equals(attachedAddr.getSubdomain())) {
            detachedAddr.setSubdomain(attachedAddr.getSubdomain());
            throw new AuthorisationException(getLoginUser(), "update", detachedAddr, "subdomain");
            throw new AuthorisationException(loginUser, "update", detachedAddr, "subdomain");
        }
        String localPart = detachedAddr.getLocalpart();
        if (localPart != null && !localPart.equals(attachedAddr.getLocalpart())) {
            detachedAddr.setLocalpart(attachedAddr.getLocalpart());
            throw new AuthorisationException(getLoginUser(), "update", detachedAddr, "localpart");
            throw new AuthorisationException(loginUser, "update", detachedAddr, "localpart");
        }
        String target = detachedAddr.getTarget();
        if (target == null) {
hsarback/src/de/hsadmin/mods/email/EMailAlias.java
@@ -17,9 +17,9 @@
import javax.persistence.Table;
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.model.SearchFilter;
import de.hsadmin.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
@@ -33,6 +33,7 @@
@SequenceGenerator(name = "EMailAliasesSeqGen", sequenceName = "emailalias_emailalias_id_seq")
@EntityInfo(name = "E-Mail-Alias")
@SearchFilter("obj.pac = :loginUserPac OR obj.pac.customer.name = :loginUserName")
@ModuleImpl(de.hsadmin.mods.email.EMailAliasModuleImpl.class)
public class EMailAlias extends AbstractEntity implements Serializable {
    
    private static final long serialVersionUID = -4711415079723587161L;
@@ -73,18 +74,14 @@
    @Override
    public void complete(EntityManager em, UnixUser loginUser) {
        if (pac == null && name != null && name.length() > 0) {
            // TODO: it's ugly having this code here, needs refactoring
            String pacName = name.substring(0, 5);
            try {
                // get the entities name (query part from FROM to WHERE)
                Entity entityAnnot = Pac.class.getAnnotation(Entity.class);
                String queryString = "SELECT obj FROM " + entityAnnot.name() + " obj WHERE " + Pac.createQueryFromStringKey(pacName);
                // set parameters
                Query query = em.createQuery(queryString);
                AbstractModuleImpl.setQueryParameter(query, queryString, "loginUser", loginUser);
                AbstractModuleImpl.setQueryParameter(query, queryString, "loginUserName", loginUser.getName());
                AbstractModuleImpl.setQueryParameter(query, queryString, "loginUserPac", loginUser.getPac());
                query.setParameter("loginUser", loginUser);
                query.setParameter("loginUserName", loginUser.getName());
                query.setParameter("loginUserPac", loginUser.getPac());
                pac = (Pac) query.getSingleResult();
            } catch (NoResultException exc) {
                throw new SecurityException("packet '" + pacName + "' not found or access denied");
hsarback/src/de/hsadmin/mods/email/EMailAliasModuleImpl.java
@@ -9,7 +9,9 @@
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.mods.pac.Pac;
import de.hsadmin.mods.user.UnixUser;
public class EMailAliasModuleImpl extends AbstractModuleImpl {
@@ -24,18 +26,20 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        Transaction transaction = getTransaction();
        UnixUser loginUser = transaction.getLoginUser();
        EMailAlias alias = (EMailAlias) newEntity;
        String name = alias.getName();
        if (name.length() > 5 && (name.charAt(5) != '-') || name.length() == 6) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        EntityManager em = getTransaction().getEntityManager();
        Query qPac = em.createQuery("SELECT obj FROM Pacs obj WHERE obj.name = :pacName");
        qPac.setParameter("pacName", name.substring(0, 5));
        Object singleResult = qPac.getSingleResult();
        Pac pac = (Pac) singleResult;
        if (pac == null || !pac.isReadAllowedFor(getLoginUser())) {
            throw new AuthorisationException(getLoginUser(), "add", newEntity);
        if (pac == null || !pac.isReadAllowedFor(loginUser)) {
            throw new AuthorisationException(loginUser, "add", newEntity);
        }
        return super.add(newEntity);
    }
hsarback/src/de/hsadmin/mods/pac/Pac.java
@@ -26,6 +26,7 @@
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.mods.cust.Customer;
import de.hsadmin.mods.user.UnixUser;
@@ -33,6 +34,7 @@
@Table(name = "packet")
@SequenceGenerator(name = "PacsSeqGen", sequenceName = "packet_packet_id_seq")
@EntityInfo(name = "Paket")
@ModuleImpl(de.hsadmin.mods.pac.PacModuleImpl.class)
public class Pac extends AbstractEntity implements Serializable {
    
    private static final long serialVersionUID = 1L;
hsarback/src/de/hsadmin/mods/pac/PacModuleImpl.java
@@ -112,7 +112,7 @@
    @Override
    public AbstractEntity update(AbstractEntity existingEntity)
            throws HSAdminException {
        throw new AuthorisationException(getLoginUser(), "update", existingEntity);
        throw new AuthorisationException(getTransaction().getLoginUser(), "update", existingEntity);
    }
    @Override
@@ -122,7 +122,7 @@
        String pacName = pac.getName();
        Date dateCancelled = pac.getCancelled();
        if (dateCancelled == null || dateCancelled.getTime() > System.currentTimeMillis()) {
            throw new AuthorisationException(getLoginUser(), "delete", existingEntity);
            throw new AuthorisationException(getTransaction().getLoginUser(), "delete", existingEntity);
        }
        GenericModuleImpl helperModule = new GenericModuleImpl(getTransaction());
        
hsarback/src/de/hsadmin/mods/user/UnixUser.java
@@ -19,6 +19,7 @@
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.EntityInfo;
import de.hsadmin.core.model.FieldValidation;
import de.hsadmin.core.model.ModuleImpl;
import de.hsadmin.core.util.Config;
import de.hsadmin.mods.pac.Pac;
@@ -26,6 +27,7 @@
@Table(name = "unixuser")
@SequenceGenerator(name = "UnixUsersSeqGen", sequenceName = "unixuser_unixuser_id_seq")
@EntityInfo(name = "UNIX-Zugang/Mailbox")
@ModuleImpl(de.hsadmin.mods.user.UnixUserModuleImpl.class)
public class UnixUser extends AbstractEntity implements Serializable {
    
    private static final long serialVersionUID = 7823071611805642906L;
@@ -187,23 +189,16 @@
        this.homedir = homedir;
    }
    /**
     * returns true if the user has the default homedir path
     */
    public boolean isDefaultHomedir() {
        return getHomedir().equals(getDefaultHomedir());
    }
    /**
     * returns the default homedir path
     */
    private String getDefaultHomedir() {
        String pacName = pac.getName();
        if (name.equals(pacName))
            return "/home/pacs/" + pacName;
        else
            return "/home/pacs/" + pacName + "/users/"
                    + name.substring(pacName.length() + 1);
            return "/home/pacs/" + pacName + "/users/" + name.substring(pacName.length() + 1);
    }
    public boolean isLocked() {
@@ -266,40 +261,22 @@
        return getPac().getAdminUser(em);
    }
    /**
     * determines whether this user account is a hostmaster account
     */
    public boolean hasHostmasterRole() {
        // TODO: hardcoded Hostsharing conventions
        String login = getName();
        return login.length() == 2 || ((login.startsWith(Config.getInstance().getProperty("accountprefix.hostmaster", "hsh01") + "-") && login.length() == 8));
    }
    /**
     * determines whether this user account has rights on the given customer
     */
    public boolean hasCustomerRoleFor(de.hsadmin.mods.cust.Customer cust) {
        // TODO: hardcoded Hostsharing conventions
        return getName().equals(cust.getName()) || hasHostmasterRole();
    }
    /**
     * determines whether this user account has admin rights on the given pac
     */
    public boolean hasPacAdminRoleFor(de.hsadmin.mods.pac.Pac pac) {
        return pac != null && 
            (pac.getName().equals(getName())
                || hasCustomerRoleFor(pac.getCustomer()) );
    }
    /**
     * determines whether this user account has admin rights on the given dom
     */
//    public boolean hasDomAdminRoleFor(de.hsadmin.mods.dom.Domain dom) {
//        // TODO: hardcoded Hostsharing conventions
//        return this.getId() == dom.getUser().getId()
//                || hasPacAdminRoleFor(dom.getUser().getPac());
//    }
    @Override
    public boolean isWriteAllowedFor(UnixUser loginUser) {
hsarback/src/de/hsadmin/mods/user/UnixUserModuleImpl.java
@@ -10,6 +10,7 @@
import de.hsadmin.core.model.AbstractEntity;
import de.hsadmin.core.model.AbstractModuleImpl;
import de.hsadmin.core.model.HSAdminException;
import de.hsadmin.core.model.Transaction;
import de.hsadmin.mods.pac.Pac;
public class UnixUserModuleImpl extends AbstractModuleImpl {
@@ -20,19 +21,14 @@
    @Override
    public AbstractEntity initialize(AbstractEntity newEntity) throws AuthorisationException {
        UnixUser newUnixUser = (UnixUser) super.initialize(newEntity);
        newUnixUser.setName(getLoginUser().getPac().getName() + '-');
        newUnixUser.setName(getTransaction().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;
    }
@@ -73,7 +69,9 @@
    @Override
    public AbstractEntity add(AbstractEntity newEntity) throws HSAdminException {
        EntityManager em = getEntityManager();
        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;
@@ -85,18 +83,18 @@
        String userName = name.toLowerCase().trim();
        for (char c : userName.toCharArray()) {
            if (!(Character.isLetterOrDigit(c) || c == '.' || c == '-' || c == '_')) {
                throw new AuthorisationException(getLoginUser(), "add", newUnixUser, "userId");
                throw new AuthorisationException(loginUser, "add", newUnixUser, "userId");
            }
        }
        if (userName.length() < 7 || userName.charAt(5) != '-' || userName.lastIndexOf('-') > 5) {
            throw new AuthorisationException(getLoginUser(), "add", newUnixUser, "userId");
            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(getLoginUser(), "add", newUnixUser, "userId");
            throw new AuthorisationException(loginUser, "add", newUnixUser, "userId");
        }
        if (newUnixUser.getPac() == null || newUnixUser.getPac().getNew()) {
            
@@ -124,7 +122,7 @@
            q.setParameter("pac", pac);
            List<?> idOfSamePac = q.getResultList();
            if (idOfSamePac.size() == 0) {
                throw new AuthorisationException(getLoginUser(), "add", newUnixUser, "userId");
                throw new AuthorisationException(loginUser, "add", newUnixUser, "userId");
            }
        }
@@ -142,43 +140,41 @@
    @Override
    public AbstractEntity update(AbstractEntity existingEntity) throws HSAdminException {
        // get the entity from the database
        Transaction transaction = getTransaction();
        UnixUser loginUser = transaction.getLoginUser();
        EntityManager em = transaction.getEntityManager();
        UnixUser detachedUnixUser = (UnixUser) existingEntity;
        UnixUser attachedUnixUser = getEntityManager().find(detachedUnixUser.getClass(),
                detachedUnixUser.getId());
        // authorisation check
        UnixUser attachedUnixUser = em.find(detachedUnixUser.getClass(), detachedUnixUser.getId());
        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());
        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))
        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");
        } 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(getLoginUser(), "update",
                throw new AuthorisationException(loginUser, "update",
                        detachedUnixUser, "shell");
        if (attachedUnixUser.isLocked() != detachedUnixUser.isLocked())
            throw new AuthorisationException(getLoginUser(), "update",
                    detachedUnixUser, "locked");
        if (attachedUnixUser.isLocked() != detachedUnixUser.isLocked()) {
            throw new AuthorisationException(loginUser, "update", detachedUnixUser, "locked");
        }
        if (detachedUnixUser.getQuotaSoftlimit() != null) {
            if (hasFullAccessOnPacOf(attachedUnixUser)) {
                attachedUnixUser.setQuotaSoftlimit(detachedUnixUser.getQuotaSoftlimit());
@@ -189,21 +185,20 @@
            else {
                Integer oldQuota = attachedUnixUser.getQuotaSoftlimit();
                Integer newQuota = detachedUnixUser.getQuotaSoftlimit();
                if (oldQuota != newQuota && !oldQuota.equals(newQuota))
                    throw new AuthorisationException(getLoginUser(), "update",
                            detachedUnixUser, "quota");
                if (oldQuota != newQuota && !oldQuota.equals(newQuota)) {
                    throw new AuthorisationException(loginUser, "update", detachedUnixUser, "quota");
                }
            }
        }
        // update entity
        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 = getEntityManager().find(detachedUnixUser.getClass(),
        UnixUser attachedUnixUser = entityManager.find(detachedUnixUser.getClass(),
                detachedUnixUser.getId());
        // authorisation check
@@ -216,16 +211,14 @@
        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) {
        return getLoginUser().hasHostmasterRole()
            || getLoginUser().getName().equals(user.getPac().getName())
            || getLoginUser().getName().equals(user.getPac().getCustomer().getName());
        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
@@ -233,31 +226,24 @@
    private void needsFullAccessOnPacOf(UnixUser user, String method)
            throws AuthorisationException {
        if (!hasFullAccessOnPacOf(user))
            throw new AuthorisationException(getLoginUser(), method, user);
            throw new AuthorisationException(getTransaction().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);
    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);
        }
    }
    // 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);
    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);
        }
    }
    // 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"))
hsarback/test/de/hsadmin/remote/RemoteTest.java
@@ -6,18 +6,18 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
    InitDataTest.class,
//    PacTest.class,
//    UnixUserTest.class,
//    MysqlUserTest.class,
//    MysqlDbTest.class,
//    PgsqlUserTest.class,
//    PgsqlDbTest.class,
//    EMailAliasTest.class,
//    DomainTest.class,
//    EMailAddressTest.class,
//    CustomerTest.class
    PacTest.class,
    UnixUserTest.class,
    MysqlUserTest.class,
    MysqlDbTest.class,
    PgsqlUserTest.class,
    PgsqlDbTest.class,
    EMailAliasTest.class,
    DomainTest.class,
    EMailAddressTest.class,
    CustomerTest.class,
//    HostmasterTest.class,
//    QueueTaskTest.class
    QueueTaskTest.class
})
public class RemoteTest {