com.vmware.identity.idm.server.ServerUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.identity.idm.server.ServerUtils.java

Source

/*
 *
 *  Copyright (c) 2012-2015 VMware, Inc.  All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not
 *  use this file except in compliance with the License.  You may obtain a copy
 *  of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 *  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 com.vmware.identity.idm.server;

/**
 * Created by IntelliJ IDEA.
 * User: mpotapova
 * Date: 1/4/12
 * Time: 4:45 PM
 * To change this template use File | Settings | File Templates.
 */
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.security.auth.login.LoginException;

import org.apache.commons.lang.SystemUtils;
import org.apache.commons.lang.Validate;

import com.vmware.identity.diagnostics.DiagnosticsLoggerFactory;
import com.vmware.identity.diagnostics.IDiagnosticsLogger;
import com.vmware.identity.idm.AuthenticationType;
import com.vmware.identity.idm.Group;
import com.vmware.identity.idm.IDMException;
import com.vmware.identity.idm.IDMLoginException;
import com.vmware.identity.idm.IDMReferralException;
import com.vmware.identity.idm.InvalidArgumentException;
import com.vmware.identity.idm.InvalidPrincipalException;
import com.vmware.identity.idm.NoSuchIdpException;
import com.vmware.identity.idm.NoSuchTenantException;
import com.vmware.identity.idm.PrincipalId;
import com.vmware.identity.idm.ValidateUtil;
import com.vmware.identity.idm.server.config.IdmServerConfig;
import com.vmware.identity.idm.server.provider.IIdentityProvider;
import com.vmware.identity.idm.server.provider.ISystemDomainIdentityProvider;
import com.vmware.identity.interop.ldap.DirectoryStoreProtocol;
import com.vmware.identity.interop.ldap.ILdapConnectionEx;
import com.vmware.identity.interop.ldap.ILdapConnectionExWithGetConnectionString;
import com.vmware.identity.interop.ldap.ILdapEntry;
import com.vmware.identity.interop.ldap.ILdapMessage;
import com.vmware.identity.interop.ldap.ISslX509VerificationCallback;
import com.vmware.identity.interop.ldap.LdapBindMethod;
import com.vmware.identity.interop.ldap.LdapConnectionFactory;
import com.vmware.identity.interop.ldap.LdapConnectionFactoryEx;
import com.vmware.identity.interop.ldap.LdapConstants;
import com.vmware.identity.interop.ldap.LdapOption;
import com.vmware.identity.interop.ldap.LdapSSLProtocols;
import com.vmware.identity.interop.ldap.LdapScope;
import com.vmware.identity.interop.ldap.LdapSetting;
import com.vmware.identity.interop.ldap.LdapValue;
import com.vmware.identity.interop.ldap.ReferralLdapException;
import com.vmware.identity.performanceSupport.PerfBucketKey;
import com.vmware.identity.performanceSupport.PerfMeasurementPoint;

public class ServerUtils {
    private static final IDiagnosticsLogger logger = DiagnosticsLoggerFactory.getLogger(ServerUtils.class);
    private static final long DEFAULT_LDAP_NETWORK_TIMEOUT = 30;

