mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged BRANCHES\DEV\MODEL_SPLIT to HEAD
Split the data dictionary out from the repository. There is a new DataModel project to add into eclipse Still to move a few context dependent tests git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20877 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import net.sf.acegisecurity.Authentication;
|
||||
import net.sf.acegisecurity.context.security.SecureContext;
|
||||
|
||||
/**
|
||||
* Extensions for the Alfresco security context.
|
||||
*
|
||||
* This is based on the Linux model and supports real, effective and stored authorities
|
||||
*
|
||||
* The real authority is used for auditing and reporting who the user is etc.
|
||||
* The effective authority is used for permission checks.
|
||||
*
|
||||
* RunAs support leaves the real authority and changes only the effective authority
|
||||
* That means "special" code can run code as system but still be audited as Joe
|
||||
*
|
||||
* In the future scrips etc can support a setUId flag and run as the owner of the script.
|
||||
* If the script chooses to do this ....
|
||||
* A method invocation could do the same (after entry security checks)
|
||||
*
|
||||
* TODO: extent runAs to take a nodeRef context - it can then set the stored atc and set this as effective if required.
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface AlfrescoSecureContext extends SecureContext
|
||||
{
|
||||
/**
|
||||
* Get the effective authentication - used for permission checks
|
||||
* @return
|
||||
*/
|
||||
public Authentication getEffectiveAuthentication();
|
||||
|
||||
/**
|
||||
* Get the real authenticaiton - used for auditing and everything else
|
||||
* @return
|
||||
*/
|
||||
public Authentication getRealAuthentication();
|
||||
|
||||
/**
|
||||
* Set the effective authentication held by the context
|
||||
*
|
||||
* @param effictiveAuthentication
|
||||
*/
|
||||
public void setEffectiveAuthentication(Authentication effictiveAuthentication);
|
||||
|
||||
/**
|
||||
* Set the real authentication held by the context
|
||||
*
|
||||
* @param realAuthentication
|
||||
*/
|
||||
public void setRealAuthentication(Authentication realAuthentication);
|
||||
|
||||
}
|
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import net.sf.acegisecurity.Authentication;
|
||||
import net.sf.acegisecurity.context.ContextInvalidException;
|
||||
|
||||
/**
|
||||
* Hold an Alfresco extended security context
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class AlfrescoSecureContextImpl implements AlfrescoSecureContext
|
||||
{
|
||||
private static final long serialVersionUID = -8893133731693272549L;
|
||||
|
||||
private Authentication realAuthentication;
|
||||
|
||||
private Authentication effectiveAuthentication;
|
||||
|
||||
/**
|
||||
* ACEGI
|
||||
*/
|
||||
public Authentication getAuthentication()
|
||||
{
|
||||
return getEffectiveAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* ACEGI
|
||||
*/
|
||||
public void setAuthentication(Authentication newAuthentication)
|
||||
{
|
||||
setEffectiveAuthentication(newAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* ACEGI
|
||||
*/
|
||||
public void validate() throws ContextInvalidException
|
||||
{
|
||||
if (effectiveAuthentication == null)
|
||||
{
|
||||
throw new ContextInvalidException("Effective authentication not set");
|
||||
}
|
||||
}
|
||||
|
||||
public Authentication getEffectiveAuthentication()
|
||||
{
|
||||
return effectiveAuthentication;
|
||||
}
|
||||
|
||||
public Authentication getRealAuthentication()
|
||||
{
|
||||
return realAuthentication;
|
||||
}
|
||||
|
||||
public void setEffectiveAuthentication(Authentication effictiveAuthentication)
|
||||
{
|
||||
this.effectiveAuthentication = effictiveAuthentication;
|
||||
}
|
||||
|
||||
public void setRealAuthentication(Authentication realAuthentication)
|
||||
{
|
||||
this.realAuthentication = realAuthentication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int PRIME = 31;
|
||||
int result = 1;
|
||||
result = PRIME * result + ((effectiveAuthentication == null) ? 0 : effectiveAuthentication.hashCode());
|
||||
result = PRIME * result + ((realAuthentication == null) ? 0 : realAuthentication.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final AlfrescoSecureContextImpl other = (AlfrescoSecureContextImpl) obj;
|
||||
if (effectiveAuthentication == null)
|
||||
{
|
||||
if (other.effectiveAuthentication != null)
|
||||
return false;
|
||||
}
|
||||
else if (!effectiveAuthentication.equals(other.effectiveAuthentication))
|
||||
return false;
|
||||
if (realAuthentication == null)
|
||||
{
|
||||
if (other.realAuthentication != null)
|
||||
return false;
|
||||
}
|
||||
else if (!realAuthentication.equals(other.realAuthentication))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (realAuthentication == null)
|
||||
{
|
||||
builder.append("Real authenticaion = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append("Real authenticaion = " + realAuthentication.toString());
|
||||
}
|
||||
builder.append(", ");
|
||||
|
||||
if (effectiveAuthentication == null)
|
||||
{
|
||||
builder.append("Effective authenticaion = null");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append("Effective authenticaion = " + effectiveAuthentication.toString());
|
||||
}
|
||||
builder.append(", ");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
|
||||
/**
|
||||
* Alfresco Authentication Exception and wrapper
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public class AuthenticationException extends AlfrescoRuntimeException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3546647620128092466L;
|
||||
|
||||
public AuthenticationException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public AuthenticationException(String msg, Throwable cause)
|
||||
{
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
@@ -1,627 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import net.sf.acegisecurity.Authentication;
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.UserDetails;
|
||||
import net.sf.acegisecurity.context.Context;
|
||||
import net.sf.acegisecurity.context.ContextHolder;
|
||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import net.sf.acegisecurity.providers.dao.User;
|
||||
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.log.NDC;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Utility helper methods to change the authenticated context for threads.
|
||||
*/
|
||||
public class AuthenticationUtil implements InitializingBean
|
||||
{
|
||||
static Log s_logger = LogFactory.getLog(AuthenticationUtil.class);
|
||||
|
||||
public interface RunAsWork<Result>
|
||||
{
|
||||
/**
|
||||
* Method containing the work to be done in the user transaction.
|
||||
*
|
||||
* @return Return the result of the operation
|
||||
*/
|
||||
Result doWork() throws Exception;
|
||||
}
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
||||
public static final String SYSTEM_USER_NAME = "System";
|
||||
private static String defaultAdminUserName = PermissionService.ADMINISTRATOR_AUTHORITY;
|
||||
private static String defaultGuestUserName = PermissionService.GUEST_AUTHORITY;
|
||||
private static boolean mtEnabled = false;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
// at this point default admin and guest names have been assigned
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void setDefaultAdminUserName(String defaultAdminUserName)
|
||||
{
|
||||
AuthenticationUtil.defaultAdminUserName = defaultAdminUserName;
|
||||
}
|
||||
|
||||
public void setDefaultGuestUserName(String defaultGuestUserName)
|
||||
{
|
||||
AuthenticationUtil.defaultGuestUserName = defaultGuestUserName;
|
||||
}
|
||||
|
||||
public static void setMtEnabled(boolean mtEnabled)
|
||||
{
|
||||
if (!AuthenticationUtil.mtEnabled)
|
||||
{
|
||||
AuthenticationUtil.mtEnabled = mtEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isMtEnabled()
|
||||
{
|
||||
return AuthenticationUtil.mtEnabled;
|
||||
}
|
||||
|
||||
public AuthenticationUtil()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to create an authentication token
|
||||
*/
|
||||
private static UsernamePasswordAuthenticationToken getAuthenticationToken(String userName, UserDetails providedDetails)
|
||||
{
|
||||
UserDetails ud = null;
|
||||
if (userName.equals(SYSTEM_USER_NAME))
|
||||
{
|
||||
GrantedAuthority[] gas = new GrantedAuthority[1];
|
||||
gas[0] = new GrantedAuthorityImpl("ROLE_SYSTEM");
|
||||
ud = new User(SYSTEM_USER_NAME, "", true, true, true, true, gas);
|
||||
}
|
||||
else if (userName.equalsIgnoreCase(getGuestUserName()))
|
||||
{
|
||||
GrantedAuthority[] gas = new GrantedAuthority[0];
|
||||
ud = new User(getGuestUserName().toLowerCase(), "", true, true, true, true, gas);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (providedDetails.getUsername().equals(userName))
|
||||
{
|
||||
ud = providedDetails;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuthenticationException("Provided user details do not match the user name");
|
||||
}
|
||||
}
|
||||
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(ud, "", ud.getAuthorities());
|
||||
auth.setDetails(ud);
|
||||
auth.setAuthenticated(true);
|
||||
return auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation that makes an ACEGI object on the fly
|
||||
*/
|
||||
private static UserDetails getDefaultUserDetails(String userName)
|
||||
{
|
||||
GrantedAuthority[] gas = new GrantedAuthority[1];
|
||||
gas[0] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");
|
||||
UserDetails ud = new User(userName, "", true, true, true, true, gas);
|
||||
return ud;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the username from the authentication.
|
||||
*/
|
||||
private static String getUserName(Authentication authentication)
|
||||
{
|
||||
if (authentication.getPrincipal() instanceof UserDetails)
|
||||
{
|
||||
return ((UserDetails) authentication.getPrincipal()).getUsername();
|
||||
}
|
||||
else
|
||||
{
|
||||
return authentication.getPrincipal().toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate as the given user. The user will be authenticated and all operations
|
||||
* with be run in the context of this user.
|
||||
*
|
||||
* @param userName the user name
|
||||
* @return the authentication token
|
||||
*/
|
||||
public static Authentication setFullyAuthenticatedUser(String userName)
|
||||
{
|
||||
return setFullyAuthenticatedUser(userName, getDefaultUserDetails(userName));
|
||||
}
|
||||
|
||||
private static Authentication setFullyAuthenticatedUser(String userName, UserDetails providedDetails) throws AuthenticationException
|
||||
{
|
||||
if (userName == null)
|
||||
{
|
||||
throw new AuthenticationException("Null user name");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UsernamePasswordAuthenticationToken auth = getAuthenticationToken(userName, providedDetails);
|
||||
return setFullAuthentication(auth);
|
||||
}
|
||||
catch (net.sf.acegisecurity.AuthenticationException ae)
|
||||
{
|
||||
throw new AuthenticationException(ae.getMessage(), ae);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-authenticate using a previously-created authentication.
|
||||
*/
|
||||
public static Authentication setFullAuthentication(Authentication authentication)
|
||||
{
|
||||
if (authentication == null)
|
||||
{
|
||||
clearCurrentSecurityContext();
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
AlfrescoSecureContext sc = null;
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
sc = new AlfrescoSecureContextImpl();
|
||||
ContextHolder.setContext(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc = (AlfrescoSecureContext) context;
|
||||
}
|
||||
authentication.setAuthenticated(true);
|
||||
// Sets real and effective
|
||||
sc.setRealAuthentication(authentication);
|
||||
sc.setEffectiveAuthentication(authentication);
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>WARN: Advanced usage only.</b><br/>
|
||||
* Set the system user as the currently running user for authentication purposes.
|
||||
*
|
||||
* @return Authentication
|
||||
*
|
||||
* @see #setRunAsUser(String)
|
||||
*/
|
||||
public static Authentication setRunAsUserSystem()
|
||||
{
|
||||
return setRunAsUser(SYSTEM_USER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>WARN: Advanced usage only.</b><br/>
|
||||
* Switch to the given user for all authenticated operations. The original, authenticated user
|
||||
* can still be found using {@link #getAuthenticatedUser()}.
|
||||
*
|
||||
* @param userName the user to run as
|
||||
* @return the new authentication
|
||||
*/
|
||||
public static Authentication setRunAsUser(String userName)
|
||||
{
|
||||
return setRunAsUser(userName, getDefaultUserDetails(userName));
|
||||
}
|
||||
|
||||
/*package*/ static Authentication setRunAsUser(String userName, UserDetails providedDetails) throws AuthenticationException
|
||||
{
|
||||
if (userName == null)
|
||||
{
|
||||
throw new AuthenticationException("Null user name");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UsernamePasswordAuthenticationToken auth = getAuthenticationToken(userName, providedDetails);
|
||||
return setRunAsAuthentication(auth);
|
||||
}
|
||||
catch (net.sf.acegisecurity.AuthenticationException ae)
|
||||
{
|
||||
throw new AuthenticationException(ae.getMessage(), ae);
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static Authentication setRunAsAuthentication(Authentication authentication)
|
||||
{
|
||||
if (authentication == null)
|
||||
{
|
||||
clearCurrentSecurityContext();
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
AlfrescoSecureContext sc = null;
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
sc = new AlfrescoSecureContextImpl();
|
||||
ContextHolder.setContext(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc = (AlfrescoSecureContext) context;
|
||||
}
|
||||
authentication.setAuthenticated(true);
|
||||
if (sc.getRealAuthentication() == null)
|
||||
{
|
||||
// There is no authentication in action
|
||||
sc.setRealAuthentication(authentication);
|
||||
}
|
||||
sc.setEffectiveAuthentication(authentication);
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current authentication for application of permissions. This includes
|
||||
* the any overlay details set by {@link #setRunAsUser(String)}.
|
||||
*
|
||||
* @return Authentication Returns the running authentication
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public static Authentication getRunAsAuthentication() throws AuthenticationException
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return ((AlfrescoSecureContext) context).getEffectiveAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>WARN: Advanced usage only.</b><br/>
|
||||
* Get the authentication for that was set by an real authentication.
|
||||
*
|
||||
* @return Authentication Returns the real authentication
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public static Authentication getFullAuthentication() throws AuthenticationException
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return ((AlfrescoSecureContext) context).getRealAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that is currently in effect for purposes of authentication. This includes
|
||||
* any overlays introduced by {@link #setRunAsUser(String) runAs}.
|
||||
*
|
||||
* @return Returns the name of the user
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public static String getRunAsUser() throws AuthenticationException
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
AlfrescoSecureContext ctx = (AlfrescoSecureContext) context;
|
||||
if (ctx.getEffectiveAuthentication() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return getUserName(ctx.getEffectiveAuthentication());
|
||||
}
|
||||
|
||||
public static boolean isRunAsUserTheSystemUser()
|
||||
{
|
||||
String runAsUser = getRunAsUser();
|
||||
if ((runAsUser != null) && isMtEnabled())
|
||||
{
|
||||
// get base username
|
||||
int idx = runAsUser.indexOf(TenantService.SEPARATOR);
|
||||
if (idx != -1)
|
||||
{
|
||||
runAsUser = runAsUser.substring(0, idx);
|
||||
}
|
||||
}
|
||||
return EqualsHelper.nullSafeEquals(runAsUser, AuthenticationUtil.SYSTEM_USER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fully authenticated user.
|
||||
* It returns the name of the user that last authenticated and excludes any overlay authentication set
|
||||
* by {@link #runAs(org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork, String) runAs}.
|
||||
*
|
||||
* @return Returns the name of the authenticated user
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public static String getFullyAuthenticatedUser() throws AuthenticationException
|
||||
{
|
||||
Context context = ContextHolder.getContext();
|
||||
if ((context == null) || !(context instanceof AlfrescoSecureContext))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
AlfrescoSecureContext ctx = (AlfrescoSecureContext) context;
|
||||
if (ctx.getRealAuthentication() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return getUserName(ctx.getRealAuthentication());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the system user
|
||||
*
|
||||
* @return system user name
|
||||
*/
|
||||
public static String getSystemUserName()
|
||||
{
|
||||
return SYSTEM_USER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the default admin user (the admin user created during bootstrap)
|
||||
*
|
||||
* @return admin user name
|
||||
*/
|
||||
public static String getAdminUserName()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
throw new IllegalStateException("AuthenticationUtil not yet initialised; default admin username not available");
|
||||
}
|
||||
|
||||
if (isMtEnabled())
|
||||
{
|
||||
String runAsUser = AuthenticationUtil.getRunAsUser();
|
||||
if (runAsUser != null)
|
||||
{
|
||||
String[] parts = splitUserTenant(runAsUser);
|
||||
if (parts.length == 2)
|
||||
{
|
||||
return defaultAdminUserName + TenantService.SEPARATOR + parts[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaultAdminUserName;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the name of admin role
|
||||
*/
|
||||
public static String getAdminRoleName()
|
||||
{
|
||||
return PermissionService.ADMINISTRATOR_AUTHORITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the Guest User
|
||||
*/
|
||||
public static String getGuestUserName()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
throw new IllegalStateException("AuthenticationUtil not yet initialised; default guest username not available");
|
||||
}
|
||||
return defaultGuestUserName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the guest role
|
||||
*/
|
||||
public static String getGuestRoleName()
|
||||
{
|
||||
return PermissionService.GUEST_AUTHORITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the current security information
|
||||
*/
|
||||
public static void clearCurrentSecurityContext()
|
||||
{
|
||||
ContextHolder.setContext(null);
|
||||
InMemoryTicketComponentImpl.clearCurrentSecurityContext();
|
||||
|
||||
NDC.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a unit of work as a given user. The thread's authenticated user will be returned to its normal state
|
||||
* after the call.
|
||||
*
|
||||
* @param runAsWork
|
||||
* the unit of work to do
|
||||
* @param uid
|
||||
* the user ID
|
||||
* @return Returns the work's return value
|
||||
*/
|
||||
public static <R> R runAs(RunAsWork<R> runAsWork, String uid)
|
||||
{
|
||||
Authentication originalFullAuthentication = AuthenticationUtil.getFullAuthentication();
|
||||
Authentication originalRunAsAuthentication = AuthenticationUtil.getRunAsAuthentication();
|
||||
|
||||
final R result;
|
||||
try
|
||||
{
|
||||
if (originalFullAuthentication == null)
|
||||
{
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((originalRunAsAuthentication != null) && (isMtEnabled()))
|
||||
{
|
||||
String originalRunAsUserName = getUserName(originalRunAsAuthentication);
|
||||
int idx = originalRunAsUserName.indexOf(TenantService.SEPARATOR);
|
||||
if ((idx != -1) && (idx < (originalRunAsUserName.length() - 1)))
|
||||
{
|
||||
if (uid.equals(AuthenticationUtil.getSystemUserName()))
|
||||
{
|
||||
uid = uid + TenantService.SEPARATOR + originalRunAsUserName.substring(idx + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
AuthenticationUtil.setRunAsUser(uid);
|
||||
}
|
||||
logNDC(uid);
|
||||
result = runAsWork.doWork();
|
||||
return result;
|
||||
}
|
||||
catch (Throwable exception)
|
||||
{
|
||||
// Re-throw the exception
|
||||
if (exception instanceof RuntimeException)
|
||||
{
|
||||
throw (RuntimeException) exception;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Error during run as.", exception);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (originalFullAuthentication == null)
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
logNDC(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthenticationUtil.setFullAuthentication(originalFullAuthentication);
|
||||
AuthenticationUtil.setRunAsAuthentication(originalRunAsAuthentication);
|
||||
|
||||
logNDC(getUserName(originalFullAuthentication));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ThreadLocalStack extends ThreadLocal<Stack<Authentication>> {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.ThreadLocal#initialValue()
|
||||
*/
|
||||
@Override
|
||||
protected Stack<Authentication> initialValue()
|
||||
{
|
||||
return new Stack<Authentication>();
|
||||
}
|
||||
|
||||
}
|
||||
private static ThreadLocal<Stack<Authentication>> threadLocalFullAuthenticationStack = new ThreadLocalStack();
|
||||
private static ThreadLocal<Stack<Authentication>> threadLocalRunAsAuthenticationStack = new ThreadLocalStack();
|
||||
|
||||
/**
|
||||
* Push the current authentication context onto a threadlocal stack.
|
||||
*/
|
||||
public static void pushAuthentication()
|
||||
{
|
||||
Authentication originalFullAuthentication = AuthenticationUtil.getFullAuthentication();
|
||||
Authentication originalRunAsAuthentication = AuthenticationUtil.getRunAsAuthentication();
|
||||
threadLocalFullAuthenticationStack.get().push(originalFullAuthentication);
|
||||
threadLocalRunAsAuthenticationStack.get().push(originalRunAsAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the authentication context from a threadlocal stack.
|
||||
*/
|
||||
public static void popAuthentication()
|
||||
{
|
||||
Authentication originalFullAuthentication = threadLocalFullAuthenticationStack.get().pop();
|
||||
Authentication originalRunAsAuthentication = threadLocalRunAsAuthenticationStack.get().pop();
|
||||
if (originalFullAuthentication == null)
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthenticationUtil.setFullAuthentication(originalFullAuthentication);
|
||||
AuthenticationUtil.setRunAsAuthentication(originalRunAsAuthentication);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current authenticated users
|
||||
*/
|
||||
public static void logAuthenticatedUsers()
|
||||
{
|
||||
if (s_logger.isDebugEnabled())
|
||||
{
|
||||
s_logger.debug(
|
||||
"Authentication: \n" +
|
||||
" Fully authenticated: " + AuthenticationUtil.getFullyAuthenticatedUser() + "\n" +
|
||||
" Run as: " + AuthenticationUtil.getRunAsUser());
|
||||
}
|
||||
}
|
||||
|
||||
public static void logNDC(String userName)
|
||||
{
|
||||
NDC.remove();
|
||||
|
||||
if (userName != null)
|
||||
{
|
||||
if (isMtEnabled())
|
||||
{
|
||||
String[] parts = splitUserTenant(userName);
|
||||
if (parts.length == 2)
|
||||
{
|
||||
NDC.push("Tenant:" + parts[1] + " User:" + parts[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
NDC.push("User:" + userName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NDC.push("User:" + userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] splitUserTenant(String userName)
|
||||
{
|
||||
return userName.split(TenantService.SEPARATOR);
|
||||
}
|
||||
}
|
@@ -1,598 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.service.cmr.repository.datatype.Duration;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.safehaus.uuid.UUIDGenerator;
|
||||
|
||||
/**
|
||||
* Store tickets in memory. They can be distributed in a cluster via the cache
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
public class InMemoryTicketComponentImpl implements TicketComponent
|
||||
{
|
||||
/**
|
||||
* Ticket prefix
|
||||
*/
|
||||
public static final String GRANTED_AUTHORITY_TICKET_PREFIX = "TICKET_";
|
||||
|
||||
private static ThreadLocal<String> currentTicket = new ThreadLocal<String>();
|
||||
|
||||
private boolean ticketsExpire;
|
||||
|
||||
private Duration validDuration;
|
||||
|
||||
private boolean oneOff;
|
||||
|
||||
private String guid;
|
||||
|
||||
private SimpleCache<String, Ticket> ticketsCache; // Can't use Ticket as it's private
|
||||
|
||||
private ExpiryMode expiryMode = ExpiryMode.AFTER_FIXED_TIME;
|
||||
|
||||
/**
|
||||
* IOC constructor
|
||||
*/
|
||||
public InMemoryTicketComponentImpl()
|
||||
{
|
||||
super();
|
||||
guid = GUID.generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ticket cache to support clustering
|
||||
*
|
||||
* @param ticketsCache
|
||||
*/
|
||||
public void setTicketsCache(SimpleCache<String, Ticket> ticketsCache)
|
||||
{
|
||||
this.ticketsCache = ticketsCache;
|
||||
}
|
||||
|
||||
public String getNewTicket(String userName, String sessionId) throws AuthenticationException
|
||||
{
|
||||
Date expiryDate = null;
|
||||
if (ticketsExpire)
|
||||
{
|
||||
expiryDate = Duration.add(new Date(), validDuration);
|
||||
}
|
||||
Ticket ticket = new Ticket(ticketsExpire ? expiryMode : ExpiryMode.DO_NOT_EXPIRE, expiryDate, userName,
|
||||
validDuration, sessionId == null ? Collections.<String> emptySet() : Collections.singleton(sessionId));
|
||||
ticketsCache.put(ticket.getTicketId(), ticket);
|
||||
String ticketString = GRANTED_AUTHORITY_TICKET_PREFIX + ticket.getTicketId();
|
||||
currentTicket.set(ticketString);
|
||||
return ticketString;
|
||||
}
|
||||
|
||||
public String validateTicket(String ticketString, String sessionId) throws AuthenticationException
|
||||
{
|
||||
String ticketKey = getTicketKey(ticketString);
|
||||
Ticket ticket = this.ticketsCache.get(ticketKey);
|
||||
if (ticket == null)
|
||||
{
|
||||
throw new AuthenticationException("Missing ticket for " + ticketString);
|
||||
}
|
||||
if (ticket.hasExpired())
|
||||
{
|
||||
throw new TicketExpiredException("Ticket expired for " + ticketString);
|
||||
}
|
||||
// TODO: Recheck the user details here
|
||||
// TODO: Strengthen ticket as GUID is predicatble
|
||||
if (oneOff)
|
||||
{
|
||||
ticketsCache.remove(ticketKey);
|
||||
}
|
||||
// Make sure the association with the session is recorded
|
||||
else if (sessionId != null)
|
||||
{
|
||||
Ticket newTicket = ticket.addSessionId(sessionId);
|
||||
if (newTicket != ticket)
|
||||
{
|
||||
ticketsCache.put(ticketKey, newTicket);
|
||||
ticket = newTicket;
|
||||
}
|
||||
}
|
||||
currentTicket.set(ticketString);
|
||||
return ticket.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to find a ticket
|
||||
*
|
||||
* @param ticketString
|
||||
* @return - the ticket
|
||||
*/
|
||||
private Ticket getTicketByTicketString(String ticketString)
|
||||
{
|
||||
Ticket ticket = ticketsCache.get(getTicketKey(ticketString));
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to extract the ticket id from the ticket string
|
||||
*
|
||||
* @param ticketString
|
||||
* @return - the ticket key
|
||||
*/
|
||||
private String getTicketKey(String ticketString)
|
||||
{
|
||||
if (ticketString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (ticketString.length() < GRANTED_AUTHORITY_TICKET_PREFIX.length())
|
||||
{
|
||||
throw new AuthenticationException(ticketString + " is an invalid ticket format");
|
||||
}
|
||||
|
||||
String key = ticketString.substring(GRANTED_AUTHORITY_TICKET_PREFIX.length());
|
||||
return key;
|
||||
}
|
||||
|
||||
public void invalidateTicketById(String ticketString, String sessionId)
|
||||
{
|
||||
String ticketKey = getTicketKey(ticketString);
|
||||
// If we are dissassociating the ticket from an app server session, it may still not be time to expire it, as it
|
||||
// may be in use by other sessions
|
||||
if (sessionId != null)
|
||||
{
|
||||
Ticket ticketObj = ticketsCache.get(ticketKey);
|
||||
if (ticketObj != null)
|
||||
{
|
||||
ticketObj = ticketObj.removeSessionId(sessionId);
|
||||
if (ticketObj == null)
|
||||
{
|
||||
ticketsCache.remove(ticketKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticketsCache.put(ticketKey, ticketObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ticketsCache.remove(ticketKey);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.security.authentication.TicketComponent#getUsersWithTickets(boolean)
|
||||
*/
|
||||
public Set<String> getUsersWithTickets(boolean nonExpiredOnly)
|
||||
{
|
||||
Set<String> users = new HashSet<String>();
|
||||
for (String key : ticketsCache.getKeys())
|
||||
{
|
||||
Ticket ticket = ticketsCache.get(key);
|
||||
if (ticket != null)
|
||||
{
|
||||
if ((nonExpiredOnly == false) || (! ticket.hasExpired()))
|
||||
{
|
||||
users.add(ticket.getUserName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.security.authentication.TicketComponent#countTickets(boolean)
|
||||
*/
|
||||
public int countTickets(boolean nonExpiredOnly)
|
||||
{
|
||||
if (nonExpiredOnly)
|
||||
{
|
||||
int count = 0;
|
||||
for (String key : ticketsCache.getKeys())
|
||||
{
|
||||
Ticket ticket = ticketsCache.get(key);
|
||||
if (! ticket.hasExpired())
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ticketsCache.getKeys().size();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.security.authentication.TicketComponent#invalidateTickets(boolean)
|
||||
*/
|
||||
public int invalidateTickets(boolean expiredOnly)
|
||||
{
|
||||
int count = 0;
|
||||
if (! expiredOnly)
|
||||
{
|
||||
count = ticketsCache.getKeys().size();
|
||||
ticketsCache.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (String key : ticketsCache.getKeys())
|
||||
{
|
||||
Ticket ticket = ticketsCache.get(key);
|
||||
if (ticket == null || ticket.hasExpired())
|
||||
{
|
||||
count++;
|
||||
ticketsCache.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void invalidateTicketByUser(String userName)
|
||||
{
|
||||
Set<String> toRemove = new HashSet<String>();
|
||||
|
||||
for (String key : ticketsCache.getKeys())
|
||||
{
|
||||
Ticket ticket = ticketsCache.get(key);
|
||||
// Hack: The getKeys() call might return keys for null marker objects, yielding null values
|
||||
if (ticket == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ticket.getUserName().equals(userName))
|
||||
{
|
||||
toRemove.add(ticket.getTicketId());
|
||||
}
|
||||
}
|
||||
|
||||
for (String id : toRemove)
|
||||
{
|
||||
ticketsCache.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int PRIME = 31;
|
||||
int result = 1;
|
||||
result = PRIME * result + ((guid == null) ? 0 : guid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final InMemoryTicketComponentImpl other = (InMemoryTicketComponentImpl) obj;
|
||||
if (guid == null)
|
||||
{
|
||||
if (other.guid != null)
|
||||
return false;
|
||||
}
|
||||
else if (!guid.equals(other.guid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ticket
|
||||
*
|
||||
* @author andyh
|
||||
*/
|
||||
public static class Ticket implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -5904510560161261049L;
|
||||
|
||||
private ExpiryMode expires;
|
||||
|
||||
private Date expiryDate;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String ticketId;
|
||||
|
||||
private String guid;
|
||||
|
||||
private Duration validDuration;
|
||||
|
||||
private Set<String> sessionIds;
|
||||
|
||||
private Ticket(Ticket copy, Set<String> sessionIds)
|
||||
{
|
||||
this.expires = copy.expires;
|
||||
this.expiryDate = copy.expiryDate;
|
||||
this.userName = copy.userName;
|
||||
this.validDuration = copy.validDuration;
|
||||
this.guid = copy.guid;
|
||||
this.ticketId = copy.ticketId;
|
||||
this.sessionIds = sessionIds;
|
||||
}
|
||||
|
||||
Ticket(ExpiryMode expires, Date expiryDate, String userName, Duration validDuration, Set<String> sessionIds)
|
||||
{
|
||||
this.expires = expires;
|
||||
this.expiryDate = expiryDate;
|
||||
this.userName = userName;
|
||||
this.validDuration = validDuration;
|
||||
this.sessionIds = sessionIds;
|
||||
this.guid = UUIDGenerator.getInstance().generateRandomBasedUUID().toString();
|
||||
|
||||
String encode = (expires.toString()) + ((expiryDate == null) ? new Date().toString() : expiryDate.toString()) + userName + guid;
|
||||
MessageDigest digester;
|
||||
try
|
||||
{
|
||||
digester = MessageDigest.getInstance("SHA-1");
|
||||
this.ticketId = new String(Hex.encodeHex(digester.digest(encode.getBytes())));
|
||||
}
|
||||
catch (NoSuchAlgorithmException e)
|
||||
{
|
||||
try
|
||||
{
|
||||
digester = MessageDigest.getInstance("MD5");
|
||||
this.ticketId = new String(Hex.encodeHex(digester.digest(encode.getBytes())));
|
||||
}
|
||||
catch (NoSuchAlgorithmException e1)
|
||||
{
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(encode.getBytes());
|
||||
byte[] bytes = new byte[4];
|
||||
long value = crc.getValue();
|
||||
bytes[0] = (byte) (value & 0xFF);
|
||||
value >>>= 4;
|
||||
bytes[1] = (byte) (value & 0xFF);
|
||||
value >>>= 4;
|
||||
bytes[2] = (byte) (value & 0xFF);
|
||||
value >>>= 4;
|
||||
bytes[3] = (byte) (value & 0xFF);
|
||||
this.ticketId = new String(Hex.encodeHex(bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Ticket addSessionId(String sessionId)
|
||||
{
|
||||
if (this.sessionIds.contains(sessionId))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
Set<String> newSessionIds = new HashSet<String>(this.sessionIds.size() * 2 + 2);
|
||||
newSessionIds.addAll(this.sessionIds);
|
||||
newSessionIds.add(sessionId);
|
||||
return new Ticket(this, newSessionIds);
|
||||
}
|
||||
|
||||
public Ticket removeSessionId(String sessionId)
|
||||
{
|
||||
if (this.sessionIds.contains(sessionId))
|
||||
{
|
||||
Set<String> newSessionIds;
|
||||
if (this.sessionIds.size() > 1)
|
||||
{
|
||||
newSessionIds = new HashSet<String>(this.sessionIds.size() * 2 - 2);
|
||||
newSessionIds.addAll(this.sessionIds);
|
||||
newSessionIds.remove(sessionId);
|
||||
return new Ticket(this, newSessionIds);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the ticket expired
|
||||
*
|
||||
* @return - if expired
|
||||
*/
|
||||
boolean hasExpired()
|
||||
{
|
||||
switch (expires)
|
||||
{
|
||||
case AFTER_FIXED_TIME:
|
||||
if ((expiryDate != null) && (expiryDate.compareTo(new Date()) < 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
case AFTER_INACTIVITY:
|
||||
Date now = new Date();
|
||||
if ((expiryDate != null) && (expiryDate.compareTo(now) < 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
expiryDate = Duration.add(now, validDuration);
|
||||
return false;
|
||||
}
|
||||
|
||||
case DO_NOT_EXPIRE:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Ticket))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Ticket t = (Ticket) o;
|
||||
return (this.expires == t.expires) && this.expiryDate.equals(t.expiryDate) && this.userName.equals(t.userName) && this.ticketId.equals(t.ticketId);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return ticketId.hashCode();
|
||||
}
|
||||
|
||||
protected ExpiryMode getExpires()
|
||||
{
|
||||
return expires;
|
||||
}
|
||||
|
||||
protected Date getExpiryDate()
|
||||
{
|
||||
return expiryDate;
|
||||
}
|
||||
|
||||
protected String getTicketId()
|
||||
{
|
||||
return ticketId;
|
||||
}
|
||||
|
||||
protected String getUserName()
|
||||
{
|
||||
return userName;
|
||||
}
|
||||
|
||||
protected Set<String> getSessionIds()
|
||||
{
|
||||
return sessionIds;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Are tickets single use
|
||||
*
|
||||
* @param oneOff
|
||||
*/
|
||||
public void setOneOff(boolean oneOff)
|
||||
{
|
||||
this.oneOff = oneOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do tickets expire
|
||||
*
|
||||
* @param ticketsExpire
|
||||
*/
|
||||
public void setTicketsExpire(boolean ticketsExpire)
|
||||
{
|
||||
this.ticketsExpire = ticketsExpire;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* How should tickets expire.
|
||||
* @param exipryMode
|
||||
*/
|
||||
public void setExpiryMode(String expiryMode)
|
||||
{
|
||||
this.expiryMode = ExpiryMode.valueOf(expiryMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* How long are tickets valid (XML duration as a string)
|
||||
*
|
||||
* @param validDuration
|
||||
*/
|
||||
public void setValidDuration(String validDuration)
|
||||
{
|
||||
this.validDuration = new Duration(validDuration);
|
||||
}
|
||||
|
||||
public String getAuthorityForTicket(String ticketString)
|
||||
{
|
||||
Ticket ticket = getTicketByTicketString(ticketString);
|
||||
if (ticket == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return ticket.getUserName();
|
||||
}
|
||||
|
||||
public String getCurrentTicket(String userName, String sessionId, boolean autoCreate)
|
||||
{
|
||||
String ticketString = currentTicket.get();
|
||||
if (ticketString == null)
|
||||
{
|
||||
return autoCreate ? getNewTicket(userName, sessionId) : null;
|
||||
}
|
||||
String ticketKey = getTicketKey(ticketString);
|
||||
Ticket ticketObj = this.ticketsCache.get(ticketKey);
|
||||
if (ticketObj != null && userName.equals(ticketObj.getUserName()))
|
||||
{
|
||||
if (sessionId != null)
|
||||
{
|
||||
// A current, as yet unclaimed valid ticket. Make the association with the session now
|
||||
if (ticketObj.getSessionIds().isEmpty())
|
||||
{
|
||||
this.ticketsCache.put(ticketKey, ticketObj.addSessionId(sessionId));
|
||||
}
|
||||
// The ticket is already claimed by at least one other session, so start a new one
|
||||
else
|
||||
{
|
||||
return autoCreate ? getNewTicket(userName, sessionId) : null;
|
||||
}
|
||||
}
|
||||
return ticketString;
|
||||
}
|
||||
else
|
||||
{
|
||||
return autoCreate ? getNewTicket(userName, sessionId) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCurrentTicket()
|
||||
{
|
||||
clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
public static void clearCurrentSecurityContext()
|
||||
{
|
||||
currentTicket.set(null);
|
||||
}
|
||||
|
||||
public enum ExpiryMode
|
||||
{
|
||||
AFTER_INACTIVITY, AFTER_FIXED_TIME, DO_NOT_EXPIRE;
|
||||
}
|
||||
}
|
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Manage authentication tickets
|
||||
*
|
||||
* @author andyh
|
||||
*
|
||||
*/
|
||||
public interface TicketComponent
|
||||
{
|
||||
/**
|
||||
* Register a new ticket. If a session ID is given, an association with that session ID will be recorded for the
|
||||
* returned ticket.
|
||||
*
|
||||
* @param userName
|
||||
* @param sessionId
|
||||
* the app server session ID (e.g. HttpSession ID) or <code>null</code> if not applicable.
|
||||
* @return - the ticket
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public String getNewTicket(String userName, String sessionId) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Gets the current ticket. If a session ID is given, an association with that session ID will be recorded for the
|
||||
* returned ticket.
|
||||
*
|
||||
* @param userName
|
||||
* @param sessionId
|
||||
* the app server session ID (e.g. HttpSession ID) or <code>null</code> if not applicable.
|
||||
* @param autoCreate
|
||||
* should we create one automatically if there isn't one?
|
||||
* @return - the ticket
|
||||
*/
|
||||
public String getCurrentTicket(String userName, String sessionId, boolean autoCreate);
|
||||
|
||||
/**
|
||||
* Check that a certificate is valid and can be used in place of a login. Optionally records an association between
|
||||
* the ticket and a given app server session Id. This is so that we don't expire tickets prematurely referenced by
|
||||
* more than one application server session. Tickets may be rejected because:
|
||||
* <ol>
|
||||
* <li>The certificate does not exists
|
||||
* <li>The status of the user has changed
|
||||
* <ol>
|
||||
* <li>The user is locked
|
||||
* <li>The account has expired
|
||||
* <li>The credentials have expired
|
||||
* <li>The account is disabled
|
||||
* </ol>
|
||||
* <li>The ticket may have expired
|
||||
* <ol>
|
||||
* <li>The ticked my be invalid by timed expiry
|
||||
* <li>An attemp to reuse a once only ticket
|
||||
* </ol>
|
||||
* </ol>
|
||||
*
|
||||
* @param ticket
|
||||
* @param sessionId
|
||||
* the app server session ID (e.g. HttpSession ID) or <code>null</code> if not applicable.
|
||||
* @return - the user name
|
||||
* @throws AuthenticationException
|
||||
*/
|
||||
public String validateTicket(String ticket, String sessionId) throws AuthenticationException;
|
||||
|
||||
/**
|
||||
* Invalidates a ticket, or disassociates it from an app server session. Once it has been disassociated from all
|
||||
* sessions, the ticket will be invalidated globally.
|
||||
*
|
||||
* @param ticket
|
||||
* @param sessionId
|
||||
* the app server session ID (e.g. HttpSession ID) or <code>null</code> if the ticket should be
|
||||
* invalidated globally.
|
||||
*/
|
||||
public void invalidateTicketById(String ticket, String sessionId);
|
||||
|
||||
/**
|
||||
* Invalidate all user tickets
|
||||
*
|
||||
* @param userName
|
||||
*/
|
||||
public void invalidateTicketByUser(String userName);
|
||||
|
||||
/**
|
||||
* Count tickets
|
||||
*
|
||||
* This may be higher than the user count, since a user can have more than one ticket/session
|
||||
*
|
||||
* @param nonExpiredOnly true for non expired tickets, false for all (including expired) tickets
|
||||
* @return int number of tickets
|
||||
*/
|
||||
public int countTickets(boolean nonExpiredOnly);
|
||||
|
||||
/**
|
||||
* Get set of users with tickets
|
||||
*
|
||||
* This may be lower than the ticket count, since a user can have more than one ticket/session
|
||||
*
|
||||
* @param nonExpiredOnly true for non expired tickets, false for all (including expired) tickets
|
||||
* @return Set<String> set of users with (one or more) tickets
|
||||
*/
|
||||
public Set<String> getUsersWithTickets(boolean nonExpiredOnly);
|
||||
|
||||
/**
|
||||
* Invalidate tickets
|
||||
*
|
||||
* @param expiredOnly true for EXPIRED tickets, false for ALL (including non-expired) tickets
|
||||
* @return int count of invalidated tickets
|
||||
*/
|
||||
public int invalidateTickets(boolean expiredOnly);
|
||||
|
||||
/**
|
||||
* Get the authority for the given ticket
|
||||
*
|
||||
* @param ticket
|
||||
* @return the authority
|
||||
*/
|
||||
public String getAuthorityForTicket(String ticket);
|
||||
|
||||
/**
|
||||
* Clear the current ticket
|
||||
*
|
||||
*/
|
||||
public void clearCurrentTicket();
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
||||
*
|
||||
* This file is part of Alfresco
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.repo.security.authentication;
|
||||
|
||||
public class TicketExpiredException extends AuthenticationException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3257572801815590969L;
|
||||
|
||||
public TicketExpiredException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public TicketExpiredException(String msg, Throwable cause)
|
||||
{
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user