package org.eclipse.aether.repository;

/*
 * 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.
 */

import java.io.Closeable;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.requireNonNull;

import org.eclipse.aether.RepositorySystemSession;

A glorified map of key value pairs holding (cleartext) authentication data. Authentication contexts are used internally when network operations need to access secured repositories or proxies. Each authentication context manages the credentials required to access a single host. Unlike Authentication callbacks which exist for a potentially long time like the duration of a repository system session, an authentication context has a supposedly short lifetime and should be closed as soon as the corresponding network operation has finished:
AuthenticationContext context = AuthenticationContext.forRepository( session, repository );
try {
    // get credentials
    char[] password = context.get( AuthenticationContext.PASSWORD, char[].class );
    // perform network operation using retrieved credentials
    ...
} finally {
    // erase confidential authentication data from heap memory
    AuthenticationContext.close( context );
}
The same authentication data can often be presented using different data types, e.g. a password can be presented using a character array or (less securely) using a string. For ease of use, an authentication context treats the following groups of data types as equivalent and converts values automatically during retrieval:
  • String, char[]
  • String, File
An authentication context is thread-safe.
/** * A glorified map of key value pairs holding (cleartext) authentication data. Authentication contexts are used * internally when network operations need to access secured repositories or proxies. Each authentication context * manages the credentials required to access a single host. Unlike {@link Authentication} callbacks which exist for a * potentially long time like the duration of a repository system session, an authentication context has a supposedly * short lifetime and should be {@link #close() closed} as soon as the corresponding network operation has finished: * * <pre> * AuthenticationContext context = AuthenticationContext.forRepository( session, repository ); * try { * // get credentials * char[] password = context.get( AuthenticationContext.PASSWORD, char[].class ); * // perform network operation using retrieved credentials * ... * } finally { * // erase confidential authentication data from heap memory * AuthenticationContext.close( context ); * } * </pre> * * The same authentication data can often be presented using different data types, e.g. a password can be presented * using a character array or (less securely) using a string. For ease of use, an authentication context treats the * following groups of data types as equivalent and converts values automatically during retrieval: * <ul> * <li>{@code String}, {@code char[]}</li> * <li>{@code String}, {@code File}</li> * </ul> * An authentication context is thread-safe. */
public final class AuthenticationContext implements Closeable {
The key used to store the username. The corresponding authentication data should be of type String.
/** * The key used to store the username. The corresponding authentication data should be of type {@link String}. */
public static final String USERNAME = "username";
The key used to store the password. The corresponding authentication data should be of type char[] or String.
/** * The key used to store the password. The corresponding authentication data should be of type {@code char[]} or * {@link String}. */
public static final String PASSWORD = "password";
The key used to store the NTLM domain. The corresponding authentication data should be of type String.
/** * The key used to store the NTLM domain. The corresponding authentication data should be of type {@link String}. */
public static final String NTLM_DOMAIN = "ntlm.domain";
The key used to store the NTML workstation. The corresponding authentication data should be of type String.
/** * The key used to store the NTML workstation. The corresponding authentication data should be of type * {@link String}. */
public static final String NTLM_WORKSTATION = "ntlm.workstation";
The key used to store the pathname to a private key file. The corresponding authentication data should be of type String or File.
/** * The key used to store the pathname to a private key file. The corresponding authentication data should be of type * {@link String} or {@link File}. */
public static final String PRIVATE_KEY_PATH = "privateKey.path";
The key used to store the passphrase protecting the private key. The corresponding authentication data should be of type char[] or String.
/** * The key used to store the passphrase protecting the private key. The corresponding authentication data should be * of type {@code char[]} or {@link String}. */
public static final String PRIVATE_KEY_PASSPHRASE = "privateKey.passphrase";
The key used to store the acceptance policy for unknown host keys. The corresponding authentication data should be of type Boolean. When querying this authentication data, the extra data should provide HOST_KEY_REMOTE and HOST_KEY_LOCAL, e.g. to enable a well-founded decision of the user during an interactive prompt.
/** * The key used to store the acceptance policy for unknown host keys. The corresponding authentication data should * be of type {@link Boolean}. When querying this authentication data, the extra data should provide * {@link #HOST_KEY_REMOTE} and {@link #HOST_KEY_LOCAL}, e.g. to enable a well-founded decision of the user during * an interactive prompt. */
public static final String HOST_KEY_ACCEPTANCE = "hostKey.acceptance";
The key used to store the fingerprint of the public key advertised by remote host. Note that this key is used to query the extra data passed to get(String, Map<String,String>, Class<Object>) when getting HOST_KEY_ACCEPTANCE, not the authentication data in a context.
/** * The key used to store the fingerprint of the public key advertised by remote host. Note that this key is used to * query the extra data passed to {@link #get(String, Map, Class)} when getting {@link #HOST_KEY_ACCEPTANCE}, not * the authentication data in a context. */
public static final String HOST_KEY_REMOTE = "hostKey.remote";
The key used to store the fingerprint of the public key expected from remote host as recorded in a known hosts database. Note that this key is used to query the extra data passed to get(String, Map<String,String>, Class<Object>) when getting HOST_KEY_ACCEPTANCE, not the authentication data in a context.
/** * The key used to store the fingerprint of the public key expected from remote host as recorded in a known hosts * database. Note that this key is used to query the extra data passed to {@link #get(String, Map, Class)} when * getting {@link #HOST_KEY_ACCEPTANCE}, not the authentication data in a context. */
public static final String HOST_KEY_LOCAL = "hostKey.local";
The key used to store the SSL context. The corresponding authentication data should be of type SSLContext.
/** * The key used to store the SSL context. The corresponding authentication data should be of type * {@link javax.net.ssl.SSLContext}. */
public static final String SSL_CONTEXT = "ssl.context";
The key used to store the SSL hostname verifier. The corresponding authentication data should be of type HostnameVerifier.
/** * The key used to store the SSL hostname verifier. The corresponding authentication data should be of type * {@link javax.net.ssl.HostnameVerifier}. */
public static final String SSL_HOSTNAME_VERIFIER = "ssl.hostnameVerifier"; private final RepositorySystemSession session; private final RemoteRepository repository; private final Proxy proxy; private final Authentication auth; private final Map<String, Object> authData; private boolean fillingAuthData;
Gets an authentication context for the specified repository.
Params:
  • session – The repository system session during which the repository is accessed, must not be null.
  • repository – The repository for which to create an authentication context, must not be null.
Returns:An authentication context for the repository or null if no authentication is configured for it.
/** * Gets an authentication context for the specified repository. * * @param session The repository system session during which the repository is accessed, must not be {@code null}. * @param repository The repository for which to create an authentication context, must not be {@code null}. * @return An authentication context for the repository or {@code null} if no authentication is configured for it. */
public static AuthenticationContext forRepository( RepositorySystemSession session, RemoteRepository repository ) { return newInstance( session, repository, null, repository.getAuthentication() ); }
Gets an authentication context for the proxy of the specified repository.
Params:
  • session – The repository system session during which the repository is accessed, must not be null.
  • repository – The repository for whose proxy to create an authentication context, must not be null.
Returns:An authentication context for the proxy or null if no proxy is set or no authentication is configured for it.
/** * Gets an authentication context for the proxy of the specified repository. * * @param session The repository system session during which the repository is accessed, must not be {@code null}. * @param repository The repository for whose proxy to create an authentication context, must not be {@code null}. * @return An authentication context for the proxy or {@code null} if no proxy is set or no authentication is * configured for it. */
public static AuthenticationContext forProxy( RepositorySystemSession session, RemoteRepository repository ) { Proxy proxy = repository.getProxy(); return newInstance( session, repository, proxy, ( proxy != null ) ? proxy.getAuthentication() : null ); } private static AuthenticationContext newInstance( RepositorySystemSession session, RemoteRepository repository, Proxy proxy, Authentication auth ) { if ( auth == null ) { return null; } return new AuthenticationContext( session, repository, proxy, auth ); } private AuthenticationContext( RepositorySystemSession session, RemoteRepository repository, Proxy proxy, Authentication auth ) { this.session = requireNonNull( session, "repository system session cannot be null" ); this.repository = repository; this.proxy = proxy; this.auth = auth; authData = new HashMap<>(); }
Gets the repository system session during which the authentication happens.
Returns:The repository system session, never null.
/** * Gets the repository system session during which the authentication happens. * * @return The repository system session, never {@code null}. */
public RepositorySystemSession getSession() { return session; }
Gets the repository requiring authentication. If getProxy() is not null, the data gathered by this authentication context does not apply to the repository's host but rather the proxy.
Returns:The repository to be contacted, never null.
/** * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by * this authentication context does not apply to the repository's host but rather the proxy. * * @return The repository to be contacted, never {@code null}. */
public RemoteRepository getRepository() { return repository; }
Gets the proxy (if any) to be authenticated with.
Returns:The proxy or null if authenticating directly with the repository's host.
/** * Gets the proxy (if any) to be authenticated with. * * @return The proxy or {@code null} if authenticating directly with the repository's host. */
public Proxy getProxy() { return proxy; }
Gets the authentication data for the specified key.
Params:
  • key – The key whose authentication data should be retrieved, must not be null.
Returns:The requested authentication data or null if none.
/** * Gets the authentication data for the specified key. * * @param key The key whose authentication data should be retrieved, must not be {@code null}. * @return The requested authentication data or {@code null} if none. */
public String get( String key ) { return get( key, null, String.class ); }
Gets the authentication data for the specified key.
Params:
  • key – The key whose authentication data should be retrieved, must not be null.
  • type – The expected type of the authentication data, must not be null.
Type parameters:
  • <T> – The data type of the authentication data.
Returns:The requested authentication data or null if none or if the data doesn't match the expected type.
/** * Gets the authentication data for the specified key. * * @param <T> The data type of the authentication data. * @param key The key whose authentication data should be retrieved, must not be {@code null}. * @param type The expected type of the authentication data, must not be {@code null}. * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type. */
public <T> T get( String key, Class<T> type ) { return get( key, null, type ); }
Gets the authentication data for the specified key.
Params:
  • key – The key whose authentication data should be retrieved, must not be null.
  • data – Any (read-only) extra data in form of key value pairs that might be useful when getting the authentication data, may be null.
  • type – The expected type of the authentication data, must not be null.
Type parameters:
  • <T> – The data type of the authentication data.
Returns:The requested authentication data or null if none or if the data doesn't match the expected type.
/** * Gets the authentication data for the specified key. * * @param <T> The data type of the authentication data. * @param key The key whose authentication data should be retrieved, must not be {@code null}. * @param data Any (read-only) extra data in form of key value pairs that might be useful when getting the * authentication data, may be {@code null}. * @param type The expected type of the authentication data, must not be {@code null}. * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type. */
public <T> T get( String key, Map<String, String> data, Class<T> type ) { requireNonNull( key, "authentication key cannot be null" ); if ( key.length() == 0 ) { throw new IllegalArgumentException( "authentication key cannot be empty" ); } Object value; synchronized ( authData ) { value = authData.get( key ); if ( value == null && !authData.containsKey( key ) && !fillingAuthData ) { if ( auth != null ) { try { fillingAuthData = true; auth.fill( this, key, data ); } finally { fillingAuthData = false; } value = authData.get( key ); } if ( value == null ) { authData.put( key, value ); } } } return convert( value, type ); } private <T> T convert( Object value, Class<T> type ) { if ( !type.isInstance( value ) ) { if ( String.class.equals( type ) ) { if ( value instanceof File ) { value = ( (File) value ).getPath(); } else if ( value instanceof char[] ) { value = new String( (char[]) value ); } } else if ( File.class.equals( type ) ) { if ( value instanceof String ) { value = new File( (String) value ); } } else if ( char[].class.equals( type ) ) { if ( value instanceof String ) { value = ( (String) value ).toCharArray(); } } } if ( type.isInstance( value ) ) { return type.cast( value ); } return null; }
Puts the specified authentication data into this context. This method should only be called from implementors of Authentication.fill(AuthenticationContext, String, Map<String,String>). Passed in character arrays are not cloned and become owned by this context, i.e. get erased when the context gets closed.
Params:
  • key – The key to associate the authentication data with, must not be null.
  • value – The (cleartext) authentication data to store, may be null.
/** * Puts the specified authentication data into this context. This method should only be called from implementors of * {@link Authentication#fill(AuthenticationContext, String, Map)}. Passed in character arrays are not cloned and * become owned by this context, i.e. get erased when the context gets closed. * * @param key The key to associate the authentication data with, must not be {@code null}. * @param value The (cleartext) authentication data to store, may be {@code null}. */
public void put( String key, Object value ) { requireNonNull( key, "authentication key cannot be null" ); if ( key.length() == 0 ) { throw new IllegalArgumentException( "authentication key cannot be empty" ); } synchronized ( authData ) { Object oldValue = authData.put( key, value ); if ( oldValue instanceof char[] ) { Arrays.fill( (char[]) oldValue, '\0' ); } } }
Closes this authentication context and erases sensitive authentication data from heap memory. Closing an already closed context has no effect.
/** * Closes this authentication context and erases sensitive authentication data from heap memory. Closing an already * closed context has no effect. */
public void close() { synchronized ( authData ) { for ( Object value : authData.values() ) { if ( value instanceof char[] ) { Arrays.fill( (char[]) value, '\0' ); } } authData.clear(); } }
Closes the specified authentication context. This is a convenience method doing a null check before calling close() on the given context.
Params:
  • context – The authentication context to close, may be null.
/** * Closes the specified authentication context. This is a convenience method doing a {@code null} check before * calling {@link #close()} on the given context. * * @param context The authentication context to close, may be {@code null}. */
public static void close( AuthenticationContext context ) { if ( context != null ) { context.close(); } } }