    public static IDMException getRemoteException(Exception ex) {
        assert ((ex != null));

        IDMException idmEx = null;

        logger.error(String.format("Exception '%s'", ex.toString()), ex);

        if (ex instanceof LoginException) {
            idmEx = new IDMLoginException(ex.getMessage());
        } else if (ex instanceof ReferralLdapException) {
            return new IDMReferralException(ex.getMessage());
        } else if (ex instanceof InvalidPrincipalException) {
            return new InvalidPrincipalException(ex.getMessage(), ((InvalidPrincipalException) ex).getPrincipal());
        } else if (ex.getClass().equals(IDMLoginException.class)) {
            return new IDMLoginException(ex.getMessage(), ((IDMLoginException) ex).getUri());
        } else if (ex instanceof IllegalArgumentException) {
            idmEx = new InvalidArgumentException(ex.getMessage());
        } else if (ex instanceof IDMException) {
            idmEx = (IDMException) ex;

            // we do not expose the chain for any other exception
            // for IDM exception we should not do this also -
            // for one we don't want to expose it, for another chain could contain
            // exception types that RMI will not be able to create on the client
            // but if the chain is not present -> no need to do anything.
            if (idmEx.getCause() != null) {
                Class<? extends IDMException> theClass = idmEx.getClass();

                try {
                    idmEx = theClass.getConstructor(new Class[] { String.class })
                            .newInstance(new Object[] { idmEx.getMessage() });
                } catch (Exception e) {
                    // this should never fail, but to satisfy java checked exception error, we will fall back to
                    // plain old IDM exception
                    logger.error(String.format("Exception '%s'", ex.toString()), ex);
                    idmEx = new IDMException(ex.getMessage());
                }
            }
        } else {
            logger.error("Caught an unexpected exception", ex);
            idmEx = new IDMException(ex.getMessage());
        }

        return idmEx;
    }

    public static boolean isNullOrEmpty(String str) {
        return (str == null) || (str.isEmpty());
    }

    public static boolean isEquals(String src, String dst) {
        return (src == dst) || (src == null && dst == null) || (src != null && src.equalsIgnoreCase(dst));
    }

    public static String getAttributeKeyValueAsString(String keyAttribute, String valueAttribute) {
        ValidateUtil.validateNotEmpty(keyAttribute, "keyAttribute");
        ValidateUtil.validateNotEmpty(valueAttribute, "valueAttribute");

        return String.format("%s:%s", keyAttribute, valueAttribute);
    }

    public static Map.Entry<String, String> getAttributeKeyValueFromString(String attibuteKeyValueString) {
        ValidateUtil.validateNotEmpty(attibuteKeyValueString, "attibuteKeyValueString");

        int delimiterIndex = attibuteKeyValueString.lastIndexOf(":");
        if (delimiterIndex == -1) {
            throw new IllegalStateException(
                    String.format("Attribute mapping '%s' is of unexpected format.", attibuteKeyValueString));
        }

        return new HashMap.SimpleImmutableEntry<String, String>(attibuteKeyValueString.substring(0, delimiterIndex),
                attibuteKeyValueString.substring(delimiterIndex + 1));
    }

    /**
     * Checks the connectivity to an identity provider
     *
     * @param providerUri Location of identity provider. non-null non-empty, required
     * @param userName    Login identifier. non-null, required
     * @param pwd         Password    non-null non-empty, required
     * @return connection:  non-null
     * @throws IDMLoginException. If one or more of the input argument is illegal.
     *                                 Or URI syntax is incorrect.
     * @throws Exception     if no connection
     * @throws IllegalArgumentException  one or more input are empty
     */
    public static ILdapConnectionEx getLdapConnectionByURIs(Collection<URI> uris, String userName, String password,
            AuthenticationType authType, boolean useGcPort) throws Exception

    {
        return getLdapConnectionByURIs(uris, userName, password, authType, useGcPort, null);
    }

    /**
     * Checks the connectivity to an identity provider
     *
     * @param providerUri Location of identity provider. non-null non-empty, required
     * @param userName    Login identifier. non-null, required
     * @param pwd         Password    non-null non-empty, required
     * @param certVerifierCallback Callback called to validate SSL certificates
     * @return connection:  non-null
     * @throws IDMLoginException. If one or more of the input argument is illegal.
     *                                 Or URI syntax is incorrect.
     * @throws Exception     if no connection
     * @throws IllegalArgumentException  one or more input are empty
     */
    public static ILdapConnectionEx getLdapConnectionByURIs(Collection<URI> uris, String userName, String password,
            AuthenticationType authType, boolean useGcPort,
            LdapCertificateValidationSettings certValidationsettings) throws Exception {
        ValidateUtil.validateNotEmpty(uris, "uris");

        // NB: not checking whether the port is Kerberos port 88.

        ILdapConnectionEx result = null;
        Exception latestEx = null;
        for (URI uri : uris) {
            if (!DirectoryStoreProtocol.isProtocolSupported(uri.getScheme())) {
                logger.warn(String.format("protocol scheme for the specified URI is not supported: [%s]",
                        uri.toString()));
                continue; //skip unsupported protocol
            }

            logger.trace("start creating connection {}", uri);
            try {
                result = getLdapConnection(uri, userName, password, authType, useGcPort, certValidationsettings);
                if (null != result) {
                    logger.trace("done creating connection");

                    return result; //done
                }
            } catch (Exception e) { //log an error, pin down the latest and continue
                latestEx = e;
                logger.error("cannot establish connection with uri: {}", uri);
            }
        }

        assert (result == null);
        if (latestEx != null) {
            throw latestEx; // could not get connection from any of them
        }
        return null;
    }

