You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by GitBox <gi...@apache.org> on 2020/05/19 20:48:18 UTC

[GitHub] [maven-wagon] michael-o commented on a change in pull request #67: Feature/MNG-5583 per endpoint support for PKI authentication

michael-o commented on a change in pull request #67:
URL: https://github.com/apache/maven-wagon/pull/67#discussion_r427585772



##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/AbstractWagon.java
##########
@@ -36,21 +49,6 @@
 import org.apache.maven.wagon.resource.Resource;
 import org.codehaus.plexus.util.IOUtil;
 
-import java.io.File;

Review comment:
       Skip the reformat, unrelated.

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -51,7 +52,300 @@
      * The absolute path to private key file
      */
     private String privateKey;
+    
+     /**
+     *

Review comment:
       Same here

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -24,9 +24,10 @@
 /**
  * This class holds the set of properties used when instance of the <code>Wagon</code>
  * will use during login operation.
+ * <br>May 2020, added PKI settings, see MNG-5583
  *
  * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
- *
+ * 

Review comment:
       Unrelated

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -24,9 +24,10 @@
 /**
  * This class holds the set of properties used when instance of the <code>Wagon</code>
  * will use during login operation.
+ * <br>May 2020, added PKI settings, see MNG-5583

Review comment:
       We have version control. This should be at most in the commit message.

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/repository/Repository.java
##########
@@ -19,13 +19,12 @@
  * under the License.
  */
 
+import java.io.Serializable;
+import java.util.Properties;
 import org.apache.maven.wagon.PathUtils;
 import org.apache.maven.wagon.WagonConstants;
 import org.codehaus.plexus.util.StringUtils;
 
-import java.io.Serializable;

Review comment:
       Same here.

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -80,37 +114,11 @@
 import org.apache.maven.wagon.proxy.ProxyInfo;
 import org.apache.maven.wagon.repository.Repository;
 import org.apache.maven.wagon.resource.Resource;
-import org.codehaus.plexus.util.StringUtils;
-
-import javax.net.ssl.HttpsURLConnection;

Review comment:
       same here

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -593,13 +603,189 @@ private static CloseableHttpClient createClient()
      */
     private BasicAuthScope proxyAuth;
 
