Index: topia-security/src/java/org/codelutin/topia/security/TopiaSecurityService.java diff -u /dev/null topia-security/src/java/org/codelutin/topia/security/TopiaSecurityService.java:1.1 --- /dev/null Wed Oct 18 08:46:39 2006 +++ topia-security/src/java/org/codelutin/topia/security/TopiaSecurityService.java Wed Oct 18 08:46:34 2006 @@ -0,0 +1,28 @@ +package org.codelutin.topia.security; + +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.framework.TopiaService; + +public interface TopiaSecurityService extends TopiaService { + + /** + * Vérifie si l'utilisateur actuellement loggué a le droit d'accéder à + * l'entité passée en paramètre pour les actions spécifiées. + * @param entientityClassty l'entité pour laquelle on vérifie les droits + * @param actions les actions [load, read, write, admin] + * @throws TopiaSecurityException + */ + public abstract void checkPermission(Class entityClass, int actions) + throws TopiaException; + + /** + * Vérifie si l'utilisateur actuellement loggué a le droit d'accéder à + * l'entité passée en paramètre pour les actions spécifiées. + * @param topiaId le topiaId de l'entité pour laquelle on vérifie les droits + * @param actions les actions [load, read, write, admin] + * @throws TopiaSecurityException + */ + public abstract void checkPermission(String topiaId, int actions) + throws TopiaException; + +} Index: topia-security/src/java/org/codelutin/topia/security/TopiaSecurityServiceImpl.java diff -u /dev/null topia-security/src/java/org/codelutin/topia/security/TopiaSecurityServiceImpl.java:1.1 --- /dev/null Wed Oct 18 08:46:39 2006 +++ topia-security/src/java/org/codelutin/topia/security/TopiaSecurityServiceImpl.java Wed Oct 18 08:46:34 2006 @@ -0,0 +1,355 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005 Code Lutin, +* Cédric Pineau, Benjamin Poussin, +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ + +package org.codelutin.topia.security; + +import static org.codelutin.topia.security.util.TopiaSecurityUtil.TOPIA_SECURITY_PERSISTENCE_CLASSES; + +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Permission; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.Subject; +import javax.security.auth.login.Configuration; + +import org.apache.commons.collections.map.ReferenceMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.topia.TopiaContext; +import org.codelutin.topia.TopiaException; +import org.codelutin.topia.TopiaServiceDAOHelper; +import org.codelutin.topia.framework.TopiaContextImplementor; +import org.codelutin.topia.security.entities.authorization.TopiaAssociationAuthorizationDAO; +import org.codelutin.topia.security.entities.authorization.TopiaAuthorization; +import org.codelutin.topia.security.entities.authorization.TopiaAuthorizationDAO; +import org.codelutin.topia.security.entities.authorization.TopiaEntityAuthorization; +import org.codelutin.topia.security.entities.authorization.TopiaEntityAuthorizationDAO; +import org.codelutin.topia.security.entities.authorization.TopiaEntityAuthorizationImpl; +import org.codelutin.topia.security.entities.authorization.TopiaIdLink; +import org.codelutin.topia.security.entities.authorization.TopiaIdLinkDAO; +import org.codelutin.topia.security.entities.user.TopiaGroupDAO; +import org.codelutin.topia.security.entities.user.TopiaUserDAO; +import org.codelutin.topia.security.jaas.TopiaConfiguration; +import org.codelutin.topia.security.jaas.TopiaPermission; +import org.codelutin.topia.security.jaas.TopiaPolicy; +import org.codelutin.topia.security.listener.PropertyReadListener; +import org.codelutin.topia.security.listener.PropertyWriteListener; +import org.codelutin.topia.security.listener.VetoableEntityListener; +import org.codelutin.topia.security.listener.VetoablePropertyListener; +import org.codelutin.topia.security.util.TopiaSecurityCaching; +import org.codelutin.topia.security.util.TopiaSecurityUtil; + +/** + * Implantation du manager pour la sécurité. C'est le point d'accès à l'ensemble + * des fonctionnalités de la sécurité. + * + * @author ruchaud + */ +public class TopiaSecurityServiceImpl implements TopiaSecurityManager, TopiaSecurityService { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(TopiaSecurityServiceImpl.class); + + /* Context ToPIA */ + private TopiaContext rootContext; + private TopiaContext securityContext; + + /* Listeners */ + private VetoableEntityListener entityListener = new VetoableEntityListener(this); + private PropertyReadListener readListener = new PropertyReadListener(this); + private PropertyWriteListener writeListener = new PropertyWriteListener(this); + private VetoablePropertyListener propertyListener = new VetoablePropertyListener(readListener, writeListener); + + /* Policy */ + private TopiaPolicy policy = new TopiaPolicy(this); + + /* Cache */ + transient private TopiaSecurityCaching entitiesLoadingCache = new TopiaSecurityCaching(2); + transient private Map> permissionsCache = new ReferenceMap(ReferenceMap.SOFT, ReferenceMap.SOFT); + + /** + * Constructeur. Initialise la sécurité à partir du contexte passer en paramètre + * @param context contexte root de la sécurité + */ + public TopiaSecurityServiceImpl() { + } + + /* (non-Javadoc) + * @see org.codelutin.topia.framework.TopiaService#getServiceName() + */ + public String getServiceName() { + return TopiaSecurityHelper.SERVICE_NAME; + } + + /* + * (non-Javadoc) + * @see org.codelutin.topia.security.TopiaSecurityManager#getPersistenceClasses() + */ + public String getPersistenceClasses() { + return TOPIA_SECURITY_PERSISTENCE_CLASSES; + } + + /* + * (non-Javadoc) + * @see org.codelutin.topia.security.TopiaSecurityManager#init() + */ + public void init(TopiaContextImplementor context) { + this.rootContext = context; + this.securityContext = null; + + rootContext.addVetoableListener(entityListener); + rootContext.addVetoableLoadListener(entityListener); + rootContext.addTopiaEntityLoadListener(propertyListener); + rootContext.addTopiaEntityListener(propertyListener); + + policy.installPolicy(); + Configuration.setConfiguration(new TopiaConfiguration("topia", this)); + } + + /* + * (non-Javadoc) + * @see org.codelutin.topia.security.TopiaSecurityManager#getSecurityContext() + */ + public TopiaContext getSecurityContext() throws TopiaException { + if(securityContext == null) { + securityContext = rootContext.beginTransaction(); + } + return securityContext; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaUser + */ + public TopiaUserDAO getTopiaUserDAO() { + try { + return TopiaServiceDAOHelper.getTopiaUserDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaUserDAO impossible", te); + } + return null; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaGroup + */ + public TopiaGroupDAO getTopiaGroupDAO() { + try { + return TopiaServiceDAOHelper.getTopiaGroupDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaGroupDAO impossible", te); + } + return null; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaAuthorization + */ + public TopiaAuthorizationDAO getTopiaAuthorizationDAO() { + try { + return TopiaServiceDAOHelper.getTopiaAuthorizationDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaAuthorizationDAO impossible", te); + } + return null; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaEntityAuthorization + */ + public TopiaEntityAuthorizationDAO getTopiaEntityAuthorizationDAO() { + try { + return TopiaServiceDAOHelper.getTopiaEntityAuthorizationDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaEntityAuthorizationDAO impossible", te); + } + return null; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaIdLinkDAO + */ + public TopiaIdLinkDAO getTopiaIdLinkDAO() { + try { + return TopiaServiceDAOHelper.getTopiaIdLinkDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaLinkAuthorizationDAO impossible", te); + } + return null; + } + + /** + * Permet de récupérer le DAO dans le contexte de sécurité. + * @return DAO du TopiaAssociationAuthorization + */ + public TopiaAssociationAuthorizationDAO getTopiaAssociationAuthorizationDAO() { + try { + return TopiaServiceDAOHelper.getTopiaAssociationAuthorizationDAO(getSecurityContext()); + } catch (TopiaException te) { + log.error("Recuperation du TopiaAssociationAuthorizationDAO impossible", te); + } + return null; + } + + /** + * Permet d'ajouter dans le cache les permissions pour un principal donné. + * @param principalName nom du principal pour lequel on doit chargé les permissions + * @throws TopiaException + */ + public Set putPermissionsCache(String principalName) throws TopiaException { + TopiaAuthorizationDAO authorizationDAO = getTopiaAuthorizationDAO(); + Collection authorizations = authorizationDAO.findAll(); + + Set permissions = new HashSet(); + permissionsCache.put(principalName, permissions); + + for (TopiaAuthorization authorization : authorizations) { + Set principals = authorization.getPrincipals(); + if(principals.contains(principalName)) { + Permission topiaPermission = new TopiaPermission(authorization); + permissions.add(topiaPermission); + } + } + return permissions; + } + + /** + * Permet de récupérer depuis le cache les permissions pour un principal donné. + * @param principalName nom du principal + * @return permmissions d'un principal + */ + public Set getPermissionsCache(String principalName) { + return permissionsCache.get(principalName); + } + + /** + * Permet de mettre dans le cache pour l'utilisateur en cours si il a droit + * l'autorisation ou non de charger une entité. + * @param topiaId identification de l'entité + * @param authorized autorisation sur l'entité, true pour autorisé et false pour + * non autorisé + */ + public void putEntitiesLoadingCache(String topiaId, boolean authorized) { + String userPrincipal = TopiaSecurityUtil.getUserPrincipal(); + if(userPrincipal != null) { + entitiesLoadingCache.put(authorized, userPrincipal, topiaId); + } + } + + /** + * Permet de récupérer dans le cache pour l'utilisateur en cours si il a droit + * l'autorisation ou non de charger une entité. + * @param topiaId identification de l'entité + * @return autorisation sur l'entité, true pour autorisé et false pour + * non autorisé + */ + public Boolean getEntitiesLoadingCache(String topiaId) { + String userPrincipal = TopiaSecurityUtil.getUserPrincipal(); + if(userPrincipal != null) { + return (Boolean) entitiesLoadingCache.get(userPrincipal, topiaId); + } + return null; + } + + /** + * Permet de supprimer un entrée dans le cache pour un utilisateur + * @param userPrincipal principal de l'utilisateur + */ + public void removeEntitiesLoadingCache(String userPrincipal) { + entitiesLoadingCache.clear(userPrincipal); + } + + /** + * Permet de tester le cache + * @param topiaId identification de l'entité + * @return vrai si il trouve sinon faux + */ + public boolean containEntitiesLoadingCache(String topiaId) { + Boolean authorized = getEntitiesLoadingCache(topiaId); + if(authorized != null) { + return true; + } else { + return false; + } + } + + /** + * Renvoi l'identifiant qui remplace l'identifiant en cours d'après la table + * de correspondance TopiaIdLink. + * @param topiaId identifiant à remplacer + * @return retourne l'identifiant remplacé + * @throws TopiaException + */ + protected String replaceByTopiaIdLink(String topiaId) throws TopiaException { + TopiaIdLinkDAO linkDAO = getTopiaIdLinkDAO(); + TopiaIdLink link = linkDAO.findByReplace(topiaId); + if(link == null) { + return topiaId; + } else { + return link.getBy(); + } + } + + /* (non-Javadoc) + * @see org.codelutin.topia.security.TopiaSecurityService#checkPermission(java.lang.Class, int) + */ + public void checkPermission(Class entityClass, int actions) throws TopiaException { + if (log.isTraceEnabled()) { + log.trace("Checking permissions to entity class : " + entityClass); + } + if (entityClass == null) { + throw new TopiaException("Class cannot be null"); + } + String topiaId = entityClass.getName() + "#*"; + checkPermission(topiaId, actions); + } + + /* (non-Javadoc) + * @see org.codelutin.topia.security.TopiaSecurityService#checkPermission(java.lang.String, int) + */ + public void checkPermission(String topiaId, int actions) throws TopiaException { + Subject subj = Subject.getSubject(AccessController.getContext()); + if (subj != null) { + try { + TopiaEntityAuthorization authorization = new TopiaEntityAuthorizationImpl( + replaceByTopiaIdLink(topiaId), actions, subj.getPrincipals()); + AccessController.checkPermission(new TopiaPermission(authorization)); + } catch (AccessControlException e) { + throw new TopiaException("access denied to object \"" + topiaId + "\" for \"" + subj + "\"", e); + } + if (log.isTraceEnabled()) { + log.trace("Permission granted for entity : " + topiaId); + } + } else { + if(log.isWarnEnabled()) { + log.warn("Use doAs() and login first"); + } + } + } + +} Index: topia-security/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java diff -u /dev/null topia-security/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java:1.1 --- /dev/null Wed Oct 18 08:46:40 2006 +++ topia-security/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java Wed Oct 18 08:46:34 2006 @@ -0,0 +1,21 @@ +package org.codelutin.topia.security; + +import org.codelutin.topia.TopiaContext; +import org.codelutin.topia.framework.TopiaContextImplementor; + +public class TopiaSecurityHelper { + public static final String SERVICE_NAME = "security"; + + public static boolean isEnabled(TopiaContext context) { + TopiaContextImplementor tci = (TopiaContextImplementor)context; + boolean result = tci.serviceEnabled(SERVICE_NAME); + return result; + } + + public static TopiaSecurityService get(TopiaContext context) { + TopiaContextImplementor tci = (TopiaContextImplementor)context; + TopiaSecurityService result = (TopiaSecurityService)tci.getService(SERVICE_NAME); + return result; + } + +}