    private static ILdapConnectionEx getLdapConnection(URI uri, String userName, String password,
            AuthenticationType authType, boolean useGcPort,
            LdapCertificateValidationSettings certValidationsettings) throws Exception {
        ValidateUtil.validateNotNull(uri, "uri");

        boolean isLdaps = uri.getScheme().compareToIgnoreCase(DirectoryStoreProtocol.LDAPS.getName()) == 0;

        List<LdapSetting> connOptions = null;
        List<LdapSetting> settings = new ArrayList<LdapSetting>();
        settings.add(new LdapSetting(LdapOption.LDAP_OPT_PROTOCOL_VERSION, LdapConstants.LDAP_VERSION3));
        settings.add(new LdapSetting(LdapOption.LDAP_OPT_REFERRALS, Boolean.FALSE));
        settings.add(new LdapSetting(LdapOption.LDAP_OPT_NETWORK_TIMEOUT, DEFAULT_LDAP_NETWORK_TIMEOUT));

        if (isLdaps) {
            //if is ldaps connection and certificate validation is enabled set the options for validation
            boolean isLdapsCertValidationEnabled = certValidationsettings != null
                    && (certValidationsettings.isForceValidation()
                            || IdmServerConfig.getInstance().isLdapsCertValidationEnabled()
                            || !certValidationsettings.isLegacy());
            if (isLdapsCertValidationEnabled) {
                ISslX509VerificationCallback certVerifierCallback = certValidationsettings
                        .getCertVerificationCallback(uri);
                settings.add(new LdapSetting(LdapOption.LDAP_OPT_X_TLS_REQUIRE_CERT,
                        LdapConstants.LDAP_OPT_X_TLS_DEMAND));
                settings.add(
                        new LdapSetting(LdapOption.LDAP_OPT_X_CLIENT_TRUSTED_FP_CALLBACK, certVerifierCallback));

                int sslMinProtocol = certValidationsettings.isLegacy()
                        ? LdapSSLProtocols.getDefaultLegacyMinProtocol().getCode()
                        : LdapSSLProtocols.getDefaultMinProtocol().getCode();
                settings.add(new LdapSetting(LdapOption.LDAP_OPT_X_TLS_PROTOCOL, sslMinProtocol));
            } else {
                settings.add(new LdapSetting(LdapOption.LDAP_OPT_X_TLS_REQUIRE_CERT,
                        LdapConstants.LDAP_OPT_X_TLS_NEVER));
            }
        }
        // When doing GSSAPI authentication, LDAP SASL binding by default does reverse DNS lookup to validate the
        // target name, this causes authentication failures because Most DNS servers in AD do not have PTR records
        // registered for all DCs, any of which could be the binding target.
        if (!SystemUtils.IS_OS_WINDOWS && authType == AuthenticationType.USE_KERBEROS
                || authType == AuthenticationType.SRP) {
            settings.add(new LdapSetting(LdapOption.LDAP_OPT_X_SASL_NOCANON, LdapConstants.LDAP_OPT_ON));
        }

        connOptions = Collections.unmodifiableList(settings);

        ILdapConnectionEx connection = null;

        // if No port# or the default port of 389 (ldap) or 636 (ldaps) is specified then useGcport takes effect;
        // otherwise, go with the explicit specified port#
        if (authType == AuthenticationType.SRP) {
            connection = (ILdapConnectionEx) LdapConnectionFactory.getInstance().getLdapConnection(uri, connOptions,
                    true);
        } else if ((uri.getPort() == -1 || uri.getPort() == LdapConstants.LDAP_PORT
                || uri.getPort() == LdapConstants.LDAP_SSL_PORT) && useGcPort) {
            connection = LdapConnectionFactoryEx.getInstance().getLdapConnection(uri.getHost(),
                    isLdaps ? LdapConstants.LDAP_SSL_GC_PORT : LdapConstants.LDAP_GC_PORT, connOptions);
        } else {
            connection = LdapConnectionFactoryEx.getInstance().getLdapConnection(uri, connOptions);
        }

        try {
            // All the client options are set, bind now

            long startTime = System.nanoTime();
            if (AuthenticationType.SRP == authType) {
                ValidateUtil.validateNotEmpty(userName, "userName");
                ValidateUtil.validateNotEmpty(password, "password");
                ((ILdapConnectionExWithGetConnectionString) connection).bindSaslSrpConnection(userName, password);
            } else if (AuthenticationType.USE_KERBEROS == authType) {
                String userUPN = null;
                int idxSep = 0;
                if (!ServerUtils.isNullOrEmpty(userName)) {
                    userUPN = ValidateUtil.normalizeIdsKrbUserName(userName);
                    idxSep = userUPN.indexOf(ValidateUtil.UPN_SEPARATOR);
                }

                connection.bindSaslConnection(
                        ServerUtils.isNullOrEmpty(userUPN) ? null : userUPN.substring(0, idxSep),
                        ServerUtils.isNullOrEmpty(userUPN) ? null : userUPN.substring(idxSep + 1), password);
            } else if (AuthenticationType.PASSWORD == authType) {
                ValidateUtil.validateNotEmpty(userName, "userName");
                ValidateUtil.validateNotEmpty(password, "password");
                connection.bindConnection(userName, password, LdapBindMethod.LDAP_BIND_SIMPLE);
            } else {
                String errMsg = String.format("Unsupported authenticationType to bind connection: [%s, %s]", uri,
                        userName);
                logger.warn(errMsg);
                throw new IllegalStateException(errMsg);
            }

            long delta = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
            if (logger.isTraceEnabled()) {
                logger.trace(String.format("\tbinding connection took [%d] ms", delta));
            }
            if (IdmServer.getPerfDataSinkInstance() != null) {
                IdmServer.getPerfDataSinkInstance().addMeasurement(
                        new PerfBucketKey(PerfMeasurementPoint.LdapBindConnection, uri.toString()), delta);
            }
        } catch (Exception ex) {
            logger.warn(String.format("cannot bind connection: [%s, %s]", uri, userName));
            if (connection != null) {
                connection.close();
            }
            throw ex;
        }

        return connection;
    }

