
org.connid.bundles.ldap.commons.LdapModifyOperation Maven / Gradle / Ivy
The newest version!
/**
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright 2011-2013 Tirasa. 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 https://oss.oracle.com/licenses/CDDL
* 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 https://oss.oracle.com/licenses/CDDL.
* 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.connid.bundles.ldap.commons;
import static java.util.Collections.min;
import static org.connid.bundles.ldap.commons.LdapUtil.addStringAttrValues;
import static org.connid.bundles.ldap.commons.LdapUtil.quietCreateLdapName;
import static org.identityconnectors.common.CollectionUtil.isEmpty;
import static org.identityconnectors.common.StringUtil.isBlank;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import org.connid.bundles.ldap.LdapConnection;
import org.connid.bundles.ldap.commons.GroupHelper.GroupMembership;
import org.connid.bundles.ldap.search.LdapSearches;
import org.identityconnectors.common.Base64;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
public abstract class LdapModifyOperation {
protected final LdapConnection conn;
protected final GroupHelper groupHelper;
public LdapModifyOperation(LdapConnection conn) {
this.conn = conn;
groupHelper = new GroupHelper(conn);
}
protected final void hashPassword(final Attribute passwordAttr, final String entryDN) {
String hashAlgorithm = conn.getConfiguration().getPasswordHashAlgorithm();
if (isBlank(hashAlgorithm) || "NONE".equalsIgnoreCase(hashAlgorithm)) {
return;
}
try {
byte[] password = (byte[]) passwordAttr.get();
if (password != null) {
String newPassword = hashBytes(password, hashAlgorithm,
entryDN != null ? entryDN.hashCode() : 0);
passwordAttr.clear();
passwordAttr.add(newPassword);
}
} catch (NamingException e) {
throw new ConnectorException(e);
}
}
private String hashBytes(final byte[] plain, final String algorithm, final long randSeed) {
String plainPassword = new String(plain);
if (plainPassword != null && plainPassword.startsWith("{")) {
String digest = plainPassword.substring(1, plainPassword.indexOf('}'));
if (digest != null && algorithm.equalsIgnoreCase(digest)) {
return plainPassword;
}
}
MessageDigest digest = null;
try {
if (algorithm.equalsIgnoreCase("SSHA") || algorithm.equalsIgnoreCase("SHA")) {
digest = MessageDigest.getInstance("SHA-1");
} else if (algorithm.equalsIgnoreCase("SMD5") || algorithm.equalsIgnoreCase("MD5")) {
digest = MessageDigest.getInstance("MD5");
}
} catch (NoSuchAlgorithmException e) {
throw new ConnectorException("Could not find MessageDigest algorithm (" + algorithm + ") implementation");
}
if (digest == null) {
throw new ConnectorException("Unsupported hash algorithm: " + algorithm);
}
byte[] salt = {};
if (algorithm.equalsIgnoreCase("SSHA") || algorithm.equalsIgnoreCase("SMD5")) {
Random rand = new Random();
rand.setSeed(System.currentTimeMillis() + randSeed);
// A RSA whitepaper
// suggested the salt length be the same as the output of the
// hash function being used. The adapter uses the length of the input,
// hoping that it is close enough an approximation.
salt = new byte[8];
rand.nextBytes(salt);
}
digest.reset();
digest.update(plain);
digest.update(salt);
byte[] hash = digest.digest();
byte[] hashPlusSalt = new byte[hash.length + salt.length];
System.arraycopy(hash, 0, hashPlusSalt, 0, hash.length);
System.arraycopy(salt, 0, hashPlusSalt, hash.length, salt.length);
StringBuilder result = new StringBuilder(algorithm.length() + hashPlusSalt.length);
result.append('{');
result.append(algorithm);
result.append('}');
result.append(Base64.encode(hashPlusSalt));
return result.toString();
}
protected static Set getAttributeValues(final String attrName, final LdapName entryDN,
final Attributes attrs) {
final Set result = new HashSet();
if (entryDN != null && !entryDN.isEmpty()) {
Rdn rdn = entryDN.getRdn(entryDN.size() - 1);
addStringAttrValues(rdn.toAttributes(), attrName, result);
}
Attribute attr = attrs.get(attrName);
if (attr != null) {
try {
NamingEnumeration> attrEnum = attr.getAll();
while (attrEnum.hasMoreElements()) {
result.add((String) attrEnum.nextElement());
}
} catch (NamingException e) {
throw new ConnectorException(e);
}
return result;
}
// If we got here, the attribute was not in the Attributes instance. So if the
// result is empty, that means the attribute is not present in either
// the entry DN or the attribute set.
return result.isEmpty() ? null : result;
}
protected final String getFirstPosixRefAttr(final String entryDN, final Set posixRefAttrs) {
if (isEmpty(posixRefAttrs)) {
throw new ConnectorException(conn.format("cannotAddToPosixGroup",
null, entryDN, GroupHelper.getPosixRefAttribute()));
}
return min(posixRefAttrs);
}
/**
* Holds the POSIX ref attributes and the respective group memberships. Retrieves them lazily so that they are only
* retrieved once, when they are needed.
*/
public final class PosixGroupMember {
private final String entryDN;
private LdapEntry entry;
private Set posixRefAttrs;
private Set posixGroupMemberships;
public PosixGroupMember(String entryDN) {
this.entryDN = entryDN;
}
public Set getPosixGroupMemberships() {
if (posixGroupMemberships == null) {
posixGroupMemberships = groupHelper.getPosixGroupMemberships(
getPosixRefAttributes());
}
return posixGroupMemberships;
}
public Set getPosixGroupMembershipsByAttrs(final Set posixRefAttrs) {
Set result = new HashSet();
for (GroupMembership member : getPosixGroupMemberships()) {
if (posixRefAttrs.contains(member.getMemberRef())) {
result.add(member);
}
}
return result;
}
public Set getPosixGroupMembershipsByGroups(final List groupDNs) {
Set groupNames = new HashSet();
for (String groupDN : groupDNs) {
groupNames.add(quietCreateLdapName(groupDN));
}
Set result = new HashSet();
for (GroupMembership member : getPosixGroupMemberships()) {
if (groupNames.contains(quietCreateLdapName(member.getGroupDN()))) {
result.add(member);
}
}
return result;
}
public Set getPosixRefAttributes() {
if (posixRefAttrs == null) {
posixRefAttrs = getAttributeValues(GroupHelper.getPosixRefAttribute(), null,
getLdapEntry().getAttributes());
}
return posixRefAttrs;
}
private LdapEntry getLdapEntry() {
if (entry == null) {
entry = LdapSearches.getEntry(conn, quietCreateLdapName(entryDN), GroupHelper.getPosixRefAttribute());
}
return entry;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy