blob: 6236d8e3d40ef5fdd80fb939a1339218da6472e1 [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;
// ensure the dn is specified
if (StringUtils.isNotBlank(dn)) {
// determine the separate
final String separator = StringUtils.indexOfIgnoreCase(dn, "/cn=") > 0 ? "/" : ",";
// attempt to locate the cd
final String cnPattern = "cn=";
final int cnIndex = StringUtils.indexOfIgnoreCase(dn, cnPattern);
if (cnIndex >= 0) {
int separatorIndex = StringUtils.indexOf(dn, separator, cnIndex);
if (separatorIndex > 0) {
username = StringUtils.substring(dn, cnIndex + cnPattern.length(), separatorIndex);
} else {
username = StringUtils.substring(dn, cnIndex + cnPattern.length());
}
}
}
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() {
}
}