Merged enterprise features

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2746 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Paul Holmes-Higgin
2006-05-03 18:34:13 +00:00
parent b620d62954
commit 737f4fa8de
15 changed files with 3535 additions and 10 deletions

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.web.app.servlet;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class AbstractAuthenticationFilter
{
private static Log logger = LogFactory.getLog(AbstractAuthenticationFilter.class);
public AbstractAuthenticationFilter()
{
super();
}
/**
* Parse the Accept-Lanaguage HTTP header value
*
* @param req HttpServletRequest
* @return Locale
*/
protected static final Locale parseAcceptLanguageHeader(HttpServletRequest req, List<String> m_languages)
{
// Default the locale
Locale locale = Locale.getDefault();
// Get the accept language header value
String acceptHeader = req.getHeader("Accept-Language");
if ( acceptHeader != null)
{
// Parse the accepted language list
StringTokenizer tokens = new StringTokenizer(acceptHeader, ",");
List<AcceptLanguage> langList = new ArrayList<AcceptLanguage>();
while ( tokens.hasMoreTokens())
{
// Get the current language token
String lang = tokens.nextToken();
float quality = 1.0f;
// Check if the optional quality has been specified
int qpos = lang.indexOf(";");
if ( qpos != -1)
{
// Parse the quality value
try
{
quality = Float.parseFloat(lang.substring(qpos+3));
}
catch (NumberFormatException ex)
{
logger.error("Error parsing Accept-Language value " + lang);
}
// Strip the quality value from the language token
lang = lang.substring(0,qpos);
}
// Add the language to the list
langList.add(new AcceptLanguage(lang, quality));
}
// Debug
if ( logger.isDebugEnabled())
logger.debug("Accept-Language list : " + langList);
// Match the client languages to the available locales
if ( langList.size() > 0)
{
// Search for the best match locale to use for this client
AcceptLanguage useLang = null;
String useName = null;
boolean match = false;
for ( AcceptLanguage curLang : langList)
{
// Match against the available languages
for(String availLang : m_languages)
{
// The accept language may be in 'cc' or 'cc_cc' format
match = false;
if ( curLang.getLanguage().length() == 2)
{
if ( availLang.startsWith(curLang.getLanguage()))
match = true;
}
else if ( availLang.equalsIgnoreCase(curLang.getLanguage()))
match = true;
// If we found a match check if it is a higher quality than the current match.
// If the quality is the same we stick with the existing match as it was nearer the
// start of the list.
if ( match == true)
{
if ( useLang == null ||
( curLang.getQuality() > useLang.getQuality()))
{
useLang = curLang;
useName = availLang;
}
}
}
}
// Debug
if ( logger.isDebugEnabled())
logger.debug("Accept-Language using " + (useLang != null ? useLang.toString() : "<none>"));
// Create the required user locale
if ( useLang != null)
{
Locale useLocale = AcceptLanguage.createLocale(useName);
if ( useLocale != null)
{
locale = useLocale;
// Debug
if ( logger.isDebugEnabled())
logger.debug("Using language " + useLang + ", locale " + locale);
}
}
}
}
// Return the selected locale
return locale;
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.web.app.servlet;
import java.util.Locale;
import java.util.StringTokenizer;
/**
* Accept Language Class
*
* <p>Holds the details of an accepted language from a HTTP Accept-Language header
*
* @author gkspencer
*/
class AcceptLanguage
{
// Language name
private String m_language;
// Quality
private float m_quality = 1.0f;
/**
* Class constructor
*
* @param lang String
* @param quality float
*/
public AcceptLanguage(String lang, float quality)
{
// Convert the language to Java format
m_language = lang.replace('-', '_');
m_quality = quality;
}
/**
* Return the language
*
* @return String
*/
public final String getLanguage()
{
return m_language;
}
/**
* Return the quality
*
* @return float
*/
public final float getQuality()
{
return m_quality;
}
/**
* Create a locale for this language
*
* @return Locale
*/
public final Locale createLocale()
{
return createLocale(getLanguage());
}
/**
* Create a locale for this language
*
* @param locName String
* @return Locale
*/
public final static Locale createLocale(String locName)
{
Locale locale = null;
StringTokenizer t = new StringTokenizer(locName, "_");
int tokens = t.countTokens();
if (tokens == 1)
{
locale = new Locale(locName);
}
else if (tokens == 2)
{
locale = new Locale(t.nextToken(), t.nextToken());
}
else if (tokens == 3)
{
locale = new Locale(t.nextToken(), t.nextToken(), t.nextToken());
}
return locale;
}
/**
* Return the accept language as a string
*
* @return String
*/
public String toString()
{
StringBuilder str = new StringBuilder();
str.append("[");
str.append(getLanguage());
str.append(",");
str.append(getQuality());
str.append("]");
return str.toString();
}
}

View File

@@ -0,0 +1,920 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
import net.sf.acegisecurity.BadCredentialsException;
import org.alfresco.config.ConfigService;
import org.alfresco.filesys.server.auth.PasswordEncryptor;
import org.alfresco.filesys.server.auth.ntlm.NTLM;
import org.alfresco.filesys.server.auth.ntlm.NTLMLogonDetails;
import org.alfresco.filesys.server.auth.ntlm.NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.TargetInfo;
import org.alfresco.filesys.server.auth.ntlm.Type1NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.Type2NTLMMessage;
import org.alfresco.filesys.server.auth.ntlm.Type3NTLMMessage;
import org.alfresco.filesys.server.config.ServerConfiguration;
import org.alfresco.filesys.util.DataPacker;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl;
import org.alfresco.repo.security.authentication.NTLMMode;
import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.LanguagesConfigElement;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* NTLM Authentication Filter Class
*
* @author GKSpencer
*/
public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter implements Filter
{
// NTLM authentication session object names
public static final String NTLM_AUTH_SESSION = "_alfNTLMAuthSess";
public static final String NTLM_AUTH_DETAILS = "_alfNTLMDetails";
// Locale object stored in the session
private static final String LOCALE = "locale";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
// NTLM flags mask, used to mask out features that are not supported
private static final int NTLM_FLAGS = NTLM.Flag56Bit + NTLM.FlagLanManKey + NTLM.FlagNegotiateNTLM +
NTLM.FlagNegotiateOEM + NTLM.FlagNegotiateUnicode;
// Debug logging
private static Log logger = LogFactory.getLog(NTLMAuthenticationFilter.class);
// Servlet context, required to get authentication service
private ServletContext m_context;
// File server configuration
private ServerConfiguration m_srvConfig;
// Various services required by NTLM authenticator
private AuthenticationService m_authService;
private AuthenticationComponent m_authComponent;
private PersonService m_personService;
private NodeService m_nodeService;
private TransactionService m_transactionService;
private ConfigService m_configService;
// Password encryptor
private PasswordEncryptor m_encryptor = new PasswordEncryptor();
// Allow guest access
private boolean m_allowGuest;
// Login page address
private String m_loginPage;
// Random number generator used to generate challenge keys
private Random m_random = new Random(System.currentTimeMillis());
// MD4 hash decoder
private MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl();
// Local server name, from either the file servers config or DNS host name
private String m_srvName;
// List of available locales (from the web-client configuration)
private List<String> m_languages;
/**
* Initialize the filter
*
* @param args FilterConfig
* @exception ServletException
*/
public void init(FilterConfig args) throws ServletException
{
// Save the servlet context, needed to get hold of the authentication service
m_context = args.getServletContext();
// Setup the authentication context
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
m_nodeService = serviceRegistry.getNodeService();
m_transactionService = serviceRegistry.getTransactionService();
m_authService = (AuthenticationService) ctx.getBean("authenticationService");
m_authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
m_personService = (PersonService) ctx.getBean("personService");
m_configService = (ConfigService) ctx.getBean("webClientConfigService");
m_srvConfig = (ServerConfiguration) ctx.getBean(ServerConfiguration.SERVER_CONFIGURATION);
// Check that the authentication component supports the required mode
if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER &&
m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH)
{
throw new ServletException("Required authentication mode not available");
}
// Get the local server name, try the file server config first
if ( m_srvConfig != null)
{
m_srvName = m_srvConfig.getServerName();
if ( m_srvName == null)
{
// CIFS server may not be running so the local server name has not been set, generate
// a server name
m_srvName = m_srvConfig.getLocalServerName(true) + "_A";
}
}
else
{
// Get the host name
try
{
// Get the local host name
m_srvName = InetAddress.getLocalHost().getHostName();
// Strip any domain name
int pos = m_srvName.indexOf(".");
if ( pos != -1)
m_srvName = m_srvName.substring(0, pos - 1);
}
catch (UnknownHostException ex)
{
// Log the error
if ( logger.isErrorEnabled())
logger.error("NTLM filter, error getting local host name", ex);
}
}
// Check if the server name is valid
if ( m_srvName == null || m_srvName.length() == 0)
throw new ServletException("Failed to get local server name");
// Check if guest access is to be allowed
String guestAccess = args.getInitParameter("AllowGuest");
if ( guestAccess != null)
{
m_allowGuest = Boolean.parseBoolean(guestAccess);
// Debug
if ( logger.isDebugEnabled() && m_allowGuest)
logger.debug("NTLM filter guest access allowed");
}
// Get a list of the available locales
LanguagesConfigElement config = (LanguagesConfigElement) m_configService.
getConfig("Languages").getConfigElement(LanguagesConfigElement.CONFIG_ELEMENT_ID);
m_languages = config.getLanguages();
}
/**
* Run the filter
*
* @param sreq ServletRequest
* @param sresp ServletResponse
* @param chain FilterChain
* @exception IOException
* @exception ServletException
*/
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException,
ServletException
{
// Get the HTTP request/response/session
HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp;
HttpSession httpSess = req.getSession(true);
// Check if there is an authorization header with an NTLM security blob
String authHdr = req.getHeader("Authorization");
boolean reqAuth = false;
if ( authHdr != null && authHdr.startsWith("NTLM"))
reqAuth = true;
// Check if the user is already authenticated
User user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if ( user != null && reqAuth == false)
{
try
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("User " + user.getUserName() + " validate ticket");
// Validate the user ticket
m_authService.validate( user.getTicket());
reqAuth = false;
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpSess));
}
catch (AuthenticationException ex)
{
if ( logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
reqAuth = true;
}
}
// If the user has been validated and we do not require re-authentication then continue to
// the next filter
if ( reqAuth == false && user != null)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Authentication not required, chaining ...");
// Chain to the next filter
chain.doFilter(sreq, sresp);
return;
}
// Check if the login page is being accessed, do not intercept the login page
if ( req.getRequestURI().endsWith(getLoginPage()) == true)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Login page requested, chaining ...");
// Chain to the next filter
chain.doFilter( sreq, sresp);
return;
}
// Check if the browser is Opera, if so then display the login page as Opera does not
// support NTLM and displays an error page if a request to use NTLM is sent to it
String userAgent = req.getHeader("user-agent");
if ( userAgent != null && userAgent.indexOf("Opera ") != -1)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Opera detected, redirecting to login page");
// Redirect to the login page
resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
return;
}
// Check the authorization header
if ( authHdr == null) {
// Debug
if ( logger.isDebugEnabled())
logger.debug("New NTLM auth request from " + req.getRemoteHost() + " (" +
req.getRemoteAddr() + ":" + req.getRemotePort() + ")");
// Send back a request for NTLM authentication
resp.setHeader("WWW-Authenticate", "NTLM");
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.flushBuffer();
}
else
{
// Decode the received NTLM blob and validate
final byte[] ntlmByts = Base64.decodeBase64( authHdr.substring(5).getBytes());
int ntlmTyp = NTLMMessage.isNTLMType(ntlmByts);
if ( ntlmTyp == NTLM.Type1)
{
// Process the type 1 NTLM message
Type1NTLMMessage type1Msg = new Type1NTLMMessage(ntlmByts);
processType1(type1Msg, req, resp, httpSess);
}
else if ( ntlmTyp == NTLM.Type3)
{
// Process the type 3 NTLM message
Type3NTLMMessage type3Msg = new Type3NTLMMessage(ntlmByts);
processType3(type3Msg, req, resp, httpSess, chain);
}
else
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("NTLM not handled, redirecting to login page");
// Redirect to the login page
resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
}
}
}
/**
* Return the login page address
*
* @return String
*/
private String getLoginPage()
{
if (m_loginPage == null)
{
m_loginPage = Application.getLoginPage(m_context);
}
return m_loginPage;
}
/**
* Delete the servlet filter
*/
public void destroy()
{
}
/**
* Process a type 1 NTLM message
*
* @param type1Msg Type1NTLMMessage
* @param req HttpServletRequest
* @param resp HttpServletResponse
* @param httpSess HttpSession
* @exception IOException
*/
private void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req, HttpServletResponse resp,
HttpSession httpSess) throws IOException
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Received type1 " + type1Msg);
// Get the existing NTLM details
NTLMLogonDetails ntlmDetails = null;
if ( httpSess != null)
{
ntlmDetails = (NTLMLogonDetails) httpSess.getAttribute(NTLM_AUTH_DETAILS);
}
// Check if cached logon details are available
if ( ntlmDetails != null && ntlmDetails.hasType2Message() && ntlmDetails.hasNTLMHashedPassword() &&
ntlmDetails.hasAuthenticationToken())
{
// Get the authentication server type2 response
Type2NTLMMessage cachedType2 = ntlmDetails.getType2Message();
byte[] type2Bytes = cachedType2.getBytes();
String ntlmBlob = "NTLM " + new String(Base64.encodeBase64(type2Bytes));
// Debug
if ( logger.isDebugEnabled())
logger.debug("Sending cached NTLM type2 to client - " + cachedType2);
// Send back a request for NTLM authentication
resp.setHeader("WWW-Authenticate", ntlmBlob);
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.flushBuffer();
return;
}
else
{
// Clear any cached logon details
httpSess.removeAttribute(NTLM_AUTH_DETAILS);
// Set the 8 byte challenge for the new logon request
byte[] challenge = null;
NTLMPassthruToken authToken = null;
if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Generate a random 8 byte challenge
challenge = new byte[8];
DataPacker.putIntelLong(m_random.nextLong(), challenge, 0);
}
else
{
// Create an authentication token for the new logon
authToken = new NTLMPassthruToken();
// Run the first stage of the passthru authentication to get the challenge
m_authComponent.authenticate( authToken);
// Get the challenge from the token
if ( authToken.getChallenge() != null)
challenge = authToken.getChallenge().getBytes();
}
// Get the flags from the client request and mask out unsupported features
int ntlmFlags = type1Msg.getFlags() & NTLM_FLAGS;
// Build a type2 message to send back to the client, containing the challenge
List<TargetInfo> tList = new ArrayList<TargetInfo>();
tList.add(new TargetInfo(NTLM.TargetServer, m_srvName));
Type2NTLMMessage type2Msg = new Type2NTLMMessage();
type2Msg.buildType2(ntlmFlags, m_srvName, challenge, null, tList);
// Store the NTLM logon details, cache the type2 message, and token if using passthru
ntlmDetails = new NTLMLogonDetails();
ntlmDetails.setType2Message( type2Msg);
ntlmDetails.setAuthenticationToken(authToken);
httpSess.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails);
// Debug
if ( logger.isDebugEnabled())
logger.debug("Sending NTLM type2 to client - " + type2Msg);
// Send back a request for NTLM authentication
byte[] type2Bytes = type2Msg.getBytes();
String ntlmBlob = "NTLM " + new String(Base64.encodeBase64(type2Bytes));
resp.setHeader("WWW-Authenticate", ntlmBlob);
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.flushBuffer();
return;
}
}
/**
* Process a type 3 NTLM message
*
* @param type3Msg Type3NTLMMessage
* @param req HttpServletRequest
* @param resp HttpServletResponse
* @param httpSess HttpSession
* @param chain FilterChain
* @exception IOException
* @exception ServletException
*/
private void processType3(Type3NTLMMessage type3Msg, HttpServletRequest req, HttpServletResponse resp,
HttpSession httpSess, FilterChain chain) throws IOException, ServletException
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Received type3 " + type3Msg);
// Get the existing NTLM details
NTLMLogonDetails ntlmDetails = null;
User user = null;
if ( httpSess != null)
{
ntlmDetails = (NTLMLogonDetails) httpSess.getAttribute(NTLM_AUTH_DETAILS);
user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
}
// Get the NTLM logon details
String userName = type3Msg.getUserName();
String workstation = type3Msg.getWorkstation();
String domain = type3Msg.getDomain();
boolean authenticated = false;
boolean useNTLM = true;
// Check if we are using cached details for the authentication
if ( user != null && ntlmDetails != null && ntlmDetails.hasNTLMHashedPassword())
{
// Check if the received NTLM hashed password matches the cached password
byte[] ntlmPwd = type3Msg.getNTLMHash();
byte[] cachedPwd = ntlmDetails.getNTLMHashedPassword();
if ( ntlmPwd != null)
{
if ( ntlmPwd.length == cachedPwd.length)
{
authenticated = true;
for ( int i = 0; i < ntlmPwd.length; i++)
{
if ( ntlmPwd[i] != cachedPwd[i])
authenticated = false;
}
}
}
// Debug
if ( logger.isDebugEnabled())
logger.debug("Using cached NTLM hash, authenticated = " + authenticated);
try
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("User " + user.getUserName() + " validate ticket");
// Validate the user ticket
m_authService.validate( user.getTicket());
// Set the current locale
I18NUtil.setLocale(Application.getLanguage(httpSess));
}
catch (AuthenticationException ex)
{
if ( logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
// Redirect to the login page
resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
return;
}
// Allow the user to access the requested page
chain.doFilter( req, resp);
return;
}
else
{
// Check if we are using local MD4 password hashes or passthru authentication
if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
{
// Get the stored MD4 hashed password for the user, or null if the user does not exist
String md4hash = m_authComponent.getMD4HashedPassword(userName);
if ( md4hash != null)
{
// Generate the local encrypted password using the challenge that was sent to the client
byte[] p21 = new byte[21];
byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
System.arraycopy(md4byts, 0, p21, 0, 16);
// Generate the local hash of the password using the same challenge
byte[] localHash = null;
try
{
localHash = m_encryptor.doNTLM1Encryption(p21, ntlmDetails.getChallengeKey());
}
catch (NoSuchAlgorithmException ex)
{
}
// Validate the password
byte[] clientHash = type3Msg.getNTLMHash();
if ( clientHash != null && localHash != null && clientHash.length == localHash.length)
{
int i = 0;
while ( i < clientHash.length && clientHash[i] == localHash[i])
i++;
if ( i == clientHash.length)
authenticated = true;
}
}
else
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("User " + userName + " does not have Alfresco account");
// Bypass NTLM authentication and display the logon screen, user account does not
// exist in Alfresco
authenticated = false;
}
}
else
{
// Passthru mode, send the hashed password details to the passthru authentication server
NTLMPassthruToken authToken = (NTLMPassthruToken) ntlmDetails.getAuthenticationToken();
authToken.setUserAndPassword( type3Msg.getUserName(), type3Msg.getNTLMHash(), PasswordEncryptor.NTLM1);
try
{
// Run the second stage of the passthru authentication
m_authComponent.authenticate(authToken);
authenticated = true;
}
catch (BadCredentialsException ex)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Authentication failed, " + ex.getMessage());
}
catch (AuthenticationException ex)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Authentication failed, " + ex.getMessage());
}
finally
{
// Clear the authentication token from the NTLM details
ntlmDetails.setAuthenticationToken(null);
}
}
// Check if the user has been authenticated, if so then setup the user environment
if ( authenticated == true)
{
UserTransaction tx = m_transactionService.getUserTransaction();
NodeRef homeSpaceRef = null;
try
{
tx.begin();
// Get user details for the authenticated user
m_authComponent.setCurrentUser(userName.toLowerCase());
// The user name used may be a different case to the NTLM supplied user name, read the current
// user and use that name
userName = m_authComponent.getCurrentUserName();
// Setup User object and Home space ID etc.
NodeRef personNodeRef = m_personService.getPerson(userName);
String currentTicket = m_authService.getCurrentTicket();
user = new User(userName, currentTicket, personNodeRef);
homeSpaceRef = (NodeRef) m_nodeService.getProperty(
personNodeRef,
ContentModel.PROP_HOMEFOLDER);
user.setHomeSpaceId(homeSpaceRef.getId());
// commit
tx.commit();
}
catch (Throwable ex)
{
try
{
tx.rollback();
}
catch (Exception ex2)
{
logger.error("Failed to rollback transaction", ex2);
}
if(ex instanceof RuntimeException)
{
throw (RuntimeException)ex;
}
else if(ex instanceof IOException)
{
throw (IOException)ex;
}
else if(ex instanceof ServletException)
{
throw (ServletException)ex;
}
else
{
throw new RuntimeException("Authentication setup failed", ex);
}
}
// Store the user
httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);
// Set the current locale from the Accept-Lanaguage header if available
Locale userLocale = parseAcceptLanguageHeader(req, m_languages);
if ( userLocale != null)
{
httpSess.setAttribute(LOCALE, userLocale);
httpSess.removeAttribute(MESSAGE_BUNDLE);
}
// Set the locale using the session
I18NUtil.setLocale(Application.getLanguage(httpSess));
// Update the NTLM logon details in the session
if ( ntlmDetails == null)
{
// No cached NTLM details
ntlmDetails = new NTLMLogonDetails( userName, workstation, domain, false, m_srvName);
httpSess.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails);
// Debug
if ( logger.isDebugEnabled())
logger.debug("No cached NTLM details, created");
}
else
{
// Update the cached NTLM details
ntlmDetails.setDetails(userName, workstation, domain, false, m_srvName);
ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash());
// Debug
if ( logger.isDebugEnabled())
logger.debug("Updated cached NTLM details");
}
// Debug
if ( logger.isDebugEnabled())
logger.debug("User logged on via NTLM, " + ntlmDetails);
// If the original URL requested was the login page then redirect to the browse view
if (req.getRequestURI().endsWith(getLoginPage()) == true)
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Login page requested, redirecting to browse page");
// Redirect to the browse view
resp.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp");
return;
}
else
{
// Allow the user to access the requested page
chain.doFilter( req, resp);
return;
}
}
else
{
// Check if NTLM should be used, switched off if the user does not exist in the Alfresco
// user database
if (useNTLM == true)
{
// Remove any existing session and NTLM details from the session
httpSess.removeAttribute(NTLM_AUTH_SESSION);
httpSess.removeAttribute(NTLM_AUTH_DETAILS);
// Force the logon to start again
resp.setHeader("WWW-Authenticate", "NTLM");
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.flushBuffer();
return;
}
else
{
// Debug
if ( logger.isDebugEnabled())
logger.debug("Redirecting to login page");
// Redirect to the login page
resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
return;
}
}
}
}
}

