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 18295) +++ xwiki-core/src/main/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImpl.java (working copy) @@ -161,8 +161,8 @@ sconfig.setPersistentLoginManager(persistent); MyFilterConfig fconfig = new MyFilterConfig(); - fconfig.setInitParameter(FormAuthenticator.LOGIN_SUBMIT_PATTERN_KEY, - xwiki.Param("xwiki.authentication.loginsubmitpage", "/loginsubmit/XWiki/XWikiLogin")); + fconfig.setInitParameter(FormAuthenticator.LOGIN_SUBMIT_PATTERN_KEY, xwiki.Param( + "xwiki.authentication.loginsubmitpage", "/loginsubmit/XWiki/XWikiLogin")); this.authenticator.init(fconfig, sconfig); } @@ -352,11 +352,13 @@ */ if (username == null) { - // If we can't find the username field then we are probably on the login screen + // If we can't find the username field then we are probably on the + // login screen return null; } - // Trim the username to allow users to enter their names with spaces before or after + // Trim the username to allow users to enter their names with spaces + // before or after String cannonicalUsername = username.replaceAll(" ", ""); // Check for empty usernames @@ -381,17 +383,29 @@ // 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 > 0) { + // The username could be in the format xwiki:Username, So Strip + // the xwiki prefix and read the Virtual Wiki Database Name + susername = cannonicalUsername.substring(j + 1); + virtualXwikiName = cannonicalUsername.substring(0, j); } - // First we check in the local database + // 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(user); + return new SimplePrincipal(virtualXwikiName != null ? context.getDatabase() + ":" + user : user); } else { context.put("message", "wrongpassword"); } @@ -445,9 +459,12 @@ if (context.getWiki().exists("XWiki." + username, context)) { user = "XWiki." + username; } else { - // Note: The result of this search depends on the Database. If the database is - // case-insensitive (like MySQL) then users will be able to log in by entering their - // username in any case. For case-sensitive databases (like HSQLDB) they'll need to + // Note: The result of this search depends on the Database. If the + // database is + // case-insensitive (like MySQL) then users will be able to log in + // by entering their + // username in any case. For case-sensitive databases (like HSQLDB) + // they'll need to // enter it exactly as they've created it. String sql = "select distinct doc.fullName from XWikiDocument as doc"; Object[][] whereParameters = new Object[][] { {"doc.space", "XWiki"}, {"doc.name", username}}; @@ -468,7 +485,8 @@ try { boolean result = false; XWikiDocument doc = context.getWiki().getDocument(username, context); - // We only allow empty password from users having a XWikiUsers object. + // We only allow empty password from users having a XWikiUsers + // object. if (doc.getObject("XWiki.XWikiUsers") != null) { String passwd = doc.getStringValue("XWiki.XWikiUsers", "password"); password = @@ -564,11 +582,13 @@ protected String stripContextPathFromURL(URL url, XWikiContext context) { String contextPath = context.getWiki().getWebAppPath(context); - // XWiki uses contextPath in the wrong way, putting a / at the end, and not at the start. Fix this here. + // XWiki uses contextPath in the wrong way, putting a / at the end, and + // not at the start. Fix this here. if (contextPath.endsWith("/") && !contextPath.startsWith("/")) { contextPath = "/" + StringUtils.chop(contextPath); } - // URLFactory.getURL applies Util.escapeURL, which might convert the contextPath into an %NN escaped string. + // URLFactory.getURL applies Util.escapeURL, which might convert the + // contextPath into an %NN escaped string. // Apply the same escape method to compensate this. contextPath = Util.escapeURL(contextPath); return StringUtils.removeStart(context.getURLFactory().getURL(url, context), contextPath); 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 18295) +++ xwiki-core/src/test/java/com/xpn/xwiki/user/impl/xwiki/XWikiAuthServiceImplTest.java (working copy) @@ -24,6 +24,9 @@ import org.jmock.Mock; import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.objects.BaseObject; +import com.xpn.xwiki.objects.classes.BaseClass; import com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase; /** @@ -88,4 +91,87 @@ assertNotNull(principal); assertEquals("XWiki.superadmin", principal.getName()); } + + /** + * Test that User is authenticated as User when xwiki:User is entered as username. + */ + + public void testLoginWithWikiPrefix() throws Exception + { + + XWikiDocument userDoc = new XWikiDocument("XWiki", "Admin"); + + BaseClass userClass = new BaseClass(); + userClass.addPasswordField("password", "Password", 20); + userClass.setClassName("XWiki.XWikiUsers"); + + 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")); + userDoc.addObject("XWiki.XWikiUsers", (BaseObject) mockUserObj.proxy()); + + this.mockXWiki.stubs().method("getDocument").with(eq("XWiki.Admin"), eq(this.getContext())).will( + returnValue(userDoc)); + 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)); + + Principal principal = this.authService.authenticate("xwiki:Admin", "admin", this.getContext()); + assertNotNull(principal); + assertEquals("xwiki:XWiki.Admin", 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 + { + + BaseClass userClass = new BaseClass(); + userClass.addPasswordField("password", "Password", 20); + userClass.setClassName("XWiki.XWikiUsers"); + + // local + + XWikiDocument userDocLocal = new XWikiDocument("local", "XWiki", "Admin"); + + 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()); + + 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)); + + Principal principalLocal = this.authService.authenticate("XWiki.Admin", "admin", this.getContext()); + assertNotNull(principalLocal); + assertEquals("XWiki.Admin", principalLocal.getName()); + + // virtual + + XWikiDocument userDocVirtual = new XWikiDocument("xwiki", "XWiki", "Admin"); + + this.getContext().setDatabase("local"); + + 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()); + + Principal principalVirtual = this.authService.authenticate("xwiki:XWiki.Admin", "admin", this.getContext()); + assertNotNull(principalVirtual); + assertEquals("XWiki.Admin", principalVirtual.getName()); + + } }