diff --git a/config/alfresco/extension/bootstrap/split-person-cleanup-context.xml.sample b/config/alfresco/extension/bootstrap/split-person-cleanup-context.xml.sample
new file mode 100644
index 0000000000..ee45de9163
--- /dev/null
+++ b/config/alfresco/extension/bootstrap/split-person-cleanup-context.xml.sample
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/netbios/NetBIOSName.java b/source/java/org/alfresco/filesys/netbios/NetBIOSName.java
index 097a029f30..3a8cadb630 100644
--- a/source/java/org/alfresco/filesys/netbios/NetBIOSName.java
+++ b/source/java/org/alfresco/filesys/netbios/NetBIOSName.java
@@ -85,6 +85,10 @@ public class NetBIOSName
public static final String SMBServer = "*SMBSERVER";
public static final String SMBServer2 = "*SMBSERV";
+ // Adapter status request name
+
+ public static final String AdapterStatusName = "*";
+
// Default time to live for name registrations
public static final int DefaultTTL = 28800; // 8 hours
diff --git a/source/java/org/alfresco/filesys/netbios/NetBIOSPacket.java b/source/java/org/alfresco/filesys/netbios/NetBIOSPacket.java
index d21dc96c51..6a1a380e09 100644
--- a/source/java/org/alfresco/filesys/netbios/NetBIOSPacket.java
+++ b/source/java/org/alfresco/filesys/netbios/NetBIOSPacket.java
@@ -114,14 +114,23 @@ public class NetBIOSPacket
public static final int ACT_ERR = 0x06;
public static final int CFT_ERR = 0x07;
- // Name flags
-
- public static final int NAME_PERM = 0x02;
- public static final int NAME_ACTIVE = 0x04;
- public static final int NAME_CONFLICT = 0x08;
- public static final int NAME_DEREG = 0x10;
- public static final int NAME_GROUP = 0x80;
-
+ // Name flags
+
+ public static final int NAME_PERM = 0x0200;
+ public static final int NAME_ACTIVE = 0x0400;
+ public static final int NAME_CONFLICT = 0x0800;
+ public static final int NAME_DEREG = 0x1000;
+ public static final int NAME_GROUP = 0x8000;
+
+ public static final int NAME_TYPE_BNODE = 0x0000;
+ public static final int NAME_TYPE_PNODE = 0x2000;
+ public static final int NAME_TYPE_MNODE = 0x4000;
+ public static final int NAME_TYPE_RESVD = 0x6000;
+
+ // Adapter status name in encoded format
+
+ private static final String AdapterStatusNBName = "CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+
// NetBIOS packet buffer
private byte[] m_nbbuf;
@@ -1252,4 +1261,75 @@ public class NetBIOSPacket
return pos;
}
+
+ /**
+ * Build an adapter status response
+ *
+ * @param nameList NetBIOSNameList
+ * @param int nodeType
+ * @return int
+ */
+ public final int buildAdapterStatusResponse(NetBIOSNameList nameList, int nodeType) {
+
+ // Fill in the header
+
+ setOpcode(NetBIOSPacket.RESP_QUERY);
+ setFlags(NetBIOSPacket.FLG_RECURSDES + NetBIOSPacket.FLG_AUTHANSWER);
+
+ setQuestionCount(0);
+ setAnswerCount(1);
+ setAdditionalCount(0);
+ setNameServiceCount(0);
+
+ // Pack the encoded adapter status name into the NetBIOS packet
+
+ int pos = NB_DATA;
+ m_nbbuf [ pos++] = ( byte) NAME_LEN;
+
+ pos = DataPacker.putString( AdapterStatusNBName, m_nbbuf, pos, true);
+
+ // Set the name type and class
+
+ DataPacker.putShort (( short) 0x21, m_nbbuf, pos);
+ pos += 2;
+
+ DataPacker.putShort (( short) 0x01, m_nbbuf, pos);
+ pos += 2;
+
+ pos = setTTL(pos, 10000);
+ pos = setResourceDataLength(pos, (nameList.numberOfNames() * 18) + 42);
+
+ // Pack the names
+
+ m_nbbuf[pos++] = (byte) nameList.numberOfNames();
+
+ for ( int i = 0; i < nameList.numberOfNames(); i++) {
+
+ // Get the current name
+
+ NetBIOSName nbName = nameList.getName( i);
+
+ // Pack the NetBIOS name and flags
+
+ System.arraycopy( nbName.getNetBIOSName(), 0, m_nbbuf, pos, NetBIOSName.NameLength);
+ pos += NetBIOSName.NameLength;
+
+ int flags = nodeType + NAME_ACTIVE;
+ if ( nbName.isGroupName())
+ flags += NAME_GROUP;
+
+ DataPacker.putShort(( short) flags, m_nbbuf, pos);
+ pos += 2;
+ }
+
+ // Zero out the statistics, MAC address area
+
+ for ( int i = 0; i < 42; i++)
+ m_nbbuf[pos++] = (byte) 0;
+
+ // Set the packet length, and return the length
+
+ setLength(pos);
+ return getLength();
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java b/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java
index ddbc0c5a46..f555db4162 100644
--- a/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java
+++ b/source/java/org/alfresco/filesys/netbios/server/NetBIOSNameServer.java
@@ -35,6 +35,7 @@ import java.util.Hashtable;
import java.util.Vector;
import org.alfresco.filesys.netbios.NetBIOSName;
+import org.alfresco.filesys.netbios.NetBIOSNameList;
import org.alfresco.filesys.netbios.NetBIOSPacket;
import org.alfresco.filesys.netbios.NetworkSettings;
import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
@@ -1105,10 +1106,20 @@ public class NetBIOSNameServer extends NetworkServer implements Runnable
char nameType = searchName.charAt(15);
int len = 0;
- while (len <= 14 && searchName.charAt(len) != ' ')
- len++;
+ while (len <= 14 && searchName.charAt(len) != ' ' && searchName.charAt(len) != 0)
+ len++;
searchName = searchName.substring(0, len);
+ // Check if this is an adapter status request
+
+ if ( searchName.equals( NetBIOSName.AdapterStatusName)) {
+
+ // Process the adapter status request
+
+ processAdapterStatus( pkt, fromAddr, fromPort);
+ return;
+ }
+
// Debug
if (logger.isDebugEnabled())
@@ -1399,6 +1410,50 @@ public class NetBIOSNameServer extends NetworkServer implements Runnable
}
/**
+ * Process an adapter status request
+ * @param pkt NetBIOSPacket
+ * @param fromAddr InetAddress
+ * @param fromPort int
+ */
+ protected final void processAdapterStatus(NetBIOSPacket pkt, InetAddress fromAddr, int fromPort) {
+
+ // Debug
+
+ if (logger.isDebugEnabled())
+ logger.debug("%% Adapter status request");
+
+ // Build the local name list
+
+ NetBIOSNameList nameList = new NetBIOSNameList();
+ for ( int i = 0; i < m_localNames.size(); i++)
+ nameList.addName( m_localNames.get( i));
+
+ // Build the name query response
+
+ int pktLen = pkt.buildAdapterStatusResponse( nameList, hasPrimaryWINSServer() ? NetBIOSPacket.NAME_TYPE_PNODE : NetBIOSPacket.NAME_TYPE_BNODE);
+
+ // Debug
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("%% NetBIOS Reply to " + fromAddr.getHostAddress() + " :-");
+ pkt.DumpPacket(false);
+ }
+
+ // Send the reply packet
+
+ try {
+
+ // Send the name query reply
+
+ sendPacket(pkt, pktLen, fromAddr, fromPort);
+ }
+ catch (java.io.IOException ex) {
+ if ( logger.isErrorEnabled())
+ logger.error(ex);
+ }
+ }
+
+ /**
* Remove a local add name listener from the NetBIOS name server.
*
* @param l AddNameListener
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/VersionHistoryPerformancePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/VersionHistoryPerformancePatch.java
index de674a4ecd..b323b22514 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/VersionHistoryPerformancePatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/VersionHistoryPerformancePatch.java
@@ -42,14 +42,17 @@ public class VersionHistoryPerformancePatch extends AbstractPatch
// Get the id
String versionedNodeId = (String)this.nodeService.getProperty(nodeRef, VersionModel.PROP_QNAME_VERSIONED_NODE_ID);
- // Set the cm:name
- this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, versionedNodeId);
+ if (versionedNodeId != null)
+ {
+ // Set the cm:name
+ this.nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, versionedNodeId);
- // Move the node
- this.nodeService.moveNode( nodeRef,
- rootNodeRef,
- VersionModel.CHILD_QNAME_VERSION_HISTORIES,
- QName.createQName(VersionModel.NAMESPACE_URI, versionedNodeId));
+ // Move the node
+ this.nodeService.moveNode( nodeRef,
+ rootNodeRef,
+ VersionModel.CHILD_QNAME_VERSION_HISTORIES,
+ QName.createQName(VersionModel.NAMESPACE_URI, versionedNodeId));
+ }
updateCount++;
}
diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
index 8d74ed1208..c831cfd457 100644
--- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
+++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java
@@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.Hashtable;
import java.util.Map;
+import javax.naming.AuthenticationNotSupportedException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
@@ -228,6 +229,10 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
catch (javax.naming.AuthenticationException ax)
{
+ }
+ catch(AuthenticationNotSupportedException e)
+ {
+
}
catch (NamingException nx)
{
@@ -254,6 +259,10 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
}
+ catch(AuthenticationNotSupportedException e)
+ {
+ logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
+ }
catch (NamingException nx)
{
logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL));
@@ -279,6 +288,10 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
}
+ catch(AuthenticationNotSupportedException e)
+ {
+ logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
+ }
catch (NamingException nx)
{
logger.info("LDAP server does not support simple DN and invalid password at "+ env.get(Context.PROVIDER_URL));
@@ -309,9 +322,13 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL));
}
+ catch(AuthenticationNotSupportedException e)
+ {
+ logger.info("LDAP server does not support the required authentication mechanism");
+ }
catch (NamingException nx)
{
- // already donw
+ // already done
}
}
}
diff --git a/source/java/org/alfresco/repo/security/person/SplitPersonCleanupBootstrapBean.java b/source/java/org/alfresco/repo/security/person/SplitPersonCleanupBootstrapBean.java
new file mode 100644
index 0000000000..43efa922b9
--- /dev/null
+++ b/source/java/org/alfresco/repo/security/person/SplitPersonCleanupBootstrapBean.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2005 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.repo.security.person;
+
+import java.util.Set;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.transaction.TransactionUtil;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.AbstractLifecycleBean;
+import org.alfresco.util.GUID;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.doomdark.uuid.UUID;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * Remove all duplicate users that have previously been split and had guids added to the uid. This been should be wired up into a custom bootstrap process
+ *
+ * @author Andy Hind
+ */
+public class SplitPersonCleanupBootstrapBean extends AbstractLifecycleBean
+{
+ protected final static Log log = LogFactory.getLog(SplitPersonCleanupBootstrapBean.class);
+
+ private NodeService nodeService;
+
+ private PersonService personService;
+
+ private TransactionService transactionService;
+
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ public void setPersonService(PersonService personService)
+ {
+ this.personService = personService;
+ }
+
+ public void setTransactionService(TransactionService transactionService)
+ {
+ this.transactionService = transactionService;
+ }
+
+ @Override
+ protected void onBootstrap(ApplicationEvent event)
+ {
+ // reindex
+ log.info("Removing person entries with GUIDS at the end of the uid ...");
+ int count = removePeopleWithGUIDBasedIds();
+ log.info("... removed " + count);
+ }
+
+ /**
+ * Can have uid+GUID or uid + "(" + GUID + ")"
+ *
+ * @return
+ */
+ private int removePeopleWithGUIDBasedIds()
+ {
+ Integer count = TransactionUtil.executeInUserTransaction(transactionService,
+ new TransactionUtil.TransactionWork()
+ {
+
+ public Integer doWork() throws Exception
+ {
+ int count = 0;
+ // A GUID should be 36 chars
+
+ Set people = personService.getAllPeople();
+ for (NodeRef person : people)
+ {
+ String uid = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(
+ person, ContentModel.PROP_USERNAME));
+ if (isUIDWithGUID(uid))
+ {
+ // Delete via the person service to get the correct tidy up
+ personService.deletePerson(uid);
+ if (log.isDebugEnabled())
+ {
+ log.debug("... removed person with uid " + uid);
+ }
+ log.info("... removed person with uid " + uid);
+ count++;
+ }
+ }
+ return count;
+ }
+
+ });
+ return count.intValue();
+
+ }
+
+ private boolean isUIDWithGUID(String uid)
+ {
+ if (uid.length() > 36)
+ {
+ // uid + GUID
+ // Check the last 36 chars are a valid guid
+ String guidString = uid.substring(uid.length() - 36);
+ try
+ {
+ UUID id = new UUID(guidString);
+ // We have a valid guid.
+ return true;
+ }
+ catch (NumberFormatException e)
+ {
+ // Not a valid GUID
+ }
+ }
+
+ if (uid.length() > 38)
+ {
+ // UID + "(" + GUID + ")"
+ String guidString = uid.substring(uid.length() - 38);
+ if (guidString.startsWith("(") && guidString.endsWith(")"))
+ {
+ guidString = guidString.substring(1, 37);
+ try
+ {
+ UUID id = new UUID(guidString);
+ // We have a valid guid.
+ return true;
+ }
+ catch (NumberFormatException e)
+ {
+ // Not a valid GUID
+ }
+ }
+
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void onShutdown(ApplicationEvent event)
+ {
+ // Nothing to do
+ }
+
+ public static void main(String[] args)
+ {
+ SplitPersonCleanupBootstrapBean tester = new SplitPersonCleanupBootstrapBean();
+ String[] test = new String[] { "andy", "andy" + GUID.generate(), "andy(" + GUID.generate() + ")",
+ GUID.generate() + "banana", "andy" + GUID.generate() + "banana",
+ "adbadbaddbadbadbadbabdbadbadbabdabdbbadbadbabdbadbadbadb"
+
+ };
+
+ for (String uid : test)
+ {
+ System.out.println(uid + " ... is a uid with guid = " + tester.isUIDWithGUID(uid));
+ }
+ }
+}