    /**
     * This function will follow AD's standard way to translate from domain <-> DN
     * (i.e. each component of child1.ssolabs.com will match to dc=child1,dc=ssolabs,dc=com)
     */
    public static String getDomainDN(String domain) {
        StringBuilder sb = new StringBuilder();
        if (ServerUtils.isNullOrEmpty(domain) == false) {
            String[] domainParts = domain.split("\\.");

            int iPart = 0;

            for (String part : domainParts) {
                if (iPart > 0) {
                    sb.append(",");
                }

                sb.append(String.format("DC=%s", part));

                iPart++;
            }
        }
        return sb.toString();
    }

    /**
     * This function will follow AD's standard way to translate from domain <-> DN
     * (i.e. each component of child1.ssolabs.com will match to dc=child1,dc=ssolabs,dc=com)
     */
    public static String getDomainFromDN(String dn) {
        final String dcPrefix = "DC=";
        StringBuilder sb = new StringBuilder();

        if (ServerUtils.isNullOrEmpty(dn) == false) {
            String[] parts = dn.toUpperCase().split(",");

            int iPart = 0;

            for (String part : parts) {
                if (part.startsWith(dcPrefix)) {
                    if (iPart++ > 0) {
                        sb.append(".");
                    }

                    sb.append(part.substring(dcPrefix.length()));
                }
            }
        }

        return sb.toString().toLowerCase();
    }

