From 41738314d781e2847d8fc5cbce067fc3ecab8627 Mon Sep 17 00:00:00 2001 From: vrachieru Date: Wed, 6 Aug 2014 23:47:40 +0300 Subject: [PATCH 1/2] XWIKI-6647 : Impersonation feature --- .../src/main/java/com/xpn/xwiki/XWiki.java | 74 +++++++++++++++++++++- .../src/main/java/com/xpn/xwiki/api/XWiki.java | 4 +- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java index acbe041..62f9d88 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/XWiki.java @@ -3480,7 +3480,79 @@ public void prepareResources(XWikiContext context) public XWikiUser checkAuth(XWikiContext context) throws XWikiException { - return getAuthService().checkAuth(context); + return checkImpersonation(getAuthService().checkAuth(context), context); + } + + public XWikiUser checkImpersonation(XWikiUser user, XWikiContext context) throws XWikiException + { + // Check impersonation + if ("1".equals(Param("xwiki.authentication.impersonate"))) { + XWikiRequest request = context.getRequest(); + if (request != null) { + String cookiename = Param("xwiki.authentication.impersonate.cookiename", "impersonate"); + String cookietype = Param("xwiki.authentication.impersonate.cookietype", "user"); + String cookieregexp = Param("xwiki.authentication.impersonate.cookieregexp", ""); + Cookie impersonationCookie = request.getCookie(cookiename); + if (impersonationCookie != null) { + String userid = null; + String cookievalue = impersonationCookie.getValue(); + + if (!"".equals(cookieregexp)) { + String[] rules = cookieregexp.split("/"); + cookievalue = cookievalue.replaceAll(rules[1], rules[2]); + LOGGER.info("New value is: " + cookievalue); + } + + if ("email".equals(cookietype)) { + String hql = ", BaseObject as obj, StringProperty as prop where doc.fullName=obj.name and obj.className='XWiki.XWikiUsers' and obj.id=prop.id.id and prop.id.name='email' and prop.value='" + + cookievalue + "'"; + if (context.getDatabase() != context.getMainXWiki()) { + String db = context.getDatabase(); + try { + context.setDatabase(context.getMainXWiki()); + List list = getStore().searchDocumentsNames(hql, 1, 0, context); + if (list != null && list.size() == 1) { + userid = (String) list.get(0); + userid = "xwiki:" + userid; + } + } finally { + context.setDatabase(db); + } + } + if (userid == null) { + List list = getStore().searchDocumentsNames(hql, 1, 0, context); + if (list != null && list.size() == 1) { + userid = (String) list.get(0); + } + } + } else { + userid = cookievalue; + } + + XWikiDocument userdoc = (userid == null) ? null : getDocument(userid, context); + if (userdoc != null && !userdoc.isNew()) { + // we only accept the user if he has programming rights + String cuser = context.getUser(); + try { + context.setUser(user.getUser()); + if (getRightService().hasProgrammingRights(null, context)) { + // setting impersonated user + LOGGER.info("SECURITY: admin user (" + user.getUser() + ") is impersonation user " + cookievalue); + user.setUser(userid); + return user; + } else { + LOGGER.error("SECURITY: non admin user (" + user.getUser() + ") has tried impersonation of user " + cookievalue); + } + } finally { + context.setUser(cuser); + } + } else { + LOGGER.error("SECURITY: failed impersonation for cookie " + cookievalue); + } + } + } + } + return user; } public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java index 14ff528..eb6e230 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/api/XWiki.java @@ -2560,7 +2560,7 @@ public String getCounter(String name) */ public XWikiUser checkAuth() throws XWikiException { - return this.context.getWiki().getAuthService().checkAuth(this.context); + return this.context.getWiki().checkImpersonation(this.context.getWiki().getAuthService().checkAuth(this.context), context); } /** @@ -2575,7 +2575,7 @@ public XWikiUser checkAuth() throws XWikiException */ public XWikiUser checkAuth(String username, String password, String rememberme) throws XWikiException { - return this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context); + return this.context.getWiki().checkImpersonation(this.context.getWiki().getAuthService().checkAuth(username, password, rememberme, this.context), context); } /** From e39773369b4f78d6ab0fd03592873b8ceb0f7dfd Mon Sep 17 00:00:00 2001 From: vrachieru Date: Thu, 7 Aug 2014 11:03:17 +0300 Subject: [PATCH 2/2] XWIKI-6647 : Impersonation feature --- .../XWiki/ImpersonateUserConfiguration.xml | 88 ++++++++++++++ .../XWiki/ImpersonateUserConfigurationGroovy.xml | 122 +++++++++++++++++++ .../XWiki/ImpersonateUserConfigurationSheet.xml | 131 +++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfiguration.xml create mode 100644 xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationGroovy.xml create mode 100644 xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationSheet.xml diff --git a/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfiguration.xml b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfiguration.xml new file mode 100644 index 0000000..4e6e61e --- /dev/null +++ b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfiguration.xml @@ -0,0 +1,88 @@ + + + + XWiki + ImpersonateUserConfiguration + + + 0 + + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1407398161000 + 1407398161000 + 1407398161000 + 1.1 + Impersonate Configuration + + + + false + xwiki/2.0 + false + + + XWiki.TagClass + + + + + + + + + 0 + 0 + checkbox + 1 + tags + 1 + 0 + Tags + 1 + , + ,| + 30 + none + 0 + + + + com.xpn.xwiki.objects.classes.StaticListClass + + + XWiki.ImpersonateUserConfiguration + 0 + XWiki.TagClass + e8c642be-15ae-4c84-9a55-1f6c8fcf7dac + + {{velocity}} +#set($cookiename = $xwiki.xWiki.Param("xwiki.authentication.impersonate.cookiename", "impersonate")) +#set($cookie = $request.getCookie($cookiename)) +#set($cookieg = $xwiki.parseGroovyFromPage("XWiki.ImpersonateUserConfigurationGroovy")) + #if($request.confirm=="1") + {{info}}Removing cookie $cookiename{{/info}} + #set($ok = $cookieg.removeCookie($cookiename, $request, $response, $xwiki)) + #set($ok = $response.sendRedirect($doc.name)) +#else +#set($cookie = $request.getCookie($cookiename)) +#if($cookie) + #set($user = $cookie.value) + #if(!$user) + #set($user = "") + #end + #if($cookieg.convertUserId($context.user,$xwiki)==$user) + #set($username = $xwiki.getUserName($context.user, false)) +{{info}}Impersonation is activated and functionnal with user $username ($context.user) and cookie ($cookie.value){{/info}} +#else +{{error}}Impersonation is activated bug failing with cookie $user and current user $context.user{{/error}} +#end + +[[Deactivate impersonation>>?confirm=1]] +#else +{{include document="XWiki.ImpersonateUserConfigurationSheet" /}} +#end +#end + diff --git a/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationGroovy.xml b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationGroovy.xml new file mode 100644 index 0000000..69b3c84 --- /dev/null +++ b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationGroovy.xml @@ -0,0 +1,122 @@ + + + + XWiki + ImpersonateUserConfigurationGroovy + + + 0 + + xwiki:XWiki.Admin + xwiki:XWiki.Admin + + xwiki:XWiki.Admin + 1407398162000 + 1407398162000 + 1407398162000 + 1.1 + + <defaultTemplate/> + <validationScript/> + <comment/> + <minorEdit>false</minorEdit> + <syntaxId>xwiki/2.0</syntaxId> + <hidden>false</hidden> + <object> + <class> + <name>XWiki.TagClass</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <tags> + <cache>0</cache> + <disabled>0</disabled> + <displayType>checkbox</displayType> + <multiSelect>1</multiSelect> + <name>tags</name> + <number>1</number> + <picker>0</picker> + <prettyName>Tags</prettyName> + <relationalStorage>1</relationalStorage> + <separator>,</separator> + <separators>,|</separators> + <size>30</size> + <sort>none</sort> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <values/> + <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType> + </tags> + </class> + <name>XWiki.ImpersonateUserConfigurationGroovy</name> + <number>0</number> + <className>XWiki.TagClass</className> + <guid>9c672571-dcba-494b-9d15-aec915964d69</guid> + </object> + <content>import javax.servlet.http.Cookie; + +public class CookieGroovy { + + public void addCookie(cookieName, cookieValue, age, request, response, xwiki) { + def cookie = new Cookie(cookieName.toString(), convertUserId(cookieValue.toString(), xwiki)); + cookie.setVersion(1); + cookie.setMaxAge(age); + cookie.setPath("/"); + if (xwiki.isVirtual()) { + def serverName = request.serverName + def domains = xwiki.getXWiki().Param("xwiki.authentication.cookiedomains") + if (domains!=null) { + for(domain in domains.split(",")) { + if (serverName.endsWith(domain)) { + cookie.setDomain(domain) + } + } + } + } + response.addCookie(cookie) + } + + public void removeCookie(cookieName, request, response, xwiki) { + def cookie = new Cookie(cookieName.toString(), ""); + cookie.setVersion(1); + cookie.setMaxAge(0); + cookie.setPath("/"); + if (xwiki.isVirtual()) { + def serverName = request.serverName + def domains = xwiki.getXWiki().Param("xwiki.authentication.cookiedomains") + if (domains!=null) { + for(domain in domains.split(",")) { + if (serverName.endsWith(domain)) { + cookie.setDomain(domain) + } + } + } + } + response.addCookie(cookie) + } + + public String convertUserId(userid, xwiki) { + def cookietype = xwiki.getXWiki().Param("xwiki.authentication.impersonate.cookietype", "user") + def cookieregexp = xwiki.getXWiki().Param("xwiki.authentication.impersonate.cookieregexp", "") + if ("email".equals(cookietype)) { + def userdoc = xwiki.getDocument(userid) + userdoc.use("XWiki.XWikiUsers") + userid = userdoc.getValue("email") + } + if (!"".equals(cookieregexp)) { + String[] rules = cookieregexp.split("/") + userid = userid.replaceAll(rules[2], rules[1]) + } + return userid; + } + + public String getCookieName(xwiki) { + return xwiki.getXWiki().Param("xwiki.authentication.impersonate.cookiename", "impersonate"); + } +}</content> +</xwikidoc> diff --git a/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationSheet.xml b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationSheet.xml new file mode 100644 index 0000000..d7448ac --- /dev/null +++ b/xwiki-platform-tools/xwiki-platform-tool-packager-plugin/src/it/basic-import-export/src/main/documents/XWiki/ImpersonateUserConfigurationSheet.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<xwikidoc> + <web>XWiki</web> + <name>ImpersonateUserConfigurationSheet</name> + <language/> + <defaultLanguage/> + <translation>0</translation> + <parent/> + <creator>xwiki:XWiki.Admin</creator> + <author>xwiki:XWiki.Admin</author> + <customClass/> + <contentAuthor>xwiki:XWiki.Admin</contentAuthor> + <creationDate>1407398161000</creationDate> + <date>1407398161000</date> + <contentUpdateDate>1407398161000</contentUpdateDate> + <version>1.1</version> + <title/> + <defaultTemplate/> + <validationScript/> + <comment/> + <minorEdit>false</minorEdit> + <syntaxId>xwiki/2.0</syntaxId> + <hidden>false</hidden> + <object> + <class> + <name>XWiki.TagClass</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <tags> + <cache>0</cache> + <disabled>0</disabled> + <displayType>checkbox</displayType> + <multiSelect>1</multiSelect> + <name>tags</name> + <number>1</number> + <picker>0</picker> + <prettyName>Tags</prettyName> + <relationalStorage>1</relationalStorage> + <separator>,</separator> + <separators>,|</separators> + <size>30</size> + <sort>none</sort> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <values/> + <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType> + </tags> + </class> + <name>XWiki.ImpersonateUserConfigurationSheet</name> + <number>0</number> + <className>XWiki.TagClass</className> + <guid>fcf3452c-9d60-4e27-b284-cf7f3ad09b68</guid> + <property> + <tags/> + </property> + </object> + <content>This configuration allows an admin user to impersonate another user for testing. + +Choose the user you would like to impersonate: + +{{velocity}} +#set($cookieg = $xwiki.parseGroovyFromPage("XWiki.ImpersonateUserConfigurationGroovy")) +#set($cookiename = $cookieg.getCookieName($xwiki)) +#set($error = false) +#set($errormsg = "Impossible to find user to impersonate") +#if($request.email || $request.userid) + #if($request.userid&&$request.userid!="") + #set($userid = $request.userid) + #if(!$userid.startsWith("XWiki.")) + #set($userid = "XWiki.${userid}") + #end + #elseif($request.email&&$request.email!="") + #set($hql = ", BaseObject as obj, StringProperty as prop where doc.fullName=obj.name and obj.className='XWiki.XWikiUsers' and obj.id=prop.id.id and prop.id.name='email' and prop.value='${request.email}'") + #set($list = $xwiki.searchDocuments($hql)) + #if($list && $list.size()==1) + #set($userid = $list.get(0)) + #elseif($list.size()>1) + Select the user to impersonate: + + #foreach($user in $list) + #set($username = $xwiki.getUserName($user, false)) + * [[$username>>?userid=${user}]] + #end + #else + #set($error = true) + #set($errormsg = "Impossible to find user with this email") + #end + #end + #set($userdoc = $xwiki.getDocument($userid)) + #set($cuserid = $cookieg.convertUserId($userid, $xwiki)) + #if(!$cuserid || $cuserid.trim()=="") + #set($error = true) + #set($errormsg = "Impossible to impersonate user without an email set") + #end + #if(!$error && !$userdoc.isNew()&&$userdoc.getObject("XWiki.XWikiUsers")) + Impersonating user: $xwiki.getUserName($userid, false) + #set($ok = $cookieg.addCookie($cookiename, $userid, -1, $request, $response, $xwiki)) + {{info}}User has been impersonated. Check status [[here>>XWiki.ImpersonateUserConfiguration]]{{/info}} + {{html clean==false}} + <script type="text/javascript"> + location = '$xwiki.getURL("XWiki.ImpersonateUserConfiguration")'; + </script> + {{/html}} + #else + #if($error) + {{warning}}$errormsg{{/warning}} + #end +#end +#end +{{/velocity}} + +{{html clean=false}} +<form action=""> +<input type="hidden" name="section" value="Impersonate" /> +email: <input type="text" name="email" value="" size="30" /> + +user id: <input type="text" name="userid" class="suggestUsers" value="" size="30" /> + +<input type="submit" class="button" value="Change User" /> +</form> +{{/html}} + +</content> +</xwikidoc>