gianugo 2003/01/03 08:58:31
Added: java/scratchpad/tests/src/org/apache/xindice/core/security PassiveCallbackHandlerTest.java XindiceLoginModuleTest.java XindiceUserManagerTest.java java/scratchpad/src/org/apache/xindice/core/security PassiveCallbackHandler.java UserManager.java UserManagerException.java XindiceLoginModule.java XindiceUserManager.java Log: Committed a first scratch implementation of security in Xindice, using a JAAS oriented approach. WARNING: This code ATM doesn't work yet, it's being committed for public review and personal comfort :-) Revision Changes Path 1.1 xml-xindice/java/scratchpad/tests/src/org/apache/xindice/core/security/PassiveCallbackHandlerTest.java Index: PassiveCallbackHandlerTest.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.LanguageCallback; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import junit.framework.TestCase; /** * Test case for PassiveAuthenticatorCallback * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class PassiveCallbackHandlerTest extends TestCase { PassiveCallbackHandler pch; /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { pch = new PassiveCallbackHandler("testuser", "testpassword"); } public void testUserAndPassword() throws Exception { NameCallback nc = new NameCallback("test"); PasswordCallback pc = new PasswordCallback("test", true); pch.handle(new Callback[] { nc, pc}); assertEquals(nc.getName(), "testuser"); assertEquals(new String(pc.getPassword()), "testpassword"); } public void testFailWithIncorrectCallbacks() { NameCallback nc = new NameCallback("test"); LanguageCallback lc = new LanguageCallback(); try { pch.handle(new Callback[] { nc, lc}); fail("An expected UnsupportedCallbackException was not raised"); } catch (IOException e) { fail("Unexpected IOEXception"); } catch (UnsupportedCallbackException e) { } } } 1.1 xml-xindice/java/scratchpad/tests/src/org/apache/xindice/core/security/XindiceLoginModuleTest.java Index: XindiceLoginModuleTest.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ import java.util.HashMap; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import junit.framework.TestCase; /** * Test for the XindiceLoginModule. * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class XindiceLoginModuleTest extends TestCase { XindiceLoginModule xlm; Subject subject; Map sharedState; Map options; CallbackHandler ch; /** * Setup the LoginModule instance. * * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { xlm = new XindiceLoginModule(); subject = new Subject(); ch = new PassiveCallbackHandler("testuser", "testpassword"); sharedState = new HashMap(); options = new HashMap(); } /** * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { xlm.logout(); } public void testValidLogin() throws LoginException { xlm.initialize(subject, ch, sharedState, options); assertTrue(xlm.login()); } public void testInvalidLogin() throws LoginException { ch = new PassiveCallbackHandler("invaliduser", "testpassword"); xlm.initialize(subject, ch, sharedState, options); assertFalse(xlm.login()); } } 1.1 xml-xindice/java/scratchpad/tests/src/org/apache/xindice/core/security/XindiceUserManagerTest.java Index: XindiceUserManagerTest.java =================================================================== package org.apache.xindice.core.security; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import junit.framework.TestCase; import org.apache.xindice.xml.dom.DOMParser; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Unit test for XindiceAuthenticator. * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class XindiceUserManagerTest extends TestCase { final String XML = "<?xml version=\"1.0\"?>" + "<users>" + "<user name=\"test\" password=\"test\">" + "<role name=\"root\"/>" + "</user>" + "<user name=\"readonly\" password=\"readonly\">" + "<role name=\"ro\"/>" + "</user>" + "<user name=\"readwrite\" password=\"readwrite\">" + "<role name=\"rw\"/>" + "</user>" + "<user name=\"manyroles\" password=\"manyroles\">" + "<role name=\"root\"/>" + "<role name=\"ro\"/>" + "<role name=\"rw\"/>" + "<role name=\"1\"/>" + "<role name=\"2\"/>" + "<role name=\"3\"/>" + "<role name=\"4\"/>" + "</user>" + "</users>"; XindiceUserManager usermanager = new XindiceUserManager(); /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { Document doc = DOMParser.toDocument(XML); usermanager.streamFromXML(doc.getDocumentElement()); } public void testAuthentication() { try { assertTrue(usermanager.checkPassword("test", "test")); assertFalse(usermanager.checkPassword("test", "wrong")); } catch (Exception e) { // Shouldn't happen fail("Got an exception:" + e.getMessage()); } } public void testAddUser() { try { usermanager.addUser("added", "added"); assertTrue(usermanager.checkPassword("added", "added")); } catch (Exception e) { // Shouldn't happen fail("Got an exception:" + e.getMessage()); }; } public void testDeleteExistingUser() { try { usermanager.deleteUser("readwrite"); assertFalse(usermanager.checkPassword("added","added")); } catch (Exception e) { fail("Got an exception while deleting a user: " + e); } } public void testDeleteNonExistingUser() { try { usermanager.deleteUser("nonexistant"); fail("Expecting an exception in deleting a non existent user, got none"); } catch (Exception e) { assertEquals(e.getMessage(), UserManagerException.NO_SUCH_USER); } } public void testDuplicateUser() { try { usermanager.addUser("test", "test"); fail("A UserManagerException was expected"); } catch (UserManagerException e) { assertEquals(e.getMessage(), UserManagerException.USER_ALREADY_EXISTS); } } public void testChangePassword() { try { usermanager.changePassword("readonly", "newpassword"); assertTrue(usermanager.checkPassword("readonly", "newpassword")); } catch (Exception e) { fail("Unexpected exception on password change:" + e.getMessage()); } } public void testChangePasswordNonExistingUser() { try { usermanager.changePassword("nonexistent", "test"); fail("A UserManagerException was expected"); } catch (UserManagerException e) { assertEquals(e.getMessage(), UserManagerException.NO_SUCH_USER); } } public void testStreamToXML() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); Document doc = null; try { doc = factory.newDocumentBuilder().newDocument(); } catch (ParserConfigurationException e) { fail("Unable to create a DOM object" + e.getMessage()); } Element element = usermanager.streamToXML(doc); assertEquals(element.getNodeName(), XindiceUserManager.CONFIGURATION); NodeList nl = element.getChildNodes(); assertTrue(nl.getLength() > 0); for (int i = 0; i < nl.getLength(); i++) { assertTrue(nl.item(i).getNodeType() == Node.ELEMENT_NODE); assertEquals(((Element)nl.item(i)).getNodeName(), XindiceUserManager.USERTAG); assertTrue(((Element)nl.item(i)).hasAttribute(XindiceUserManager.USERNAME)); assertTrue(((Element)nl.item(i)).hasAttribute(XindiceUserManager.PASSWORD)); NodeList rolesNl = nl.item(i).getChildNodes(); assertTrue(rolesNl.getLength() > 0); for (int ii = 0; ii < nl.getLength(); ii++) { assertTrue(rolesNl.item(ii).getNodeType() == Node.ELEMENT_NODE); assertEquals(((Element)rolesNl.item(ii)).getNodeName(), XindiceUserManager.ROLE); assertTrue(((Element)rolesNl.item(ii)).hasAttribute(XindiceUserManager.USERNAME)); } } XindiceUserManager newUserManager = new XindiceUserManager(); newUserManager.streamFromXML(element); try { assertTrue(newUserManager.checkPassword("test", "test")); } catch (Exception e) { fail("The serialized UserManager is not the same as the current one "); } } public void testRoles() { String[] result = (String[])usermanager.getRoles("test"); assertEquals(1, result.length); assertEquals("root", result[0]); } public void testManyRoles() { String[] result = (String[])usermanager.getRoles("manyroles"); assertEquals(7, result.length); assertEquals("root", result[0]); } } 1.1 xml-xindice/java/scratchpad/src/org/apache/xindice/core/security/PassiveCallbackHandler.java Index: PassiveCallbackHandler.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; /** * A CallbackHandler that does nothing but store and provide to * applications the username/password pairs. * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class PassiveCallbackHandler implements CallbackHandler { /** The user name */ protected String user; /** The user password */ protected String password; /** * Constructor for PassiveCallbackHandler, given a user/password pair. * * @param user the user name. * @param password the password. */ public PassiveCallbackHandler(String user, String password) { this.user = user; this.password = password; } /** * Process the Callback array, and set the username and password. * * @param callbacks an array of Callbacks: must be exactly one NameCallback and one PasswordCallback * @throws UnsupportedCallbackException if one of the Callbacks is not a Name or PasswordCallback */ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { ((NameCallback)callbacks[i]).setName(user); } else if (callbacks[i] instanceof PasswordCallback) { ((PasswordCallback)callbacks[i]).setPassword(password.toCharArray()); } else { throw new UnsupportedCallbackException(callbacks[i]); } } } } 1.1 xml-xindice/java/scratchpad/src/org/apache/xindice/core/security/UserManager.java Index: UserManager.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ /** * A simple interface for managing users, roles and passwords. * * @version $Id: UserManager.java,v 1.1 2003/01/03 16:58:31 gianugo Exp $ * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public interface UserManager { /** * Add a user. * * @param name The user name. * @param password The user password * @throws UserManagerException if the user already exists. */ void addUser(String name, String password) throws UserManagerException; /** * Delete a user. * * @param The user name * @throws UserManagerException if the user does not exist. */ void deleteUser(String name) throws UserManagerException; /** * Set a password for a given user. * * @param name * @param password * @throws UserManagerException if the user does not exist. */ void changePassword(String name, String newPassword) throws UserManagerException; /** * Check if a given password is valid. * * @param name the user name * @param password the given password * */ boolean checkPassword(String name, String password); /** * Returns an array of Object representing the roles * for a given user or null if the user does not exist. * * @return the role array */ String[] getRoles(String user); } 1.1 xml-xindice/java/scratchpad/src/org/apache/xindice/core/security/UserManagerException.java Index: UserManagerException.java =================================================================== package org.apache.xindice.core.security; /** * A simple exception for user management. * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class UserManagerException extends Exception { public static final String USER_ALREADY_EXISTS = "User already exists"; public static final String NO_SUCH_USER = "No such user"; String message = "Unknown error"; /** * Constructor UserManagerException. * @param message the specific error message. */ public UserManagerException(String message) { this.message = message; } /** * * @see java.lang.Throwable#getMessage() */ public String getMessage() { return message; } } 1.1 xml-xindice/java/scratchpad/src/org/apache/xindice/core/security/XindiceLoginModule.java Index: XindiceLoginModule.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ import java.io.IOException; 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; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; /** * This class implements a simple JAAS compatible LoginModule that * authenticates against the Xindice user base. Authentication in Xindice is * configured using the system.xml file as follows: * * <security> * <authentication type="JAAS" configuration="jaas.properties"/> * </security> * * the jaas.properties file must reside in the same * directory of the system.xml file, and must follow the standard JAAS * conventions. The default configuration uses this LoginModule to perform * authentication. * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> * @version $Id: XindiceLoginModule.java,v 1.1 2003/01/03 16:58:31 gianugo Exp $ */ public class XindiceLoginModule implements LoginModule { protected Subject m_subject; protected CallbackHandler m_handler; protected Map m_sharedState; protected Map m_options; protected UserManager m_manager; protected String user; private boolean success = false; /** * Initialize the module. This is performed by LoginContext. * * @see javax.security.auth.spi.LoginModule#initialize(Subject, * CallbackHandler, Map, Map) */ public void initialize(Subject subject, CallbackHandler handler, Map sharedState, Map options) { this.m_subject = subject; this.m_handler = handler; this.m_sharedState = sharedState; this.m_options = options; } /** * Perform the login. This is the "Phase 1", which only verifies * the user credential. * * @throws LoginException if the authentication process can't be executed. */ public boolean login() throws LoginException { // Prepare the environment. NameCallback nc = new NameCallback("user"); PasswordCallback pc = new PasswordCallback("password", true); Callback[] callbacks = new Callback[] {nc, pc}; // Handle the data. try { m_handler.handle(callbacks); } catch (IOException e) { // NOTREACHED, hopefully... throw new LoginException("A problem occurred while logging in"); } catch (UnsupportedCallbackException e) { throw new LoginException("A problem occurred while logging in"); } // Get the results. user = nc.getName(); String password = new String(pc.getPassword()); if (user.equals("testuser") && password.equals("testpassword")) success = true; return success; } /** * Commit the authentication (Phase 2). Here will go the authorization * specific code * * @throws LoginException if an error occurs (not likely ATM) */ public boolean commit() throws LoginException { if (success) m_subject.getPrincipals().add(user); return true; } /** * TBD * @see javax.security.auth.spi.LoginModule#abort() */ public boolean abort() throws LoginException { logout(); return true; } /** * Clear the instance variables. * * @see javax.security.auth.spi.LoginModule#logout() */ public boolean logout() throws LoginException { m_subject = null; m_handler = null; m_sharedState = null; user = null; return true; } } 1.1 xml-xindice/java/scratchpad/src/org/apache/xindice/core/security/XindiceUserManager.java Index: XindiceUserManager.java =================================================================== package org.apache.xindice.core.security; /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xindice" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, The dbXML * Group, L.L.C., http://www.dbxmlgroup.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Vector; import org.apache.xindice.xml.XMLSerializable; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * An Xindice based User Manager, using the SysUsers collection. * * * @author <a href="mailto:[EMAIL PROTECTED]">Gianugo Rabellino</a> */ public class XindiceUserManager implements UserManager, XMLSerializable { static final String CONFIGURATION = "users"; static final String USERTAG = "user"; static final String USERNAME = "name"; static final String PASSWORD = "password"; static final String ROLE = "role"; protected Map users; protected Map roles; public XindiceUserManager() { users = Collections.synchronizedMap(new HashMap()); roles = Collections.synchronizedMap(new HashMap()); } /** * Check if the password is correct. Will return false (for security purposes) * even if the user does not exist. * * @see org.apache.xindice.core.security.Authenticator#authenticate(java.lang.String, java.lang.String) */ public boolean checkPassword(String user, String password) { String currentPassword = (String) users.get(user); if (currentPassword != null && currentPassword.equals(password)) return true; return false; } /** * Add a user. * * @param name The user name. * @param password The user password * @throws UserManagerException if the user already exists. */ public void addUser(String name, String password) throws UserManagerException { if (!users.containsKey(name)) users.put(name,password); else throw new UserManagerException(UserManagerException.USER_ALREADY_EXISTS); } /** * Delete a user. * * @see org.apache.xindice.core.security.UserManager#deleteUser(java.lang.String) */ public void deleteUser(String name) throws UserManagerException { if (users.containsKey(name)) users.remove(name); else throw new UserManagerException(UserManagerException.NO_SUCH_USER); } /** * Change the password of a given user. * * @see org.apache.xindice.core.security.UserManager#changePassword(java.lang.String, java.lang.String) */ public void changePassword(String name, String password) throws UserManagerException { if (users.containsKey(name)) { users.remove(name); users.put(name, password); } else { throw new UserManagerException(UserManagerException.NO_SUCH_USER); } } /** * Serialize the instance in XML format. * * @see org.apache.xindice.xml.XMLSerializable#streamToXML(org.w3c.dom.Document) */ public Element streamToXML(Document doc) throws DOMException { Element root = doc.createElement(CONFIGURATION); Iterator i = users.keySet().iterator(); while (i.hasNext()) { String currentUser = (String) i.next(); String currentPassword = (String) users.get(currentUser); Element userElement = doc.createElement(USERTAG); userElement.setAttribute(USERNAME, currentUser); userElement.setAttribute(PASSWORD, currentPassword); String[] roles = getRoles(currentUser); for (int j = 0; j < roles.length; j++) { Element roleElement = doc.createElement(ROLE); roleElement.setAttribute(USERNAME, roles[j]); System.err.println("Added " + roles[j] + " to user " + currentUser); userElement.appendChild(roleElement); } root.appendChild(userElement); } return root; } /** * Populate the instance from an XML. * TODO: make it more robust, this implementation is *really* rough. * * @see org.apache.xindice.xml.XMLSerializable#streamFromXML(org.w3c.dom.Element) */ public void streamFromXML(Element element) throws DOMException { NodeList nl = element.getChildNodes(); for (int i = 0; i< nl.getLength(); i++) { Node node = nl.item(i); if (node.getNodeType() != Node.ELEMENT_NODE) continue; Element current = (Element)node; if (current.getNodeName().equals(USERTAG)) { String name = current.getAttribute(USERNAME); String password = current.getAttribute(PASSWORD); if (!users.containsKey(name)) { users.put(name, password); //Populate the roles NodeList rolesNl = current.getChildNodes(); ArrayList roleNames = new ArrayList(5); for (int ii = 0; ii < rolesNl.getLength(); ii++) { Node currentRoleNode = rolesNl.item(ii); if (node.getNodeType() != Node.ELEMENT_NODE) continue; Element currentRole = (Element)currentRoleNode; if (currentRole.getNodeName().equals(ROLE) && currentRole.hasAttribute(USERNAME)) roleNames.add(currentRole.getAttribute(USERNAME)); else throw new DOMException(DOMException.SYNTAX_ERR, "Unexpected Element: " + currentRole.getNodeName()); } roles.put(name, roleNames); } } } } /** * Returns an array of String representing the roles * for a given user or null if the user does not exist. * * @return the role array */ public String[] getRoles(String user) { ArrayList roleList = (ArrayList) roles.get(user); if (roleList != null) return (String[]) roleList.toArray(new String[1]); return null; } }