View File

@@ -0,0 +1,317 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;
import org.alfresco.config.ConfigService;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.LanguagesConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Sample authentication for Novell ICHAINS.
*
* @author Andy Hind
*/
public class NovellIChainsHTTPRequestAuthenticationFilter extends AbstractAuthenticationFilter implements Filter
{
private static final String LOCALE = "locale";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
private static Log logger = LogFactory.getLog(NovellIChainsHTTPRequestAuthenticationFilter.class);
private ServletContext context;
private String loginPage;
private AuthenticationComponent authComponent;
private AuthenticationService authService;
private TransactionService transactionService;
private PersonService personService;
private NodeService nodeService;
private List<String> m_languages;
public NovellIChainsHTTPRequestAuthenticationFilter()
{
super();
}
public void destroy()
{
// Nothing to do
}
/**
* Run the filter
*
* @param sreq
* ServletRequest
* @param sresp
* ServletResponse
* @param chain
* FilterChain
* @exception IOException
* @exception ServletException
*/
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException,
ServletException
{
// Get the HTTP request/response/session
HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp;
HttpSession httpSess = req.getSession(true);
// Check for the ICHAINS header
String authHdr = req.getHeader("x-user");
if(logger.isDebugEnabled())
{
if(authHdr == null)
{
logger.debug("x-user header not found.");
}
else
{
logger.debug("x-user header is <" + authHdr + ">");
}
}
// Throw an error if we have an unknown authentication
if ((authHdr == null) || (authHdr.length() < 1))
{
resp.sendRedirect(req.getContextPath() + "/jsp/noaccess.jsp");
return;
}
// Get the user
String userName = authHdr;
if(logger.isDebugEnabled())
{
logger.debug("User = "+ userName);
}
// See if there is a user in the session and test if it matches
User user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
if (user != null)
{
try
{
// Debug
if (logger.isDebugEnabled())
logger.debug("User " + user.getUserName() + " validate ticket");
// Validate the user ticket
if (user.getUserName().equals(userName))
{
// Set the current locale
authComponent.setCurrentUser(user.getUserName());
I18NUtil.setLocale(Application.getLanguage(httpSess));
chain.doFilter(sreq, sresp);
return;
}
else
{
// No match
setAuthenticatedUser(req, httpSess, userName);
}
}
catch (AuthenticationException ex)
{
if (logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
}
}
setAuthenticatedUser(req, httpSess, userName);
// Redirect the login page as it is never seen as we always login by name
if (req.getRequestURI().endsWith(getLoginPage()) == true)
{
if (logger.isDebugEnabled())
logger.debug("Login page requested, chaining ...");
resp.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp");
return;
}
else
{
chain.doFilter(sreq, sresp);
return;
}
}
/**
* Set the authenticated user.
*
* It does not check that the user exists at the moment.
*
* @param req
* @param httpSess
* @param userName
*/
private void setAuthenticatedUser(HttpServletRequest req, HttpSession httpSess, String userName)
{
// Set the authentication
authComponent.setCurrentUser(userName);
User user = new User(userName, authService.getCurrentTicket(), personService.getPerson(userName));
// Set up the user information
UserTransaction tx = transactionService.getUserTransaction();
NodeRef homeSpaceRef = null;
try
{
tx.begin();
homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(userName),
ContentModel.PROP_HOMEFOLDER);
user.setHomeSpaceId(homeSpaceRef.getId());
tx.commit();
}
catch (Throwable ex)
{
logger.error(ex);
try
{
tx.rollback();
}
catch (Exception ex2)
{
logger.error("Failed to rollback transaction", ex2);
}
if(ex instanceof RuntimeException)
{
throw (RuntimeException)ex;
}
else
{
throw new RuntimeException("Failed to set authenticated user", ex);
}
}
// Store the user
httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);
// Set the current locale from the Accept-Lanaguage header if available
Locale userLocale = parseAcceptLanguageHeader(req, m_languages);
if (userLocale != null)
{
httpSess.setAttribute(LOCALE, userLocale);
httpSess.removeAttribute(MESSAGE_BUNDLE);
}
// Set the locale using the session
I18NUtil.setLocale(Application.getLanguage(httpSess));
}
public void init(FilterConfig config) throws ServletException
{
this.context = config.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();
authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
authService = (AuthenticationService) ctx.getBean("authenticationService");
personService = (PersonService) ctx.getBean("personService");
// Get a list of the available locales
ConfigService configServiceService = (ConfigService) ctx.getBean("webClientConfigService");
LanguagesConfigElement configElement = (LanguagesConfigElement) configServiceService.
getConfig("Languages").getConfigElement(LanguagesConfigElement.CONFIG_ELEMENT_ID);
m_languages = configElement.getLanguages();
}
/**
* Return the login page address
*
* @return String
*/
private String getLoginPage()
{
if (loginPage == null)
{
loginPage = Application.getLoginPage(context);
}
return loginPage;
}
}

