Index: acct_mgr/admin.py
===================================================================
--- acct_mgr/admin.py	(revision 2186)
+++ acct_mgr/admin.py	(working copy)
@@ -28,6 +28,75 @@
     return [(name, value) for name, value in inspect.getmembers(cls)
             if isinstance(value, Option)]
 
+def _setorder(req, stores):
+    """Pull the password store ordering out of the req object"""
+    for store in stores.get_all_stores():
+        stores[store] = int(req.args.get(store.__class__.__name__, 0))
+        continue
+
+class StoreOrder(dict):
+    """Keeps the order of the Password Stores"""
+
+    instance = 0
+
+    def __init__(self, d={}, stores=[], list=[]):
+        self.instance += 1
+        self.d = {}
+        self.sxref = {}
+        for store in stores:
+            self.d[store] = 0
+            self[0] = store
+            self.sxref[store.__class__.__name__] = store
+            continue
+        for i, s in enumerate(list):
+            self.d[s] = i + 1
+            self[i + 1] = s
+
+    def __getitem__(self, key):
+        """Lookup a store in the list"""
+        return self.d[key]
+
+    def __setitem__(self, key, value):
+        if isinstance(key, Component):
+            order = self.d[key]
+            self.d[key] = value
+            self.d[order].remove(key)
+            self[value] = key
+        elif isinstance(key, basestring):
+            self.d[self.sxref[key]] = value
+        elif isinstance(key, int):
+            self.d.setdefault(key, [])
+            self.d[key].append(value)
+        else:
+            raise KeyError('Invalid key type (%s) for StoreOrder'
+                           % str(type(key)))
+        pass
+
+    def get_enabled_stores(self):
+        """Return an ordered list of password stores
+
+        All stores that are order 0 are dropped from the list.
+        """
+        keys = [k for k in self.d.keys() if isinstance(k, int)]
+        keys.sort()
+        storelist = []
+        for k in keys[1:]:
+            storelist.extend(self.d[k])
+            continue
+        return storelist
+
+    def get_enabled_store_names(self):
+        """Returns the class names of the enabled password stores"""
+        stores = self.get_enabled_stores()
+        return [s.__class__.__name__ for s in stores]
+
+    def get_all_stores(self):
+        return [k for k in self.d.keys() if isinstance(k, Component)]
+
+    def numstores(self):
+        return len(self.get_all_stores())
+
+
 class AccountManagerAdminPage(Component):
 
     implements(IAdminPanelProvider)
@@ -48,34 +117,42 @@
             return self._do_users(req)
 
     def _do_config(self, req):
+        stores = StoreOrder(stores=self.account_manager.stores,
+                            list=self.account_manager.password_store)
         if req.method == 'POST':
-            selected_class = req.args.get('selected')
-            self.config.set('account-manager', 'password_store', selected_class)
-            selected = self.account_manager.password_store
-            for attr, option in _getoptions(selected):
-                newvalue = req.args.get('%s.%s' % (selected_class, attr))
-                if newvalue is not None:
-                    self.config.set(option.section, option.name, newvalue)
-                    self.config.save()
-        try:
-            selected = self.account_manager.password_store
-        except AttributeError:
-            selected = None
-        sections = [
-            {'name': store.__class__.__name__,
-             'classname': store.__class__.__name__,
-             'selected': store is selected,
-             'options': [
-                {'label': attr,
-                 'name': '%s.%s' % (store.__class__.__name__, attr),
-                 'value': option.__get__(store, store),
-                }
-                for attr, option in _getoptions(store)
-             ],
-            } for store in self.account_manager.stores
-        ]
+            _setorder(req, stores)
+            self.config.set('account-manager', 'password_store',
+                            ','.join(stores.get_enabled_store_names()))
+            for store in stores.get_all_stores():
+                for attr, option in _getoptions(store):
+                    newvalue = req.args.get('%s.%s' % (store.__class__.__name__, attr))
+                    self.log.debug("%s.%s: %s" % (store.__class__.__name__, attr, newvalue))
+                    if newvalue is not None:
+                        self.config.set(option.section, option.name, newvalue)
+                        self.config.save()
+        sections = []
+        for store in self.account_manager.stores:
+            options = []
+            for attr, option in _getoptions(store):
+                opt_val = option.__get__(store, store)
+                opt_val = isinstance(opt_val, Component) and \
+                          opt_val.__class__.__name__ or opt_val
+                options.append(
+                            {'label': attr,
+                            'name': '%s.%s' % (store.__class__.__name__, attr),
+                            'value': opt_val,
+                            })
+                continue
+            sections.append(
+                        {'name': store.__class__.__name__,
+                        'classname': store.__class__.__name__,
+                        'order': stores[store],
+                        'options' : options,
+                        })
+            continue
         sections = sorted(sections, key=lambda i: i['name'])
