mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-16 17:55:15 +00:00
Merged V2.0 to HEAD
5523: Merged V1.4 to V2.0 5494: db.schema.update=false disables ALL metadata queries 5500: AR-1399 NTProtocolHander search handle leakage 5522: AR-1412 IndexRemoteTransactionTracker startup 5541: Merged V1.4 to V2.0 5525: Pass-through authentication and domain mapping Resolved minor conflict on AlfrescoAuthenticator.java 5526: Domain mapping support git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5546 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
parent
08897ad76b
commit
fb1dd4080b
@ -39,8 +39,11 @@
|
|||||||
<!-- Forces the reindexing of nodes where content may have been missing before -->
|
<!-- Forces the reindexing of nodes where content may have been missing before -->
|
||||||
<!--
|
<!--
|
||||||
This component can be triggered at intervals where asynchronous content sharing
|
This component can be triggered at intervals where asynchronous content sharing
|
||||||
between clustered servers has been set up.
|
between clustered servers has been set up. If content sharing is synchronous
|
||||||
|
(see ReplicatingContentStore.setOutboundThreadPoolExecutor) then this component
|
||||||
|
is not required.
|
||||||
-->
|
-->
|
||||||
|
<!--
|
||||||
<bean id="missingContentReindexTrigger" class="org.alfresco.util.TriggerBean">
|
<bean id="missingContentReindexTrigger" class="org.alfresco.util.TriggerBean">
|
||||||
<property name="jobDetail">
|
<property name="jobDetail">
|
||||||
<bean class="org.springframework.scheduling.quartz.JobDetailBean">
|
<bean class="org.springframework.scheduling.quartz.JobDetailBean">
|
||||||
@ -59,7 +62,6 @@
|
|||||||
<property name="scheduler">
|
<property name="scheduler">
|
||||||
<ref bean="schedulerFactory" />
|
<ref bean="schedulerFactory" />
|
||||||
</property>
|
</property>
|
||||||
<!-- Give the server 5 minutes and then check for missing content -->
|
|
||||||
<property name="startDelayMinutes">
|
<property name="startDelayMinutes">
|
||||||
<value>5</value>
|
<value>5</value>
|
||||||
</property>
|
</property>
|
||||||
@ -67,5 +69,6 @@
|
|||||||
<value>0</value>
|
<value>0</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
-->
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Schema update messages
|
# Schema update messages
|
||||||
|
|
||||||
|
schema.update.msg.bypassing=Bypassing schema update checks.
|
||||||
schema.update.msg.executing_script=Executing database script: {0}
|
schema.update.msg.executing_script=Executing database script: {0}
|
||||||
schema.update.msg.optional_statement_failed=Optional statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3}
|
schema.update.msg.optional_statement_failed=Optional statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3}
|
||||||
schema.update.msg.dumping_schema_create=Generating unmodified schema creation script: {0}
|
schema.update.msg.dumping_schema_create=Generating unmodified schema creation script: {0}
|
||||||
|
@ -245,7 +245,7 @@ public class AlfrescoAuthenticator extends CifsAuthenticator
|
|||||||
{
|
{
|
||||||
// Create an authentication token for the session
|
// Create an authentication token for the session
|
||||||
|
|
||||||
NTLMPassthruToken authToken = new NTLMPassthruToken();
|
NTLMPassthruToken authToken = new NTLMPassthruToken( mapClientAddressToDomain( sess.getRemoteAddress()));
|
||||||
|
|
||||||
// Run the first stage of the passthru authentication to get the challenge
|
// Run the first stage of the passthru authentication to get the challenge
|
||||||
|
|
||||||
|
@ -24,8 +24,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.filesys.server.auth;
|
package org.alfresco.filesys.server.auth;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
@ -33,7 +36,11 @@ import javax.transaction.UserTransaction;
|
|||||||
import net.sf.acegisecurity.Authentication;
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
|
||||||
import org.alfresco.config.ConfigElement;
|
import org.alfresco.config.ConfigElement;
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.filesys.server.SrvSession;
|
import org.alfresco.filesys.server.SrvSession;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.DomainMapping;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.RangeDomainMapping;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.SubnetDomainMapping;
|
||||||
import org.alfresco.filesys.server.config.InvalidConfigurationException;
|
import org.alfresco.filesys.server.config.InvalidConfigurationException;
|
||||||
import org.alfresco.filesys.server.config.ServerConfiguration;
|
import org.alfresco.filesys.server.config.ServerConfiguration;
|
||||||
import org.alfresco.filesys.server.core.SharedDevice;
|
import org.alfresco.filesys.server.core.SharedDevice;
|
||||||
@ -53,6 +60,7 @@ import org.alfresco.filesys.smb.server.VirtualCircuit;
|
|||||||
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
import org.alfresco.filesys.smb.server.repo.ContentContext;
|
||||||
import org.alfresco.filesys.util.DataPacker;
|
import org.alfresco.filesys.util.DataPacker;
|
||||||
import org.alfresco.filesys.util.HexDump;
|
import org.alfresco.filesys.util.HexDump;
|
||||||
|
import org.alfresco.filesys.util.IPAddress;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
|
import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
|
||||||
@ -969,4 +977,44 @@ public abstract class CifsAuthenticator
|
|||||||
m_authComponent.setGuestUserAsCurrentUser();
|
m_authComponent.setGuestUserAsCurrentUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a client IP address to a domain
|
||||||
|
*
|
||||||
|
* @param clientIP InetAddress
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
protected final String mapClientAddressToDomain( InetAddress clientIP)
|
||||||
|
{
|
||||||
|
// Check if there are any domain mappings
|
||||||
|
|
||||||
|
if ( m_config.hasDomainMappings() == false)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// convert the client IP address to an integer value
|
||||||
|
|
||||||
|
int clientAddr = IPAddress.asInteger( clientIP);
|
||||||
|
for ( DomainMapping domainMap : m_config.getDomainMappings())
|
||||||
|
{
|
||||||
|
if ( domainMap.isMemberOfDomain( clientAddr))
|
||||||
|
{
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug( "Mapped client IP " + clientIP + " to domain " + domainMap.getDomain());
|
||||||
|
|
||||||
|
return domainMap.getDomain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug( "Failed to map client IP " + clientIP + " to a domain");
|
||||||
|
|
||||||
|
// No domain mapping for the client address
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1119,6 +1119,8 @@ public class AuthenticateSession
|
|||||||
|
|
||||||
if (getPCShare().hasDomain())
|
if (getPCShare().hasDomain())
|
||||||
pkt.packString(getPCShare().getDomain(), false);
|
pkt.packString(getPCShare().getDomain(), false);
|
||||||
|
else if ( domain != null)
|
||||||
|
pkt.packString( domain, false);
|
||||||
else
|
else
|
||||||
pkt.packString("?", false);
|
pkt.packString("?", false);
|
||||||
|
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 Alfresco, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Mozilla Public License version 1.1
|
||||||
|
* with a permitted attribution clause. You may obtain a
|
||||||
|
* copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.alfresco.org/legal/license.txt
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||||
|
* either express or implied. See the License for the specific
|
||||||
|
* language governing permissions and limitations under the
|
||||||
|
* License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.filesys.server.auth.passthru;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain Mapping Class
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public abstract class DomainMapping {
|
||||||
|
|
||||||
|
// Domain name
|
||||||
|
|
||||||
|
private String m_domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class consructor
|
||||||
|
*
|
||||||
|
* @param domain String
|
||||||
|
*/
|
||||||
|
public DomainMapping( String domain)
|
||||||
|
{
|
||||||
|
m_domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain name
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getDomain()
|
||||||
|
{
|
||||||
|
return m_domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client address is a member of this domain
|
||||||
|
*
|
||||||
|
* @param clientIP int
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public abstract boolean isMemberOfDomain( int clientIP);
|
||||||
|
}
|
@ -358,7 +358,11 @@ public class PassthruAuthenticator extends CifsAuthenticator implements SessionL
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AuthenticateSession authSess = m_passthruServers.openSession();
|
// Try and map the client address to a domain
|
||||||
|
|
||||||
|
String domain = mapClientAddressToDomain( sess.getRemoteAddress());
|
||||||
|
|
||||||
|
AuthenticateSession authSess = m_passthruServers.openSession( false, domain);
|
||||||
if (authSess != null)
|
if (authSess != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -126,6 +126,16 @@ public class PassthruServerDetails
|
|||||||
return m_lastAuthTime;
|
return m_lastAuthTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the domain that the offline server belongs to
|
||||||
|
*
|
||||||
|
* @param domain String
|
||||||
|
*/
|
||||||
|
public final void setDomain(String domain)
|
||||||
|
{
|
||||||
|
m_domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the online status for the server
|
* Set the online status for the server
|
||||||
*
|
*
|
||||||
|
@ -306,27 +306,34 @@ public class PassthruServers
|
|||||||
*/
|
*/
|
||||||
public final AuthenticateSession openSession()
|
public final AuthenticateSession openSession()
|
||||||
{
|
{
|
||||||
return openSession( false);
|
return openSession( false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a new session to an authentication server
|
* Open a new session to an authentication server
|
||||||
*
|
*
|
||||||
* @param useExtSec boolean
|
* @param useExtSec boolean
|
||||||
|
* @param clientDomain String
|
||||||
* @return AuthenticateSession
|
* @return AuthenticateSession
|
||||||
*/
|
*/
|
||||||
public final AuthenticateSession openSession(boolean useExtSec)
|
public final AuthenticateSession openSession(boolean useExtSec, String clientDomain)
|
||||||
{
|
{
|
||||||
// Get the details of an authentication server to connect to
|
// Get the details of an authentication server to connect to
|
||||||
|
|
||||||
|
PassthruServerDetails passthruServer = null;
|
||||||
|
|
||||||
|
if ( clientDomain != null)
|
||||||
|
passthruServer = getAuthenticationServer( clientDomain);
|
||||||
|
else
|
||||||
|
passthruServer = getAuthenticationServer();
|
||||||
|
|
||||||
PassthruServerDetails passthruServer = getAuthenticationServer();
|
|
||||||
if ( passthruServer == null)
|
if ( passthruServer == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
if ( logger.isDebugEnabled())
|
if ( logger.isDebugEnabled())
|
||||||
logger.debug("Open authenticate session to " + passthruServer);
|
logger.debug("Open authenticate session to " + passthruServer + ( clientDomain != null ? " (routed for client domain " + clientDomain + ")" : ""));
|
||||||
|
|
||||||
// Open a new authentication session to the server
|
// Open a new authentication session to the server
|
||||||
|
|
||||||
@ -402,6 +409,49 @@ public class PassthruServers
|
|||||||
return passthruServer;
|
return passthruServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the details of an online server to use for authentication of the specified client
|
||||||
|
* domain
|
||||||
|
*
|
||||||
|
* @params clientDomain String
|
||||||
|
* @return PassthruServerDetails
|
||||||
|
*/
|
||||||
|
protected PassthruServerDetails getAuthenticationServer( String clientDomain)
|
||||||
|
{
|
||||||
|
// Rotate the head of the list and return the new head of list server details
|
||||||
|
|
||||||
|
PassthruServerDetails passthruServer = null;
|
||||||
|
|
||||||
|
synchronized ( m_onlineList)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
while ( idx < m_onlineList.size() && passthruServer == null)
|
||||||
|
{
|
||||||
|
// Get the current passthru server details
|
||||||
|
|
||||||
|
PassthruServerDetails curServer = m_onlineList.get( idx);
|
||||||
|
|
||||||
|
if ( curServer.getDomain() != null && curServer.getDomain().equals( clientDomain))
|
||||||
|
{
|
||||||
|
// Use this passthru server
|
||||||
|
|
||||||
|
passthruServer = curServer;
|
||||||
|
|
||||||
|
// Move to the back of the list
|
||||||
|
|
||||||
|
m_onlineList.add( m_onlineList.remove( idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the server index
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return passthruServer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move a server from the list of online servers to the offline list
|
* Move a server from the list of online servers to the offline list
|
||||||
*
|
*
|
||||||
@ -502,6 +552,17 @@ public class PassthruServers
|
|||||||
|
|
||||||
String srvName = tokens.nextToken().trim();
|
String srvName = tokens.nextToken().trim();
|
||||||
|
|
||||||
|
// Check if the server address also contains a domain name
|
||||||
|
|
||||||
|
String domain = null;
|
||||||
|
int pos = srvName.indexOf( '\\');
|
||||||
|
|
||||||
|
if ( pos != -1)
|
||||||
|
{
|
||||||
|
domain = srvName.substring(0, pos);
|
||||||
|
srvName = srvName.substring( pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
// If a name a has been specified convert it to an address, if an address has been specified
|
// If a name a has been specified convert it to an address, if an address has been specified
|
||||||
// then convert to a name.
|
// then convert to a name.
|
||||||
|
|
||||||
@ -549,7 +610,7 @@ public class PassthruServers
|
|||||||
{
|
{
|
||||||
// Create the passthru server details
|
// Create the passthru server details
|
||||||
|
|
||||||
PassthruServerDetails passthruServer = new PassthruServerDetails(srvName, null, srvAddr, false);
|
PassthruServerDetails passthruServer = new PassthruServerDetails(srvName, domain, srvAddr, false);
|
||||||
m_offlineList.add( passthruServer);
|
m_offlineList.add( passthruServer);
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 Alfresco, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Mozilla Public License version 1.1
|
||||||
|
* with a permitted attribution clause. You may obtain a
|
||||||
|
* copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.alfresco.org/legal/license.txt
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||||
|
* either express or implied. See the License for the specific
|
||||||
|
* language governing permissions and limitations under the
|
||||||
|
* License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.filesys.server.auth.passthru;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.util.IPAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address Range Domain Mapping Class
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class RangeDomainMapping extends DomainMapping {
|
||||||
|
|
||||||
|
// Range from/to addresses
|
||||||
|
|
||||||
|
private int m_rangeFrom;
|
||||||
|
private int m_rangeTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class constructor
|
||||||
|
*
|
||||||
|
* @param domain String
|
||||||
|
* @param rangeFrom int
|
||||||
|
* @param rangeTo int
|
||||||
|
*/
|
||||||
|
public RangeDomainMapping( String domain, int rangeFrom, int rangeTo)
|
||||||
|
{
|
||||||
|
super( domain);
|
||||||
|
|
||||||
|
m_rangeFrom = rangeFrom;
|
||||||
|
m_rangeTo = rangeTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the from range address
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getRangeFrom()
|
||||||
|
{
|
||||||
|
return m_rangeFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the to range address
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getRangeTo()
|
||||||
|
{
|
||||||
|
return m_rangeTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client address is a member of this domain
|
||||||
|
*
|
||||||
|
* @param clientIP int
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isMemberOfDomain( int clientIP)
|
||||||
|
{
|
||||||
|
if (clientIP >= m_rangeFrom && clientIP <= m_rangeTo)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain mapping as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
str.append("[");
|
||||||
|
str.append(getDomain());
|
||||||
|
str.append(",");
|
||||||
|
str.append(IPAddress.asString( getRangeFrom()));
|
||||||
|
str.append(":");
|
||||||
|
str.append(IPAddress.asString( getRangeTo()));
|
||||||
|
str.append("]");
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 Alfresco, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Mozilla Public License version 1.1
|
||||||
|
* with a permitted attribution clause. You may obtain a
|
||||||
|
* copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.alfresco.org/legal/license.txt
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||||
|
* either express or implied. See the License for the specific
|
||||||
|
* language governing permissions and limitations under the
|
||||||
|
* License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.filesys.server.auth.passthru;
|
||||||
|
|
||||||
|
import org.alfresco.filesys.util.IPAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subnet Domain Mapping Class
|
||||||
|
*
|
||||||
|
* @author gkspencer
|
||||||
|
*/
|
||||||
|
public class SubnetDomainMapping extends DomainMapping {
|
||||||
|
|
||||||
|
// Subnet and mask for the domain
|
||||||
|
|
||||||
|
private int m_subnet;
|
||||||
|
private int m_mask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class constructor
|
||||||
|
*
|
||||||
|
* @param domain String
|
||||||
|
* @param subnet int
|
||||||
|
* @param mask int
|
||||||
|
*/
|
||||||
|
public SubnetDomainMapping( String domain, int subnet, int mask)
|
||||||
|
{
|
||||||
|
super( domain);
|
||||||
|
|
||||||
|
m_subnet = subnet;
|
||||||
|
m_mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the subnet
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getSubnet()
|
||||||
|
{
|
||||||
|
return m_subnet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the subnet mask
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public final int getSubnetMask()
|
||||||
|
{
|
||||||
|
return m_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client address is a member of this domain
|
||||||
|
*
|
||||||
|
* @param clientIP int
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isMemberOfDomain( int clientIP)
|
||||||
|
{
|
||||||
|
if (( clientIP & m_mask) == m_subnet)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain mapping as a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
str.append("[");
|
||||||
|
str.append(getDomain());
|
||||||
|
str.append(",");
|
||||||
|
str.append(IPAddress.asString( getSubnet()));
|
||||||
|
str.append(":");
|
||||||
|
str.append(IPAddress.asString( getSubnetMask()));
|
||||||
|
str.append("]");
|
||||||
|
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -75,6 +75,9 @@ import org.alfresco.filesys.server.auth.acl.AccessControlManager;
|
|||||||
import org.alfresco.filesys.server.auth.acl.AccessControlParser;
|
import org.alfresco.filesys.server.auth.acl.AccessControlParser;
|
||||||
import org.alfresco.filesys.server.auth.acl.DefaultAccessControlManager;
|
import org.alfresco.filesys.server.auth.acl.DefaultAccessControlManager;
|
||||||
import org.alfresco.filesys.server.auth.acl.InvalidACLTypeException;
|
import org.alfresco.filesys.server.auth.acl.InvalidACLTypeException;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.DomainMapping;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.RangeDomainMapping;
|
||||||
|
import org.alfresco.filesys.server.auth.passthru.SubnetDomainMapping;
|
||||||
import org.alfresco.filesys.server.core.DeviceContext;
|
import org.alfresco.filesys.server.core.DeviceContext;
|
||||||
import org.alfresco.filesys.server.core.DeviceContextException;
|
import org.alfresco.filesys.server.core.DeviceContextException;
|
||||||
import org.alfresco.filesys.server.core.ShareMapper;
|
import org.alfresco.filesys.server.core.ShareMapper;
|
||||||
@ -402,6 +405,10 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
|||||||
private PersonService m_personService;
|
private PersonService m_personService;
|
||||||
private TransactionService m_transactionService;
|
private TransactionService m_transactionService;
|
||||||
|
|
||||||
|
// Domain mappings, by subnet
|
||||||
|
|
||||||
|
private List<DomainMapping> m_domainMappings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*/
|
*/
|
||||||
@ -2260,6 +2267,75 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
|||||||
setJCEProvider("cryptix.jce.provider.CryptixCrypto");
|
setJCEProvider("cryptix.jce.provider.CryptixCrypto");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if any domain mappings have been specified
|
||||||
|
|
||||||
|
ConfigElement domainMappings = config.getConfigElement( "DomainMappings");
|
||||||
|
if ( domainMappings != null)
|
||||||
|
{
|
||||||
|
// Get the domain mapping elements
|
||||||
|
|
||||||
|
List<ConfigElement> mappings = domainMappings.getChildren();
|
||||||
|
if ( mappings != null)
|
||||||
|
{
|
||||||
|
DomainMapping mapping = null;
|
||||||
|
|
||||||
|
for ( ConfigElement domainMap : mappings)
|
||||||
|
{
|
||||||
|
if ( domainMap.getName().equals( "Domain"))
|
||||||
|
{
|
||||||
|
// Get the domain name
|
||||||
|
|
||||||
|
String name = domainMap.getAttribute( "name");
|
||||||
|
|
||||||
|
// Check if the domain is specified by subnet or range
|
||||||
|
|
||||||
|
if ( domainMap.hasAttribute( "subnet"))
|
||||||
|
{
|
||||||
|
String subnetStr = domainMap.getAttribute( "subnet");
|
||||||
|
String maskStr = domainMap.getAttribute( "mask");
|
||||||
|
|
||||||
|
// Parse the subnet and mask, to validate and convert to int values
|
||||||
|
|
||||||
|
int subnet = IPAddress.parseNumericAddress( subnetStr);
|
||||||
|
int mask = IPAddress.parseNumericAddress( maskStr);
|
||||||
|
|
||||||
|
if ( subnet == 0 || mask == 0)
|
||||||
|
throw new AlfrescoRuntimeException( "Invalid subnet/mask for domain mapping " + name);
|
||||||
|
|
||||||
|
// Create the subnet domain mapping
|
||||||
|
|
||||||
|
mapping = new SubnetDomainMapping( name, subnet, mask);
|
||||||
|
}
|
||||||
|
else if ( domainMap.hasAttribute( "rangeFrom"))
|
||||||
|
{
|
||||||
|
String rangeFromStr = domainMap.getAttribute( "rangeFrom");
|
||||||
|
String rangeToStr = domainMap.getAttribute( "rangeTo");
|
||||||
|
|
||||||
|
// Parse the range from/to values and convert to int values
|
||||||
|
|
||||||
|
int rangeFrom = IPAddress.parseNumericAddress( rangeFromStr);
|
||||||
|
int rangeTo = IPAddress.parseNumericAddress( rangeToStr);
|
||||||
|
|
||||||
|
if ( rangeFrom == 0 || rangeTo == 0)
|
||||||
|
throw new AlfrescoRuntimeException( "Invalid address range domain mapping " + name);
|
||||||
|
|
||||||
|
// Create the subnet domain mapping
|
||||||
|
|
||||||
|
mapping = new RangeDomainMapping( name, rangeFrom, rangeTo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new AlfrescoRuntimeException( "Invalid domain mapping specified");
|
||||||
|
|
||||||
|
// Create the domain mapping
|
||||||
|
|
||||||
|
if ( m_domainMappings == null)
|
||||||
|
m_domainMappings = new ArrayList<DomainMapping>();
|
||||||
|
m_domainMappings.add( mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if an authenticator has been specified
|
// Check if an authenticator has been specified
|
||||||
|
|
||||||
ConfigElement authElem = config.getConfigElement("authenticator");
|
ConfigElement authElem = config.getConfigElement("authenticator");
|
||||||
@ -3197,6 +3273,26 @@ public class ServerConfiguration extends AbstractLifecycleBean
|
|||||||
return domainName;
|
return domainName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there are domain mappings
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasDomainMappings()
|
||||||
|
{
|
||||||
|
return m_domainMappings != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the domain mappings
|
||||||
|
*
|
||||||
|
* @return List<DomainMapping>
|
||||||
|
*/
|
||||||
|
public final List<DomainMapping> getDomainMappings()
|
||||||
|
{
|
||||||
|
return m_domainMappings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the primary filesystem shared device, or null if not available
|
* Return the primary filesystem shared device, or null if not available
|
||||||
*
|
*
|
||||||
|
@ -3414,7 +3414,6 @@ public class NTProtocolHandler extends CoreProtocolHandler
|
|||||||
|
|
||||||
if (searchDone == true || ctx.hasMoreFiles() == false)
|
if (searchDone == true || ctx.hasMoreFiles() == false)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
|
if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
|
||||||
@ -3422,6 +3421,17 @@ public class NTProtocolHandler extends CoreProtocolHandler
|
|||||||
|
|
||||||
// Release the search context
|
// Release the search context
|
||||||
|
|
||||||
|
vc.deallocateSearchSlot(searchId);
|
||||||
|
}
|
||||||
|
else if (( srchFlag & FindFirstNext.CloseSearch) != 0)
|
||||||
|
{
|
||||||
|
// Debug
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
|
||||||
|
logger.debug("End start search [" + searchId + "] (Close)");
|
||||||
|
|
||||||
|
// Release the search context
|
||||||
|
|
||||||
vc.deallocateSearchSlot(searchId);
|
vc.deallocateSearchSlot(searchId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3677,6 +3687,17 @@ public class NTProtocolHandler extends CoreProtocolHandler
|
|||||||
|
|
||||||
// Release the search context
|
// Release the search context
|
||||||
|
|
||||||
|
vc.deallocateSearchSlot(searchId);
|
||||||
|
}
|
||||||
|
else if (( srchFlag & FindFirstNext.CloseSearch) != 0)
|
||||||
|
{
|
||||||
|
// Debug
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled() && m_sess.hasDebug(SMBSrvSession.DBG_SEARCH))
|
||||||
|
logger.debug("End start search [" + searchId + "] (Close)");
|
||||||
|
|
||||||
|
// Release the search context
|
||||||
|
|
||||||
vc.deallocateSearchSlot(searchId);
|
vc.deallocateSearchSlot(searchId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,6 +181,23 @@ public class IPAddress
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a raw IP address array as a String
|
||||||
|
*
|
||||||
|
* @param ipaddr int
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final static String asString(int ipaddr)
|
||||||
|
{
|
||||||
|
byte[] ipbyts = new byte[4];
|
||||||
|
ipbyts[0] = (byte) ((ipaddr >> 24) & 0xFF);
|
||||||
|
ipbyts[1] = (byte) ((ipaddr >> 16) & 0xFF);
|
||||||
|
ipbyts[2] = (byte) ((ipaddr >> 8) & 0xFF);
|
||||||
|
ipbyts[3] = (byte) (ipaddr & 0xFF);
|
||||||
|
|
||||||
|
return asString( ipbyts);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a raw IP address array as a String
|
* Convert a raw IP address array as a String
|
||||||
*
|
*
|
||||||
|
@ -78,6 +78,17 @@
|
|||||||
join status.transaction as txn
|
join status.transaction as txn
|
||||||
</query>
|
</query>
|
||||||
|
|
||||||
|
<query name="txn.GetLastRemoteTxnId">
|
||||||
|
select
|
||||||
|
max(txn.id)
|
||||||
|
from
|
||||||
|
org.alfresco.repo.domain.hibernate.NodeStatusImpl as status
|
||||||
|
join status.transaction as txn
|
||||||
|
join txn.server as server
|
||||||
|
where
|
||||||
|
server.ipAddress != :serverIpAddress
|
||||||
|
</query>
|
||||||
|
|
||||||
<query name="txn.CountTransactions">
|
<query name="txn.CountTransactions">
|
||||||
select
|
select
|
||||||
count(txn.id)
|
count(txn.id)
|
||||||
|
@ -82,6 +82,7 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
|||||||
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
|
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
|
||||||
private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
|
private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
|
||||||
|
|
||||||
|
private static final String MSG_BYPASSING_SCHEMA_UPDATE = "schema.update.msg.bypassing";
|
||||||
private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script";
|
private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script";
|
||||||
private static final String MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed";
|
private static final String MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed";
|
||||||
private static final String MSG_DUMPING_SCHEMA_CREATE = "schema.update.msg.dumping_schema_create";
|
private static final String MSG_DUMPING_SCHEMA_CREATE = "schema.update.msg.dumping_schema_create";
|
||||||
@ -650,12 +651,16 @@ public class SchemaBootstrap extends AbstractLifecycleBean
|
|||||||
if (updateSchema)
|
if (updateSchema)
|
||||||
{
|
{
|
||||||
updateSchema(cfg, session, connection);
|
updateSchema(cfg, session, connection);
|
||||||
}
|
|
||||||
|
|
||||||
// verify that all patches have been applied correctly
|
// verify that all patches have been applied correctly
|
||||||
checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts
|
checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts
|
||||||
checkSchemaPatchScripts(cfg, session, connection, preUpdateScriptPatches, false); // check scripts
|
checkSchemaPatchScripts(cfg, session, connection, preUpdateScriptPatches, false); // check scripts
|
||||||
checkSchemaPatchScripts(cfg, session, connection, postUpdateScriptPatches, false); // check scripts
|
checkSchemaPatchScripts(cfg, session, connection, postUpdateScriptPatches, false); // check scripts
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.info(I18NUtil.getMessage(MSG_BYPASSING_SCHEMA_UPDATE));
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the configuration
|
// Reset the configuration
|
||||||
cfg.setProperty(Environment.CONNECTION_PROVIDER, defaultConnectionProviderFactoryClass);
|
cfg.setProperty(Environment.CONNECTION_PROVIDER, defaultConnectionProviderFactoryClass);
|
||||||
|
@ -277,6 +277,7 @@ public interface NodeDaoService
|
|||||||
|
|
||||||
public Transaction getTxnById(long txnId);
|
public Transaction getTxnById(long txnId);
|
||||||
public Transaction getLastTxn();
|
public Transaction getLastTxn();
|
||||||
|
public Transaction getLastRemoteTxn();
|
||||||
public Transaction getLastTxnForStore(final StoreRef storeRef);
|
public Transaction getLastTxnForStore(final StoreRef storeRef);
|
||||||
public int getTxnUpdateCount(final long txnId);
|
public int getTxnUpdateCount(final long txnId);
|
||||||
public int getTxnDeleteCount(final long txnId);
|
public int getTxnDeleteCount(final long txnId);
|
||||||
|
@ -1185,6 +1185,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
* Queries for transactions
|
* Queries for transactions
|
||||||
*/
|
*/
|
||||||
private static final String QUERY_GET_LAST_TXN_ID = "txn.GetLastTxnId";
|
private static final String QUERY_GET_LAST_TXN_ID = "txn.GetLastTxnId";
|
||||||
|
private static final String QUERY_GET_LAST_REMOTE_TXN_ID = "txn.GetLastRemoteTxnId";
|
||||||
private static final String QUERY_GET_LAST_TXN_ID_FOR_STORE = "txn.GetLastTxnIdForStore";
|
private static final String QUERY_GET_LAST_TXN_ID_FOR_STORE = "txn.GetLastTxnIdForStore";
|
||||||
private static final String QUERY_GET_TXN_UPDATE_COUNT_FOR_STORE = "txn.GetTxnUpdateCountForStore";
|
private static final String QUERY_GET_TXN_UPDATE_COUNT_FOR_STORE = "txn.GetTxnUpdateCountForStore";
|
||||||
private static final String QUERY_GET_TXN_DELETE_COUNT_FOR_STORE = "txn.GetTxnDeleteCountForStore";
|
private static final String QUERY_GET_TXN_DELETE_COUNT_FOR_STORE = "txn.GetTxnDeleteCountForStore";
|
||||||
@ -1222,6 +1223,30 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
|
|||||||
return txn;
|
return txn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Transaction getLastRemoteTxn()
|
||||||
|
{
|
||||||
|
HibernateCallback callback = new HibernateCallback()
|
||||||
|
{
|
||||||
|
public Object doInHibernate(Session session)
|
||||||
|
{
|
||||||
|
Query query = session.getNamedQuery(QUERY_GET_LAST_REMOTE_TXN_ID);
|
||||||
|
query.setString("serverIpAddress", ipAddress)
|
||||||
|
.setMaxResults(1)
|
||||||
|
.setReadOnly(true);
|
||||||
|
return query.uniqueResult();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Long txnId = (Long) getHibernateTemplate().execute(callback);
|
||||||
|
Transaction txn = null;
|
||||||
|
if (txnId != null)
|
||||||
|
{
|
||||||
|
txn = (Transaction) getSession().get(TransactionImpl.class, txnId);
|
||||||
|
}
|
||||||
|
// done
|
||||||
|
return txn;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Transaction getLastTxnForStore(final StoreRef storeRef)
|
public Transaction getLastTxnForStore(final StoreRef storeRef)
|
||||||
{
|
{
|
||||||
|
@ -243,36 +243,18 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected enum InIndex
|
||||||
* Gets the last indexed transaction working back from the provided index.
|
|
||||||
* This method can be used to hunt for a starting point for indexing of
|
|
||||||
* transactions not yet in the index.
|
|
||||||
*/
|
|
||||||
protected long getLastIndexedTxn(long lastTxnId)
|
|
||||||
{
|
{
|
||||||
// get the last transaction
|
YES, NO, INDETERMINATE;
|
||||||
long lastFoundTxnId = lastTxnId + 10L;
|
|
||||||
boolean found = false;
|
|
||||||
while (!found && lastFoundTxnId >= 0)
|
|
||||||
{
|
|
||||||
// reduce the transaction ID
|
|
||||||
lastFoundTxnId = lastFoundTxnId - 10L;
|
|
||||||
// break out as soon as we find a transaction that is in the index
|
|
||||||
found = isTxnIdPresentInIndex(lastFoundTxnId);
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// done
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
logger.debug("Found last index txn before " + lastTxnId + ": " + lastFoundTxnId);
|
|
||||||
}
|
|
||||||
return lastFoundTxnId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isTxnIdPresentInIndex(long txnId)
|
/**
|
||||||
|
* Determines if a given transaction is definitely in the index or not.
|
||||||
|
*
|
||||||
|
* @param txnId a specific transaction
|
||||||
|
* @return Returns <tt>true</tt> if the transaction is definitely in the index
|
||||||
|
*/
|
||||||
|
protected InIndex isTxnIdPresentInIndex(long txnId)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
@ -282,7 +264,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
Transaction txn = nodeDaoService.getTxnById(txnId);
|
Transaction txn = nodeDaoService.getTxnById(txnId);
|
||||||
if (txn == null)
|
if (txn == null)
|
||||||
{
|
{
|
||||||
return true;
|
return InIndex.YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
// count the changes in the transaction
|
// count the changes in the transaction
|
||||||
@ -290,28 +272,38 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
int deleteCount = nodeDaoService.getTxnDeleteCount(txnId);
|
int deleteCount = nodeDaoService.getTxnDeleteCount(txnId);
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Transaction has " + updateCount + " updates and " + deleteCount + " deletes: " + txnId);
|
logger.debug("Transaction " + txnId + " has " + updateCount + " updates and " + deleteCount + " deletes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the stores
|
|
||||||
boolean found = false;
|
InIndex result = InIndex.NO;
|
||||||
List<StoreRef> storeRefs = nodeService.getStores();
|
if (updateCount == 0 && deleteCount == 0)
|
||||||
for (StoreRef storeRef : storeRefs)
|
|
||||||
{
|
{
|
||||||
boolean inStore = isTxnIdPresentInIndex(storeRef, txn, updateCount, deleteCount);
|
// If there are no update or deletes, then it is impossible to know if the transaction was removed
|
||||||
if (inStore)
|
// from the index or was never there in the first place.
|
||||||
|
result = InIndex.INDETERMINATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get the stores
|
||||||
|
List<StoreRef> storeRefs = nodeService.getStores();
|
||||||
|
for (StoreRef storeRef : storeRefs)
|
||||||
{
|
{
|
||||||
// found in a particular store
|
boolean inStore = isTxnIdPresentInIndex(storeRef, txn, updateCount, deleteCount);
|
||||||
found = true;
|
if (inStore)
|
||||||
break;
|
{
|
||||||
|
// found in a particular store
|
||||||
|
result = InIndex.YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// done
|
// done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Transaction " + txnId + " was " + (found ? "found" : "not found") + " in indexes.");
|
logger.debug("Transaction " + txnId + " present in indexes: " + result);
|
||||||
}
|
}
|
||||||
return found;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -340,7 +332,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Index has results for txn (OK): " + txnId);
|
logger.debug("Index has results for txn " + txnId + " for store " + storeRef);
|
||||||
}
|
}
|
||||||
return true; // there were updates/creates and results for the txn were found
|
return true; // there were updates/creates and results for the txn were found
|
||||||
}
|
}
|
||||||
@ -348,7 +340,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("Index has no results for txn (Index out of date): " + txnId);
|
logger.debug("Transaction " + txnId + " not in index for store " + storeRef + ". Possibly out of date.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -450,7 +442,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
nodeRef);
|
nodeRef);
|
||||||
indexer.deleteNode(assocRef);
|
indexer.deleteNode(assocRef);
|
||||||
}
|
}
|
||||||
else // node created
|
else // node created
|
||||||
{
|
{
|
||||||
|
@ -132,8 +132,8 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long txnId = txn.getId();
|
long txnId = txn.getId();
|
||||||
boolean txnInIndex = isTxnIdPresentInIndex(txnId);
|
InIndex txnInIndex = isTxnIdPresentInIndex(txnId);
|
||||||
if (!txnInIndex)
|
if (txnInIndex != InIndex.YES)
|
||||||
{
|
{
|
||||||
String msg = I18NUtil.getMessage(ERR_INDEX_OUT_OF_DATE);
|
String msg = I18NUtil.getMessage(ERR_INDEX_OUT_OF_DATE);
|
||||||
logger.warn(msg);
|
logger.warn(msg);
|
||||||
|
@ -40,6 +40,7 @@ public class IndexRemoteTransactionTracker extends AbstractReindexComponent
|
|||||||
private static Log logger = LogFactory.getLog(IndexRemoteTransactionTracker.class);
|
private static Log logger = LogFactory.getLog(IndexRemoteTransactionTracker.class);
|
||||||
|
|
||||||
private boolean remoteOnly;
|
private boolean remoteOnly;
|
||||||
|
private boolean started;
|
||||||
private long currentTxnId;
|
private long currentTxnId;
|
||||||
|
|
||||||
public IndexRemoteTransactionTracker()
|
public IndexRemoteTransactionTracker()
|
||||||
@ -67,17 +68,11 @@ public class IndexRemoteTransactionTracker extends AbstractReindexComponent
|
|||||||
@Override
|
@Override
|
||||||
protected void reindexImpl()
|
protected void reindexImpl()
|
||||||
{
|
{
|
||||||
if (currentTxnId < 0)
|
if (!started)
|
||||||
{
|
{
|
||||||
// initialize the starting point
|
// Initialize the starting poing
|
||||||
Transaction lastTxn = nodeDaoService.getLastTxn();
|
currentTxnId = getLastIndexedTxn();
|
||||||
if (lastTxn == null)
|
started = true;
|
||||||
{
|
|
||||||
// there is nothing to do
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long lastTxnId = lastTxn.getId();
|
|
||||||
currentTxnId = getLastIndexedTxn(lastTxnId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
@ -109,6 +104,88 @@ public class IndexRemoteTransactionTracker extends AbstractReindexComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final long DECREMENT_COUNT = 10L;
|
||||||
|
/**
|
||||||
|
* Finds the last indexed transaction. It works backwards from the
|
||||||
|
* last index in increments, respecting the {@link #setRemoteOnly(boolean) remoteOnly}
|
||||||
|
* flag.
|
||||||
|
*
|
||||||
|
* @return Returns the last index transaction or -1 if there is none
|
||||||
|
*/
|
||||||
|
protected long getLastIndexedTxn()
|
||||||
|
{
|
||||||
|
// get the last transaction
|
||||||
|
Transaction txn = null;
|
||||||
|
if (remoteOnly)
|
||||||
|
{
|
||||||
|
txn = nodeDaoService.getLastRemoteTxn();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txn = nodeDaoService.getLastTxn();
|
||||||
|
}
|
||||||
|
if (txn == null)
|
||||||
|
{
|
||||||
|
// There is no last transaction to use
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
long currentTxnId = txn.getId();
|
||||||
|
while (currentTxnId >= 0L)
|
||||||
|
{
|
||||||
|
// Check if the current txn is in the index
|
||||||
|
InIndex txnInIndex = isTxnIdPresentInIndex(currentTxnId);
|
||||||
|
if (txnInIndex == InIndex.YES)
|
||||||
|
{
|
||||||
|
// We found somewhere to start
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get back in time
|
||||||
|
long lastCheckTxnId = currentTxnId;
|
||||||
|
currentTxnId -= DECREMENT_COUNT;
|
||||||
|
if (currentTxnId < 0L)
|
||||||
|
{
|
||||||
|
currentTxnId = -1L;
|
||||||
|
}
|
||||||
|
// We don't know if this number we have is a local or remote txn, so get the very next one
|
||||||
|
Transaction nextTxn = null;
|
||||||
|
if (remoteOnly)
|
||||||
|
{
|
||||||
|
List<Transaction> nextTxns = nodeDaoService.getNextRemoteTxns(currentTxnId, 1);
|
||||||
|
if (nextTxns.size() > 0)
|
||||||
|
{
|
||||||
|
nextTxn = nextTxns.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Transaction> nextTxns = nodeDaoService.getNextTxns(currentTxnId, 1);
|
||||||
|
if (nextTxns.size() > 0)
|
||||||
|
{
|
||||||
|
nextTxn = nextTxns.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextTxn == null)
|
||||||
|
{
|
||||||
|
// There was nothing relevant after this, so keep going back in time
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (nextTxn.getId() >= lastCheckTxnId)
|
||||||
|
{
|
||||||
|
// Decrementing by DECREMENT_COUNT was not enough
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Adjust the last one we looked at to reflect the correct txn id
|
||||||
|
currentTxnId = nextTxn.getId();
|
||||||
|
}
|
||||||
|
// We are close enough to the beginning, so just go for the first transaction
|
||||||
|
if (currentTxnId < 0L)
|
||||||
|
{
|
||||||
|
currentTxnId = -1L;
|
||||||
|
}
|
||||||
|
return currentTxnId;
|
||||||
|
}
|
||||||
|
|
||||||
private static final int MAX_TXN_COUNT = 1000;
|
private static final int MAX_TXN_COUNT = 1000;
|
||||||
private List<Transaction> getNextTransactions(long currentTxnId)
|
private List<Transaction> getNextTransactions(long currentTxnId)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,8 @@ import java.security.Security;
|
|||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
import net.sf.acegisecurity.Authentication;
|
import net.sf.acegisecurity.Authentication;
|
||||||
import net.sf.acegisecurity.AuthenticationServiceException;
|
import net.sf.acegisecurity.AuthenticationServiceException;
|
||||||
import net.sf.acegisecurity.BadCredentialsException;
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
@ -53,7 +55,9 @@ import org.alfresco.repo.security.authentication.AuthenticationException;
|
|||||||
import org.alfresco.repo.security.authentication.NTLMMode;
|
import org.alfresco.repo.security.authentication.NTLMMode;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.cmr.security.NoSuchPersonException;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
@ -95,6 +99,10 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
|
|
||||||
private boolean m_allowGuest;
|
private boolean m_allowGuest;
|
||||||
|
|
||||||
|
// Allow authenticated users that do not have an Alfresco person to logon as guest
|
||||||
|
|
||||||
|
private boolean m_allowAuthUserAsGuest;
|
||||||
|
|
||||||
// Table of currently active passthru authentications and the associated authentication session
|
// Table of currently active passthru authentications and the associated authentication session
|
||||||
//
|
//
|
||||||
// If the two authentication stages are not completed within a reasonable time the authentication
|
// If the two authentication stages are not completed within a reasonable time the authentication
|
||||||
@ -114,6 +122,7 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
|
|
||||||
private PersonService m_personService;
|
private PersonService m_personService;
|
||||||
private NodeService m_nodeService;
|
private NodeService m_nodeService;
|
||||||
|
private TransactionService m_transactionService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passthru Session Reaper Thread
|
* Passthru Session Reaper Thread
|
||||||
@ -362,6 +371,16 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
m_allowGuest = Boolean.parseBoolean(guest);
|
m_allowGuest = Boolean.parseBoolean(guest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow authenticated users with no alfresco person record to logon with guest access
|
||||||
|
*
|
||||||
|
* @param auth String
|
||||||
|
*/
|
||||||
|
public void setAllowAuthUserAsGuest(String auth)
|
||||||
|
{
|
||||||
|
m_allowAuthUserAsGuest = Boolean.parseBoolean(auth);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the JCE provider
|
* Set the JCE provider
|
||||||
*
|
*
|
||||||
@ -461,6 +480,16 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
m_nodeService = nodeService;
|
m_nodeService = nodeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the transaction service
|
||||||
|
*
|
||||||
|
* @param transService TransactionService
|
||||||
|
*/
|
||||||
|
public final void setTransactionService(TransactionService transService)
|
||||||
|
{
|
||||||
|
m_transactionService = transService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the authentication session timeout, in milliseconds
|
* Return the authentication session timeout, in milliseconds
|
||||||
*
|
*
|
||||||
@ -756,7 +785,7 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
|
|
||||||
// Open an authentication session for the new token and add to the active session list
|
// Open an authentication session for the new token and add to the active session list
|
||||||
|
|
||||||
authSess = m_passthruServers.openSession();
|
authSess = m_passthruServers.openSession( false, ntlmToken.getClientDomain());
|
||||||
|
|
||||||
// Check if the session was opened to the passthru server
|
// Check if the session was opened to the passthru server
|
||||||
|
|
||||||
@ -792,6 +821,8 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
UserTransaction tx = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Stage two of the authentication, send the hashed password to the authentication server
|
// Stage two of the authentication, send the hashed password to the authentication server
|
||||||
@ -835,6 +866,11 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
|
|
||||||
ntlmToken.setAuthenticated(true);
|
ntlmToken.setAuthenticated(true);
|
||||||
|
|
||||||
|
// Wrap the service calls in a transaction
|
||||||
|
|
||||||
|
tx = m_transactionService.getUserTransaction( true);
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
// Map the passthru username to an Alfresco person
|
// Map the passthru username to an Alfresco person
|
||||||
|
|
||||||
NodeRef userNode = m_personService.getPerson(username);
|
NodeRef userNode = m_personService.getPerson(username);
|
||||||
@ -862,6 +898,31 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
logger.debug("Setting current user using username " + username);
|
logger.debug("Setting current user using username " + username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (NoSuchPersonException ex)
|
||||||
|
{
|
||||||
|
// Check if authenticated users are allowed on as guest when there is no Alfresco person record
|
||||||
|
|
||||||
|
if ( m_allowAuthUserAsGuest == true)
|
||||||
|
{
|
||||||
|
// Set the guest authority
|
||||||
|
|
||||||
|
GrantedAuthority[] authorities = new GrantedAuthority[1];
|
||||||
|
authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);
|
||||||
|
|
||||||
|
ntlmToken.setAuthorities(authorities);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
if ( logger.isDebugEnabled())
|
||||||
|
logger.debug("Allow passthru authenticated user to logon as guest, user=" + ntlmToken.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Logon failure, no matching person record
|
||||||
|
|
||||||
|
throw new AuthenticationServiceException("Logon failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
// Error connecting to the authentication server
|
// Error connecting to the authentication server
|
||||||
@ -899,6 +960,12 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
else
|
else
|
||||||
throw new BadCredentialsException("Logon failure");
|
throw new BadCredentialsException("Logon failure");
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// General error
|
||||||
|
|
||||||
|
throw new AuthenticationServiceException("General error", ex);
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Make sure the authentication session is closed
|
// Make sure the authentication session is closed
|
||||||
@ -919,6 +986,19 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commit or rollback the transaction, if active
|
||||||
|
|
||||||
|
if ( tx != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch ( Exception ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security.authentication.ntlm;
|
package org.alfresco.repo.security.authentication.ntlm;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
import net.sf.acegisecurity.GrantedAuthority;
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
import net.sf.acegisecurity.providers.*;
|
import net.sf.acegisecurity.providers.*;
|
||||||
|
|
||||||
@ -37,6 +39,11 @@ public class NTLMLocalToken extends UsernamePasswordAuthenticationToken
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = -7946514578455279387L;
|
private static final long serialVersionUID = -7946514578455279387L;
|
||||||
|
|
||||||
|
// Optional client domain and IP address, used to route the passthru authentication to the correct server(s)
|
||||||
|
|
||||||
|
private String m_clientDomain;
|
||||||
|
private String m_clientAddr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*/
|
*/
|
||||||
@ -45,6 +52,17 @@ public class NTLMLocalToken extends UsernamePasswordAuthenticationToken
|
|||||||
super(null, null);
|
super(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param ipAddr InetAddress
|
||||||
|
*/
|
||||||
|
protected NTLMLocalToken( InetAddress ipAddr)
|
||||||
|
{
|
||||||
|
if ( ipAddr != null)
|
||||||
|
m_clientAddr = ipAddr.getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor
|
* Class constructor
|
||||||
*
|
*
|
||||||
@ -55,6 +73,21 @@ public class NTLMLocalToken extends UsernamePasswordAuthenticationToken
|
|||||||
super(username.toLowerCase(), plainPwd);
|
super(username.toLowerCase(), plainPwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param username String
|
||||||
|
* @param plainPwd String
|
||||||
|
* @param domain String
|
||||||
|
* @param ipAddr String
|
||||||
|
*/
|
||||||
|
public NTLMLocalToken(String username, String plainPwd, String domain, String ipAddr) {
|
||||||
|
super(username != null ? username.toLowerCase() : "", plainPwd);
|
||||||
|
|
||||||
|
m_clientDomain = domain;
|
||||||
|
m_clientAddr = ipAddr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the user logged on as a guest
|
* Check if the user logged on as a guest
|
||||||
*
|
*
|
||||||
@ -103,4 +136,44 @@ public class NTLMLocalToken extends UsernamePasswordAuthenticationToken
|
|||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client domain name is set
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasClientDomain()
|
||||||
|
{
|
||||||
|
return m_clientDomain != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the client domain
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getClientDomain()
|
||||||
|
{
|
||||||
|
return m_clientDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client IP address is set
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public final boolean hasClientAddress()
|
||||||
|
{
|
||||||
|
return m_clientAddr != null ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the client IP address
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public final String getClientAddress()
|
||||||
|
{
|
||||||
|
return m_clientAddr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.security.authentication.ntlm;
|
package org.alfresco.repo.security.authentication.ntlm;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Used to provide passthru authentication to a remote Windows server using multiple stages that
|
* <p>Used to provide passthru authentication to a remote Windows server using multiple stages that
|
||||||
* allows authentication details to be passed between a client and the remote authenticating server without
|
* allows authentication details to be passed between a client and the remote authenticating server without
|
||||||
@ -59,6 +61,28 @@ public class NTLMPassthruToken extends NTLMLocalToken
|
|||||||
super("", "");
|
super("", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @params domain String
|
||||||
|
*/
|
||||||
|
public NTLMPassthruToken( String domain)
|
||||||
|
{
|
||||||
|
// We do not know the username yet, and will not know the password
|
||||||
|
|
||||||
|
super("", "", domain, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor
|
||||||
|
*
|
||||||
|
* @param ipAddr InetAddress
|
||||||
|
*/
|
||||||
|
public NTLMPassthruToken( InetAddress ipAddr)
|
||||||
|
{
|
||||||
|
super( ipAddr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the challenge
|
* Return the challenge
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user