Author: jaz
Date: Tue Apr 21 20:14:27 2009 New Revision: 767281 URL: http://svn.apache.org/viewvc?rev=767281&view=rev Log: initial implementation of new Authenticator API. Part 1: define the API for external authentication modules (done) Part 2: update LoginServices to call AuthHelper for external modules (in progress) Part 3: create example Authenticator (in progress) Part 4: update LDAP implementation to use new API (not started) Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthHelper.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthInterfaceResolver.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthenticationComparator.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/Authenticator.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/AuthenticatorException.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestFailAuthenticator.java ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestPassAuthenticator.java Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthHelper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthHelper.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthHelper.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthHelper.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,93 @@ +package org.ofbiz.common.authentication; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.common.authentication.api.Authenticator; +import org.ofbiz.common.authentication.api.AuthenticatorException; +import org.ofbiz.service.LocalDispatcher; + +/** + * AuthHelper + */ +public class AuthHelper { + + private static final String module = AuthHelper.class.getName(); + protected static List<Authenticator> authenticators = new ArrayList<Authenticator>(); + protected static boolean authenticatorsLoaded = false; + + + public static boolean authenticate(String username, String password, boolean isServiceAuth) throws AuthenticatorException { + if (!authenticatorsLoaded) throw new AuthenticatorException("Authenticators never loaded; be sure to call AuthHelper.loadAuthenticators()"); + for (Authenticator auth : authenticators) { + boolean pass = auth.authenticate(username, password, isServiceAuth); + if (pass) { + return true; + } else if (auth.isSingleAuthenticator()) { + throw new AuthenticatorException(); + } + } + return false; + } + + public static void logout(String username) throws AuthenticatorException { + if (!authenticatorsLoaded) throw new AuthenticatorException("Authenticators never loaded; be sure to call AuthHelper.loadAuthenticators()"); + for (Authenticator auth : authenticators) { + auth.logout(username); + } + } + + public static void syncUser(String username) throws AuthenticatorException { + if (!authenticatorsLoaded) throw new AuthenticatorException("Authenticators never loaded; be sure to call AuthHelper.loadAuthenticators()"); + for (Authenticator auth : authenticators) { + if (auth.isUserSynchronized()) { + auth.syncUser(username); + } + } + } + + public static void updatePassword(String username, String password, String newPassword) throws AuthenticatorException { + if (!authenticatorsLoaded) throw new AuthenticatorException("Authenticators never loaded; be sure to call AuthHelper.loadAuthenticators()"); + for (Authenticator auth : authenticators) { + auth.updatePassword(username, password, newPassword); + } + } + + public static boolean authenticatorsLoaded() { + return authenticatorsLoaded; + } + + public static void loadAuthenticators(LocalDispatcher dispatcher) { + if (!authenticatorsLoaded) { + loadAuthenticators_internal(dispatcher); + } + } + + private synchronized static void loadAuthenticators_internal(LocalDispatcher dispatcher) { + if (!authenticatorsLoaded) { + AuthInterfaceResolver resolver = new AuthInterfaceResolver(); + List<Class> implementations = resolver.getImplementations(); + + for (Class c : implementations) { + try { + Authenticator auth = (Authenticator) c.newInstance(); + if (auth.isEnabled()) { + auth.initialize(dispatcher); + authenticators.add(auth); + } + } catch (InstantiationException e) { + Debug.logError(e, module); + } catch (IllegalAccessException e) { + Debug.logError(e, module); + } catch (ClassCastException e) { + Debug.logError(e, module); + } + } + + Collections.sort(authenticators, new AuthenticationComparator()); + authenticatorsLoaded = true; + } + } +} Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthInterfaceResolver.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthInterfaceResolver.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthInterfaceResolver.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthInterfaceResolver.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,159 @@ +package org.ofbiz.common.authentication; + +import java.util.List; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.net.URL; +import java.net.URLDecoder; +import java.io.IOException; +import java.io.File; +import java.io.FileInputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.common.authentication.api.Authenticator; + +/** + * AuthInterfaceResolver + */ +public class AuthInterfaceResolver { + + private static final String module = AuthInterfaceResolver.class.getName(); + protected List<Class> authenticators = new ArrayList<Class>(); + protected ClassLoader loader; + + public AuthInterfaceResolver() { + loader = getContextClassLoader(); + } + + public List<Class> getImplementations() { + find("org.ofbiz"); + return authenticators; + } + + protected void find(String packageName) { + packageName = packageName.replace('.', '/'); + Enumeration<URL> urls; + + try { + urls = loader.getResources(packageName); + } + catch (IOException io) { + Debug.logWarning(io, "Could not read package: " + packageName, module); + return; + } + + while (urls.hasMoreElements()) { + try { + String urlPath = urls.nextElement().getFile(); + urlPath = URLDecoder.decode(urlPath, "UTF-8"); + if (Debug.verboseOn()) + Debug.logVerbose("Found library file [" + urlPath + "]", module); + + if (urlPath.startsWith("file:")) { + urlPath = urlPath.substring(5); + } + + if (urlPath.indexOf('!') > 0) { + urlPath = urlPath.substring(0, urlPath.indexOf('!')); + } + + if (Debug.verboseOn()) + Debug.logVerbose("Scanning for classes in [" + urlPath + "]", module); + + File file = new File(urlPath); + if (file.isDirectory()) { + readDirectory(packageName, file); + } else { + readJar(packageName, file); + } + } + catch (IOException io) { + Debug.logError(io, "Could not read resource entries", module); + } + } + } + + protected void readDirectory(String parent, File location) { + File[] files = location.listFiles(); + StringBuffer buf; + + if (files == null) { + Debug.logWarning("Could not list directory " + location.getAbsolutePath() + " when looking for component classes", module); + return; + } + + for (File file : files) { + buf = new StringBuffer(); + buf.append(parent); + if (buf.length() > 0) + buf.append("/"); + buf.append(file.getName()); + String packageOrClass = (parent == null ? file.getName() : buf.toString()); + + if (file.isDirectory()) { + readDirectory(packageOrClass, file); + } else if (file.getName().endsWith(".class")) { + checkFile(packageOrClass); + } + } + } + + protected void readJar(String parent, File jarfile) { + try { + JarEntry entry; + JarInputStream jarStream = new JarInputStream(new FileInputStream(jarfile)); + + while ((entry = jarStream.getNextJarEntry()) != null) { + String name = entry.getName(); + if (!entry.isDirectory() && name.startsWith(parent) && name.endsWith(".class")) { + checkFile(name); + } + } + } + catch (IOException io) { + Debug.logError(io, "Could not search jar file [" + jarfile + "]", module); + } + } + + protected void checkFile(String name) { + String externalName = name.substring(0, name.indexOf('.')).replace('/', '.'); + if (Debug.verboseOn()) + Debug.logVerbose("Converted file value [" + name + "] to class [" + externalName + "]", module); + try { + resolveClass(loader.loadClass(externalName)); + } catch (ClassNotFoundException e) { + Debug.logWarning("No class found - " + externalName, module); + } + } + + protected ClassLoader getContextClassLoader() { + return AccessController.doPrivileged( + new PrivilegedAction<ClassLoader>() { + public ClassLoader run() { + ClassLoader cl = null; + try { + cl = Thread.currentThread().getContextClassLoader(); + + } catch (SecurityException e) { + Debug.logError(e, e.getMessage(), module); + } + return cl; + } + }); + } + + + public void resolveClass(Class clazz) { + Class[] ifaces = clazz.getInterfaces(); + for (Class iface : ifaces) { + if (Authenticator.class.equals(iface)) { + authenticators.add(clazz); + } + } + } +} + Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthenticationComparator.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthenticationComparator.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthenticationComparator.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/AuthenticationComparator.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,55 @@ +package org.ofbiz.common.authentication; + +import java.util.Comparator; + +import org.ofbiz.common.authentication.api.Authenticator; + +/** + * AuthenticationComparator + */ +public class AuthenticationComparator implements Comparator { + + /** + * Compares its two arguments for order. Returns a negative integer, + * zero, or a positive integer as the first argument is less than, equal + * to, or greater than the second.<p> + * <p/> + * The implementor must ensure that <tt>sgn(compare(x, y)) == + * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This + * implies that <tt>compare(x, y)</tt> must throw an exception if and only + * if <tt>compare(y, x)</tt> throws an exception.)<p> + * <p/> + * The implementor must also ensure that the relation is transitive: + * <tt>((compare(x, y)>0) && (compare(y, z)>0))</tt> implies + * <tt>compare(x, z)>0</tt>.<p> + * <p/> + * Finally, the implementer must ensure that <tt>compare(x, y)==0</tt> + * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all + * <tt>z</tt>.<p> + * <p/> + * It is generally the case, but <i>not</i> strictly required that + * <tt>(compare(x, y)==0) == (x.equals(y))</tt>. Generally speaking, + * any comparator that violates this condition should clearly indicate + * this fact. The recommended language is "Note: this comparator + * imposes orderings that are inconsistent with equals." + * + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than the + * second. + * @throws ClassCastException if the arguments' types prevent them from + * being compared by this Comparator. + */ + public int compare(Object o1, Object o2) { + Authenticator a1 = (Authenticator) o1; + Authenticator a2 = (Authenticator) o2; + if (a1.getWeight() < a2.getWeight()) { + return -1; + } else if (a1.getWeight() > a2.getWeight()) { + return 1; + } else { + return a1.getClass().getName().compareTo(a2.getClass().getName()); + } + } +} Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/Authenticator.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/Authenticator.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/Authenticator.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/Authenticator.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,73 @@ +package org.ofbiz.common.authentication.api; + +import org.ofbiz.service.LocalDispatcher; + +/** + * Authenticator + */ +public interface Authenticator { + + /** + * Method called when authenticator is first initialized (the delegator + * object can be obtained from the LocalDispatcher) + * @param dispatcher The ServiceDispatcher to use for this Authenticator + */ + public void initialize(LocalDispatcher dispatcher); + + /** + * Method to authenticate a user + * @param username User's username + * @param password User's password + * @param isServiceAuth true if authentication is for a service call + * @return true if the user is authenticated + * @throws AuthenticatorException when a fatal error occurs during authentication + */ + public boolean authenticate(String username, String password, boolean isServiceAuth) throws AuthenticatorException; + + /** + * Logs a user out + * @param username User's username + * @throws AuthenticatorException when logout fails + */ + public void logout(String username) throws AuthenticatorException; + + /** + * Reads user information and syncs it to OFBiz (i.e. UserLogin, Person, etc) + * @param username User's username + * @throws AuthenticatorException user synchronization fails + */ + public void syncUser(String username) throws AuthenticatorException; + + /** + * Updates a user's password + * @param username User's username + * @param password User's current password + * @param newPassword User's new password + * @throws AuthenticatorException when update password fails + */ + public void updatePassword(String username, String password, String newPassword) throws AuthenticatorException; + + /** + * Weight of this authenticator (lower weights are run first) + * @return the weight of this Authenicator + */ + public float getWeight(); + + /** + * Is the user synchronzied back to OFBiz + * @return true if the user record is copied to the OFB database + */ + public boolean isUserSynchronized(); + + /** + * Is this expected to be the only authenticator, if so errors will be thrown when users cannot be found + * @return true if this is expected to be the only Authenticator + */ + public boolean isSingleAuthenticator(); + + /** + * Flag to test if this Authenticator is enabled + * @return true if the Authenticator is enabled + */ + public boolean isEnabled(); +} Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/AuthenticatorException.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/AuthenticatorException.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/AuthenticatorException.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/api/AuthenticatorException.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,81 @@ +package org.ofbiz.common.authentication.api; + +import java.util.List; + +import org.ofbiz.base.util.GeneralException; + +/** + * AuthenticatorException + */ +public class AuthenticatorException extends GeneralException { + + /** + * Creates new <code>GeneralException</code> without detail message. + */ + public AuthenticatorException() { + super(); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message. + * + * @param msg the detail message. + */ + public AuthenticatorException(String msg) { + super(msg); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message and nested Exception. + * + * @param msg the detail message. + * @param nested the nested exception. + */ + public AuthenticatorException(String msg, Throwable nested) { + super(msg, nested); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message and nested Exception. + * + * @param nested the nested exception. + */ + public AuthenticatorException(Throwable nested) { + super(nested); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message, list and nested Exception. + * + * @param msg the detail message. + * @param messages error message list. + */ + public AuthenticatorException(String msg, List<String> messages) { + super(msg, messages); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message, list and nested Exception. + * + * @param msg the detail message. + * @param messages error message list. + * @param nested the nexted exception + */ + public AuthenticatorException(String msg, List<String> messages, Throwable nested) { + super(msg, messages, nested); + } + + /** + * Constructs an <code>GeneralException</code> with the specified detail message list and nested Exception. + * + * @param messages error message list. + * @param nested the nested exception. + */ + public AuthenticatorException(List<String> messages, Throwable nested) { + super(messages, nested); + } + + public AuthenticatorException(List<String> messages) { + super(messages); + } +} Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestFailAuthenticator.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestFailAuthenticator.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestFailAuthenticator.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestFailAuthenticator.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,119 @@ +package org.ofbiz.common.authentication.example; + +import org.ofbiz.common.authentication.api.Authenticator; +import org.ofbiz.common.authentication.api.AuthenticatorException; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.base.util.Debug; + +/** + * LocalAuthenticator + */ +public class TestFailAuthenticator implements Authenticator { + + private static final String module = TestFailAuthenticator.class.getName(); + protected GenericDelegator delegator; + protected LocalDispatcher dispatcher; + protected float weight = 1; + + /** + * Method called when authenticator is first initialized (the delegator + * object can be obtained from the LocalDispatcher) + * + * @param dispatcher The ServiceDispatcher to use for this Authenticator + */ + public void initialize(LocalDispatcher dispatcher) { + this.dispatcher = dispatcher; + this.delegator = dispatcher.getDelegator(); + Debug.logInfo(this.getClass().getName() + " Authenticator initialized", module); + } + + /** + * Method to authenticate a user + * + * @param username User's username + * @param password User's password + * @param isServiceAuth true if authentication is for a service call + * @return true if the user is authenticated + * @throws org.ofbiz.common.authentication.api.AuthenticatorException + * when a fatal error occurs during authentication + */ + public boolean authenticate(String username, String password, boolean isServiceAuth) throws AuthenticatorException { + Debug.logInfo(this.getClass().getName() + " Authenticator authenticate() -- returning false", module); + return false; + } + + /** + * Logs a user out + * + * @param username User's username + * @throws org.ofbiz.common.authentication.api.AuthenticatorException + * when logout fails + */ + public void logout(String username) throws AuthenticatorException { + Debug.logInfo(this.getClass().getName() + " Authenticator logout()", module); + } + + /** + * Reads user information and syncs it to OFBiz (i.e. UserLogin, Person, etc) + * + * @param username User's username + * @throws org.ofbiz.common.authentication.api.AuthenticatorException + * user synchronization fails + */ + public void syncUser(String username) throws AuthenticatorException { + Debug.logInfo(this.getClass().getName() + " Authenticator syncUser()", module); + // no user info to sync + } + + /** + * Updates a user's password + * + * @param username User's username + * @param password User's current password + * @param newPassword User's new password + * @throws org.ofbiz.common.authentication.api.AuthenticatorException + * when update password fails + */ + public void updatePassword(String username, String password, String newPassword) throws AuthenticatorException { + Debug.logInfo(this.getClass().getName() + " Authenticator updatePassword()", module); + } + + /** + * Weight of this authenticator (lower weights are run first) + * + * @return the weight of this Authenicator + */ + public float getWeight() { + return 1; + } + + /** + * Is the user synchronzied back to OFBiz + * + * @return true if the user record is copied to the OFB database + */ + public boolean isUserSynchronized() { + Debug.logInfo(this.getClass().getName() + " Authenticator isUserSynchronized()", module); + return true; + } + + /** + * Is this expected to be the only authenticator, if so errors will be thrown when users cannot be found + * + * @return true if this is expected to be the only Authenticator + */ + public boolean isSingleAuthenticator() { + Debug.logInfo(this.getClass().getName() + " Authenticator isSingleAuthenticator()", module); + return false; + } + + /** + * Flag to test if this Authenticator is enabled + * + * @return true if the Authenticator is enabled + */ + public boolean isEnabled() { + return false; + } +} Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestPassAuthenticator.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestPassAuthenticator.java?rev=767281&view=auto ============================================================================== --- ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestPassAuthenticator.java (added) +++ ofbiz/trunk/framework/common/src/org/ofbiz/common/authentication/example/TestPassAuthenticator.java Tue Apr 21 20:14:27 2009 @@ -0,0 +1,39 @@ +package org.ofbiz.common.authentication.example; + +import org.ofbiz.common.authentication.api.AuthenticatorException; +import org.ofbiz.common.authentication.api.Authenticator; +import org.ofbiz.base.util.Debug; + +/** + * TestPassAuthenticator + */ +public class TestPassAuthenticator extends TestFailAuthenticator implements Authenticator { + + private static final String module = TestPassAuthenticator.class.getName(); + + /** + * Method to authenticate a user + * + * @param username User's username + * @param password User's password + * @param isServiceAuth true if authentication is for a service call + * @return true if the user is authenticated + * @throws org.ofbiz.common.authentication.api.AuthenticatorException + * when a fatal error occurs during authentication + */ + @Override + public boolean authenticate(String username, String password, boolean isServiceAuth) throws AuthenticatorException { + Debug.logInfo(this.getClass().getName() + " Authenticator authenticate() -- returning false", module); + return true; + } + + /** + * Flag to test if this Authenticator is enabled + * + * @return true if the Authenticator is enabled + */ + @Override + public boolean isEnabled() { + return false; + } +} |
Free forum by Nabble | Edit this page |