You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xindice-dev@xml.apache.org by gi...@apache.org on 2003/01/03 17:58:31 UTC
cvs commit: xml-xindice/java/scratchpad/src/org/apache/xindice/core/security PassiveCallbackHandler.java UserManager.java UserManagerException.java XindiceLoginModule.java XindiceUserManager.java
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 apache@apache.org.
*
* 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:gianugo@apache.org">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 apache@apache.org.
*
* 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:gianugo@apache.org">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:gianugo@apache.org">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 apache@apache.org.
*
* 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:gianugo@apache.org">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 apache@apache.org.
*
* 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:gianugo@apache.org">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:gianugo@apache.org">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 apache@apache.org.
*
* 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:gianugo@apache.org">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 apache@apache.org.
*
* 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:gianugo@apache.org">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;
}
}