    public static String getStringValue(LdapValue[] value) {
        String strValue = null;
        if ((value != null) && (value.length == 1)) {
            strValue = value[0].getString();
        }
        return strValue;
    }

    public static boolean getBooleanValue(LdapValue[] value) {
        boolean bVal = false;

        if ((value != null) && (value.length == 1)) {
            bVal = Boolean.parseBoolean(value[0].getString());
        }

        return bVal;
    }

    public static String[] getMultiStringValue(LdapValue[] value) {
        String[] strValues = null;
        if ((value != null) && (value.length > 0)) {
            strValues = new String[value.length];
            for (int i = 0; i < value.length; i++) {
                strValues[i] = value[i].getString();
            }
        }
        return strValues;
    }

    public static Collection<String> getMultiStringValueAsCollection(LdapValue[] value) {
        String[] strings = ServerUtils.getMultiStringValue(value);
        return (strings == null) ? null : Arrays.asList(ServerUtils.getMultiStringValue(value));
    }

    public static byte[] getBinaryValue(LdapValue[] value) {
        byte[] binaryValue = null;
        if ((value != null) && (value.length == 1)) {
            binaryValue = value[0].getValue();
        }
        return binaryValue;
    }

    public static LdapValue[] getLdapValue(Collection<String> multiString) {
        LdapValue[] value = null;
        if ((multiString != null) && (multiString.isEmpty() == false)) {
            value = new LdapValue[multiString.size()];
            int i = 0;
            for (String provider : multiString) {
                value[i] = new LdapValue(provider);
                i++;
            }
        }

        return value;
    }

    public static LdapValue[] getLdapValue(String str) {
        LdapValue[] value = null;
        if (ServerUtils.isNullOrEmpty(str) == false) {
            value = new LdapValue[] { new LdapValue(str) };
        }

        return value;
    }

    public static LdapValue[] getLdapValue(int val) {
        return new LdapValue[] { new LdapValue(val) };
    }

    public static LdapValue[] getLdapValue(boolean val) {
        return val ? getLdapValue("TRUE") : getLdapValue("FALSE");
    }

    public static LdapValue[] getLdapValue(long val) {
        return new LdapValue[] { new LdapValue(val) };
    }

    public static LdapValue[] getLdapValue(byte[] bytes) {
        LdapValue[] value = null;
        if ((bytes != null) && (bytes.length > 0)) {
            value = new LdapValue[] { new LdapValue(bytes) };
        }
        return value;
    }

    public static LdapValue[] getLdapValue(int[] integers) {
        LdapValue[] value = null;
        if ((integers != null) && (integers.length > 0)) {
            value = new LdapValue[integers.length];
            int i = 0;
            for (int integerVal : integers) {
                value[i] = new LdapValue(integerVal);
                i++;
            }
        }

        return value;
    }

    private static byte[] getCertBytes(Certificate cert) {
        byte[] bytes = null;

        try {
            bytes = cert.getEncoded();
        } catch (CertificateEncodingException ex) {
            throw new RuntimeException("Failed to get certificate encoded bytes");
        }

        return bytes;
    }

    public static LdapValue[] getLdapValue(Certificate cert) {
        LdapValue[] value = null;
        if (cert != null) {
            byte[] bytes = getCertBytes(cert);

            if ((bytes != null) && (bytes.length > 0)) {
                value = new LdapValue[] { new LdapValue(bytes) };
            }
        }

        return value;
    }