+    /**
+     * initializes a custom http client given user specified keystore/truststore
+     * information from settings.xml
+     * see httsp://issues.apache.org/jira/browser/MNG-5583
+     * @return a client
+     * @throws SSLInitializationException if there's an issue loading keystore/truststore
+     */
+    private CloseableHttpClient initilaizeLocalHttpClientWithCustomSslSocketFactory() throws SSLInitializationException 
+    {
+        String sslProtocolsStr = System.getProperty( "https.protocols" );
+        String cipherSuitesStr = System.getProperty( "https.cipherSuites" );
+        String[] sslProtocols = sslProtocolsStr != null ? sslProtocolsStr.split( " *, *" ) : null;
+        String[] cipherSuites = cipherSuitesStr != null ? cipherSuitesStr.split( " *, *" ) : null;
+
+        SSLSocketFactory socketFactory = null;
+        TrustManager[] trustManagers = null;
+        KeyManager[] keyManagers = null;
+        try 
+        {
+            if ( authenticationInfo.getTrustStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getTrustStoreType() == null ? "JKS"
+                        : authenticationInfo.getTrustStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                } 
+                //also a null password is fine with windows and even with JKS files
+                char[] keyPass = authenticationInfo.getTrustStorePassword() != null
+                        ? authenticationInfo.getTrustStorePassword().toCharArray()
+                        : null;
+                keystore.load( fis, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                if ( fis != null ) 
+                {
+                    fis.close();
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                TrustManagerFactory fac = TrustManagerFactory.getInstance( alg );
+                fac.init( keystore );
+                trustManagers = fac.getTrustManagers();
+            }
+
+            if ( authenticationInfo.getKeyStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getKeyStoreType() == null ? "JKS"
+                        : authenticationInfo.getKeyStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                char[] keyStorePass = authenticationInfo.getKeyStorePassword() != null
+                        ? authenticationInfo.getKeyStorePassword().toCharArray()
+                        : null;
+                char[] keyPass = authenticationInfo.getKeyPassword() != null
+                        ? authenticationInfo.getKeyPassword().toCharArray()
+                        : null;
+                KeyManagerFactory fac = KeyManagerFactory.getInstance( alg );
+                keystore.load( fis, keyStorePass );
+                fac.init( keystore, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                keyPass = null;
+                String alias = authenticationInfo.getKeyAlias();
+                if ( alias != null )
+                {
+                    //borrowed from tomcat's code
+                    //user has explicitly specified a key alias, great.
+                    //let's make sure it exists in the key store that it has a 
+                    //key pair
+                    if ( keystore.containsAlias( alias ) ) 
+                    {
+                        if ( !keystore.isKeyEntry( alias ) ) 
+                        {
+                            alias = null;
+                        }
+                    } 
+                    else if ( keystore.containsAlias( alias.toLowerCase() ) ) 
+                    {
+                        alias = alias.toLowerCase();

Review comment:
       Prone to locale issues.

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -382,12 +390,12 @@ private static PoolingHttpClientConnectionManager createConnManager()
         {
             sslConnectionSocketFactory =
                 new SSLConnectionSocketFactory( HttpsURLConnection.getDefaultSSLSocketFactory(), sslProtocols,
-                                                cipherSuites,
+                    cipherSuites,
                                                 SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
         }
-
+        
         Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register( "http",
-                                                                                                                 PlainConnectionSocketFactory.INSTANCE ).register(
+                        PlainConnectionSocketFactory.INSTANCE ).register(

Review comment:
       Drop reformat

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -51,7 +52,300 @@
      * The absolute path to private key file
      */
     private String privateKey;
+    
+     /**
+     *
+     *
+     * The path to the trust store. If not defined, the JRE's cacert store is
+     * used.
+     *
+     *
+     */
+    private String trustStore;
+
+    /**
+     *
+     *
+     * The password to the trust store.
+     *
+     *
+     */
+    private String trustStorePassword;

Review comment:
       The upstream model does not allow that. Given that other password fields are strings too, this is acceptable, but not ideal.

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -51,7 +52,300 @@
      * The absolute path to private key file
      */
     private String privateKey;
+    
+     /**
+     *
+     *
+     * The path to the trust store. If not defined, the JRE's cacert store is
+     * used.
+     *
+     *
+     */
+    private String trustStore;
+
+    /**
+     *
+     *
+     * The password to the trust store.
+     *
+     *
+     */
+    private String trustStorePassword;
+
+    /**
+     *
+     *
+     * The type of trust store, default is JKS
+     *
+     * .
+     */
+    private String trustStoreType;
+
+    /**
+     *
+     *
+     * The path to the keystore used for authentication purposes, or null
+     *
+     * .
+     */
+    private String keyStore;
+
+    /**
+     *
+     *
+     * Keystore password, can be null
+     *
+     * .
+     */
+    private String keyStorePassword;
+
+    /**
+     *
+     *
+     * Keystore if the key store has multiple key pairs, this can be used to
+     * explicitly select a specific certificate via it's alias. If null, the
+     * most appropriate certificate is automatically selected by the SSL Factory
+     *
+     * .
+     */
+    private String keyAlias;
+
+    /**
+     *
+     *
+     * The password to unlock the key, can be null
+     *
+     * .
+     */
+    private String keyPassword;

Review comment:
       Same here

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -593,13 +603,189 @@ private static CloseableHttpClient createClient()
      */
     private BasicAuthScope proxyAuth;
 
+    /**
+     * initializes a custom http client given user specified keystore/truststore
+     * information from settings.xml
+     * see httsp://issues.apache.org/jira/browser/MNG-5583
+     * @return a client
+     * @throws SSLInitializationException if there's an issue loading keystore/truststore
+     */
+    private CloseableHttpClient initilaizeLocalHttpClientWithCustomSslSocketFactory() throws SSLInitializationException 
+    {
+        String sslProtocolsStr = System.getProperty( "https.protocols" );
+        String cipherSuitesStr = System.getProperty( "https.cipherSuites" );
+        String[] sslProtocols = sslProtocolsStr != null ? sslProtocolsStr.split( " *, *" ) : null;
+        String[] cipherSuites = cipherSuitesStr != null ? cipherSuitesStr.split( " *, *" ) : null;
+
+        SSLSocketFactory socketFactory = null;
+        TrustManager[] trustManagers = null;
+        KeyManager[] keyManagers = null;
+        try 
+        {
+            if ( authenticationInfo.getTrustStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getTrustStoreType() == null ? "JKS"
+                        : authenticationInfo.getTrustStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                } 
+                //also a null password is fine with windows and even with JKS files
+                char[] keyPass = authenticationInfo.getTrustStorePassword() != null
+                        ? authenticationInfo.getTrustStorePassword().toCharArray()
+                        : null;
+                keystore.load( fis, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                if ( fis != null ) 
+                {
+                    fis.close();
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                TrustManagerFactory fac = TrustManagerFactory.getInstance( alg );
+                fac.init( keystore );
+                trustManagers = fac.getTrustManagers();
+            }
+
+            if ( authenticationInfo.getKeyStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getKeyStoreType() == null ? "JKS"
+                        : authenticationInfo.getKeyStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                char[] keyStorePass = authenticationInfo.getKeyStorePassword() != null
+                        ? authenticationInfo.getKeyStorePassword().toCharArray()
+                        : null;
+                char[] keyPass = authenticationInfo.getKeyPassword() != null
+                        ? authenticationInfo.getKeyPassword().toCharArray()
+                        : null;
+                KeyManagerFactory fac = KeyManagerFactory.getInstance( alg );
+                keystore.load( fis, keyStorePass );
+                fac.init( keystore, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                keyPass = null;
+                String alias = authenticationInfo.getKeyAlias();
+                if ( alias != null )
+                {
+                    //borrowed from tomcat's code
+                    //user has explicitly specified a key alias, great.
+                    //let's make sure it exists in the key store that it has a 
+                    //key pair
+                    if ( keystore.containsAlias( alias ) ) 
+                    {
+                        if ( !keystore.isKeyEntry( alias ) ) 
+                        {
+                            alias = null;
+                        }
+                    } 
+                    else if ( keystore.containsAlias( alias.toLowerCase() ) ) 
+                    {
+                        alias = alias.toLowerCase();
+                        if ( !keystore.isKeyEntry( alias ) ) 
+                        {
+                            alias = null;
+                        }
+                    }
+                    if ( alias == null ) 
+                    {
+                        //TODO this should be I18N
+                        throw new IOException( "key alias not found" );
+                    }
+                    //ok we found the alias with a key.
+                }
+
+                keyManagers = fac.getKeyManagers();
+                if ( alias != null ) 
+                {
+                    //filter down the key managers to just the user's selected cert.
+                    for ( int k = 0; k < keyManagers.length; k++ ) 
+                    {
+                        if ( keyManagers[k] instanceof X509KeyManager ) 
+                        {
+                            keyManagers[k] = new JSSEKeyManager( (X509KeyManager) keyManagers[k], alias );
+                        }
+                    }
+                }
+
+            }
+            final SSLContext context = SSLContexts.custom().useSSL().build();
+            context.init( keyManagers, trustManagers, new SecureRandom() );
+            socketFactory = context.getSocketFactory();
+            if ( socketFactory == null )
+            {
+                socketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+            }
+        } 
+        catch ( Exception ex ) 
+        {
+            throw new SSLInitializationException( ex.getMessage(), ex );
+        }
+
+        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
+                socketFactory,
+                sslProtocols,
+                cipherSuites,
+                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER );
+
+         Registry<ConnectionSocketFactory> registry = RegistryBuilder.
+            <ConnectionSocketFactory>create().register( "http",
+                    PlainConnectionSocketFactory.INSTANCE ).register(
+        "https", sslConnectionSocketFactory ).build();
+
+        PoolingHttpClientConnectionManager connManager =
+            new PoolingHttpClientConnectionManager( registry, null, null, null, CONN_TTL, TimeUnit.SECONDS );
+        if ( persistentPool )
+        {
+            connManager.setDefaultMaxPerRoute( MAX_CONN_PER_ROUTE );
+            connManager.setMaxTotal( MAX_CONN_TOTAL );
+        }
+        else
+        {
+            connManager.setMaxTotal( 1 );
+        }
+  
+        CloseableHttpClient httpClientWithCustomSslSocketFactory = HttpClientBuilder.create() 
+            .useSystemProperties() 
+            .disableConnectionState() 
+            .setConnectionManager( connManager ) 
+            .setRetryHandler( createRetryHandler() )
+            .setServiceUnavailableRetryStrategy( createServiceUnavailableRetryStrategy() )
+            .setDefaultAuthSchemeRegistry( createAuthSchemeRegistry() )
+            .setRedirectStrategy( new WagonRedirectStrategy() )
+            .build();
+        return httpClientWithCustomSslSocketFactory;
+    }
+    
+    
     public void openConnectionInternal()
     {
         repository.setUrl( getURL( repository ) );
 
         credentialsProvider = new BasicCredentialsProvider();
         authCache = new BasicAuthCache();
-
+        

Review comment:
       trailing ws

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -614,11 +800,23 @@ public void openConnectionInternal()
                                                                     getRepository().getPort() );
                 credentialsProvider.setCredentials( targetScope, creds );
             }
+            //MNG-5583 per endpoint PKI authentication
+            if ( authenticationInfo.getTrustStore() != null || authenticationInfo.getKeyStore() != null ) 
+            {
+                //cache the client for this specific server host:port combination
+                String key = repository.getProtocol() + repository.getHost() + repository.getPort();
+                if ( !httpClientWithCustomSslSocketFactoryCache.containsKey( key ) )
+                {
+                    httpClientWithCustomSslSocketFactoryCache.put( key, 
+                            initilaizeLocalHttpClientWithCustomSslSocketFactory() );
+                }
+            }
         }
 
         ProxyInfo proxyInfo = getProxyInfo( getRepository().getProtocol(), getRepository().getHost() );
         if ( proxyInfo != null )
         {
+            //TODO add PKI support?

Review comment:
       This would require two things:
   
   * A proxy which speaks HTTPS as its protocol
   * The proxy from above + TLS mutual auth supported
   
   If this cannot be set up with OSS tools no need to add a TODO here. Maybe Apache's mod_proxy might be tried as forwarding proxy.

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/repository/Repository.java
##########
@@ -65,7 +64,7 @@
     private String username = null;
 
     private String password = null;
-
+    

Review comment:
       traling ws

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -593,13 +603,189 @@ private static CloseableHttpClient createClient()
      */
     private BasicAuthScope proxyAuth;
 
+    /**
+     * initializes a custom http client given user specified keystore/truststore
+     * information from settings.xml
+     * see httsp://issues.apache.org/jira/browser/MNG-5583

Review comment:
       Typo

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -382,12 +390,12 @@ private static PoolingHttpClientConnectionManager createConnManager()
         {
             sslConnectionSocketFactory =
                 new SSLConnectionSocketFactory( HttpsURLConnection.getDefaultSSLSocketFactory(), sslProtocols,
-                                                cipherSuites,
+                    cipherSuites,

Review comment:
       Drop reformat

##########
File path: wagon-providers/wagon-http-shared/src/main/java/org/apache/maven/wagon/shared/http/AbstractHttpClientWagon.java
##########
@@ -593,13 +603,189 @@ private static CloseableHttpClient createClient()
      */
     private BasicAuthScope proxyAuth;
 
+    /**
+     * initializes a custom http client given user specified keystore/truststore
+     * information from settings.xml
+     * see httsp://issues.apache.org/jira/browser/MNG-5583
+     * @return a client
+     * @throws SSLInitializationException if there's an issue loading keystore/truststore
+     */
+    private CloseableHttpClient initilaizeLocalHttpClientWithCustomSslSocketFactory() throws SSLInitializationException 
+    {
+        String sslProtocolsStr = System.getProperty( "https.protocols" );
+        String cipherSuitesStr = System.getProperty( "https.cipherSuites" );
+        String[] sslProtocols = sslProtocolsStr != null ? sslProtocolsStr.split( " *, *" ) : null;
+        String[] cipherSuites = cipherSuitesStr != null ? cipherSuitesStr.split( " *, *" ) : null;
+
+        SSLSocketFactory socketFactory = null;
+        TrustManager[] trustManagers = null;
+        KeyManager[] keyManagers = null;
+        try 
+        {
+            if ( authenticationInfo.getTrustStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getTrustStoreType() == null ? "JKS"
+                        : authenticationInfo.getTrustStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                } 
+                //also a null password is fine with windows and even with JKS files
+                char[] keyPass = authenticationInfo.getTrustStorePassword() != null
+                        ? authenticationInfo.getTrustStorePassword().toCharArray()
+                        : null;
+                keystore.load( fis, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                if ( fis != null ) 
+                {
+                    fis.close();
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                TrustManagerFactory fac = TrustManagerFactory.getInstance( alg );
+                fac.init( keystore );
+                trustManagers = fac.getTrustManagers();
+            }
+
+            if ( authenticationInfo.getKeyStore() != null ) 
+            {
+                KeyStore keystore = KeyStore.getInstance( authenticationInfo.getKeyStoreType() == null ? "JKS"
+                        : authenticationInfo.getKeyStoreType() );
+                FileInputStream fis = null;
+                //on windows platforms, the truststoreType of "WINDOWS" mounts
+                //to the windows certificate store, so a null input stream is just fine
+                File file = new File( ( authenticationInfo.getTrustStore() ) );
+                if ( file.exists() ) 
+                {
+                    fis = new FileInputStream( file );
+                }
+                String alg = KeyManagerFactory.getDefaultAlgorithm();
+                char[] keyStorePass = authenticationInfo.getKeyStorePassword() != null
+                        ? authenticationInfo.getKeyStorePassword().toCharArray()
+                        : null;
+                char[] keyPass = authenticationInfo.getKeyPassword() != null
+                        ? authenticationInfo.getKeyPassword().toCharArray()
+                        : null;
+                KeyManagerFactory fac = KeyManagerFactory.getInstance( alg );
+                keystore.load( fis, keyStorePass );
+                fac.init( keystore, keyPass );
+                if ( keyPass != null ) 
+                {
+                    for ( int i = 0; i < keyPass.length; i++ ) 
+                    {
+                        keyPass[i] = 0;
+                    }
+                }
+                keyPass = null;
+                String alias = authenticationInfo.getKeyAlias();
+                if ( alias != null )
+                {
+                    //borrowed from tomcat's code
+                    //user has explicitly specified a key alias, great.
+                    //let's make sure it exists in the key store that it has a 
+                    //key pair
+                    if ( keystore.containsAlias( alias ) ) 
+                    {
+                        if ( !keystore.isKeyEntry( alias ) ) 
+                        {
+                            alias = null;
+                        }
+                    } 
+                    else if ( keystore.containsAlias( alias.toLowerCase() ) ) 
+                    {
+                        alias = alias.toLowerCase();
+                        if ( !keystore.isKeyEntry( alias ) ) 
+                        {
+                            alias = null;
+                        }
+                    }
+                    if ( alias == null ) 
+                    {
+                        //TODO this should be I18N
+                        throw new IOException( "key alias not found" );

Review comment:
       Why is that an IOE?

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/authentication/AuthenticationInfo.java
##########
@@ -51,7 +52,300 @@
      * The absolute path to private key file
      */
     private String privateKey;
+    
+     /**
+     *
+     *
+     * The path to the trust store. If not defined, the JRE's cacert store is
+     * used.
+     *
+     *
+     */
+    private String trustStore;
+
+    /**
+     *
+     *
+     * The password to the trust store.
+     *
+     *
+     */
+    private String trustStorePassword;
+
+    /**
+     *
+     *
+     * The type of trust store, default is JKS
+     *
+     * .
+     */
+    private String trustStoreType;
+
+    /**
+     *
+     *
+     * The path to the keystore used for authentication purposes, or null
+     *
+     * .
+     */
+    private String keyStore;
+
+    /**
+     *
+     *
+     * Keystore password, can be null
+     *
+     * .
+     */
+    private String keyStorePassword;
+
+    /**
+     *
+     *
+     * Keystore if the key store has multiple key pairs, this can be used to
+     * explicitly select a specific certificate via it's alias. If null, the
+     * most appropriate certificate is automatically selected by the SSL Factory
+     *
+     * .
+     */
+    private String keyAlias;
+
+    /**
+     *
+     *
+     * The password to unlock the key, can be null
+     *
+     * .
+     */
+    private String keyPassword;
+
+    /**
+     *
+     *
+     * The key store type, defaults to JKS
+     *
+     * .
+     */
+    private String keyStoreType;
+
+    /**
+     *
+     *
+     * The path to the trust store. If not defined, the JRE's cacert store is
+     * used.
+     *
+     *
+     * @return path, name or null
+     */
+    public String getTrustStore()
+    {
+        return trustStore;
+    }
+
+    /**
+     *
+     *
+     * The path to the trust store. If not defined, the JRE's cacert store is
+     * used.
+     *
+     *
+     * @param trustStore path name or null
+     */
+    public void setTrustStore( String trustStore )
+    {
+        this.trustStore = trustStore;
+    }
+
+    /**
+     *
+     *
+     * The password to the trust store.
+     *
+     *
+     * @return password or null
+     */
+    public String getTrustStorePassword()
+    {
+        return trustStorePassword;
+    }
+
+    /**
+     *
+     *
+     * The password to the trust store.
+     *
+     *
+     * @param trustStorePassword password or null
+     */
+    public void setTrustStorePassword( String trustStorePassword ) 
+    {
+        this.trustStorePassword = trustStorePassword;
+    }
+
+    /**
+     *
+     *
+     * The type of trust store, default is JKS
+     *
+     * .
+     *
+     * @return type
+     */
+    public String getTrustStoreType()
+    {
+        return trustStoreType;
+    }
 
+    /**
+     *
+     *
+     * The type of trust store, default is JKS
+     *
+     * .
+     *
+     * @param trustStoreType key store type
+     */
+    public void setTrustStoreType( String trustStoreType )
+    {
+        this.trustStoreType = trustStoreType;
+    }
+
+    /**
+     *
+     *
+     * The path to the keystore used for authentication purposes, or null
+     *
+     * .
+     *
+     * @return path, named keystore (such as MY) or null

Review comment:
       Bad example, if at all `Windows-MY`.

##########
File path: wagon-provider-api/src/main/java/org/apache/maven/wagon/repository/Repository.java
##########
@@ -53,7 +52,7 @@
 
     private String url;
 
-    private RepositoryPermissions permissions;
+    private RepositoryPermissions permissions; 

Review comment:
       traling ws




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org