MER-C/wiki-java

Handling of multiple logged-in Wiki instances broken by new JDK cookie manager

PeterBowman opened this issue · 5 comments

JDK cookies are used in Wiki.java since 61eba0f (0.34). The default CookieStore implementation manages cookies on a system-wide manner, which means that URL connections handled by multiple Wiki.java instances are consequently overriden (i.e. each new Wiki.java instance makes all previously created instances re-use its cookies).

I noticed this while running an app that queries two distinct wikis through the same account. My bot user has bot rights on plwiktionary, hence I configure an assertion as shown below:

Wiki plwikt = Wiki.createInstance("pl.wiktionary.org");
plwikt.login("User", "password");
plwikt.setAssertionMode(Wiki.ASSERT_USER | Wiki.ASSERT_BOT);
plwikt.getSiteStatistics(); // fine

Wiki ruwikt = Wiki.createInstance("ru.wiktionary.org");
ruwikt.login("User", "password");
ruwikt.setAssertionMode(Wiki.ASSERT_USER);
ruwikt.getSiteStatistics(); // fine

plwikt.getSiteStatistics(); // error

A java.lang.AssertionError: Assertion that the user has the "bot" right failed. is thrown after the last line. The cookies set by plwikt on initialization and later login are overriden by the ruwikt instance, and in fact, I don't have bot permissions on ruwiktionary.

A similar example will lead to the same result with non-bot accounts: log in with the first Wiki.java instance as a regular user, set the assertion, and don't log in through the second instance.

An alternative approach that helps to reproduce this bug involves using two accounts:

Wiki user1 = Wiki.createInstance("test.wikipedia.org");
user1.login("User1", "password1");
user1.setAssertionMode(Wiki.ASSERT_USER);
user1.edit("Sandbox", "1", "1"); // correct, performed by User1

Wiki user2 = Wiki.createInstance("test.wikipedia.org");
user2.login("User2", "password2");
user2.setAssertionMode(Wiki.ASSERT_USER);
user2.edit("Sandbox", "2", "2"); // correct, performed by User2

user1.edit("Sandbox", "1?", "1?"); // WRONG, performed by User2

I tried https://stackoverflow.com/a/17513786. The assertion issue seems solved, but I get a FailedLoginException in the dual-user sample snippet upon logging in with user2:

result=Aborted
reason=Cannot log in when using MediaWiki\Session\BotPasswordSessionProvider sessions.

Perhaps something like this could restore the old grabCookies mechanism and avoid setting the system-wide cookie handler:

CookieHandler.setDefault(cookies);

Perhaps something like this could restore the old grabCookies mechanism and avoid setting the system-wide cookie handler:

Done in my fork at PeterBowman@a95d5c8 and seems to solve this. Since it's more of a copy-paste of your former code, @MER-C, I'd like to ask if this solution is robust enough. I'm not familiarized with the reasons behind that grabCookies implementation. Also, I have incidentally restored a previous TODO notice.

MER-C commented

Reproduced with the following:

Wiki testWiki = Wiki.createInstance("test.wikipedia.org");
Wiki enWiki = Wiki.createInstance("en.wikipedia.org");
enWiki.getPageText("Main Page");        
// should still be logged in...
testWiki.setAssertionMode(Wiki.ASSERT_USER);
testWiki.getPageText("Main Page");

I've gone for a slightly modified StackOverflow solution that shoves as much onto the JDK as possible. Please reopen if the commit doesn't fix the bug.

Thanks PeterBowman for issuing this bug. Updated to 0.34 and my bot suddenly broke because of this.