    public static LdapValue[] getLdapValue(ArrayList<? extends Certificate> certs) {
        LdapValue[] value = null;
        if ((certs != null) && (certs.isEmpty() == false)) {
            value = new LdapValue[certs.size()];
            int i = 0;
            for (Certificate cert : certs) {
                byte[] bytes = getCertBytes(cert);

                if ((bytes != null) && (bytes.length > 0)) {
                    value[i] = new LdapValue(bytes);
                }
                i++;
            }
        }

        return value;
    }

    public static LdapValue[] getLdapValue(PrivateKey key) {
        LdapValue[] value = null;
        if (key != null) {
            byte[] bytes = key.getEncoded();

            if ((bytes != null) && (bytes.length > 0)) {
                value = new LdapValue[] { new LdapValue(bytes) };
            }
        }

        return value;
    }

    public static Integer getIntegerValue(LdapValue[] value) {
        Integer intValue = null;
        if ((value != null) && (value.length == 1)) {
            intValue = value[0].getInteger();
        }
        return intValue;
    }

    public static int getIntValue(LdapValue[] value) {
        if ((value == null) || (value.length != 1)) {
            throw new IllegalArgumentException("Int value cannot be null.");
        }

        return value[0].getInt();
    }

    public static Long getLongValue(LdapValue[] value) {
        Long longValue = null;
        if ((value != null) && (value.length == 1)) {
            longValue = value[0].getLong();
        }
        return longValue;
    }

    public static long getNativeLongValue(LdapValue[] value) {
        if ((value == null) || (value.length != 1)) {
            throw new IllegalArgumentException("long value cannot be null.");
        }

        return value[0].getNativeLong();
    }

    public static int[] getMultiIntValue(LdapValue[] value) {
        int[] intValues = null;
        if ((value != null) && (value.length > 0)) {
            intValues = new int[value.length];
            for (int i = 0; i < value.length; i++) {
                intValues[i] = value[i].getInt();
            }
        }
        return intValues;
    }

    public static PrivateKey getPrivateKeyValue(LdapValue[] value) {
        PrivateKey privateKey = null;

        if ((value != null) && (value.length == 1)) {
            byte[] privateKeyBytes = value[0].getValue();
            if (privateKeyBytes != null) {
                try {
                    KeyFactory keyFactory = KeyFactory.getInstance("RSA");

                    EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

                    privateKey = keyFactory.generatePrivate(privateKeySpec);
                } catch (NoSuchAlgorithmException ex1) {
                    throw new RuntimeException("No such algorithm");
                } catch (InvalidKeySpecException ex2) {
                    throw new RuntimeException("Invalid key spec");
                }
            }
        }
        return privateKey;
    }

    private static X509Certificate getCert(LdapValue value) {
        X509Certificate cert = null;

        if (value != null) {
            byte[] certBytes = value.getValue();

            if (certBytes != null) {
                try {
                    ByteArrayInputStream inpstream = new ByteArrayInputStream(certBytes);
                    CertificateFactory cf = CertificateFactory.getInstance("X.509");
                    cert = (X509Certificate) cf.generateCertificate(inpstream);
                } catch (CertificateException e) {
                    throw new RuntimeException("Failed to generate certificate");
                }
            }
        }

        return cert;
    }

    public static X509Certificate getCertificateValue(LdapValue[] value) {
        X509Certificate cert = null;

        if (value != null && value.length == 1 && value[0] != null) {
            cert = getCert(value[0]);
        }
        return cert;
    }

    public static ArrayList<Certificate> getCertificateValues(LdapValue[] value) {
        ArrayList<Certificate> certs = new ArrayList<Certificate>();

        if (value != null && value.length >= 1) {
            for (int i = 0; i < value.length; i++) {
                X509Certificate cert = getCert(value[i]);

                if (cert != null) {
                    certs.add(cert);
                }
            }
        }
        return certs;
    }

    public static Collection<X509Certificate> getX509CertificateValues(LdapValue[] value) {
        Collection<X509Certificate> certs = new ArrayList<X509Certificate>();

        if (value != null && value.length >= 1) {
            for (int i = 0; i < value.length; i++) {
                X509Certificate cert = getCert(value[i]);

                if (cert != null) {
                    certs.add(cert);
                }
            }
        }
        return certs;
    }

