Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NETBEANS-5956: Adding default java trust store to xml retriever #3207

Merged
merged 5 commits into from Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion ide/xml.retriever/nbproject/project.properties
Expand Up @@ -17,7 +17,7 @@
# under the License.

is.autoload=true
javac.source=1.6
javac.source=1.8

test.config.stableBTD.includes=**/*Test.class
test.config.stableBTD.excludes=\
Expand Down
Expand Up @@ -31,8 +31,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.HashMap;
import org.netbeans.modules.xml.retriever.*;
import java.util.Map;

/**
*
Expand All @@ -48,23 +47,23 @@ public interface ResourceRetriever {
public boolean accept(String baseAddr, String currentAddr) throws URISyntaxException;

/**
* Given the base doc address and the current address (that could be either relative or absoulte), determine the final address to fetch doc and get the stream of that doc.
* Given the base doc address and the current address (that could be either relative or absolute), determine the final address to fetch doc and get the stream of that doc.
* The method may throw {@link ResourceRedirectException} if the Retriever resolves the resource
* to a different URL incompatible with the Retriever instance.
*
* @param baseAddress address of the base document where the link was found
* @param documentAddress current document address as mentioned in the base doc
* @return Hash map has the "key" as the final address from where the file was fetched and "value" has the input sream of the file.
* @return Map has the "key" as the final address from where the file was fetched and "value" has the input stream of the file.
*/
public HashMap<String,InputStream> retrieveDocument(
public Map<String,InputStream> retrieveDocument(
String baseAddress, String documentAddress) throws IOException,URISyntaxException;


/**
* Given the base doc address and the current address (that could be either relative or absoulte), determine the final address to fetch doc and get the stream of that doc.
* @param baseAddress address of the base document where the link was found
* @param documentAddress current document address as mentioned in the base doc
* @return Hash map has the "key" as the final address from where the file was fetched and "value" has the input sream of the file.
* @return Hash map has the "key" as the final address from where the file was fetched and "value" has the input stream of the file.
*/
public String getEffectiveAddress(
String baseAddress, String documentAddress) throws IOException,URISyntaxException;
Expand Down
Expand Up @@ -31,14 +31,13 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.netbeans.modules.xml.retriever.*;

/**
*
* @author girix
*/
public class ResourceRetrieverFactory {
private static ArrayList<ResourceRetriever> registeredResourceRetrievers = new ArrayList<ResourceRetriever>();
private static final List<ResourceRetriever> registeredResourceRetrievers = new ArrayList<ResourceRetriever>();

static{
registeredResourceRetrievers.add(new FileResourceRetriever());
Expand All @@ -55,7 +54,7 @@ public static ResourceRetriever getResourceRetriever(String baseAddress, String
}

public static List<ResourceRetriever>getRegisteredResourceRetrievers(){
return (List<ResourceRetriever>) registeredResourceRetrievers;
return registeredResourceRetrievers;
}

public static boolean removeRegisteredResourceRetriever(ResourceRetriever oldResourceRetriever){
Expand Down
Expand Up @@ -37,6 +37,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.modules.xml.retriever.*;
Expand Down Expand Up @@ -86,7 +87,7 @@ public HashMap<String,File> goGetIt() throws IOException, URISyntaxException{
throw new IOException("File already exists"); //NOI18N
}

HashMap<String, InputStream> srcAddrNContent;
Map<String, InputStream> srcAddrNContent;
ResourceRetriever rr;

for (;;) {
Expand Down
Expand Up @@ -19,25 +19,29 @@

package org.netbeans.modules.xml.retriever.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import javax.net.ssl.*;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.ErrorManager;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;

/**
Expand All @@ -51,7 +55,9 @@ public class SecureURLResourceRetriever extends URLResourceRetriever {

/** Creates a new instance of SecureURLResourceRetriever */
public SecureURLResourceRetriever() {}
private static final KeyStore DEFAULT_TRUST_STORE = null;

@Override
public boolean accept(String baseAddr, String currentAddr) throws URISyntaxException {
URI currURI = new URI(currentAddr);
if( (currURI.isAbsolute()) && (currURI.getScheme().equalsIgnoreCase(URI_SCHEME)))
Expand All @@ -64,15 +70,16 @@ public boolean accept(String baseAddr, String currentAddr) throws URISyntaxExcep
return false;
}

public HashMap<String, InputStream> retrieveDocument(String baseAddress, String documentAddress) throws IOException,URISyntaxException{
@Override
public Map<String, InputStream> retrieveDocument(String baseAddress, String documentAddress) throws IOException,URISyntaxException{
String effAddr = getEffectiveAddress(baseAddress, documentAddress);
if(effAddr == null)
return null;
URI currURI = new URI(effAddr);
HashMap<String, InputStream> result = null;
if (acceptedCertificates==null) acceptedCertificates = new HashSet();
InputStream is = getInputStreamOfURL(currURI.toURL(), ProxySelector.getDefault().select(currURI).get(0));
result = new HashMap<String, InputStream>();
result = new HashMap<>();
result.put(effectiveURL.toString(), is);
return result;
}
Expand All @@ -87,13 +94,26 @@ protected void configureURLConnection(URLConnection ucn) {

// Install the trust manager for retriever
private void setRetrieverTrustManager(HttpsURLConnection con) {
TrustManager[] defaultTrustManagers;
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(DEFAULT_TRUST_STORE);
defaultTrustManagers = tmf.getTrustManagers();
} catch (KeyStoreException | NoSuchAlgorithmException ex) {
defaultTrustManagers = new TrustManager[0];
}
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
// ask user to accept the unknown certificate
Expand All @@ -119,45 +139,48 @@ public void checkServerTrusted(X509Certificate[] certs, String authType)
}
}
};
TrustManager[] combinedTrustManagers = (TrustManager[]) Stream.of(defaultTrustManagers, trustAllCerts)
.flatMap(Stream::of)
.toArray(size -> new TrustManager[size]);

KeyManager[] keyManagersFromSystemProperties = null;
try {
KeyStore keyStoreFromSystemProperties = null;
char[] keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword", "").toCharArray();
if (System.getProperty("javax.net.ssl.keyStore") != null) {
File keyStoreFile = new File(System.getProperty("javax.net.ssl.keyStore"));
if (keyStoreFile.exists()) {
KeyStore keyStore = KeyStore.getInstance(System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()));
try ( InputStream keyStoreStream = new FileInputStream(keyStoreFile)) {
keyStore.load(keyStoreStream, keyStorePassword);
}

// #208324: proper key managers need to be passed, so let's configure at least the defaults...
KeyManager[] mgrs;
if (System.getProperty("javax.net.ssl.keyStorePassword") != null && // NOI18N
System.getProperty("javax.net.ssl.keyStore") != null) { // NOI18N
try {
KeyStore ks = KeyStore.getInstance("JKS"); // NOI18N
ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), //NOI18N
System.getProperty("javax.net.ssl.keyStorePassword").toCharArray() //NOI18N
);
// Set up key manager factory to use our key store
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks,System.getProperty("javax.net.ssl.keyStorePassword").toCharArray()); // NOI18N
mgrs = kmf.getKeyManagers();
} catch (IOException ex) {
// this is somewhat expected, i.e. JKS file not present
mgrs = null;
} catch (java.security.GeneralSecurityException e) {
ErrorManager.getDefault().notify(e);
return;
keyStoreFromSystemProperties = keyStore;
}
}
} else {
mgrs = null;

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStoreFromSystemProperties, keyStorePassword);
keyManagersFromSystemProperties = keyManagerFactory.getKeyManagers();
} catch (GeneralSecurityException | IOException ex) {
keyManagersFromSystemProperties = new KeyManager[0];
}

try {
SSLContext sslContext = SSLContext.getInstance("SSL"); //NOI18N
sslContext.init(mgrs, trustAllCerts, new java.security.SecureRandom());
sslContext.init(keyManagersFromSystemProperties, combinedTrustManagers, new java.security.SecureRandom());
con.setSSLSocketFactory(sslContext.getSocketFactory());
con.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String string, SSLSession sSLSession) {
// accept all hosts
return true;
}
});
} catch (java.security.GeneralSecurityException e) {
con.setHostnameVerifier(this::acceptAllHosts);
} catch (GeneralSecurityException e) {
ErrorManager.getDefault().notify(e);
}
}


