blob: 51269335edc915ef05b06b495318da957d912d28 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nifi.security.util;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class CertificateUtils {
private static final Logger logger = LoggerFactory.getLogger(CertificateUtils.class);
/**
* Returns true if the given keystore can be loaded using the given keystore
* type and password. Returns false otherwise.
*
* @param keystore the keystore to validate
* @param keystoreType the type of the keystore
* @param password the password to access the keystore
* @return true if valid; false otherwise
*/
public static boolean isStoreValid(final URL keystore, final KeystoreType keystoreType, final char[] password) {
if (keystore == null) {
throw new IllegalArgumentException("keystore may not be null");
} else if (keystoreType == null) {
throw new IllegalArgumentException("keystore type may not be null");
} else if (password == null) {
throw new IllegalArgumentException("password may not be null");
}
BufferedInputStream bis = null;
final KeyStore ks;
try {
// load the keystore
bis = new BufferedInputStream(keystore.openStream());
ks = KeyStore.getInstance(keystoreType.name());
ks.load(bis, password);
return true;
} catch (Exception e) {
return false;
} finally {
if (bis != null) {
try {
bis.close();
} catch (final IOException ioe) {
logger.warn("Failed to close input stream", ioe);
}
}
}
}
/**
* Extracts the username from the specified DN. If the username cannot be
* extracted because the CN is in an unrecognized format, the entire CN is
* returned. If the CN cannot be extracted because the DN is in an
* unrecognized format, the entire DN is returned.
*
* @param dn the dn to extract the username from
* @return the exatracted username
*/
public static String extractUsername(String dn) {
String username = dn;
String cn = "";
// ensure the dn is specified
if (StringUtils.isNotBlank(dn)) {
// attempt to locate the cn
if (dn.startsWith("CN=")) {
cn = StringUtils.substringBetween(dn, "CN=", ",");
} else if (dn.startsWith("/CN=")) {
cn = StringUtils.substringBetween(dn, "CN=", "/");
} else if (dn.startsWith("C=") || dn.startsWith("/C=")) {
cn = StringUtils.substringAfter(dn, "CN=");
} else if (dn.startsWith("/") && StringUtils.contains(dn, "CN=")) {
cn = StringUtils.substringAfter(dn, "CN=");
}
// attempt to get the username from the cn
if (StringUtils.isNotBlank(cn)) {
if (cn.endsWith(")")) {
username = StringUtils.substringBetween(cn, "(", ")");
} else if (cn.contains(" ")) {
username = StringUtils.substringAfterLast(cn, " ");
} else {
username = cn;
}
}
}
return username;
}
/**
* Returns a list of subject alternative names. Any name that is represented
* as a String by X509Certificate.getSubjectAlternativeNames() is converted
* to lowercase and returned.
*
* @param certificate a certificate
* @return a list of subject alternative names; list is never null
* @throws CertificateParsingException if parsing the certificate failed
*/
public static List<String> getSubjectAlternativeNames(final X509Certificate certificate) throws CertificateParsingException {
final Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames == null) {
return new ArrayList<>();
}
final List<String> result = new ArrayList<>();
for (final List<?> generalName : altNames) {
/**
* generalName has the name type as the first element a String or
* byte array for the second element. We return any general names
* that are String types.
*
* We don't inspect the numeric name type because some certificates
* incorrectly put IPs and DNS names under the wrong name types.
*/
final Object value = generalName.get(1);
if (value instanceof String) {
result.add(((String) value).toLowerCase());
}
}
return result;
}
private CertificateUtils() {
}
}