Bug 237042 - [e3.4] use secure storage to save passwords
Summary: [e3.4] use secure storage to save passwords
Status: RESOLVED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Mylyn (show other bugs)
Version: dev   Edit
Hardware: PC Windows XP
: P2 enhancement (vote)
Target Milestone: 3.2   Edit
Assignee: Robert Elves CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 208935
  Show dependency tree
 
Reported: 2008-06-13 06:41 EDT by Tomasz Zarna CLA
Modified: 2009-05-29 17:30 EDT (History)
3 users (show)

See Also:


Attachments
fix (10.57 KB, patch)
2009-05-21 00:04 EDT, Robert Elves CLA
no flags Details | Diff
migration (4.07 KB, patch)
2009-05-21 02:51 EDT, Robert Elves CLA
no flags Details | Diff
unit test (4.56 KB, patch)
2009-05-21 12:22 EDT, Robert Elves CLA
no flags Details | Diff
patch revised (22.31 KB, patch)
2009-05-26 16:37 EDT, Robert Elves CLA
no flags Details | Diff
update (21.09 KB, patch)
2009-05-27 04:14 EDT, Robert Elves CLA
no flags Details | Diff
update (21.27 KB, patch)
2009-05-27 20:34 EDT, Robert Elves CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tomasz Zarna CLA 2008-06-13 06:41:06 EDT
I'm getting tired of reentering my Bugzilla's password every time I upgraded to a new Eclipse and/or Mylyn build :) Seriously, it's not the big deal, but I think you should consider using Secure Storage[1] to save Bugzilla's (or any repository in general) password. We did that in CVS some time ago[2], don't want to be the only one who is using it ;)

[1] Help > Workbench User Guide > Reference > Secure Storage
[2] bug 222124
Comment 1 Steffen Pingel CLA 2008-06-13 06:50:28 EDT
+1 

