mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2E to HEAD
17246: ETHREEOH-3208: User profiles for users authenticated by immutable subsystems are now read only - Introduced MutableAuthenticationService interface, only implemented by Alfresco native authentication service - Split out those methods from AuthenticationService that mutate the user store and added isAuthenticationMutable() - Now both Alfresco Explorer and Share user profile / password edit link rendering is conditional on isAuthenticationMutable - Works with authentication chain containing mixture of internally and externally authenticated users 17247: Fix failing unit tests - rm-public-services-security-context.xml needed to be brought in line with public-services-security-context.xml (and will forever more!) 17248: ETHREEOH-1593: alfUser cookie value should be base 64 encoded to allow for non-ASCII characters 17253: *RECORD ONLY* ETHREEOH-2885: web.xml must conform to the schema to work on JBoss git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18098 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
package org.alfresco.web.app.servlet;
|
package org.alfresco.web.app.servlet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import javax.faces.context.FacesContext;
|
import javax.faces.context.FacesContext;
|
||||||
@@ -36,7 +37,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.springframework.extensions.surf.util.I18NUtil;
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.SessionUser;
|
import org.alfresco.repo.SessionUser;
|
||||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||||
@@ -50,7 +50,6 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.web.app.Application;
|
import org.alfresco.web.app.Application;
|
||||||
import org.alfresco.web.bean.LoginBean;
|
import org.alfresco.web.bean.LoginBean;
|
||||||
@@ -58,6 +57,8 @@ import org.alfresco.web.bean.repository.User;
|
|||||||
import org.alfresco.web.bean.users.UserPreferencesBean;
|
import org.alfresco.web.bean.users.UserPreferencesBean;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.extensions.surf.util.Base64;
|
||||||
|
import org.springframework.extensions.surf.util.I18NUtil;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||||
|
|
||||||
@@ -556,13 +557,23 @@ public final class AuthenticationHelper
|
|||||||
public static void setUsernameCookie(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String username)
|
public static void setUsernameCookie(HttpServletRequest httpRequest, HttpServletResponse httpResponse, String username)
|
||||||
{
|
{
|
||||||
Cookie authCookie = getAuthCookie(httpRequest);
|
Cookie authCookie = getAuthCookie(httpRequest);
|
||||||
|
// Let's Base 64 encode the username so it is a legal cookie value
|
||||||
|
String encodedUsername;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
encodedUsername = Base64.encodeBytes(username.getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
if (authCookie == null)
|
if (authCookie == null)
|
||||||
{
|
{
|
||||||
authCookie = new Cookie(COOKIE_ALFUSER, username);
|
authCookie = new Cookie(COOKIE_ALFUSER, encodedUsername);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
authCookie.setValue(username);
|
authCookie.setValue(encodedUsername);
|
||||||
}
|
}
|
||||||
authCookie.setPath(httpRequest.getContextPath());
|
authCookie.setPath(httpRequest.getContextPath());
|
||||||
// TODO: make this configurable - currently 7 days (value in seconds)
|
// TODO: make this configurable - currently 7 days (value in seconds)
|
||||||
|
@@ -56,7 +56,7 @@ import org.alfresco.service.cmr.repository.TemplateService;
|
|||||||
import org.alfresco.service.cmr.rule.RuleService;
|
import org.alfresco.service.cmr.rule.RuleService;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
import org.alfresco.service.cmr.security.AccessStatus;
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.web.app.Application;
|
import org.alfresco.web.app.Application;
|
||||||
@@ -208,12 +208,12 @@ public class NavigationBean implements Serializable
|
|||||||
/**
|
/**
|
||||||
* @param authService The AuthenticationService to set.
|
* @param authService The AuthenticationService to set.
|
||||||
*/
|
*/
|
||||||
public void setAuthenticationService(AuthenticationService authService)
|
public void setAuthenticationService(MutableAuthenticationService authService)
|
||||||
{
|
{
|
||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AuthenticationService getAuthService()
|
protected MutableAuthenticationService getAuthService()
|
||||||
{
|
{
|
||||||
if (authService == null)
|
if (authService == null)
|
||||||
this.authService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAuthenticationService();
|
this.authService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAuthenticationService();
|
||||||
@@ -1024,7 +1024,9 @@ public class NavigationBean implements Serializable
|
|||||||
*/
|
*/
|
||||||
public boolean isAllowUserConfig()
|
public boolean isAllowUserConfig()
|
||||||
{
|
{
|
||||||
return this.clientConfig.getAllowUserConfig();
|
// For correct behaviour, we ask the authentication chain whether this particular user is mutable
|
||||||
|
return this.clientConfig.getAllowUserConfig()
|
||||||
|
&& this.authService.isAuthenticationMutable(this.authService.getCurrentUserName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1157,7 +1159,7 @@ public class NavigationBean implements Serializable
|
|||||||
UserPreferencesBean preferences;
|
UserPreferencesBean preferences;
|
||||||
|
|
||||||
/** The Authentication service bean reference */
|
/** The Authentication service bean reference */
|
||||||
transient private AuthenticationService authService;
|
transient private MutableAuthenticationService authService;
|
||||||
|
|
||||||
/** The PermissionService reference */
|
/** The PermissionService reference */
|
||||||
transient private PermissionService permissionService;
|
transient private PermissionService permissionService;
|
||||||
|
@@ -43,14 +43,13 @@ import org.alfresco.model.ContentModel;
|
|||||||
import org.alfresco.repo.tenant.TenantService;
|
import org.alfresco.repo.tenant.TenantService;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.OwnableService;
|
import org.alfresco.service.cmr.security.OwnableService;
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.service.cmr.usage.ContentUsageService;
|
import org.alfresco.service.cmr.usage.ContentUsageService;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
|
||||||
import org.springframework.extensions.surf.util.Pair;
|
import org.springframework.extensions.surf.util.Pair;
|
||||||
import org.alfresco.web.app.Application;
|
import org.alfresco.web.app.Application;
|
||||||
import org.alfresco.web.app.context.UIContextService;
|
import org.alfresco.web.app.context.UIContextService;
|
||||||
@@ -102,7 +101,7 @@ public class CreateUserWizard extends BaseWizardBean
|
|||||||
protected String sizeQuotaUnits = null;
|
protected String sizeQuotaUnits = null;
|
||||||
|
|
||||||
/** AuthenticationService bean reference */
|
/** AuthenticationService bean reference */
|
||||||
transient private AuthenticationService authenticationService;
|
transient private MutableAuthenticationService authenticationService;
|
||||||
|
|
||||||
/** PersonService bean reference */
|
/** PersonService bean reference */
|
||||||
transient private PersonService personService;
|
transient private PersonService personService;
|
||||||
@@ -129,7 +128,7 @@ public class CreateUserWizard extends BaseWizardBean
|
|||||||
/**
|
/**
|
||||||
* @param authenticationService The AuthenticationService to set.
|
* @param authenticationService The AuthenticationService to set.
|
||||||
*/
|
*/
|
||||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
public void setAuthenticationService(MutableAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
this.authenticationService = authenticationService;
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
@@ -137,7 +136,7 @@ public class CreateUserWizard extends BaseWizardBean
|
|||||||
/**
|
/**
|
||||||
* @return authenticationService
|
* @return authenticationService
|
||||||
*/
|
*/
|
||||||
private AuthenticationService getAuthenticationService()
|
private MutableAuthenticationService getAuthenticationService()
|
||||||
{
|
{
|
||||||
if (authenticationService == null)
|
if (authenticationService == null)
|
||||||
{
|
{
|
||||||
|
@@ -36,7 +36,7 @@ import org.alfresco.service.cmr.repository.ContentService;
|
|||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.service.cmr.usage.ContentUsageService;
|
import org.alfresco.service.cmr.usage.ContentUsageService;
|
||||||
import org.alfresco.web.app.servlet.DownloadContentServlet;
|
import org.alfresco.web.app.servlet.DownloadContentServlet;
|
||||||
@@ -57,7 +57,7 @@ public class UsersBeanProperties implements Serializable
|
|||||||
transient private SearchService searchService;
|
transient private SearchService searchService;
|
||||||
|
|
||||||
/** AuthenticationService bean reference */
|
/** AuthenticationService bean reference */
|
||||||
transient private AuthenticationService authenticationService;
|
transient private MutableAuthenticationService authenticationService;
|
||||||
|
|
||||||
/** PersonService bean reference */
|
/** PersonService bean reference */
|
||||||
transient private PersonService personService;
|
transient private PersonService personService;
|
||||||
@@ -111,7 +111,7 @@ public class UsersBeanProperties implements Serializable
|
|||||||
/**
|
/**
|
||||||
* @return the authenticationService
|
* @return the authenticationService
|
||||||
*/
|
*/
|
||||||
public AuthenticationService getAuthenticationService()
|
public MutableAuthenticationService getAuthenticationService()
|
||||||
{
|
{
|
||||||
//check for null for cluster environment
|
//check for null for cluster environment
|
||||||
if (authenticationService == null)
|
if (authenticationService == null)
|
||||||
@@ -167,7 +167,7 @@ public class UsersBeanProperties implements Serializable
|
|||||||
/**
|
/**
|
||||||
* @param authenticationService The AuthenticationService to set.
|
* @param authenticationService The AuthenticationService to set.
|
||||||
*/
|
*/
|
||||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
public void setAuthenticationService(MutableAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
this.authenticationService = authenticationService;
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
@@ -387,6 +387,15 @@ public class UsersDialog extends BaseDialogBean implements IContextListener, Cha
|
|||||||
return (quota != null && quota != -1L) ? quota : null;
|
return (quota != null && quota != -1L) ? quota : null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public NodePropertyResolver resolverUserMutable = new NodePropertyResolver()
|
||||||
|
{
|
||||||
|
public Object get(Node personNode)
|
||||||
|
{
|
||||||
|
return properties.getAuthenticationService().isAuthenticationMutable(
|
||||||
|
(String) personNode.getProperties().get("userName"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action handler to show all the users currently in the system
|
* Action handler to show all the users currently in the system
|
||||||
@@ -404,6 +413,7 @@ public class UsersDialog extends BaseDialogBean implements IContextListener, Cha
|
|||||||
{
|
{
|
||||||
node.addPropertyResolver("sizeLatest", this.resolverUserSizeLatest);
|
node.addPropertyResolver("sizeLatest", this.resolverUserSizeLatest);
|
||||||
node.addPropertyResolver("quota", this.resolverUserQuota);
|
node.addPropertyResolver("quota", this.resolverUserQuota);
|
||||||
|
node.addPropertyResolver("isMutable", this.resolverUserMutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return null to stay on the same page
|
// return null to stay on the same page
|
||||||
|
@@ -24,8 +24,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.web.bean.wizard;
|
package org.alfresco.web.bean.wizard;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -48,13 +46,12 @@ import org.alfresco.repo.tenant.TenantService;
|
|||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.OwnableService;
|
import org.alfresco.service.cmr.security.OwnableService;
|
||||||
import org.alfresco.service.cmr.security.PermissionService;
|
import org.alfresco.service.cmr.security.PermissionService;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
|
||||||
import org.alfresco.web.app.Application;
|
import org.alfresco.web.app.Application;
|
||||||
import org.alfresco.web.app.context.UIContextService;
|
import org.alfresco.web.app.context.UIContextService;
|
||||||
import org.alfresco.web.bean.repository.Node;
|
import org.alfresco.web.bean.repository.Node;
|
||||||
@@ -66,7 +63,7 @@ import org.alfresco.web.ui.common.Utils;
|
|||||||
import org.alfresco.web.ui.common.component.UIActionLink;
|
import org.alfresco.web.ui.common.component.UIActionLink;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.commons.validator.EmailValidator;
|
import org.apache.commons.validator.EmailValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Roast
|
* @author Kevin Roast
|
||||||
@@ -101,7 +98,7 @@ public class NewUserWizard extends AbstractWizardBean
|
|||||||
private NodeRef homeSpaceLocation = null;
|
private NodeRef homeSpaceLocation = null;
|
||||||
|
|
||||||
/** AuthenticationService bean reference */
|
/** AuthenticationService bean reference */
|
||||||
transient private AuthenticationService authenticationService;
|
transient private MutableAuthenticationService authenticationService;
|
||||||
|
|
||||||
/** NamespaceService bean reference */
|
/** NamespaceService bean reference */
|
||||||
transient private NamespaceService namespaceService;
|
transient private NamespaceService namespaceService;
|
||||||
@@ -131,12 +128,12 @@ public class NewUserWizard extends AbstractWizardBean
|
|||||||
/**
|
/**
|
||||||
* @param authenticationService The AuthenticationService to set.
|
* @param authenticationService The AuthenticationService to set.
|
||||||
*/
|
*/
|
||||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
public void setAuthenticationService(MutableAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
this.authenticationService = authenticationService;
|
this.authenticationService = authenticationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthenticationService getAuthenticationService()
|
private MutableAuthenticationService getAuthenticationService()
|
||||||
{
|
{
|
||||||
if (authenticationService == null)
|
if (authenticationService == null)
|
||||||
{
|
{
|
||||||
|
@@ -36,7 +36,7 @@ import org.alfresco.service.cmr.model.FileInfo;
|
|||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.BaseSpringTest;
|
import org.alfresco.util.BaseSpringTest;
|
||||||
import org.alfresco.util.TestWithUserUtils;
|
import org.alfresco.util.TestWithUserUtils;
|
||||||
@@ -105,7 +105,7 @@ public class FormsTest
|
|||||||
assertNotNull(fileFolderService);
|
assertNotNull(fileFolderService);
|
||||||
this.formsService = (FormsService)super.applicationContext.getBean("FormsService");
|
this.formsService = (FormsService)super.applicationContext.getBean("FormsService");
|
||||||
assertNotNull(this.formsService);
|
assertNotNull(this.formsService);
|
||||||
final AuthenticationService authenticationService = (AuthenticationService)
|
final MutableAuthenticationService authenticationService = (MutableAuthenticationService)
|
||||||
applicationContext.getBean("authenticationService");
|
applicationContext.getBean("authenticationService");
|
||||||
authenticationService.clearCurrentSecurityContext();
|
authenticationService.clearCurrentSecurityContext();
|
||||||
final MutableAuthenticationDao authenticationDAO = (MutableAuthenticationDao)
|
final MutableAuthenticationDao authenticationDAO = (MutableAuthenticationDao)
|
||||||
|
@@ -138,10 +138,10 @@
|
|||||||
<f:facet name="header">
|
<f:facet name="header">
|
||||||
<h:outputText value="#{msg.actions}" />
|
<h:outputText value="#{msg.actions}" />
|
||||||
</f:facet>
|
</f:facet>
|
||||||
<a:actionLink value="#{msg.modify}" image="/images/icons/edituser.gif" showLink="false" action="wizard:editUser" actionListener="#{DialogManager.bean.setupUserAction}">
|
<a:actionLink rendered="#{r.isMutable}" value="#{msg.modify}" image="/images/icons/edituser.gif" showLink="false" action="wizard:editUser" actionListener="#{DialogManager.bean.setupUserAction}">
|
||||||
<f:param name="id" value="#{r.id}" />
|
<f:param name="id" value="#{r.id}" />
|
||||||
</a:actionLink>
|
</a:actionLink>
|
||||||
<a:actionLink value="#{msg.change_password}" image="/images/icons/change_password.gif" showLink="false" action="dialog:changePassword" actionListener="#{DialogManager.bean.setupUserAction}">
|
<a:actionLink rendered="#{r.isMutable}" value="#{msg.change_password}" image="/images/icons/change_password.gif" showLink="false" action="dialog:changePassword" actionListener="#{DialogManager.bean.setupUserAction}">
|
||||||
<f:param name="id" value="#{r.id}" />
|
<f:param name="id" value="#{r.id}" />
|
||||||
</a:actionLink>
|
</a:actionLink>
|
||||||
<a:booleanEvaluator value="#{r.userName != 'admin'}">
|
<a:booleanEvaluator value="#{r.userName != 'admin'}">
|
||||||
|
Reference in New Issue
Block a user