View File

@@ -0,0 +1,979 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Alfresco Network License. You may obtain a
* copy of the License at
*
* http://www.alfrescosoftware.com/legal/
*
* Please view the license relevant to your network subscription.
*
* BY CLICKING THE "I UNDERSTAND AND ACCEPT" BOX, OR INSTALLING,
* READING OR USING ALFRESCO'S Network SOFTWARE (THE "SOFTWARE"),
* YOU ARE AGREEING ON BEHALF OF THE ENTITY LICENSING THE SOFTWARE
* ("COMPANY") THAT COMPANY WILL BE BOUND BY AND IS BECOMING A PARTY TO
* THIS ALFRESCO NETWORK AGREEMENT ("AGREEMENT") AND THAT YOU HAVE THE
* AUTHORITY TO BIND COMPANY. IF COMPANY DOES NOT AGREE TO ALL OF THE
* TERMS OF THIS AGREEMENT, DO NOT SELECT THE "I UNDERSTAND AND AGREE"
* BOX AND DO NOT INSTALL THE SOFTWARE OR VIEW THE SOURCE CODE. COMPANY
* HAS NOT BECOME A LICENSEE OF, AND IS NOT AUTHORIZED TO USE THE
* SOFTWARE UNLESS AND UNTIL IT HAS AGREED TO BE BOUND BY THESE LICENSE
* TERMS. THE "EFFECTIVE DATE" FOR THIS AGREEMENT SHALL BE THE DAY YOU
* CHECK THE "I UNDERSTAND AND ACCEPT" BOX.
*/
package org.alfresco.web.bean;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.faces.validator.ValidatorException;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.context.IContextListener;
import org.alfresco.web.app.context.UIContextService;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.ui.common.SortableSelectItem;
import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.IBreadcrumbHandler;
import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.component.UIBreadcrumb;
import org.alfresco.web.ui.common.component.UIGenericPicker;
import org.alfresco.web.ui.common.component.UIModeList;
import org.alfresco.web.ui.common.component.data.UIRichList;
import org.apache.log4j.Logger;
/**
* Backing Bean for the Groups Management pages.
*
* @author Kevin Roast
*/
public class GroupsBean implements IContextListener
{
private static final String FILTER_CHILDREN = "children";
private static final String FILTER_ALL = "all";
private static final String DEFAULT_OUTCOME = "finish";
private static final String MSG_GROUPS = "root_groups";
private static Logger logger = Logger.getLogger(GroupsBean.class);
/** The NodeService to be used by the bean */
private NodeService nodeService;
/** The AuthorityService to be used by the bean */
private AuthorityService authService;
/** personService bean reference */
private PersonService personService;
/** Component references */
private UIRichList groupsRichList;
private UIRichList usersRichList;
/** datamodel for table of users added to group */
private DataModel usersDataModel = null;
/** Currently visible Group Authority */
private String group = null;
private String groupName = null;
/** Action group authority */
private String actionGroup = null;
private String actionGroupName = null;
private int actionGroupItems = 0;
/** selected users to be added to a group */
private List<UserAuthorityDetails> usersForGroup = null;
/** Dialog properties */
private String name = null;
/** RichList view mode */
private String viewMode = "icons";
/** List filter mode */
private String filterMode = FILTER_CHILDREN;
/** Groups path breadcrumb location */
private List<IBreadcrumbHandler> location = null;
// ------------------------------------------------------------------------------
// Construction
/**
* Default Constructor
*/
public GroupsBean()
{
UIContextService.getInstance(FacesContext.getCurrentInstance()).registerBean(this);
}
// ------------------------------------------------------------------------------
// Bean property getters and setters
/**
* @param nodeService The NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param authService The AuthorityService to set.
*/
public void setAuthorityService(AuthorityService authService)
{
this.authService = authService;
}
/**
* @param permissionService The PermissionService to set.
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @return Returns the groups RichList to set.
*/
public UIRichList getGroupsRichList()
{
return this.groupsRichList;
}
/**
* @param list The RichList to set.
*/
public void setGroupsRichList(UIRichList list)
{
this.groupsRichList = list;
}
/**
* @return Returns the users RichList.
*/
public UIRichList getUsersRichList()
{
return this.usersRichList;
}
/**
* @param usersRichList The RichList to set.
*/
public void setUsersRichList(UIRichList usersRichList)
{
this.usersRichList = usersRichList;
}
/**
* @return Returns the usersDataModel.
*/
public DataModel getUsersDataModel()
{
if (this.usersDataModel == null)
{
this.usersDataModel = new ListDataModel();
}
this.usersDataModel.setWrappedData(this.usersForGroup);
return this.usersDataModel;
}
/**
* @param usersDataModel The usersDataModel to set.
*/
public void setUsersDataModel(DataModel usersDataModel)
{
this.usersDataModel = usersDataModel;
}
/**
* @return Returns the name.
*/
public String getName()
{
return this.name;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return Returns the viewMode.
*/
public String getViewMode()
{
return this.viewMode;
}
/**
* @param viewMode The viewMode to set.
*/
public void setViewMode(String viewMode)
{
this.viewMode = viewMode;
}
/**
* @return Returns the filterMode.
*/
public String getFilterMode()
{
return this.filterMode;
}
/**
* @param filterMode The filterMode to set.
*/
public void setFilterMode(String filterMode)
{
this.filterMode = filterMode;
// clear datalist cache ready to change results based on filter setting
contextUpdated();
}
/**
* @return Returns the Group being used for the current action screen.
*/
public String getActionGroup()
{
return this.actionGroup;
}
/**
* @param actionSpace Set the Group to be used for the current action screen.
*/
public void setActionGroup(String group)
{
this.actionGroup = group;
if (group != null)
{
// calculate action group metadata
setActionGroupName(this.authService.getShortName(group));
int count = this.authService.getContainedAuthorities(AuthorityType.GROUP, group, false).size();
count += this.authService.getContainedAuthorities(AuthorityType.USER, group, false).size();
setActionGroupItems(count);
}
else
{
setActionGroupName(null);
setActionGroupItems(0);
}
// clear value used by Create Group form
this.name = null;
// clear list for Add Users to Group screen
this.usersForGroup = new ArrayList<UserAuthorityDetails>();
}
/**
* @return Returns the actionGroupName.
*/
public String getActionGroupName()
{
return this.actionGroupName;
}
/**
* @param actionGroupName The actionGroupName to set.
*/
public void setActionGroupName(String actionGroupName)
{
this.actionGroupName = actionGroupName;
}
/**
* @return Returns the action Group Items count.
*/
public int getActionGroupItems()
{
return this.actionGroupItems;
}
/**
* @param actionGroupItems The action Group Items count to set.
*/
public void setActionGroupItems(int actionGroupItems)
{
this.actionGroupItems = actionGroupItems;
}
/**
* @return The currently displayed group or null if at the root.
*/
public String getCurrentGroup()
{
return this.group;
}
/**
* Set the current Group Authority.
* <p>
* Setting this value causes the UI to update and display the specified node as current.
*
* @param group The current group authority.
*/
public void setCurrentGroup(String group, String groupName)
{
if (logger.isDebugEnabled())
logger.debug("Setting current group: " + group);
// set the current Group Authority for our UI context operations
this.group = group;
this.groupName = groupName;
// inform that the UI needs updating after this change
contextUpdated();
}
/**
* @return Returns the groupName.
*/
public String getGroupName()
{
return this.groupName;
}
/**
* @param groupName The groupName to set.
*/
public void setGroupName(String groupName)
{
this.groupName = groupName;
}
/**
* @return Breadcrumb location list
*/
public List<IBreadcrumbHandler> getLocation()
{
if (this.location == null)
{
List<IBreadcrumbHandler> loc = new ArrayList<IBreadcrumbHandler>(8);
loc.add(new GroupBreadcrumbHandler(null,
Application.getMessage(FacesContext.getCurrentInstance(), MSG_GROUPS)));
this.location = loc;
}
return this.location;
}
/**
* @param location Breadcrumb location list
*/
public void setLocation(List<IBreadcrumbHandler> location)
{
this.location = location;
}
/**
* @return The list of group objects to display. Returns the list of root groups or the
* list of sub-groups for the current group if set.
*/
public List<Map> getGroups()
{
List<Map> groups;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
Set<String> authorities;
boolean immediate = (this.filterMode.equals(FILTER_CHILDREN));
if (this.group == null)
{
// root groups
if (immediate == true)
{
authorities = this.authService.getAllRootAuthorities(AuthorityType.GROUP);
}
else
{
authorities = this.authService.getAllAuthorities(AuthorityType.GROUP);
}
}
else
{
// sub-group of an existing group
authorities = this.authService.getContainedAuthorities(AuthorityType.GROUP, group, immediate);
}
groups = new ArrayList<Map>(authorities.size());
for (String authority : authorities)
{
Map authMap = new HashMap(3, 1.0f);
String name = this.authService.getShortName(authority);
authMap.put("name", name);
authMap.put("id", authority);
groups.add(authMap);
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
groups = Collections.<Map>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return groups;
}
/**
* @return The list of user objects to display. Returns the list of user for the current group.
*/
public List<Map> getUsers()
{
List<Map> users;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
Set<String> authorities;
if (this.group == null)
{
authorities = Collections.<String>emptySet();
}
else
{
// users of an existing group
boolean immediate = (this.filterMode.equals(FILTER_CHILDREN));
authorities = this.authService.getContainedAuthorities(AuthorityType.USER, group, immediate);
}
users = new ArrayList<Map>(authorities.size());
for (String authority : authorities)
{
Map authMap = new HashMap(3, 1.0f);
String userName = this.authService.getShortName(authority);
authMap.put("userName", userName);
authMap.put("id", authority);
// get Person details for this Authority
NodeRef ref = this.personService.getPerson(authority);
String firstName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_LASTNAME);
// build a sensible label for display
StringBuilder label = new StringBuilder(48);
label.append(firstName)
.append(' ')
.append(lastName);
authMap.put("name", label.toString());
users.add(authMap);
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
users = Collections.<Map>emptyList();
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
return users;
}
/**
* Validate password field data is acceptable
*/
public void validateGroupName(FacesContext context, UIComponent component, Object value)
throws ValidatorException
{
String name = (String)value;
if (name.indexOf('\'') != -1 || name.indexOf('"') != -1 || name.indexOf('\\') != -1)
{
String err = MessageFormat.format(Application.getMessage(context, "groups_err_group_name"),
new Object[]{"', \", \\"});
throw new ValidatorException(new FacesMessage(err));
}
}
/**
* Query callback method executed by the Generic Picker component.
* This method is part of the contract to the Generic Picker, it is up to the backing bean
* to execute whatever query is appropriate and return the results.
*
* @param filterIndex Index of the filter drop-down selection
* @param contains Text from the contains textbox
*
* @return An array of SelectItem objects containing the results to display in the picker.
*/
public SelectItem[] pickerCallback(int filterIndex, String contains)
{
FacesContext context = FacesContext.getCurrentInstance();
SelectItem[] items;
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(context);
tx.begin();
// build xpath to match available User/Person objects
ServiceRegistry services = Repository.getServiceRegistry(context);
NodeRef peopleRef = personService.getPeopleContainer();
String xpath = "*[like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "firstName, '%" + contains + "%', false)" +
" or " + "like(@" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + "lastName, '%" + contains + "%', false)]";
List<NodeRef> nodes = services.getSearchService().selectNodes(
peopleRef,
xpath,
null,
services.getNamespaceService(),
false);
items = new SelectItem[nodes.size()];
for (int index=0; index<nodes.size(); index++)
{
NodeRef personRef = nodes.get(index);
String firstName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
String username = (String)this.nodeService.getProperty(personRef, ContentModel.PROP_USERNAME);
SelectItem item = new SortableSelectItem(username, firstName + " " + lastName, lastName);
items[index] = item;
}
// commit the transaction
tx.commit();
}
catch (Exception err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err );
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
items = new SelectItem[0];
}
return items;
}
/**
* Set the Group to be used for next action dialog
*/
public void setupGroupAction(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String group = params.get("id");
if (group != null && group.length() != 0)
{
if (logger.isDebugEnabled())
logger.debug("Setup for action, setting current Group to: " + group);
// prepare a node for the action context
setActionGroup(group);
// clear datalist cache ready from return from action dialog
contextUpdated();
}
}
/**
* Clear the Group action context - e.g. ready for a Create Root Group operation
*/
public void clearGroupAction(ActionEvent event)
{
setActionGroup(null);
// clear datalist cache ready from return from action dialog
contextUpdated();
}
/**
* Action called when a Group folder is clicked.
* Navigate into the Group and show child Groups and child Users.
*/
public void clickGroup(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String group = params.get("id");
if (group != null && group.length() != 0)
{
// refresh UI based on node selection
updateUILocation(group);
}
}
/**
* Action handler called on Create Group finish button click.
*/
public String finishCreate()
{
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// create new Group using Authentication Service
this.authService.createAuthority(AuthorityType.GROUP, getActionGroup(), this.name);
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
return outcome;
}
/**
* Action handler called on Delete Group finish button click.
*/
public String finishDelete()
{
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// delete group using the Authentication Service
this.authService.deleteAuthority(getActionGroup());
// commit the transaction
tx.commit();
// remove this node from the breadcrumb if required
List<IBreadcrumbHandler> location = getLocation();
GroupBreadcrumbHandler handler = (GroupBreadcrumbHandler)location.get(location.size() - 1);
// see if the current breadcrumb location is our Group
if ( getActionGroup().equals(handler.Group) )
{
location.remove(location.size() - 1);
// now work out which Group to set the list to refresh against
if (location.size() != 0)
{
handler = (GroupBreadcrumbHandler)location.get(location.size() - 1);
this.setCurrentGroup(handler.Group, handler.Label);
}
}
// clear action context
setActionGroup(null);
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
return outcome;
}
/**
* Remove specified user from the current group
*/
public void removeUser(ActionEvent event)
{
UIActionLink link = (UIActionLink)event.getComponent();
Map<String, String> params = link.getParameterMap();
String authority = params.get("id");
if (authority != null && authority.length() != 0)
{
try
{
this.authService.removeAuthority(this.group, authority);
// refresh UI after change
contextUpdated();
}
catch (Throwable err)
{
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
}
}
}
/**
* Action handler called when Finish button clicked on Add User to Group page
*/
public String finishAddUser()
{
String outcome = DEFAULT_OUTCOME;
UserTransaction tx = null;
try
{
FacesContext context = FacesContext.getCurrentInstance();
tx = Repository.getUserTransaction(context);
tx.begin();
// add each selected user to the current group in turn
for (UserAuthorityDetails wrapper : this.usersForGroup)
{
this.authService.addAuthority(getActionGroup(), wrapper.authority);
}
// commit the transaction
tx.commit();
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
Utils.addErrorMessage(MessageFormat.format(Application.getMessage(
FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), err.getMessage()), err);
outcome = null;
}
return outcome;
}
/**
* Add the selected User to the list for adding to a Group
*/
public void addSelectedUsers(ActionEvent event)
{
UIGenericPicker picker = (UIGenericPicker)event.getComponent().findComponent("picker");
String[] results = picker.getSelectedResults();
if (results != null)
{
for (int i=0; i<results.length; i++)
{
String authority = results[i];
// check for same authority so not added twice
boolean foundExisting = false;
for (int n=0; n<this.usersForGroup.size(); n++)
{
UserAuthorityDetails wrapper = this.usersForGroup.get(n);
if (authority.equals(wrapper.getAuthority()))
{
foundExisting = true;
break;
}
}
if (foundExisting == false)
{
StringBuilder label = new StringBuilder(48);
// build a display label showing the user person name
if (this.personService.personExists(authority) == true)
{
// found a Person with a User authority
NodeRef ref = this.personService.getPerson(authority);
String firstName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_FIRSTNAME);
String lastName = (String)this.nodeService.getProperty(ref, ContentModel.PROP_LASTNAME);
// build a sensible label for display
label.append(firstName)
.append(' ')
.append(lastName);
// add a wrapper object with the details to the results list for display
UserAuthorityDetails userDetails = new UserAuthorityDetails(label.toString(), authority);
this.usersForGroup.add(userDetails);
}
}
}
}
}
/**
* Action handler called when the Remove button is pressed to remove a user from the results list
*/
public void removeUserSelection(ActionEvent event)
{
UserAuthorityDetails wrapper = (UserAuthorityDetails)this.usersDataModel.getRowData();
if (wrapper != null)
{
this.usersForGroup.remove(wrapper);
}
}
/**
* Change the current view mode based on user selection
*/
public void viewModeChanged(ActionEvent event)
{
UIModeList viewList = (UIModeList)event.getComponent();
// update view mode from user selection
setViewMode(viewList.getValue().toString());
}
/**
* Change the current list filter mode based on user selection
*/
public void filterModeChanged(ActionEvent event)
{
UIModeList viewList = (UIModeList)event.getComponent();
// update list filter mode from user selection
setFilterMode(viewList.getValue().toString());
}
/**
* Update the breadcrumb with the clicked Group location
*/
private void updateUILocation(String group)
{
String groupName = this.authService.getShortName(group);
this.location.add(new GroupBreadcrumbHandler(group, groupName));
this.setCurrentGroup(group, groupName);
}
// ------------------------------------------------------------------------------
// IContextListener implementation
/**
* @see org.alfresco.web.app.context.IContextListener#contextUpdated()
*/
public void contextUpdated()
{
if (logger.isDebugEnabled())
logger.debug("Invalidating Group Management Components...");
// force a requery of the richlist dataset
this.groupsRichList.setValue(null);
this.usersRichList.setValue(null);
}
// ------------------------------------------------------------------------------
// Inner classes
/**
* Class to handle breadcrumb interaction for Group pages
*/
private class GroupBreadcrumbHandler implements IBreadcrumbHandler
{
private static final long serialVersionUID = 1871876653151036630L;
/**
* Constructor
*
* @param group The group for this navigation element if any
* @param label Element label
*/
public GroupBreadcrumbHandler(String group, String label)
{
this.Group = group;
this.Label = label;
}
/**
* @see java.lang.Object#toString()
*/
public String toString()
{
return this.Label;
}
/**
* @see org.alfresco.web.ui.common.component.IBreadcrumbHandler#navigationOutcome(org.alfresco.web.ui.common.component.UIBreadcrumb)
*/
public String navigationOutcome(UIBreadcrumb breadcrumb)
{
// All group breadcrumb elements relate to a Group
// when selected we set the current Group Id and return
setCurrentGroup(this.Group, this.Label);
setLocation( (List)breadcrumb.getValue() );
return null;
}
public String Group;
public String Label;
}
/**
* Simple wrapper bean exposing user authority and person details for JSF results list
*/
public static class UserAuthorityDetails
{
public UserAuthorityDetails(String name, String authority)
{
this.name = name;
this.authority = authority;
}
public String getName()
{
return this.name;
}
public String getAuthority()
{
return this.authority;
}
private String name;
private String authority;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
* Copyright (C) 2005-2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
@@ -41,10 +41,24 @@ public class PageTag extends TagSupport
private final static String SCRIPTS_WEBDAV = "/scripts/webdav.js\"></script>\n";
private final static String STYLES_START = "<link rel=\"stylesheet\" href=\"";
private final static String STYLES_MAIN = "/css/main.css\" TYPE=\"text/css\">\n";
/**
* Please ensure you understand the terms of the license before changing the contents of this file.
*/
private final static String ALF_URL = "http://www.alfresco.com";
private final static String ALF_LOGO = "/images/logo/alfresco_logo.gif";
private final static String ALF_TEXT = "Content managed by Alfresco";
private final static String ALF_COPY = "Alfresco Software Inc. (C) 2005-2006 All rights reserved.";
private final static String ALF_LOGO = "http://www.alfresco.com/images/alfresco_community_horizont.gif";
private final static String ALF_TEXT = "Alfresco Community";
private final static String ALF_COPY = "Supplied free of charge with " +
"<a class=footer href='http://www.alfresco.com/services/support/communityterms/#support'>no support</a>, " +
"<a class=footer href='http://www.alfresco.com/services/support/communityterms/#certification'>no certification</a>, " +
"<a class=footer href='http://www.alfresco.com/services/support/communityterms/#maintenance'>no maintenance</a>, " +
"<a class=footer href='http://www.alfresco.com/services/support/communityterms/#warranty'>no warranty</a> and " +
"<a class=footer href='http://www.alfresco.com/services/support/communityterms/#indemnity'>no indemnity</a> by " +
"<a class=footer href='http://www.alfresco.com'>Alfresco</a> or its " +
"<a class=footer href='http://www.alfresco.com/partners/'>Certified Partners</a>. " +
"<a class=footer href='http://www.alfresco.com/services/support/'>Click here for support</a>. " +
"Alfresco Software Inc. <20> 2005-2006 All rights reserved.";
private static Log logger = LogFactory.getLog(PageTag.class);
private static String alfresco = null;
@@ -185,17 +199,22 @@ public class PageTag extends TagSupport
return loginPage;
}
/**
* Please ensure you understand the terms of the license before changing the contents of this file.
*/
private String getAlfrescoButton()
{
if (alfresco == null)
{
String reqPath = ((HttpServletRequest)pageContext.getRequest()).getContextPath();
alfresco = "<center>" +
alfresco = "<center><table><tr><td>" +
"<a href='" + ALF_URL + "'>" +
"<img border=0 alt='' title='" + ALF_TEXT + "' align=absmiddle src='" + reqPath + ALF_LOGO + "'>" +
"</a>&nbsp;" +
"<span style='font-family:Arial,Helvetica,sans-serif;font-size:10px'>" + ALF_COPY +
"</span></center>";
"<img border=0 alt='' title='" + ALF_TEXT + "' align=absmiddle src='" + ALF_LOGO + "'>" +
"</a></td><td align=center>" +
"<span class=footer>" + ALF_COPY +
"</span></td><td><a href='http://sourceforge.net/projects/alfresco'><img border=0 alt='' title='SourceForge' align=absmiddle src='http://sflogo.sourceforge.net/sflogo.php?group_id=143373&type=1'></a>" +
"</td></tr></table></center>";
}
return alfresco;