| /* |
| * 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() { |
| } |
| } |