001package org.eclipse.aether.util.repository;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.List;
024
025import javax.net.ssl.HostnameVerifier;
026
027import org.eclipse.aether.repository.Authentication;
028import org.eclipse.aether.repository.AuthenticationContext;
029
030/**
031 * A utility class to build authentication info for repositories and proxies.
032 */
033public final class AuthenticationBuilder
034{
035
036    private final List<Authentication> authentications;
037
038    /**
039     * Creates a new authentication builder.
040     */
041    public AuthenticationBuilder()
042    {
043        authentications = new ArrayList<Authentication>();
044    }
045
046    /**
047     * Builds a new authentication object from the current data of this builder. The state of the builder itself remains
048     * unchanged.
049     * 
050     * @return The authentication or {@code null} if no authentication data was supplied to the builder.
051     */
052    public Authentication build()
053    {
054        if ( authentications.isEmpty() )
055        {
056            return null;
057        }
058        if ( authentications.size() == 1 )
059        {
060            return authentications.get( 0 );
061        }
062        return new ChainedAuthentication( authentications );
063    }
064
065    /**
066     * Adds username data to the authentication.
067     * 
068     * @param username The username, may be {@code null}.
069     * @return This builder for chaining, never {@code null}.
070     */
071    public AuthenticationBuilder addUsername( String username )
072    {
073        return addString( AuthenticationContext.USERNAME, username );
074    }
075
076    /**
077     * Adds password data to the authentication.
078     * 
079     * @param password The password, may be {@code null}.
080     * @return This builder for chaining, never {@code null}.
081     */
082    public AuthenticationBuilder addPassword( String password )
083    {
084        return addSecret( AuthenticationContext.PASSWORD, password );
085    }
086
087    /**
088     * Adds password data to the authentication. The resulting authentication object uses an encrypted copy of the
089     * supplied character data and callers are advised to clear the input array soon after this method returns.
090     * 
091     * @param password The password, may be {@code null}.
092     * @return This builder for chaining, never {@code null}.
093     */
094    public AuthenticationBuilder addPassword( char[] password )
095    {
096        return addSecret( AuthenticationContext.PASSWORD, password );
097    }
098
099    /**
100     * Adds NTLM data to the authentication.
101     * 
102     * @param workstation The NTLM workstation name, may be {@code null}.
103     * @param domain The NTLM domain name, may be {@code null}.
104     * @return This builder for chaining, never {@code null}.
105     */
106    public AuthenticationBuilder addNtlm( String workstation, String domain )
107    {
108        addString( AuthenticationContext.NTLM_WORKSTATION, workstation );
109        return addString( AuthenticationContext.NTLM_DOMAIN, domain );
110    }
111
112    /**
113     * Adds private key data to the authentication.
114     * 
115     * @param pathname The (absolute) path to the private key file, may be {@code null}.
116     * @param passphrase The passphrase protecting the private key, may be {@code null}.
117     * @return This builder for chaining, never {@code null}.
118     */
119    public AuthenticationBuilder addPrivateKey( String pathname, String passphrase )
120    {
121        if ( pathname != null )
122        {
123            addString( AuthenticationContext.PRIVATE_KEY_PATH, pathname );
124            addSecret( AuthenticationContext.PRIVATE_KEY_PASSPHRASE, passphrase );
125        }
126        return this;
127    }
128
129    /**
130     * Adds private key data to the authentication. The resulting authentication object uses an encrypted copy of the
131     * supplied character data and callers are advised to clear the input array soon after this method returns.
132     * 
133     * @param pathname The (absolute) path to the private key file, may be {@code null}.
134     * @param passphrase The passphrase protecting the private key, may be {@code null}.
135     * @return This builder for chaining, never {@code null}.
136     */
137    public AuthenticationBuilder addPrivateKey( String pathname, char[] passphrase )
138    {
139        if ( pathname != null )
140        {
141            addString( AuthenticationContext.PRIVATE_KEY_PATH, pathname );
142            addSecret( AuthenticationContext.PRIVATE_KEY_PASSPHRASE, passphrase );
143        }
144        return this;
145    }
146
147    /**
148     * Adds a hostname verifier for SSL. <strong>Note:</strong> This method assumes that all possible instances of the
149     * verifier's runtime type exhibit the exact same behavior, i.e. the behavior of the verifier depends solely on the
150     * runtime type and not on any configuration. For verifiers that do not fit this assumption, use
151     * {@link #addCustom(Authentication)} with a suitable implementation instead.
152     * 
153     * @param verifier The hostname verifier, may be {@code null}.
154     * @return This builder for chaining, never {@code null}.
155     */
156    public AuthenticationBuilder addHostnameVerifier( HostnameVerifier verifier )
157    {
158        if ( verifier != null )
159        {
160            authentications.add( new ComponentAuthentication( AuthenticationContext.SSL_HOSTNAME_VERIFIER, verifier ) );
161        }
162        return this;
163    }
164
165    /**
166     * Adds custom string data to the authentication. <em>Note:</em> If the string data is confidential, use
167     * {@link #addSecret(String, char[])} instead.
168     * 
169     * @param key The key for the authentication data, must not be {@code null}.
170     * @param value The value for the authentication data, may be {@code null}.
171     * @return This builder for chaining, never {@code null}.
172     */
173    public AuthenticationBuilder addString( String key, String value )
174    {
175        if ( value != null )
176        {
177            authentications.add( new StringAuthentication( key, value ) );
178        }
179        return this;
180    }
181
182    /**
183     * Adds sensitive custom string data to the authentication.
184     * 
185     * @param key The key for the authentication data, must not be {@code null}.
186     * @param value The value for the authentication data, may be {@code null}.
187     * @return This builder for chaining, never {@code null}.
188     */
189    public AuthenticationBuilder addSecret( String key, String value )
190    {
191        if ( value != null )
192        {
193            authentications.add( new SecretAuthentication( key, value ) );
194        }
195        return this;
196    }
197
198    /**
199     * Adds sensitive custom string data to the authentication. The resulting authentication object uses an encrypted
200     * copy of the supplied character data and callers are advised to clear the input array soon after this method
201     * returns.
202     * 
203     * @param key The key for the authentication data, must not be {@code null}.
204     * @param value The value for the authentication data, may be {@code null}.
205     * @return This builder for chaining, never {@code null}.
206     */
207    public AuthenticationBuilder addSecret( String key, char[] value )
208    {
209        if ( value != null )
210        {
211            authentications.add( new SecretAuthentication( key, value ) );
212        }
213        return this;
214    }
215
216    /**
217     * Adds custom authentication data to the authentication.
218     * 
219     * @param authentication The authentication to add, may be {@code null}.
220     * @return This builder for chaining, never {@code null}.
221     */
222    public AuthenticationBuilder addCustom( Authentication authentication )
223    {
224        if ( authentication != null )
225        {
226            authentications.add( authentication );
227        }
228        return this;
229    }
230
231}