/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://IdentityConnectors.dev.java.net/legal/license.txt
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at identityconnectors/legal/license.txt.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.racf;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import static org.identityconnectors.racf.RacfConstants.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.naming.LimitExceededException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.identityconnectors.common.CollectionUtil;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.exceptions.AlreadyExistsException;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.exceptions.UnknownUidException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeInfo;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.ObjectClassInfo;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.identityconnectors.framework.common.objects.PredefinedAttributes;
import org.identityconnectors.framework.common.objects.Schema;
import org.identityconnectors.framework.common.objects.Uid;
class LdapUtil {
private final Pattern _connectionPattern = Pattern.compile("racfuserid=(.*)\\+racfgroupid=([^,]*),.*");
private RacfConnector _connector;
private Schema _schema;
private RACFPasswordEnvelopeUtilities _passwdEnvDecrypter;
public LdapUtil(RacfConnector connector) {
_connector = connector;
_schema = _connector.schema();
StringBuffer pemcert = loadBuffer(( (RacfConfiguration) _connector.getConfiguration() ).getActiveSyncCertificate());
StringBuffer pemkey = loadBuffer(( (RacfConfiguration) _connector.getConfiguration() ).getActiveSyncPrivateKey());
String decryptorClass = ( (RacfConfiguration) _connector.getConfiguration() ).getActiveSyncPasswordDecryptorClass();
if (pemcert.length() > 0 && pemkey.length() > 0) {
_passwdEnvDecrypter = RACFPasswordEnvelopeUtilities.newRACFPasswordEnvelopeDecryptor(decryptorClass, pemcert.toString(), pemkey.toString());
}
}
static private Pattern _uidPattern = Pattern.compile("racfid=(\\w+),([^,]+).+", Pattern.CASE_INSENSITIVE);
public String createUniformUid(Uid oldUid) {
return createUniformUid(oldUid.getUidValue());
}
public String createUniformUid(String oldUidString) {
return createUniformUid(oldUidString, ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix());
}
static public String createUniformUid(String oldUidString, String suffix) {
Matcher matcher = _uidPattern.matcher(oldUidString);
if (matcher.matches()) {
return "racfid=" + matcher.group(1).toUpperCase() + "," + matcher.group(2).toLowerCase() + "," + suffix;
} else {
return oldUidString;
}
}
private StringBuffer loadBuffer(String[] vals) {
StringBuffer buffer = new StringBuffer();
if (vals != null) {
for (int i = 0; i < vals.length; i++) {
buffer.append((String) vals[i]);
buffer.append("\n");
}
}
return buffer;
}
public Uid createViaLdap(ObjectClass objectClass, Set<Attribute> attrs, OperationOptions options) {
Map<String, Attribute> attributes = CollectionUtil.newCaseInsensitiveMap();
attributes.putAll(AttributeUtil.toMap(attrs));
if (objectClass.is(RacfConnector.RACF_CONNECTION_NAME)) {
try {
Name name = AttributeUtil.getNameFromAttributes(attrs);
Map<String, Attribute> newAttributes = AttributeUtil.toMap(attrs);
( (RacfConnection) _connector.getConnection() ).getDirContext().createSubcontext(name.getNameValue(), createLdapAttributesFromConnectorAttributes(newAttributes));
return new Uid(createUniformUid(name.getNameValue()));
}
catch (NamingException e) {
throw new ConnectorException(e);
}
} else if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
Name name = AttributeUtil.getNameFromAttributes(attrs);
try {
Attribute groups = attributes.remove(ATTR_LDAP_GROUPS);
Attribute owners = attributes.remove(ATTR_LDAP_CONNECT_OWNER);
Attribute expired = attributes.remove(ATTR_LDAP_EXPIRED);
Attribute password = attributes.get(ATTR_LDAP_PASSWORD);
_connector.throwErrorIfNull(groups);
_connector.throwErrorIfNullOrEmpty(expired);
_connector.throwErrorIfNullOrEmpty(password);
_connector.checkConnectionConsistency(groups, owners);
if (expired != null && password == null) {
throw new ConnectorException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.EXPIRED_NO_PASSWORD));
}
if (userExists(name.getNameValue())) {
throw new AlreadyExistsException();
}
// Some attributes cannot be specified during create, only modify.
// Save these off to the side.
//
Set<Attribute> changes = new HashSet<Attribute>();
Attribute enable = attributes.remove(ATTR_LDAP_ENABLED);
Attribute enableDate = attributes.remove(ATTR_LDAP_RESUME_DATE);
Attribute disableDate = attributes.remove(ATTR_LDAP_REVOKE_DATE);
if (expired != null) {
changes.add(expired);
}
if (password != null) {
changes.add(password);
}
if (enable != null) {
changes.add(enable);
}
if (enableDate != null) {
changes.add(enableDate);
}
if (disableDate != null) {
changes.add(disableDate);
}
String id = name.getNameValue();
Uid uid = new Uid(id);
Map<String, Attribute> newAttributes = CollectionUtil.newCaseInsensitiveMap();
newAttributes.putAll(attributes);
addObjectClass(objectClass, newAttributes);
( (RacfConnection) _connector.getConnection() ).getDirContext().createSubcontext(createDnFromName(objectClass, id), createLdapAttributesFromConnectorAttributes(objectClass, newAttributes));
if (groups != null) {
if (attributes.get(ATTR_LDAP_DEFAULT_GROUP) != null) {
_connector.setGroupMembershipsForUser(uid.getUidValue(), groups, owners, (String) attributes.get(ATTR_LDAP_DEFAULT_GROUP).getValue().get(0));
} else {
_connector.setGroupMembershipsForUser(uid.getUidValue(), groups, owners);
}
}
// Now, process the deferred attributes
//
if (changes.size() > 0) {
changes.add(uid);
updateViaLdap(objectClass, changes, options);
}
return uid;
}
catch (NamingException e) {
if (e.toString().contains("INVALID USER")) {
throw new AlreadyExistsException();
} else {
throw new ConnectorException(e);
}
}
} else if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
Name name = AttributeUtil.getNameFromAttributes(attrs);
try {
Attribute members = attributes.remove(ATTR_LDAP_GROUP_USERIDS);
Attribute groupOwners = attributes.remove(ATTR_LDAP_CONNECT_OWNER);
String id = name.getNameValue();
Uid uid = new Uid(id);
Map<String, Attribute> newAttributes = new HashMap<String, Attribute>(attributes);
addObjectClass(objectClass, newAttributes);
( (RacfConnection) _connector.getConnection() ).getDirContext().createSubcontext(createDnFromName(objectClass, id), createLdapAttributesFromConnectorAttributes(objectClass, newAttributes));
if (members != null) {
_connector.setGroupMembershipsForGroups(id, members, groupOwners);
}
return uid;
}
catch (NamingException e) {
if (e.toString().contains("INVALID GROUP")) {
throw new AlreadyExistsException();
} else {
throw new ConnectorException(e);
}
}
} else {
throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, objectClass.getObjectClassValue()));
}
}
public void deleteViaLdap(ObjectClass objectClass, Uid uid) {
try {
( (RacfConnection) _connector.getConnection() ).getDirContext().destroySubcontext(createDnFromName(objectClass, uid.getUidValue()));
}
catch (NamingException e) {
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
if (e.toString().contains("INVALID USER")) {
throw new UnknownUidException();
} else {
throw new ConnectorException(e);
}
} else if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
if (e.toString().contains("INVALID GROUP")) {
throw new UnknownUidException();
} else {
throw new ConnectorException(e);
}
} else {
throw ConnectorException.wrap(e);
}
}
}
public List<String> getGroupsForUserViaLdap(String user) {
//return getConnectionInfo("racfuserid=" + RacfConnector.extractRacfIdFromLdapId(user), 2);
return getConnectionInfo("racfuserid=" + user, 2);
}
public List<String> getMembersOfGroupViaLdap(String group) {
//return getConnectionInfo("racfgroupid=" + RacfConnector.extractRacfIdFromLdapId(group), 1);
return getConnectionInfo("racfgroupid=" + group, 1);
}
private List<String> getConnectionInfo(String query, int index) {
SearchControls subTreeControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 4095, 0, null, true, true);
List<String> objects = new LinkedList<String>();
try {
String search = "profileType=connect," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
NamingEnumeration<SearchResult> connections = ( (RacfConnection) _connector.getConnection() ).getDirContext().search(search, query, subTreeControls);
while (connections.hasMore()) {
SearchResult userRoot = connections.next();
String name = userRoot.getNameInNamespace();
Matcher matcher = _connectionPattern.matcher(name);
if (matcher.matches()) {
objects.add(matcher.group(index));
} else {
throw new ConnectorException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.PATTERN_FAILED, name));
}
}
return objects;
}
catch (LimitExceededException e) {
// GAEL - This one is really annoying...
//TODO: cope with this
throw ConnectorException.wrap(e);
}
catch (NamingException e) {
throw new ConnectorException(e);
}
}
public List<String> getUsersViaLdap(String query) {
RacfConfiguration configuration = (RacfConfiguration) _connector.getConfiguration();
String[] queries = configuration.getUserQueries();
// If we are querying ALL users, and we have a partitioned Query,
// we will use it instead
//
if (( "*".equals(query) || query == null ) && queries != null && queries.length > 0) {
Set<String> users = new HashSet<String>();
for (String subquery : queries) {
users.addAll(getUsersViaLdap0(subquery));
}
List<String> userList = new ArrayList<String>(users.size());
userList.addAll(users);
return userList;
} else {
return getUsersViaLdap0(query);
}
}
private List<String> getUsersViaLdap0(String query) {
SearchControls subTreeControls = new SearchControls(SearchControls.ONELEVEL_SCOPE, 4095, 0, null, true, true);
List<String> userNames = new LinkedList<String>();
try {
String search = "profileType=user," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
NamingEnumeration<SearchResult> users = ( (RacfConnection) _connector.getConnection() ).getDirContext().search(search, getLdapFilterForFilterString(query), subTreeControls);
while (users.hasMore()) {
SearchResult userRoot = users.next();
String name = userRoot.getNameInNamespace();
if (name.startsWith("racfid=irrcerta,")
|| name.startsWith("racfid=irrmulti,")
|| name.startsWith("racfid=irrsitec,")) {
// Ignore
} else {
userNames.add(RacfConnector.extractRacfIdFromLdapId(name));
}
}
}
catch (LimitExceededException e) {
//TODO: cope with this
throw ConnectorException.wrap(e);
}
catch (NamingException e) {
if (!e.toString().contains("NO ENTRIES MEET SEARCH CRITERIA")) {
throw new ConnectorException(e);
}
}
return userNames;
}
public List<String> getGroupsViaLdap(String query) {
RacfConfiguration configuration = (RacfConfiguration) _connector.getConfiguration();
String[] queries = configuration.getGroupQueries();
// If we are querying ALL groups, and we have a partitioned Query,
// we will use it instead
//
if (( "*".equals(query) || query == null ) && queries != null && queries.length > 0) {
Set<String> groups = new HashSet<String>();
for (String subquery : queries) {
groups.addAll(getGroupsViaLdap0(subquery));
}
List<String> groupList = new ArrayList<String>(groups.size());
groupList.addAll(groups);
return groupList;
} else {
return getGroupsViaLdap0(query);
}
}
public List<String> getGroupsViaLdap0(String query) {
SearchControls subTreeControls = new SearchControls(SearchControls.ONELEVEL_SCOPE, 4095, 0, null, true, true);
List<String> groupNames = new LinkedList<String>();
try {
String search = "profileType=group," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
NamingEnumeration<SearchResult> groups = ( (RacfConnection) _connector.getConnection() ).getDirContext().search(search, getLdapFilterForFilterString(query), subTreeControls);
while (groups.hasMore()) {
SearchResult userRoot = groups.next();
String name = userRoot.getNameInNamespace();
groupNames.add(RacfConnector.extractRacfIdFromLdapId(name));
}
}
catch (LimitExceededException e) {
//TODO: cope with this
throw ConnectorException.wrap(e);
}
catch (NamingException e) {
if (!e.toString().contains("NO ENTRIES MEET SEARCH CRITERIA")) {
throw new ConnectorException(e);
}
}
return groupNames;
}
private String getLdapFilterForFilterString(String filter) {
String filterText = "(objectclass=*)";
if (filter != null) {
filterText = filter;
}
return filterText;
}
private boolean userExists(String user) {
List<String> users = getUsersViaLdap("racfid=" + user.toUpperCase());
return users.size() == 1;
}
private boolean groupExists(String group) {
List<String> groups = getGroupsViaLdap("racfid=" + group.toUpperCase());
return groups.size() == 1;
}
public Map<String, Object> getAttributesFromLdap(ObjectClass objectClass, String name, Set<String> originalAttributesToGet) throws NamingException {
Map<String, Object> attributesRead = CollectionUtil.newCaseInsensitiveMap();
Set<String> attributesToGet = new HashSet<String>(originalAttributesToGet);
// This is artificial, so remove it
//
attributesToGet.remove(ATTR_LDAP_ACCOUNTID);
attributesToGet.remove(Name.NAME);
// Now special case 'name-only', since that includes accountId
//
if (attributesToGet.isEmpty()) {
Uid uid = new Uid(name);
attributesRead.put(Uid.NAME, uid);
attributesRead.put(Name.NAME, name);
if (_connector.getConfiguration().getIsSunIdm()) {
attributesRead.put(ATTR_LDAP_ACCOUNTID, name);
}
return attributesRead;
}
// If we need to get the connection owner, we need to lookup the connect branch
//
boolean owners = attributesToGet.remove(ATTR_LDAP_CONNECT_OWNER);
// Since Enable is indicated by ATTRIBUTES attribute containing REVOKE
// we must ensure we fetch the Attribute
//
boolean enable = attributesToGet.remove(OperationalAttributes.ENABLE_NAME);
if (enable && !attributesToGet.contains(ATTR_LDAP_ATTRIBUTES)) {
attributesToGet.add(ATTR_LDAP_ATTRIBUTES);
}
SearchResult ldapObject = getAttributesFromLdap(createDnFromName(objectClass, name), attributesRead, attributesToGet);
Uid uid = new Uid(name);
attributesRead.put(Uid.NAME, uid);
attributesRead.put(Name.NAME, name);
if (_connector.getConfiguration().getIsSunIdm()) {
attributesRead.put(ATTR_LDAP_ACCOUNTID, name);
}
// For Users, we need to do a separate query against the connections to pick up
// Connection info
//
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
if (owners) {
// First, get the connections for the user
//
String query = "profileType=Connect," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
SearchControls subTreeControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 4095, 0, attributesToGet.toArray(new String[0]), true, true);
NamingEnumeration<SearchResult> results = _connector.getConnection().getDirContext().search(query, "(racfuserid=" + name + ")", subTreeControls);
List<String> groupsForUser = new ArrayList<String>();
while (results.hasMore()) {
SearchResult result = results.next();
String connection = result.getNameInNamespace();
String[] ids = RacfConnector.extractRacfIdAndGroupIdFromLdapId(connection);
String group = ids[1];
groupsForUser.add(group);
}
attributesRead.put(ATTR_LDAP_GROUPS, groupsForUser);
List<String> ownersForUser = new ArrayList<String>();
Set<String> connectAttributesToGet = new HashSet<String>();
connectAttributesToGet.add(ATTR_LDAP_CONNECT_OWNER);
for (String group : groupsForUser) {
String root = "racfuserid=" + name + "+racfgroupid=" + group + ",profileType=Connect," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
ownersForUser.add(getConnectOwner(root));
}
attributesRead.put(ATTR_LDAP_CONNECT_OWNER, ownersForUser);
}
}
// For Groups, we need to do a separate query against the connections to pick up
// Connection info
//
// TODO: Gael - a lot here. We need to handle universal groups.
if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
if (owners && ( attributesRead.get(ATTR_LDAP_GROUP_USERIDS) != null )) {
List<String> ownersForGroup = new ArrayList<String>();
List<String> usersForGroup = new ArrayList<String>();
//Set<String> connectAttributesToGet = new HashSet<String>();
// connectAttributesToGet.add(ATTR_LDAP_OWNER);
if (attributesRead.get(ATTR_LDAP_GROUP_USERIDS) instanceof String) {
usersForGroup.add((String) attributesRead.get(ATTR_LDAP_GROUP_USERIDS));
} else {
usersForGroup.addAll((List<String>) attributesRead.get(ATTR_LDAP_GROUP_USERIDS));
}
for (String user : usersForGroup) {
user = RacfConnector.extractRacfIdFromLdapId(user);
String root = "racfuserid=" + user + "+racfgroupid=" + name + ",profileType=Connect," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
ownersForGroup.add(RacfConnector.extractRacfIdFromLdapId(getConnectOwner(root)));
}
attributesRead.put(ATTR_LDAP_CONNECT_OWNER, ownersForGroup);
}
}
// Remap ACCOUNT attributes as needed
//
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
// 'racfattributes' comes back as a String, we need to transform it into a list
// Gael: This code handles well the diff between ISS LDAP and TDS LDAP
// TDS LDAP returns RACF Attributes as a LIST whereas ISS LDAP sometimes
// returns a single value with multiple values separated by a space.
Object racfAttributes = attributesRead.get(ATTR_LDAP_ATTRIBUTES);
if (racfAttributes != null) {
List<String> realRacfAttributes = new ArrayList<String>();
if (racfAttributes instanceof String) {
for (String attribute : ( (String) racfAttributes ).split("\\s+")) {
realRacfAttributes.add(attribute);
}
} else if (racfAttributes instanceof List) {
for (Object attribute : ( (List) racfAttributes )) {
for (String attributePart : attribute.toString().split("\\s+")) {
realRacfAttributes.add(attributePart);
}
}
}
// TODO: Gael - Until I find the meaning of PASSWORD in the racfattributes,
// I remove it (I see it in 1.12, not in 1.5)
realRacfAttributes.remove("PASSWORD");
// __ENABLE__ is indicated by the REVOKED ATTRIBUTE
// We also remove REVOKED from attribute list, since we display it separately
//
boolean revoked = realRacfAttributes.remove("REVOKED");
attributesRead.put(OperationalAttributes.ENABLE_NAME, !revoked);
// avoid empty list
if (!realRacfAttributes.isEmpty()) {
attributesRead.put(ATTR_LDAP_ATTRIBUTES, realRacfAttributes);
}
}
// Last Access date must be converted
// TODO: Gael - All these dates convert are wrong with TDS.
// Formats have changed
// 1.5 : yy.ddd
// 1.11, 1.12: mm/dd/yy
if (attributesRead.containsKey(ATTR_LDAP_LAST_ACCESS)) {
Object value = attributesRead.get(ATTR_LDAP_LAST_ACCESS);
Long converted = null;
if (_connector.getConfiguration().getIsTivoliDirectoryServer()) {
try {
SimpleDateFormat lastAccessTDS = new SimpleDateFormat("MM/dd/yy");
converted = lastAccessTDS.parse(value.toString()).getTime();
}
catch (ParseException pe) {
converted = null;
}
} else {
converted = _connector.convertFromRacfTimestamp(value);
}
attributesRead.put(PredefinedAttributes.LAST_LOGIN_DATE_NAME, converted);
}
// TSO SIZE must be converted
//
if (attributesRead.containsKey(ATTR_LDAP_TSO_LOGON_SIZE)) {
Object value = attributesRead.get(ATTR_LDAP_TSO_LOGON_SIZE);
Integer converted = Integer.parseInt((String) value);
attributesRead.put(ATTR_LDAP_TSO_LOGON_SIZE, converted);
}
// password envelope must be converted
//
if (attributesRead.containsKey(ATTR_LDAP_PASSWORD_ENVELOPE)) {
Object value = attributesRead.get(ATTR_LDAP_PASSWORD_ENVELOPE);
byte[] encrypted = (byte[]) value;
if (_passwdEnvDecrypter != null) {
byte[] decrypted = _passwdEnvDecrypter.decrypt(encrypted);
String pw = _passwdEnvDecrypter.getPassword(decrypted);
if (pw != null) {
attributesRead.put(OperationalAttributes.PASSWORD_NAME, AttributeBuilder.buildPassword(pw.toCharArray()).getValue().get(0));
}
}
}
// TSO MAXSIZE must be converted
//
if (attributesRead.containsKey(ATTR_LDAP_TSO_MAX_REGION_SIZE)) {
Object value = attributesRead.get(ATTR_LDAP_TSO_MAX_REGION_SIZE);
Integer converted = Integer.parseInt((String) value);
attributesRead.put(ATTR_LDAP_TSO_MAX_REGION_SIZE, converted);
}
// password change date must be converted
if (attributesRead.containsKey(ATTR_LDAP_PASSWORD_CHANGE)) {
Object value = attributesRead.get(ATTR_LDAP_PASSWORD_CHANGE);
Long converted = null;
if (_connector.getConfiguration().getIsTivoliDirectoryServer()) {
try {
SimpleDateFormat pwdChangedTDS = new SimpleDateFormat("MM/dd/yy");
converted = pwdChangedTDS.parse(value.toString()).getTime();
}
catch (ParseException pe) {
converted = null;
}
} else {
converted = _connector.convertFromRacfTimestamp(value);
}
attributesRead.put(PredefinedAttributes.LAST_PASSWORD_CHANGE_DATE_NAME, converted);
// password change date is 00.000 if expired
//
Boolean expired = "00.000".equals(value);
attributesRead.put(OperationalAttributes.PASSWORD_EXPIRED_NAME, expired);
} else { //If no password change date attr in TDS => means pwd expired
attributesRead.put(OperationalAttributes.PASSWORD_EXPIRED_NAME, true);
}
// Revoke date must be converted
//
long now = new Date().getTime();
if (attributesRead.containsKey(ATTR_LDAP_REVOKE_DATE)) {
Object value = attributesRead.get(ATTR_LDAP_REVOKE_DATE);
Long converted = null;
if (_connector.getConfiguration().getIsTivoliDirectoryServer()) {
try {
SimpleDateFormat resumeRevokeFormatTDS = new SimpleDateFormat("MM/dd/yy");
converted = resumeRevokeFormatTDS.parse(value.toString()).getTime();
}
catch (ParseException pe) {
converted = null;
}
} else {
converted = _connector.convertFromResumeRevokeFormat(value);
}
if (converted == null || converted < now) {
attributesRead.put(OperationalAttributes.DISABLE_DATE_NAME, null);
} else {
attributesRead.put(OperationalAttributes.DISABLE_DATE_NAME, converted);
}
}
// Resume date must be converted
//
if (attributesRead.containsKey(ATTR_LDAP_RESUME_DATE)) {
Object value = attributesRead.get(ATTR_LDAP_RESUME_DATE);
Long converted = null;
if (_connector.getConfiguration().getIsTivoliDirectoryServer()) {
try {
SimpleDateFormat resumeRevokeFormatTDS = new SimpleDateFormat("MM/dd/yy");
converted = resumeRevokeFormatTDS.parse(value.toString()).getTime();
}
catch (ParseException pe) {
converted = null;
}
} else {
converted = _connector.convertFromResumeRevokeFormat(value);
}
if (converted == null || converted < now) {
attributesRead.put(OperationalAttributes.ENABLE_DATE_NAME, null);
} else {
attributesRead.put(OperationalAttributes.ENABLE_DATE_NAME, converted);
}
}
// Groups must be filled in if null
//
if (!attributesRead.containsKey(ATTR_LDAP_GROUPS)) {
attributesRead.put(ATTR_LDAP_GROUPS, new LinkedList<Object>());
}
// Group Owners must be filled in if null
//
if (!attributesRead.containsKey(ATTR_LDAP_CONNECT_OWNER)) {
attributesRead.put(ATTR_LDAP_CONNECT_OWNER, new LinkedList<Object>());
}
// Names/Uids must be made uniform
//
makeUniformUid(attributesRead, ATTR_LDAP_GROUPS);
makeUniformUid(attributesRead, ATTR_LDAP_DEFAULT_GROUP);
makeUniformUid(attributesRead, ATTR_LDAP_OWNER);
makeUniformUid(attributesRead, ATTR_LDAP_CONNECT_OWNER);
}
// Remap GROUP attributes as needed
//
if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
if (attributesRead.containsKey(ATTR_LDAP_SUP_GROUP)) {
Object value = attributesRead.get(ATTR_LDAP_SUP_GROUP);
if (value instanceof String) {
if (( (String) value ).startsWith("racfid=NONE,")) {
attributesRead.put(ATTR_LDAP_SUP_GROUP, null);
}
}
}
// Groups must be filled in if null
//
if (!attributesRead.containsKey(ATTR_LDAP_SUB_GROUPS)) {
attributesRead.put(ATTR_LDAP_SUB_GROUPS, new LinkedList<Object>());
}
// Members must be filled in if null
//
if (!attributesRead.containsKey(ATTR_LDAP_GROUP_USERIDS)) {
attributesRead.put(ATTR_LDAP_GROUP_USERIDS, new LinkedList<Object>());
}
// Group Owners must be filled in if null
//
if (!attributesRead.containsKey(ATTR_LDAP_CONNECT_OWNER)) {
attributesRead.put(ATTR_LDAP_CONNECT_OWNER, new LinkedList<Object>());
}
// Names/Uids must be made uniform
//
makeUniformUid(attributesRead, ATTR_LDAP_OWNER);
makeUniformUid(attributesRead, ATTR_LDAP_SUP_GROUP);
makeUniformUid(attributesRead, ATTR_LDAP_SUB_GROUPS);
makeUniformUid(attributesRead, ATTR_LDAP_CONNECT_OWNER);
makeUniformUid(attributesRead, ATTR_LDAP_GROUP_USERIDS);
}
return attributesRead;
}
static boolean isUidValued(String name) {
return ATTR_LDAP_GROUPS.equalsIgnoreCase(name)
|| ATTR_LDAP_DEFAULT_GROUP.equalsIgnoreCase(name)
|| ATTR_LDAP_OWNER.equalsIgnoreCase(name)
|| ATTR_LDAP_CONNECT_OWNER.equalsIgnoreCase(name)
|| ATTR_LDAP_SUP_GROUP.equalsIgnoreCase(name)
|| ATTR_LDAP_SUB_GROUPS.equalsIgnoreCase(name)
|| ATTR_LDAP_CONNECT_OWNER.equalsIgnoreCase(name)
|| ATTR_LDAP_GROUP_USERIDS.equalsIgnoreCase(name);
}
private void makeUniformUid(Map<String, Object> attributesRead, String attributename) {
if (attributesRead.containsKey(attributename)) {
Object value = attributesRead.get(attributename);
if (value instanceof List) {
List list = (List) value;
for (int i = 0; i < list.size(); i++) {
list.set(i, RacfConnector.extractRacfIdFromLdapId(list.get(i).toString()));
}
} else if (value != null) {
value = RacfConnector.extractRacfIdFromLdapId(value.toString());
}
attributesRead.put(attributename, value);
}
}
private String getConnectOwner(String query) throws NamingException {
Map<String, Object> attributesRead = CollectionUtil.newCaseInsensitiveMap();
Set<String> attributesToGet = new HashSet<String>();
attributesToGet.add(ATTR_LDAP_CONNECT_OWNER);
getAttributesFromLdap(query, attributesRead, attributesToGet);
if (!attributesRead.isEmpty()) {
return createUniformUid((String) attributesRead.get(ATTR_LDAP_CONNECT_OWNER));
} else {
return "";
}
}
private SearchResult getAttributesFromLdap(String ldapName, Map<String, Object> attributesRead,
Set<String> attributesToGet) throws NamingException {
SearchControls subTreeControls = new SearchControls(SearchControls.SUBTREE_SCOPE, 4095, 0, attributesToGet.toArray(new String[0]), true, true);
SearchResult ldapObject = null;
NamingEnumeration<SearchResult> results = _connector.getConnection().getDirContext().search(ldapName, "(objectclass=*)", subTreeControls);
ldapObject = results.next();
Attributes attributes = ldapObject.getAttributes();
NamingEnumeration<? extends javax.naming.directory.Attribute> attributeEnum = attributes.getAll();
while (attributeEnum.hasMore()) {
javax.naming.directory.Attribute attribute = attributeEnum.next();
// Some attributes expect Lists, but may return a singleton,
// these must be mapped back into Lists
Object value = getValueFromAttribute(attribute);
// Gael: We need to get rid of some attributes if they have "NONE" or "NONE SPECIFIED"
// as their value. This was before ZOS 1.11 and TDS
if (!_connector.getConfiguration().getIsTivoliDirectoryServer()){
if ("NONE".equals(value) && isNoneAttribute(attribute.getID())) continue;
else if ("NONE SPECIFIED".equals(value) && isNoneSpecifiedAttribute(attribute.getID())) continue;
else if ("NO-INSTALLATION-DATA".equals(value) && ATTR_LDAP_DATA.equalsIgnoreCase(attribute.getID())) continue;
else if ("NO INSTALLATION DATA".equals(value) && ATTR_LDAP_DATA.equalsIgnoreCase(attribute.getID())) continue;
else if ("NO-MODEL-NAME".equals(value) && ATTR_LDAP_MODEL.equalsIgnoreCase(attribute.getID())) continue;
else if ("NO MODEL DATA SET".equals(value) && ATTR_LDAP_MODEL.equalsIgnoreCase(attribute.getID())) continue;
else if ("UNKNOWN".equals(value) && ATTR_LDAP_PROGRAMMER_NAME.equalsIgnoreCase(attribute.getID())) continue;
else if ("UNKNOWN".equals(value) && ATTR_LDAP_LAST_ACCESS.equalsIgnoreCase(attribute.getID())) continue;
else if ("ANYTIME".equals(value) && ATTR_LDAP_LOGON_TIME.equalsIgnoreCase(attribute.getID())) continue;
else if ("NO SUBGROUPS".equals(value) && ATTR_LDAP_SUB_GROUPS.equalsIgnoreCase(attribute.getID())) continue;
else{}
}
if (ATTR_LDAP_GROUPS.equalsIgnoreCase(attribute.getID())) {
if (!( value instanceof List )) {
List newValue = new LinkedList();
newValue.add(value);
value = newValue;
}
attributesRead.put(attribute.getID(), value);
}
else {
attributesRead.put(attribute.getID(), value);
}
}
return ldapObject;
}
private boolean isNoneAttribute(String name) {
return ATTR_LDAP_OMVS_MAX_CPUTIME.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_MAX_ADDR_SPACE.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_MAX_FILES.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_MAX_MEMORY_MAP.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_MAX_THREADS.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_MAX_PROCESSES.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_UID.equalsIgnoreCase(name)
|| ATTR_LDAP_OVM_UID.equalsIgnoreCase(name)
|| ATTR_LDAP_OMVS_GROUP_ID.equalsIgnoreCase(name)
|| ATTR_LDAP_OVM_GROUP_ID.equalsIgnoreCase(name)
|| ATTR_LDAP_CLASS_NAME.equalsIgnoreCase(name)
|| ATTR_LDAP_REVOKE_DATE.equalsIgnoreCase(name)
|| ATTR_LDAP_RESUME_DATE.equalsIgnoreCase(name)
|| ATTR_LDAP_ATTRIBUTES.equalsIgnoreCase(name);
}
private boolean isNoneSpecifiedAttribute(String name) {
return ATTR_LDAP_SECURITY_LEVEL.equalsIgnoreCase(name)
|| ATTR_LDAP_SECURITY_CAT_LIST.equalsIgnoreCase(name)
|| ATTR_LDAP_SECURITY_LABEL.equalsIgnoreCase(name)
|| ATTR_LDAP_LANG_PRIMARY.equalsIgnoreCase(name)
|| ATTR_LDAP_LANG_SECONDARY.equalsIgnoreCase(name);
}
static Object getValueFromAttribute(javax.naming.directory.Attribute attribute) throws NamingException {
switch (attribute.size()) {
case 0:
return null;
case 1:
return attribute.get();
default: {
List<Object> values = new LinkedList<Object>();
NamingEnumeration ne = attribute.getAll();
while (ne.hasMore()) {
values.add(ne.next());
}
return values;
}
}
}
public Uid updateViaLdap(ObjectClass objectClass, Set<Attribute> attrs, OperationOptions options) {
Map<String, Attribute> attributes = CollectionUtil.newCaseInsensitiveMap();
attributes.putAll(AttributeUtil.toMap(attrs));
Uid uid = AttributeUtil.getUidAttribute(attrs);
String profileType = "group";
if (!objectClass.is(ObjectClass.ACCOUNT_NAME) && !objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
throw new ConnectorException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, objectClass));
}
if (uid != null) {
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
profileType = "user";
Attribute expired = attributes.get(ATTR_LDAP_EXPIRED);
Attribute password = attributes.get(ATTR_LDAP_PASSWORD);
if (expired != null && password == null) {
throw new ConnectorException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.EXPIRED_NO_PASSWORD));
}
}
String[] attrToFetch = new String[attributes.size()];
int i = 0;
for (Attribute attribute : attributes.values()) {
attrToFetch[i] = attribute.getName().toLowerCase();
i++;
}
try {
SearchControls subTreeControls = new SearchControls(SearchControls.OBJECT_SCOPE, 0, 0, attrToFetch, true, true);
String search = "racfid=" + uid.getUidValue() + ",profileType=" + profileType + "," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
NamingEnumeration<SearchResult> entries = ( (RacfConnection) _connector.getConnection() ).getDirContext().search(search, "(objectclass=*)", subTreeControls);
if (!entries.hasMoreElements()) {
throw new UnknownUidException();
}
Attributes curAttrs = entries.next().getAttributes();
Attributes diffValues = diffEntries(createLdapAttributesFromConnectorAttributes(objectClass, attributes), curAttrs);
if (diffValues.size() > 0) {
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
Attribute groups = attributes.remove(ATTR_LDAP_GROUPS);
Attribute groupOwners = attributes.remove(ATTR_LDAP_CONNECT_OWNER);
if (( groups != null ) && ( diffValues.remove(ATTR_LDAP_GROUPS) != null )) {
diffValues.remove(ATTR_LDAP_CONNECT_OWNER);
_connector.throwErrorIfNull(groups);
_connector.throwErrorIfNull(groupOwners);
if (curAttrs.get(ATTR_LDAP_DEFAULT_GROUP.toUpperCase()) != null) {
_connector.setGroupMembershipsForUser(uid.getUidValue(), groups, groupOwners, curAttrs.get(ATTR_LDAP_GROUPS), (String) curAttrs.get(ATTR_LDAP_DEFAULT_GROUP.toUpperCase()).get());
} else {
_connector.setGroupMembershipsForUser(uid.getUidValue(), groups, groupOwners);
}
}
( (RacfConnection) _connector.getConnection() ).getDirContext().modifyAttributes(createDnFromName(objectClass, uid.getUidValue()), DirContext.REPLACE_ATTRIBUTE, diffValues);
if (diffValues.get(ATTR_LDAP_DEFAULT_GROUP) != null) {
boolean toRemove = true;
String defGroup = RacfConnector.extractRacfIdFromLdapId((String)curAttrs.get(ATTR_LDAP_DEFAULT_GROUP.toUpperCase()).get());
for (Object gr : groups.getValue()) {
if (((String)gr).equalsIgnoreCase(defGroup)) {
toRemove = false;
break;
}
}
if (toRemove) {
String dn = "racfgroupid="+ defGroup +"+racfuserid="+uid.getUidValue()+ ",profileType=connect," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
( (RacfConnection) _connector.getConnection() ).getDirContext().destroySubcontext(dn);
}
}
} else if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
Attribute members = attributes.remove(ATTR_LDAP_GROUP_USERIDS);
Attribute groupOwners = attributes.remove(ATTR_LDAP_CONNECT_OWNER);
( (RacfConnection) _connector.getConnection() ).getDirContext().modifyAttributes(createDnFromName(objectClass, uid.getUidValue()), DirContext.REPLACE_ATTRIBUTE, diffValues);
if (members != null) {
_connector.setGroupMembershipsForGroups(uid.getUidValue(), members, groupOwners);
}
}
}
}
catch (NamingException e) {
if (e.toString().contains("INVALID USER") || e.toString().contains("INVALID GROUP")) {
throw new AlreadyExistsException();
} else {
throw new ConnectorException(e);
}
}
}
return uid;
}
protected void addObjectClass(ObjectClass objectClass, Map<String, Attribute> attrs) {
List<Object> values = new ArrayList<Object>();
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
for (String userObjectClass : ( (RacfConfiguration) _connector.getConfiguration() ).getUserObjectClasses()) {
values.add(userObjectClass);
}
} else if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
for (String groupObjectClass : ( (RacfConfiguration) _connector.getConfiguration() ).getGroupObjectClasses()) {
values.add(groupObjectClass);
}
}
attrs.put("objectclass", AttributeBuilder.build("objectclass", values));
}
private Attributes createLdapAttributesFromConnectorAttributes(ObjectClass objectClass, Map<String, Attribute> attributes) {
Attributes basicAttributes = new BasicAttributes(true);
Set<ObjectClassInfo> objectClassInfos = _schema.getObjectClassInfo();
ObjectClassInfo accountInfo = null;
for (ObjectClassInfo objectClassInfo : objectClassInfos) {
if (objectClassInfo.is(objectClass.getObjectClassValue())) {
accountInfo = objectClassInfo;
}
}
Set<AttributeInfo> attributeInfos = accountInfo.getAttributeInfo();
Set<String> racfAttributes = CollectionUtil.newCaseInsensitiveSet();
boolean setRacfAttributes = false;
boolean negateAttributes = false;
for (Attribute attribute : attributes.values()) {
String attributeName = attribute.getName().toLowerCase();
if (attribute.getValue() == null) { // TODO Gael this is an issue (see INSTALLATION DATA or OMVSHOME)
//throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.BAD_ATTRIBUTE_VALUE, (String) null));
continue;
}
if (attribute.is(Name.NAME) || attribute.is(Uid.NAME)) {
// Ignore Name, Uid
continue;
} else if (attribute.is("objectclass")) {
BasicAttribute objectClassAttribute = new BasicAttribute("objectclass");
for (Object value : attribute.getValue()) {
objectClassAttribute.add(value);
}
basicAttributes.put(objectClassAttribute);
//} else if (attribute.is(ATTR_LDAP_SUP_GROUP)) {
// TODO: GAEL - Need to verifiy superior group exists
} else if (attribute.is(ATTR_LDAP_ATTRIBUTES)) {
for (Object value : attribute.getValue()) {
if (value == null) { // TODO: check if this is not too restrictive
throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.BAD_ATTRIBUTE_VALUE, (String) null));
} else {
String string = value.toString();
if (!RacfConnector.POSSIBLE_ATTRIBUTES.contains(string)) {
//TODO Gael: solve this issue with PASSWORD ATTRIBUTE, throws this exception on UPDATE op
//This is also wrong since racfAttributes can be used to set many keywords for both altuser and adduser
// add: racfattributes
// racfattributes: resume norevoke => check this anyway...
//throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.BAD_ATTRIBUTE_VALUE, string));
} else {
racfAttributes.add(string);
setRacfAttributes = true; //TODO temporary, need to solve the RACF ATTRIBUTE update issue
}
}
}
negateAttributes = true;
//setRacfAttributes = true; //TODO temporary, need to solve the RACF ATTRIBUTE update issue
} else if (attribute.is(ATTR_LDAP_AUTHORIZATION_DATE)
|| attribute.is(ATTR_LDAP_PASSWORD_INTERVAL)
|| attribute.is(ATTR_LDAP_RACF_ID)
|| attribute.is(ATTR_LDAP_LAST_ACCESS)
|| attribute.is(ATTR_LDAP_PASSWORD_CHANGE)
|| attribute.is(ATTR_LDAP_SUB_GROUP)
|| attribute.is(ATTR_LDAP_GROUP_USERIDS)) {
// Ignore read-only attrs
//
} else if (attribute.is(PredefinedAttributes.GROUPS_NAME)) {
// Groups handled separately
//
} else if (attribute.is(OperationalAttributes.CURRENT_PASSWORD_NAME)) {
// Ignore current password
//
} else if (attribute.is(ATTR_LDAP_EXPIRED)) {
if (AttributeUtil.getBooleanValue(attribute)) {
racfAttributes.add("Expired");
} else {
racfAttributes.add("noExpired");
}
setRacfAttributes = true;
} else if (attribute.is(ATTR_LDAP_ENABLED)) {
if (AttributeUtil.getBooleanValue(attribute)) {
racfAttributes.add("RESUME");
} else {
racfAttributes.add("REVOKE");
}
setRacfAttributes = true;
} else if (attribute.is(ATTR_LDAP_RESUME_DATE) || attribute.is(ATTR_LDAP_REVOKE_DATE)) {
basicAttributes.put(attribute.getName(), AttributeUtil.getStringValue(attribute));
} else if (attribute.is(ATTR_LDAP_PASSWORD)) {
// remap password
//
List<Object> value = attribute.getValue();
if (value == null || value.size() != 1) {
throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.MUST_BE_SINGLE_VALUE));
}
GuardedString password = AttributeUtil.getGuardedStringValue(attribute);
GuardedStringAccessor accessor = new GuardedStringAccessor();
password.access(accessor);
basicAttributes.put(ATTR_LDAP_PASSWORD, new String(accessor.getArray()));
} else {
AttributeInfo attributeInfo = getAttributeInfo(attributeInfos, attributeName);
if (attributeInfo == null) {
throw new IllegalArgumentException(( (RacfConfiguration) _connector.getConfiguration() ).getMessage(RacfMessages.UNKNOWN_ATTRIBUTE, attributeName));
}
basicAttributes.put(makeBasicAttribute(attributeName, attribute.getValue()));
}
}
if (setRacfAttributes) {
// Since RACF LDAP does't obey replace semantics, we need to patch in
// any values that should be removed
//
//TODO: an alternative implementation would be to read the user object
// and get the set of current values for ATTRIBUTE. This has the
// advantage of getting the exact set of values, but the disadvantage
// that it requires an extra read of the user.
//NOTE: this probably also applies to 'RacfConnectAttributes', which we
// are not currently supporting
List<Object> finalValue = new LinkedList<Object>();
if (negateAttributes) {
for (String attrValue : RacfConnector.POSSIBLE_ATTRIBUTES) {
if (!racfAttributes.contains(attrValue)) {
finalValue.add("NO" + attrValue);
}
}
}
finalValue.addAll(racfAttributes);
basicAttributes.put(makeBasicAttribute(ATTR_LDAP_ATTRIBUTES, finalValue));
}
return basicAttributes;
}
private Attributes createLdapAttributesFromConnectorAttributes(Map<String, Attribute> attributes) {
Attributes basicAttributes = new BasicAttributes();
for (Attribute attribute : attributes.values()) {
String attributeName = attribute.getName().toLowerCase();
if (attribute.is(Name.NAME) || attribute.is(Uid.NAME)) {
// Ignore Name, Uid
//
} else {
basicAttributes.put(makeBasicAttribute(attributeName, attribute.getValue()));
}
}
return basicAttributes;
}
private BasicAttribute makeBasicAttribute(String name, List<Object> racfAttributes) {
BasicAttribute attribute = new BasicAttribute(name);
for (Object value : racfAttributes) {
if (value != null) {
value = value.toString();
}
attribute.add(value);
}
return attribute;
}
private AttributeInfo getAttributeInfo(Set<AttributeInfo> attributeInfos, String name) {
for (AttributeInfo attributeInfo : attributeInfos) {
if (attributeInfo.getName().equalsIgnoreCase(name)) {
return attributeInfo;
}
}
return null;
}
/**
* Create a RACF LDAP DN given a name.
*
* @param name
* @return DN form
*/
String createDnFromName(ObjectClass objectClass, String name) {
if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
return "racfid=" + name.toUpperCase() + ",profiletype=user," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
} else if (objectClass.is(RacfConnector.RACF_GROUP_NAME)) {
return "racfid=" + name.toUpperCase() + ",profiletype=group," + ( (RacfConfiguration) _connector.getConfiguration() ).getSuffix();
} else {
return name;
}
}
private Attributes diffEntries(Attributes newValues, Attributes curValues) {
NamingEnumeration<javax.naming.directory.Attribute> attrEnum = (NamingEnumeration<javax.naming.directory.Attribute>) curValues.getAll();
try {
while (attrEnum.hasMore()) {
javax.naming.directory.Attribute curAttr = attrEnum.next();
javax.naming.directory.Attribute newAttr = newValues.get(curAttr.getID());
if (( newAttr != null ) && ( curAttr.size() == newAttr.size() )) {
// ok.. we have the attribute both in current entry and new entry
// lets compare.
if (newAttr.size() == 0) {
// Houston.. we have an empty one
}
if (newAttr.size() == 1) {
Object newValue = newAttr.get();
Object curValue = curAttr.get();
if (( newValue instanceof String ) && ( curValue instanceof String )) {
if (( (String) newValue ).equalsIgnoreCase(_connector.extractRacfIdFromLdapId((String) curValue))) {
newValues.remove(newAttr.getID());
}
}
} else { //multi value attr
NamingEnumeration newValue = newAttr.getAll();
NamingEnumeration curValue = curAttr.getAll();
ArrayList newList = new ArrayList();
ArrayList curList = new ArrayList();
while (newValue.hasMoreElements()) {
newList.add(newValue.next());
}
while (curValue.hasMoreElements()) {
curList.add(curValue.next());
}
if (newList.size() == curList.size()) {
ArrayList safeCurList = new ArrayList();
for (Object s : curList) {
safeCurList.add(_connector.extractRacfIdFromLdapId((String) s));
}
newList.removeAll(safeCurList);
if (newList.isEmpty()) {
newValues.remove(newAttr.getID());
}
}
}
}
}
}
catch (Exception e) {
}
return newValues;
}
}