Tomasz, do you know if the Equinox Security Framework is also available for Eclipse 3.3?
Comment 2 Tomasz Zarna CLA 2008-06-13 09:50:18 EDT
(In reply to comment #1)
> Tomasz, do you know if the Equinox Security Framework is also available for
> Eclipse 3.3?

I've just talked to Oleg Besedin, and he told me that unfortunately the answer is no. The reason for this is that "the org.eclipse.equinox.security bundle contains other stuff that needs latest and greatest OSGi. In theory it should be possible to separate that code out and the secure storage itself *should* then run on 3.3. But definitely not in the form it is today"
Comment 3 Steffen Pingel CLA 2008-06-13 19:33:47 EDT
Thanks. We might need some type of extension point / compatibility layer that only uses the new API if available.
Comment 4 Philippe Marschall CLA 2009-04-30 00:52:59 EDT
+1
That would be a very welcome addition.
Comment 5 Steffen Pingel CLA 2009-04-30 01:02:08 EDT
We'll consider it as part of Mylyn 3.3 planning. Mylyn 3.2 will most likely be the last release with Eclipse 3.3 support so we should be able to consume new platform APIs for the next release.
Comment 6 Robert Elves CLA 2009-05-21 00:04:18 EDT
Created attachment 136601 [details]
fix

Patch as applied to head.
Comment 7 Robert Elves CLA 2009-05-21 00:05:10 EDT
Steffen over to you for doing the branch...
Comment 8 Robert Elves CLA 2009-05-21 02:51:35 EDT
Created attachment 136619 [details]
migration

Here's the migration portion of the patch.  Needs unit test coverage.
Comment 9 Robert Elves CLA 2009-05-21 12:22:36 EDT
Created attachment 136674 [details]
unit test

Unit testage. Just afer applying will need the migrate method made public on TaskRepositoryManager (masked by interface so should be fine).
Comment 10 Steffen Pingel CLA 2009-05-21 17:48:29 EDT
Rob, I think the migration needs to happen in a job, otherwise the keystore password prompt is displayed while the splash is showing:

"main" prio=10 tid=0x08060800 nid=0x1cfc runnable [0xb7dc2000..0xb7dc4208]
   java.lang.Thread.State: RUNNABLE
	at org.eclipse.swt.internal.gtk.OS.Call(Native Method)
	at org.eclipse.swt.widgets.Display.sleep(Display.java:3885)
	at org.eclipse.jface.window.Window.runEventLoop(Window.java:826)
	at org.eclipse.jface.window.Window.open(Window.java:801)
	at org.eclipse.equinox.internal.security.ui.storage.DefaultPasswordProvider$1.run(DefaultPasswordProvider.java:49)
	at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:179)
	at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:150)
	at org.eclipse.swt.widgets.Display.syncExec(Display.java:4105)
	at org.eclipse.equinox.internal.security.ui.storage.DefaultPasswordProvider.getPassword(DefaultPasswordProvider.java:47)
	at org.eclipse.equinox.internal.security.storage.PasswordProviderModuleExt.getPassword(PasswordProviderModuleExt.java:35)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesRoot.getModulePassword(SecurePreferencesRoot.java:254)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesRoot.getPassword(SecurePreferencesRoot.java:219)
	at org.eclipse.equinox.internal.security.storage.SecurePreferences.put(SecurePreferences.java:224)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesWrapper.put(SecurePreferencesWrapper.java:110)
	at org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager.migrateToSecureStorage(TaskRepositoryManager.java:339)
	at org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager.loadRepositories(TaskRepositoryManager.java:302)
	at org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager.readRepositories(TaskRepositoryManager.java:271)
	at org.eclipse.mylyn.internal.tasks.core.RepositoryExternalizationParticipant.load(RepositoryExternalizationParticipant.java:69)
	at org.eclipse.mylyn.internal.tasks.core.externalization.AbstractExternalizationParticipant.performLoad(AbstractExternalizationParticipant.java:83)
	at org.eclipse.mylyn.internal.tasks.core.externalization.AbstractExternalizationParticipant.execute(AbstractExternalizationParticipant.java:73)
	at org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager$1.run(ExternalizationManager.java:118)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager.load(ExternalizationManager.java:107)
	at org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager.load(ExternalizationManager.java:85)
	at org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin.initializeDataSources(TasksUiPlugin.java:808)
	at org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin.start(TasksUiPlugin.java:597)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:782)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:773)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:754)
	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:352)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:280)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:408)
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:111)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:449)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:211)
	at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:376)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:452)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at org.eclipse.osgi.internal.loader.BundleLoader.loadClass(BundleLoader.java:321)
	at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:231)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1193)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:160)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:874)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:243)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:51)
	at org.eclipse.ui.internal.WorkbenchPlugin$1.run(WorkbenchPlugin.java:267)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.ui.internal.WorkbenchPlugin.createExtension(WorkbenchPlugin.java:263)
	at org.eclipse.ui.internal.WorkbenchPlugin.getElementFactory(WorkbenchPlugin.java:497)
	at org.eclipse.ui.internal.Workbench.getElementFactory(Workbench.java:2894)
	at org.eclipse.ui.internal.EditorReference.getRestoredInput(EditorReference.java:393)
	at org.eclipse.ui.internal.EditorReference.getEditorInput(EditorReference.java:362)
	at org.eclipse.ui.internal.EditorReference.createPartHelper(EditorReference.java:591)
	at org.eclipse.ui.internal.EditorReference.createPart(EditorReference.java:462)
	at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:595)
	at org.eclipse.ui.internal.EditorAreaHelper.setVisibleEditor(EditorAreaHelper.java:271)
	at org.eclipse.ui.internal.EditorManager.setVisibleEditor(EditorManager.java:1417)
	at org.eclipse.ui.internal.EditorManager$5.runWithException(EditorManager.java:942)
	at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
	- locked <0xafa4dfb8> (a org.eclipse.swt.widgets.RunnableLock)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3460)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3107)
	at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
	at org.eclipse.ui.internal.Workbench$28.runWithException(Workbench.java:1384)
	at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
	- locked <0xb24b55b0> (a org.eclipse.swt.widgets.RunnableLock)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3460)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3107)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2316)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Comment 11 Steffen Pingel CLA 2009-05-21 17:49:04 EDT
Similar problem when editors are restored:

"main" prio=10 tid=0x08060800 nid=0x1d9a runnable [0xb7deb000..0xb7ded208]
   java.lang.Thread.State: RUNNABLE
	at org.eclipse.swt.internal.gtk.OS.Call(Native Method)
	at org.eclipse.swt.widgets.Display.sleep(Display.java:3885)
	at org.eclipse.jface.window.Window.runEventLoop(Window.java:826)
	at org.eclipse.jface.window.Window.open(Window.java:801)
	at org.eclipse.equinox.internal.security.ui.storage.DefaultPasswordProvider$1.run(DefaultPasswordProvider.java:49)
	at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:179)
	at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:150)
	at org.eclipse.swt.widgets.Display.syncExec(Display.java:4105)
	at org.eclipse.equinox.internal.security.ui.storage.DefaultPasswordProvider.getPassword(DefaultPasswordProvider.java:47)
	at org.eclipse.equinox.internal.security.storage.PasswordProviderModuleExt.getPassword(PasswordProviderModuleExt.java:35)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesRoot.getModulePassword(SecurePreferencesRoot.java:254)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesRoot.getPassword(SecurePreferencesRoot.java:219)
	at org.eclipse.equinox.internal.security.storage.SecurePreferences.get(SecurePreferences.java:262)
	at org.eclipse.equinox.internal.security.storage.SecurePreferencesWrapper.get(SecurePreferencesWrapper.java:106)
	at org.eclipse.mylyn.tasks.core.TaskRepository.getAuthInfo(TaskRepository.java:299)
	- locked <0x7787d178> (a java.lang.Object)
	at org.eclipse.mylyn.tasks.core.TaskRepository.getCredentials(TaskRepository.java:369)
	- locked <0x774a0168> (a org.eclipse.mylyn.tasks.core.TaskRepository)
	at org.eclipse.mylyn.tasks.core.TaskRepository.getUserName(TaskRepository.java:504)
	at org.eclipse.mylyn.tasks.core.TaskRepository.getUserName(TaskRepository.java:494)
	at org.eclipse.mylyn.internal.bugzilla.ui.editor.BugzillaPeoplePart.addSelfToCC(BugzillaPeoplePart.java:100)
	at org.eclipse.mylyn.internal.bugzilla.ui.editor.BugzillaPeoplePart.createControl(BugzillaPeoplePart.java:78)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.initializePart(AbstractTaskEditorPage.java:1147)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.access$6(AbstractTaskEditorPage.java:1144)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage$15.run(AbstractTaskEditorPage.java:776)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.createParts(AbstractTaskEditorPage.java:767)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.createParts(AbstractTaskEditorPage.java:759)
	at org.eclipse.mylyn.internal.bugzilla.ui.editor.BugzillaTaskEditorPage.createParts(BugzillaTaskEditorPage.java:236)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.createFormContentInternal(AbstractTaskEditorPage.java:643)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.createFormContent(AbstractTaskEditorPage.java:588)
	at org.eclipse.ui.forms.editor.FormPage$1.run(FormPage.java:152)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.ui.forms.editor.FormPage.createPartControl(FormPage.java:150)
	at org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage.createPartControl(AbstractTaskEditorPage.java:547)
	at org.eclipse.ui.forms.editor.FormEditor.pageChange(FormEditor.java:465)
	at org.eclipse.ui.part.MultiPageEditorPart.setActivePage(MultiPageEditorPart.java:1076)
	at org.eclipse.ui.forms.editor.FormEditor.setActivePage(FormEditor.java:597)
	at org.eclipse.ui.forms.editor.SharedHeaderFormEditor.setActivePage(SharedHeaderFormEditor.java:110)
	at org.eclipse.mylyn.tasks.ui.editors.TaskEditor.addPages(TaskEditor.java:189)
	at org.eclipse.ui.forms.editor.FormEditor.createPages(FormEditor.java:138)
	at org.eclipse.ui.forms.editor.SharedHeaderFormEditor.createPages(SharedHeaderFormEditor.java:98)
	at org.eclipse.ui.part.MultiPageEditorPart.createPartControl(MultiPageEditorPart.java:357)
	at org.eclipse.ui.internal.EditorReference.createPartHelper(EditorReference.java:662)
	at org.eclipse.ui.internal.EditorReference.createPart(EditorReference.java:462)
	at org.eclipse.ui.internal.WorkbenchPartReference.getPart(WorkbenchPartReference.java:595)
	at org.eclipse.ui.internal.EditorAreaHelper.setVisibleEditor(EditorAreaHelper.java:271)
	at org.eclipse.ui.internal.EditorManager.setVisibleEditor(EditorManager.java:1417)
	at org.eclipse.ui.internal.EditorManager$5.runWithException(EditorManager.java:942)
	at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
	- locked <0x7787d140> (a org.eclipse.swt.widgets.RunnableLock)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3460)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3107)
	at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
	at org.eclipse.ui.internal.Workbench$28.runWithException(Workbench.java:1384)
	at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
	- locked <0x773a0cb0> (a org.eclipse.swt.widgets.RunnableLock)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3460)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3107)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2316)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Comment 12 Robert Elves CLA 2009-05-26 16:37:46 EDT
Created attachment 137222 [details]
patch revised
Comment 13 Steffen Pingel CLA 2009-05-26 21:11:18 EDT
Patch looks good. A couple of thoughts:

Instead of adding a new method setNeedsSecureStorage() in AbstractRepositorySettingsPage I would expect clients to simply invoke repository.setProperty(ITasksCoreConstants.PROPERTY_USE_SECURE_STORAGE, "true") in their applyTo() method. If you want to put this in API I think it would be better if a setUseSecureStorage() was added to TaskRepository. For now it prefer it we would leave this out since the method wouldn't make much sense as API on Eclipse 3.3.

Is it necessary to store all usernames in plain text or does that mainly apply to the repository username, e.g. for HTTP auth it could also make sense to encrypt both username and password?
Comment 14 Robert Elves CLA 2009-05-27 04:14:31 EDT
Created attachment 137280 [details]
update

Thanks Steffen. Here is an updated patch that address these two issues.
Comment 15 Robert Elves CLA 2009-05-27 20:34:31 EDT
Created attachment 137433 [details]
update

fixed a bug, update test coverage
Comment 16 Steffen Pingel CLA 2009-05-28 03:56:03 EDT
Patch looks good to me.
Comment 17 Robert Elves CLA 2009-05-29 17:30:11 EDT
Patch applied. Created bug#278474 to address migration for 3.3.