    public static Collection<String> getConnectionStringFromUris(Collection<URI> uris) {
        List<String> connectionStrs = new ArrayList<String>();
        for (URI uri : uris) {
            connectionStrs.add(uri.toString());
        }
        return Collections.unmodifiableCollection(connectionStrs);
    }

    public static Collection<URI> toURIObjects(Collection<String> uriStrings) {
        List<URI> result = new ArrayList<URI>();
        for (String uriStr : uriStrings) {
            try {
                result.add(new URI(uriStr));
            } catch (URISyntaxException e) {
                logger.warn(String.format("bad uri: [%s]", uriStr));
            }
        }
        return Collections.unmodifiableCollection(result);
    }

    public static void validateNotEmptyUsername(String username) throws InvalidPrincipalException {
        if (ValidateUtil.isEmpty(username)) {
            throw new InvalidPrincipalException("Empty principal name is not allowed", username);
        }
    }

    public static void validateNotNullTenant(TenantInformation tenantInfo, String tenantName)
            throws NoSuchTenantException {
        if (tenantInfo == null) {
            throw new NoSuchTenantException(String.format("No such tenant [%s]", tenantName));
        }

        return;
    }

    public static void validateNotNullIdp(IIdentityProvider provider, String tenantName, String domainName)
            throws NoSuchIdpException {
        if (provider == null) {
            throw new NoSuchIdpException(String.format("No %s provider in tenant [%s] for domain [%s]",
                    provider instanceof ISystemDomainIdentityProvider ? "system" : "such", tenantName, domainName));
        }

        return;
    }

    public static void validateNotNullSystemIdp(ISystemDomainIdentityProvider provider, String tenantName)
            throws NoSuchIdpException {
        if (provider == null) {
            throw new NoSuchIdpException(String.format("No system provider in tenant [%s]", tenantName));
        }

        return;
    }

    /**
     * Extract the domain name from the specified FQDN {@code hostName}
     * @param hostName cannot be null or empty
     * @return
     */
    public static String extractDomainName(String hostName) {
        Validate.notEmpty(hostName);
        return hostName.substring(hostName.indexOf('.') + 1);
    }

    /**
     * Construct a principalId with accountName and domainName
     * @param accountName cannot be null
     * @param domainAlias can be null
     * @return a constructed principalId or null (if domainName is null)
     */
    public static PrincipalId getPrincipalAliasId(String principalName, String domainAlias) {
        return !ServerUtils.isNullOrEmpty(domainAlias) ? new PrincipalId(principalName, domainAlias) : null;
    }

    /**
     * Given an optional upn, an account name and domain name construct PrincipalId.
     * @param upn optional upn name. Id specified, must be in Upn format.
     * @param accountName account name of the principal. required.
     * @param domainName domain name of the domain the principal is in. required.
     * @return PrincipalId representing the user.
     */
    public static PrincipalId getPrincipalId(String upn, String accountName, String domainName) {
        ValidateUtil.validateNotNull(accountName, "accountName");
        ValidateUtil.validateNotNull(domainName, "domainName");

        // we are unifying on iUpn for now.
        // keeping upn parameter in case we switch to eUpn,
        // or decide to include eUpn into the PrincipalId.
        PrincipalId id = new PrincipalId(accountName, domainName);

        return id;
    }

    /**
     * Convert a given {@code PrinciplaId} object to UPN string.
     * @param id cannot be null
     * @return string ID of the object in UPN format.
     */
    public static String getUpn(PrincipalId id) {
        ValidateUtil.validateNotNull(id, "id");
        return String.format("%s@%s", id.getName(), id.getDomain());
    }