private boolean acceptAllHosts(String host, SSLSession sslSession) {
return true;
asbachb marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public String getEffectiveAddress(String baseAddress, String documentAddress) throws IOException, URISyntaxException {
URI currURI = new URI(documentAddress);
String result = null;
Expand Down
Expand Up @@ -39,7 +39,6 @@
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import org.netbeans.modules.xml.retriever.*;

/**
*
Expand Down Expand Up @@ -71,6 +70,7 @@ public class URLResourceRetriever implements ResourceRetriever{
public URLResourceRetriever() {
}

@Override
public boolean accept(String baseAddr, String currentAddr) throws URISyntaxException {
URI currURI = new URI(currentAddr);
if( (currURI.isAbsolute()) && (currURI.getScheme().equalsIgnoreCase(URI_SCHEME)))
Expand All @@ -85,18 +85,19 @@ public boolean accept(String baseAddr, String currentAddr) throws URISyntaxExcep
return false;
}

public HashMap<String, InputStream> retrieveDocument(String baseAddress,
@Override
public Map<String, InputStream> retrieveDocument(String baseAddress,
String documentAddress) throws IOException,URISyntaxException{

String effAddr = getEffectiveAddress(baseAddress, documentAddress);
if(effAddr == null)
return null;
URI currURI = new URI(effAddr);
HashMap<String, InputStream> result = null;
Map<String, InputStream> result = null;

InputStream is = getInputStreamOfURL(currURI.toURL(), ProxySelector.
getDefault().select(currURI).get(0));
result = new HashMap<String, InputStream>();
result = new HashMap<>();
result.put(effectiveURL.toString(), is);
return result;

Expand Down Expand Up @@ -167,10 +168,12 @@ public InputStream getInputStreamOfURL(URL downloadURL, Proxy proxy) throws IOEx

}

@Override
public long getStreamLength() {
return streamLength;
}

@Override
public String getEffectiveAddress(String baseAddress, String documentAddress) throws IOException, URISyntaxException {
return resolveURL(baseAddress, documentAddress, true);
}
Expand Down
@@ -0,0 +1,58 @@
/*
* 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.netbeans.modules.xml.retriever.impl;

import java.awt.Dialog;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;

/**
*
* @author Benjamin Asbach
*/
public class MockDialogDisplayer extends DialogDisplayer {

boolean invoked;

Object descriptionValue;

public MockDialogDisplayer() {
}

@Override
public Object notify(NotifyDescriptor descriptor) {
this.invoked = true;

descriptor.setValue(descriptionValue);
return null;
}

@Override
public Dialog createDialog(DialogDescriptor descriptor) {
this.invoked = true;

return null;
}

public void reset() {
this.invoked = false;
this.descriptionValue = DialogDescriptor.NO_OPTION;
}
}