-        return 'admin_accountsconfig.html', {'sections': sections}
+        numstores = range(0, stores.numstores() + 1)
+        return 'admin_accountsconfig.html', {'sections': sections, 'numstores': numstores}
 
     def _do_users(self, req):
         perm = PermissionSystem(self.env)
@@ -87,6 +164,10 @@
             'listing_enabled': listing_enabled,
             'create_enabled': create_enabled,
             'delete_enabled': delete_enabled,
+            'acctmgr' : { 'username' : None,
+                          'name' : None,
+                          'email' : None,
+                        }
         }
 
         if req.method == 'POST':
@@ -96,6 +177,7 @@
                         _create_user(req, self.env, check_permissions=False)
                     except TracError, e:
                         data['registration_error'] = e.message
+                        data['acctmgr'] = e.acctmgr
                 else:
                     data['registration_error'] = 'The password store does ' \
                                                  'not support creating users'
Index: acct_mgr/api.py
===================================================================
--- acct_mgr/api.py	(revision 2186)
+++ acct_mgr/api.py	(working copy)
@@ -10,7 +10,7 @@
 # Author: Matthew Good <trac@matt-good.net>
 
 from trac.core import *
-from trac.config import Option, ExtensionOption
+from trac.config import Option, ExtensionOption, OrderedExtensionsOption
 
 class IPasswordStore(Interface):
     """An interface for Components that provide a storage method for users and
@@ -76,12 +76,15 @@
     The methods will be handled by the underlying password storage
     implementation set in trac.ini with the "account-manager.password_format"
     setting.
+
+    The "account-manager.password_store" may be an ordered list of password
+    stores.  if it is a list, then each password store is queried in turn.
     """
 
     implements(IAccountChangeListener)
 
-    _password_store = ExtensionOption('account-manager', 'password_store',
-                                      IPasswordStore)
+    _password_store = OrderedExtensionsOption('account-manager', 'password_store',
+                                              IPasswordStore, include_missing=False)
     _password_format = Option('account-manager', 'password_format')
     stores = ExtensionPoint(IPasswordStore)
     change_listeners = ExtensionPoint(IAccountChangeListener)
@@ -89,31 +92,62 @@
     # Public API
 
     def get_users(self):
-        return self.password_store.get_users()
+        users = []
+        for store in self._password_store:
+            users.extend(store.get_users())
+        return users
 
     def has_user(self, user):
-        return self.password_store.has_user(user)
+        exists = False
+        for store in self._password_store:
+            if store.has_user(user):
+                exists = True
+                break
+            continue
+        return exists
 
     def set_password(self, user, password):
-        if self.password_store.set_password(user, password):
-            self._notify('created', user, password)
+        store = self.find_user_store(user)
+        if store and not hasattr(store, 'set_password'):
+            raise TracError('The authentication backend for the user, %s, '
+                            'does not support setting the password' % user)
+        elif not store:
+            store = self.get_supporting_store('set_password')
+        if store:
+            if store.set_password(user, password):
+                self._notify('created', user, password)
+            else:
+                self._notify('password_changed', user, password)
         else:
-            self._notify('password_changed', user, password)
+            raise TracError('None of the IPasswordStore components listed in '
+                            'the trac.ini support setting the password or '
+                            'creating users')
 
     def check_password(self, user, password):
-        return self.password_store.check_password(user, password)
+        valid = False
+        for store in self._password_store:
+            if store.check_password(user, password):
+                valid = True
+                break
+            continue
+        return valid
 
     def delete_user(self, user):
-        if self.password_store.delete_user(user):
-            self._notify('deleted', user)
+        store = self.find_user_store(user)
+        if hasattr(store, 'delete_user'):
+            if store and store.delete_user(user):
+                self._notify('deleted', user)
 
     def supports(self, operation):
         try:
