Index: xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImpl.java =================================================================== --- xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImpl.java (revision 18352) +++ xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImpl.java (working copy) @@ -381,36 +381,47 @@ // This is needed for virtual mode to work if (context != null) { String susername = cannonicalUsername; + String virtualXwikiName = null; int i = cannonicalUsername.indexOf("."); int j = cannonicalUsername.indexOf(":"); if (i != -1) { susername = cannonicalUsername.substring(i + 1); - } else if (j != -1) { + } else if (j > 0) { // The username could be in the format xwiki:Username, so strip the wiki prefix. + // read the Virtual Wiki Database Name susername = cannonicalUsername.substring(j + 1); + virtualXwikiName = cannonicalUsername.substring(0, j); } - // First we check in the local database + String db = context.getDatabase(); + try { - String user = findUser(susername, context); - if (user != null) { - if (checkPassword(user, password, context)) { - return new SimplePrincipal(user); + + // Set the context database to the virtual wiki database name. + if (virtualXwikiName != null) + context.setDatabase(virtualXwikiName); + + // Check in the local database or database with virtual xwiki name. + try { + String user = findUser(susername, context); + if (user != null) { + if (checkPassword(user, password, context)) { + return new SimplePrincipal(virtualXwikiName != null ? context.getDatabase() + ":" + user + : user); + } else { + context.put("message", "wrongpassword"); + } } else { - context.put("message", "wrongpassword"); + context.put("message", "wronguser"); } - } else { - context.put("message", "wronguser"); + } catch (Exception e) { + // continue } - } catch (Exception e) { - // continue - } - if (!context.isMainWiki()) { - // Then we check in the main database - String db = context.getDatabase(); - try { + if (!context.isMainWiki()) { + // Then we check in the main database + context.setDatabase(context.getMainXWiki()); try { String user = findUser(susername, context); @@ -429,13 +440,15 @@ context.put("message", "loginfailed"); return null; } - } finally { - context.setDatabase(db); + + } else { + // error message was already set + return null; } - } else { - // error message was already set - return null; + } finally { + context.setDatabase(db); } + } else { context.put("message", "loginfailed"); return null; Index: xwiki-core/src/test/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImplTest.java =================================================================== --- xwiki-core/src/test/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImplTest.java (revision 18352) +++ xwiki-core/src/test/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImplTest.java (working copy) @@ -123,4 +123,58 @@ assertNotNull(principal); assertEquals("XWiki.SomeUser", principal.getName()); } + + /** + * Test that user is authenticated with a global account when a local one with the same name exists. + */ + + public void testLogintoVirtualXwikiWithWikiPrefixUsername() throws Exception + { + + // Setup a simple user profile documents + XWikiDocument userDocLocal = new XWikiDocument("local", "XWiki", "Admin"); + XWikiDocument userDocVirtual = new XWikiDocument("xwiki", "XWiki", "Admin"); + + // Make a simple XWiki.XWikiUsers class that will contain a default password field + BaseClass userClass = new BaseClass(); + userClass.addPasswordField("password", "Password", 20); + userClass.setClassName("XWiki.XWikiUsers"); + + // Mock the XWikiUsers object, since a real objects requires more mocking on the XWiki object + Mock mockUserObj = mock(BaseObject.class, new Class[] {}, new Object[] {}); + mockUserObj.stubs().method("setWiki"); + mockUserObj.stubs().method("setName"); + mockUserObj.stubs().method("setNumber"); + mockUserObj.stubs().method("getStringValue").with(eq("password")).will(returnValue("admin")); + userDocLocal.addObject("XWiki.XWikiUsers", (BaseObject) mockUserObj.proxy()); + + // Prepare the XWiki mock for local + this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.Admin"), eq(this.getContext())).will( + returnValue(userDocLocal)); + this.mockXWiki.stubs().method("getClass").with(eq("XWiki.XWikiUsers"), eq(this.getContext())).will( + returnValue(userClass)); + this.mockXWiki.stubs().method("exists").will(returnValue(true)); + this.mockXWiki.stubs().method("isVirtualMode").will(returnValue(false)); + + // Run the test: Using Xwiki.Admin should correctly authenticate the Admin user + Principal principalLocal = this.authService.authenticate("XWiki.Admin", "admin", this.getContext()); + assertNotNull(principalLocal); + assertEquals("XWiki.Admin", principalLocal.getName()); + + // Set the database name to local. + this.getContext().setDatabase("local"); + + // Prepare the XWiki mock for virtual + this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.Admin"), eq(this.getContext())).will( + returnValue(userDocVirtual)); + this.mockXWiki.stubs().method("isVirtualMode").will(returnValue(true)); + userDocVirtual.addObject("XWiki.XWikiUsers", (BaseObject) mockUserObj.proxy()); + + // Finally run the test: Using xwiki:Xwiki.Admin should correctly authenticate the Admin user + Principal principalVirtual = this.authService.authenticate("xwiki:XWiki.Admin", "admin", this.getContext()); + assertNotNull(principalVirtual); + assertEquals("XWiki.Admin", principalVirtual.getName()); + + } + }