    /**
     * Convert a given pair of {@code accountName} and {@code domainName} to UPN string.
     * @param accountName cannot be null or empty
     * @param domainName  cannot be null or empty
     * @return string ID of the object in UPN format.
     */
    public static String getUpn(String accountName, String domainName) {
        ValidateUtil.validateNotNull(accountName, "accountName");
        ValidateUtil.validateNotNull(domainName, "domainName");
        ValidateUtil.validateNotEmpty(accountName, "accountName");
        ValidateUtil.validateNotEmpty(domainName, "domainName");
        return String.format("%s@%s", accountName, domainName);
    }

    /**
     * @param A list of strings
     * @param String to lookup
     * @param whether the lookup is case sensitive or not
     * @return true or false (if there is a match in the desired case sensitive mode)
     */
    public static boolean contains(List<String> list, String str, boolean bcaseSensitive) {
        if (list == null || list.isEmpty() || isNullOrEmpty(str))
            return false;

        if (bcaseSensitive) {
            return list.contains(str);
        }

        for (String s : list) {
            if (s.equalsIgnoreCase(str))
                return true;
        }
        return false;
    }

    public static PrincipalId normalizeAliasInPrincipal(PrincipalId principal, String domainName,
            String aliasName) {
        ValidateUtil.validateNotNull(principal, "principal");
        ValidateUtil.validateNotEmpty(domainName, "domainName");

        PrincipalId normalizedPrincipal = null;
        // make the user principal to always contain domain name, not alias
        if (principal.getDomain().equalsIgnoreCase(aliasName)) {
            normalizedPrincipal = new PrincipalId(principal.getName(), domainName);
        } else {
            normalizedPrincipal = principal;
        }

        return normalizedPrincipal;
    }

    public static String getGroupAliasNetbios(Group g) {
        String aliasNetbios = null;
        if ((g != null) && (g.getAlias() != null)) {
            aliasNetbios = String.format("%s%c%s", g.getAlias().getDomain(), ValidateUtil.NETBIOS_SEPARATOR,
                    g.getAlias().getName());
        }

        return aliasNetbios;
    }

    public static boolean isValidDN(ILdapConnectionEx connection, String dn) {
        String[] attrsList = {};

        ILdapMessage message = null;
        try {
            message = connection.search(dn, LdapScope.SCOPE_BASE, "objectclass=*", attrsList, false);
            ILdapEntry[] entries = message.getEntries();

            if (entries == null || entries.length != 1) {
                return false;
            }
        } catch (Exception e) {
            logger.info(String.format("DN: [%s] does not exist", dn));
            return false;
        } finally {
            if (message != null) {
                message.close();
            }
        }
        return true;
    }

    public static void disposeLdapMessages(Collection<ILdapMessage> messages) {
        if ((messages != null) && (messages.size() > 0)) {
            for (ILdapMessage message : messages) {
                if (message != null) {
                    message.close();
                }
            }
        }
    }

    public static void check_directory_service() throws Exception {
        IdmServerConfig config = IdmServerConfig.getInstance();
        // Gives total 2 minutes wait time for vmware directory to come up
        int retryCount = 1;
        boolean keepTrying = false;

        ILdapConnectionEx connection = null;
        try {
            do {
                keepTrying = false;
                try {
                    connection = ServerUtils.getLdapConnectionByURIs(config.getSystemDomainConnectionInfo(),
                            config.getSystemDomainUserName(), config.getSystemDomainPassword(),
                            config.getSystemDomainAuthenticationType(), false);
                } catch (Exception ex) {
                    logger.info(String.format("Waiting for vmware directory to come up - Retry %d", retryCount));
                    keepTrying = true;
                    if (retryCount == 12) {
                        logger.error("Failed to connect to vmware directory.");
                        throw ex;
                    } else
                        Thread.sleep(1000 * 10); // retry every 10 seconds
                    retryCount++;
                }
            } while (keepTrying);
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    public static PrincipalId getPrincipalId(String upn) {
        ValidateUtil.validateNotEmpty(upn, "upn");
        String[] parts = upn.split("@");
        if (parts.length == 2)
            return new PrincipalId(parts[0], parts[1]);
        else
            throw new IllegalArgumentException("the upn format is invalid");
    }
}