Index: topia/src/java/org/codelutin/topia/security/TopiaLoginModule.java diff -u topia/src/java/org/codelutin/topia/security/TopiaLoginModule.java:1.4 topia/src/java/org/codelutin/topia/security/TopiaLoginModule.java:1.5 --- topia/src/java/org/codelutin/topia/security/TopiaLoginModule.java:1.4 Tue Jul 19 13:15:13 2005 +++ topia/src/java/org/codelutin/topia/security/TopiaLoginModule.java Wed Jul 20 12:49:53 2005 @@ -24,7 +24,7 @@ * Created: 29 avr. 2005 * * @author Arnaud Thimel -* @version $Revision: 1.4 $ +* @version $Revision: 1.5 $ */ package org.codelutin.topia.security; @@ -32,8 +32,6 @@ import java.io.IOException; import java.util.List; import java.util.Map; - -import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; @@ -41,10 +39,11 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; - +import javax.security.auth.Subject; import org.codelutin.topia.TopiaContext; import org.codelutin.topia.TopiaContextFactory; import org.codelutin.topia.TopiaException; +import org.codelutin.topia.TopiaNotFoundException; /** * LoginModule compatible avec Topia */ @@ -110,8 +109,11 @@ //Véricfication du login/pass et récupération des Principal try { - principals = context.authenticate(login, password); + principals = context.getSecurityHelper().authenticate(login, password); } catch (TopiaSecurityException e) { + System.err.println("Login failed : " + e.getMessage()); + return false; + } catch (TopiaNotFoundException e) { System.err.println("Login failed : " + e.getMessage()); return false; } Index: topia/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java diff -u /dev/null topia/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java:1.1 --- /dev/null Wed Jul 20 12:49:58 2005 +++ topia/src/java/org/codelutin/topia/security/TopiaSecurityHelper.java Wed Jul 20 12:49:53 2005 @@ -0,0 +1,368 @@ +/* *##% + * Copyright (C) 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. + *##%*/ + +/* * + * TopiaSecurityHelper.java + * + * Created: 15 juillet 2005 17:39:35 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/07/20 12:49:53 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.topia.security; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Vector; +import org.codelutin.topia.TopiaContext; +import org.codelutin.util.HashMapMultiKey; +import org.codelutin.util.ListenerSet; + +public class TopiaSecurityHelper { // TopiaSecurityHelper + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Logger log = Logger.getLogger("org.codelutin.topia.TopiaSecurityHelper"); + + protected TopiaContext context = null; + protected Properties properties = null; + + protected ListenerSet permissionListeners = new ListenerSet( + TopiaPermissionListener.class); + + protected HashMapMultiKey permissions = new HashMapMultiKey(); + + protected boolean permFileModified = false; + + public TopiaSecurityHelper(TopiaContext context, Properties properties){ + this.context = context; + this.properties = properties; + } + + /** + * Authentifie l'utilisateur en fonction des paramètres du fichier de propriétés + * @param login + * @param password + * @return la liste des TopiaPrincipal de l'utilisateur + * @throws TopiaSecurityException + */ + public List authenticate(String login, String password) + throws TopiaSecurityException { + String authType = properties.getProperty("topia.auth.type"); + if ("simple".equalsIgnoreCase(authType)) { + return simpleAuthentication(login, password); + } else if ("ldap".equalsIgnoreCase(authType)) { + return ldapAuthentication(login, password); + // } else if ("xmi".equalsIgnoreCase(authType)) { + // return xmiAuthentication(login, password); + } + throw new TopiaSecurityException("Invalid auth type : " + authType); + } + + /** + * Authentification basée sur les fichiers textes + * @param login + * @param password + * @return la liste des TopiaPrincipal de l'utilisateur + * @throws TopiaSecurityException + */ + protected List simpleAuthentication(String login, String password) + throws TopiaSecurityException { + Properties props = new Properties(); + String fileName = properties.getProperty("topia.auth.simple.file.login"); + if (fileName == null) + throw new TopiaSecurityException( + "Authentication filename must be specified"); + try { + props.load(new FileInputStream(fileName)); + } catch (FileNotFoundException e) { + throw new TopiaSecurityException("Invalid authentication file : " + + fileName); + } catch (IOException ioe) { + throw new TopiaSecurityException( + "Unable to read authentication file : " + fileName); + } + String hashMode = properties.getProperty("topia.auth.simple.hash"); + if (hashMode != null) { + try { + password = new String(MessageDigest.getInstance(hashMode).digest( + password.getBytes())); + } catch (NoSuchAlgorithmException nsaE) { + throw new TopiaSecurityException("Invalid hash algorithm : " + + hashMode); + } + } + if (!password.equals(props.getProperty(login))) + throw new TopiaSecurityException("Wrong Login/Password"); + Vector principals = new Vector(); + principals.addElement(new TopiaUserPrincipal(login)); + + String groupsFileName = properties.getProperty("topia.auth.simple.file.groups"); + props = new Properties(); + try { + props.load(new FileInputStream(groupsFileName)); + } catch (FileNotFoundException e1) { + e1.printStackTrace(); + } catch (IOException e1) { + e1.printStackTrace(); + } + for (Enumeration e = props.keys(); e.hasMoreElements();) { + String key = (String) e.nextElement(); + + for (StringTokenizer sTK = new StringTokenizer(props.getProperty(key), + ","); sTK.hasMoreTokens();) { + if (login.equals(sTK.nextToken().trim())) { + principals.addElement(new TopiaGroupPrincipal(key)); + break; + } + } + } + return principals; + } + + /** + * Authntification basée sur un ldap + * @param login + * @param password + * @return la liste des TopiaPrincipal de l'utilisateur + * @throws TopiaSecurityException + */ + protected List ldapAuthentication(String login, String password) + throws TopiaSecurityException { + throw new TopiaSecurityException("ldapAuthentication not supported"); + //TODO Arno ;) + } + + /** + * Authentification basée sur l'utilisation de la BD de l'application + * @param login + * @param password + * @return la liste des TopiaPrincipal de l'utilisateur + * @throws TopiaSecurityException + */ + // protected abstract List xmiAuthentication(String login, String password) + // throws TopiaSecurityException; + + /** + * Charge en mémoire les fichiers contenant les permissions + */ + public void loadPermissions() { + loadPermissions("readPerm.file", "read"); + loadPermissions("writePerm.file", "write"); + loadPermissions("adminPerm.file", "admin"); + permFileModified = false; + } + + /** + * Charge en mémoire le fichier (fileName) contenant les permissions + * associées à l'action action + * @param fileName + * @param action + */ + private void loadPermissions(String fileName, String action) { + Properties props = new Properties(); + try { + props.load(new FileInputStream(fileName)); + HashMapMultiKey.Key multiKey = new HashMapMultiKey.Key().add(action); + for (Enumeration en = props.keys(); en.hasMoreElements();) { + String key = (String) en.nextElement(); + Vector propValues = new Vector(); + String principals = props.getProperty(key).replaceAll(" +", " "); + StringTokenizer sTK = new StringTokenizer(principals, ";"); + while (sTK.hasMoreTokens()) + try { + principals = sTK.nextToken(); + TopiaPermission perm = + new TopiaPermission(key + " " + principals, action); + addNoSecurityPermission(perm, true); + propValues.addElement(perm); + } catch (TopiaSecurityException e1) { + e1.printStackTrace(); + } + permissions.put(multiKey.add(key), propValues); + } + } catch (FileNotFoundException e) { + //Aucune permission n'est chargée puisque le fichier n'existe pas... + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Sauvegarde les permissions dans les fichiers + * + */ + public void storePermissions() { + if (permFileModified) { + storePermissions("readPerm.file", "read"); + storePermissions("writePerm.file", "write"); + storePermissions("adminPerm.file", "admin"); + permFileModified = false; + } + } + + /** + * Sauvegardes les permissions de type "action" dans le fichier fileName + * @param fileName + * @param action + */ + private void storePermissions(String fileName, String action) { + Properties props = new Properties(); + List list = permissions.getKeys(action); + for (Iterator it = list.iterator(); it.hasNext(); ) { + HashMapMultiKey.Key key = (HashMapMultiKey.Key)it.next(); + String propKey = (String)key.get(1); + String value = ""; + Vector values = (Vector)permissions.get(key); + if (values == null || values.size()==0) + continue; + for (Enumeration en = values.elements(); en.hasMoreElements(); ) { + TopiaPermission perm = (TopiaPermission)en.nextElement(); + value += perm.principalsToString() + ";"; + } + props.put(propKey, value.substring(0, value.lastIndexOf(";"))); + } + try { + props.store(new FileOutputStream(fileName), null); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * Ajoute à l'application la Permission perm + * @param perm + * @throws TopiaSecurityException + */ + public void addPermission(TopiaPermission perm) + throws TopiaSecurityException { + TopiaAccessController.checkPermission("perm", "admin"); + addNoSecurityPermission(perm, true); + } + + /** + * Ajoute à l'application la Permission perm sans control de sécurité + * @param perm + * @param informListeners si true, informe les listeners concernés + * @throws TopiaSecurityException + */ + private void addNoSecurityPermission(TopiaPermission perm, boolean informListeners) + throws TopiaSecurityException { + HashMapMultiKey.Key key; + key = new HashMapMultiKey.Key().add(perm.getActions()).add(perm.getId()); + Vector perms = (Vector)permissions.get(key); + if (perms == null) + perms = new Vector(); + if (!perms.contains(perm)) + perms.add(perm); + permissions.put(key, perms); + permFileModified = true; + if (informListeners) { + try { + permissionListeners.fire("permissionAdded", new TopiaPermissionEvent( + this, perm)); + } catch (Exception e) { + throw new TopiaSecurityException("Error while adding permission " + + perm, e); + } + } + } + + /** + * Modifie la Permission perm + * @param perm + * @throws TopiaSecurityException + */ + public void modifyPermission(TopiaPermission perm) + throws TopiaSecurityException { + TopiaAccessController.checkPermission("perm", "admin"); + List list = permissions.getKeys(perm.getId()); + boolean found = false; + for (Iterator it = list.iterator(); !found && it.hasNext(); ) { + HashMapMultiKey.Key key = (HashMapMultiKey.Key)it.next(); + Vector perms = (Vector)permissions.get(key); + for (Enumeration en = perms.elements(); !found && en.hasMoreElements(); ) { + TopiaPermission topiaPerm = (TopiaPermission)en.nextElement(); + if (topiaPerm.getPrincipals().equals(perm.getPrincipals())) { + found = true; + if (!topiaPerm.getActions().equals(perm.getActions())) { + perms.remove(topiaPerm); + if (perms.isEmpty()) + permissions.remove(key); + addNoSecurityPermission(perm, false); + } + } + } + } + + permFileModified = true; + try { + permissionListeners.fire("permissionModified", + new TopiaPermissionEvent(this, perm)); + } catch (Exception e) { + throw new TopiaSecurityException("Error while modifying permission " + + perm, e); + } + } + + /** + * Retire la permission perm + * @param perm + * @throws TopiaSecurityException + */ + public void removePermission(TopiaPermission perm) + throws TopiaSecurityException { + TopiaAccessController.checkPermission("perm", "admin"); + HashMapMultiKey.Key key; + key = new HashMapMultiKey.Key().add(perm.getActions()).add(perm.getId()); + Vector perms = (Vector)permissions.get(key); + if ((perms != null) && (perms.contains(perm))) { + permFileModified = true; + perms.remove(perm); + if (perms.isEmpty()) + permissions.remove(key); + } + try { + permissionListeners.fire("permissionRemoved", + new TopiaPermissionEvent(this, perm)); + } catch (Exception e) { + throw new TopiaSecurityException("Error while removing permission " + + perm, e); + } + } + +} // TopiaSecurityHelper +