-            store = self.password_store
+            stores = self.password_store
         except AttributeError:
             return False
         else:
-            return hasattr(store, operation)
+            if self.get_supporting_store(operation):
+                return True
+            else:
+                return False
 
     def password_store(self):
         try:
@@ -126,11 +160,55 @@
                 if config_key is None:
                     continue
                 if config_key() == fmt:
-                    return store
+                    return [store]
             # if the "password_format" is not set re-raise the AttributeError
             raise
     password_store = property(password_store)
 
+    def get_supporting_store(self, operation):
+        """Returns the IPasswordStore that implements the specified operaion
+
+        None is returned if no supporting store can be found
+        """
+        supports = False
+        for store in self.password_store:
+            if hasattr(store, operation):
+                supports = True
+                break
+            continue
+        store = supports and store or None
+        return store
+
+    def get_all_supporting_stores(self, operation):
+        """Returns a list of stores that implement the specified operation"""
+        stores = []
+        for store in self.password_store:
+            if hasattr(store, operation):
+                stores.append(store)
+            continue
+        return stores
+
+    def find_user_store(self, user):
+        """Locates which store contains the user specified.
+
+        If the user isn't found in any IPasswordStore in the chain, None is
+        returned
+        """
+        ignore_auth_case = self.env.config.get('trac', 'ignore_auth_case')
+        user_stores = []
+        for store in self._password_store:
+            userlist = store.get_users()
+            if ignore_auth_case:
+                userlist = [u.lower() for u in userlist]
+            user_stores.append((store, userlist))
+            continue
+        user = ignore_auth_case and user.lower() or user
+        for store in user_stores:
+            if user in store[1]:
+                return store[0]
+            continue
+        return None
+
     def _notify(self, func, *args):
         func = 'user_' + func
         for l in self.change_listeners:
Index: acct_mgr/web_ui.py
===================================================================
--- acct_mgr/web_ui.py	(revision 2186)
+++ acct_mgr/web_ui.py	(working copy)
@@ -29,25 +29,38 @@
     mgr = AccountManager(env)
 
     user = req.args.get('user')
+    name = req.args.get('name')
+    email = req.args.get('email')
+    acctmgr = {'username' : user,
+               'name' : name,
+               'email' : email,
+              }
+    error = TracError('')
+    error.acctmgr = acctmgr
     if not user:
-        raise TracError('Username cannot be empty.')
+        error.message = 'Username cannot be empty.'
+        raise error
 
     if mgr.has_user(user):
-        raise TracError('Another account with that name already exists.')
+        error.message = 'Another account with that name already exists.'
+        raise error
 
     if check_permissions:
         # disallow registration of accounts which have existing permissions
         permission_system = perm.PermissionSystem(env)
         if permission_system.get_user_permissions(user) != \
            permission_system.get_user_permissions('authenticated'):
-            raise TracError('Another account with that name already exists.')
+            error.message = 'Another account with that name already exists.'
+            raise error
 
     password = req.args.get('password')
     if not password:
-        raise TracError('Password cannot be empty.')
+        error.message = 'Password cannot be empty.'
+        raise error
 
     if password != req.args.get('password_confirm'):
-        raise TracError('The passwords must match.')
+        error.message = 'The passwords must match.'
+        raise error
 
     mgr.set_password(user, password)
 
@@ -131,7 +144,7 @@
         self._write_check(log=True)
 
     def _write_check(self, log=False):
-        writable = AccountManager(self.env).supports('set_password')
+        writable = AccountManager(self.env).get_all_supporting_stores('set_password')
         if not writable and log:
             self.log.warn('AccountModule is disabled because the password '
                           'store does not support writing.')
@@ -139,10 +152,13 @@
 
     #IPreferencePanelProvider methods
     def get_preference_panels(self, req):
-        if not self._write_check():
+        writable = self._write_check()
+        if not writable:
             return
         if req.authname and req.authname != 'anonymous':
-            yield 'account', 'Account'
+            user_store = AccountManager(self.env).find_user_store(req.authname)
+            if user_store in writable:
+                yield 'account', 'Account'
 
     def render_preference_panel(self, req, panel):
         data = {'account': self._do_account(req)}
@@ -294,12 +310,17 @@
         if req.authname != 'anonymous':
             req.redirect(req.href.prefs('account'))
         action = req.args.get('action')
-        data = {}
+        data = {'acctmgr' : { 'username' : None,
+                              'name' : None,
+                              'email' : None,
+                            },
+                }
         if req.method == 'POST' and action == 'create':
             try:
                 _create_user(req, self.env)
             except TracError, e:
                 data['registration_error'] = e.message
+                data['acctmgr'] = e.acctmgr
             else:
                 req.redirect(req.href.login())
         data['reset_password_enabled'] = \
Index: acct_mgr/db.py
===================================================================
--- acct_mgr/db.py	(revision 2186)
+++ acct_mgr/db.py	(working copy)
@@ -55,11 +55,13 @@
                        "WHERE authenticated=1 AND name='password' "
                        "AND sid=%s", (hash, user))
         if cursor.rowcount > 0:
+            db.commit()
             return False # updated existing password
         cursor.execute("INSERT INTO session_attribute "
                        "(sid,authenticated,name,value) "
                        "VALUES (%s,1,'password',%s)",
                        (user, hash))
+        db.commit()
         return True
 
     def check_password(self, user, password):
@@ -87,4 +89,5 @@
                        "AND sid=%s", (user,))
         # TODO cursor.rowcount doesn't seem to get # deleted
         # is there another way to get count instead of using has_user?
+        db.commit()
         return True
Index: acct_mgr/templates/admin_accountsconfig.html
===================================================================
--- acct_mgr/templates/admin_accountsconfig.html	(revision 2186)
+++ acct_mgr/templates/admin_accountsconfig.html	(working copy)
@@ -16,8 +16,13 @@
       <fieldset py:for="section in sections">
         <legend>
           <label>
+            <select name="${section.classname}" >
+              <option py:for="order in numstores" value="${order}" selected="${order == section.order or None}">${order == 0 and '--' or order}</option>
+            </select>
+<!--
             <input type="radio" name="selected" value="$section.classname"
                    checked="${section.selected and 'checked' or None}" />
+-->
             $section.name
           </label>
         </legend>
Index: acct_mgr/templates/register.html
===================================================================
--- acct_mgr/templates/register.html	(revision 2186)
+++ acct_mgr/templates/register.html	(working copy)
@@ -29,7 +29,7 @@
           <div>
             <input type="hidden" name="action" value="create" />
             <label>Username:
-              <input type="text" name="user" class="textwidget" size="20" />
+              <input type="text" name="user" class="textwidget" size="20" value="${acctmgr.username}" />
             </label>
           </div>
           <div>
@@ -48,12 +48,12 @@
           <legend>Optional</legend>
           <div>
             <label>Name:
-              <input type="text" name="name" class="textwidget" size="20" />
+              <input type="text" name="name" class="textwidget" size="20"  value="${acctmgr.name}"/>
             </label>
           </div>
           <div>
             <label>Email:
-              <input type="text" name="email" class="textwidget" size="20" />
+              <input type="text" name="email" class="textwidget" size="20"  value="${acctmgr.email}"/>
             </label>
             <p py:if="reset_password_enabled">Entering your email address will
             enable you to reset your password if you ever forget it.</p>
Index: acct_mgr/templates/admin_users.html
===================================================================
--- acct_mgr/templates/admin_users.html	(revision 2186)
+++ acct_mgr/templates/admin_users.html	(working copy)
@@ -19,7 +19,7 @@
 
         <legend>Add Account:</legend>
         <div class="field">
-          <label>Username: <input type="text" name="user" class="textwidget" /></label>
+          <label>Username: <input type="text" name="user" class="textwidget" value="${acctmgr.username}" /></label>
         </div>
         <div class="field">
           <label>Password: <input type="password" name="password" class="textwidget" /></label>
@@ -28,10 +28,10 @@
           <label>Confirm password: <input type="password" name="password_confirm" class="textwidget" /></label>
         </div>
         <div class="field">
-          <label>Name: <input type="text" name="name" class="textwidget" /></label>
+          <label>Name: <input type="text" name="name" class="textwidget" value="${acctmgr.name}" /></label>
         </div>
         <div class="field">
-          <label>Email: <input type="text" name="email" class="textwidget" /></label>
+          <label>Email: <input type="text" name="email" class="textwidget" value="${acctmgr.email}" /></label>
         </div>
         <p class="help">Add a new user account.</p>
         <div class="buttons">
