View Javadoc
1   /*******************************************************************************
2    * Copyright (c) 2012 Sonatype, Inc.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *    Sonatype, Inc. - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.aether.repository;
12  
13  import java.io.UnsupportedEncodingException;
14  import java.security.MessageDigest;
15  import java.security.NoSuchAlgorithmException;
16  
17  import org.eclipse.aether.RepositorySystemSession;
18  
19  /**
20   * A helper to calculate a fingerprint/digest for the authentication data of a repository/proxy. Such a fingerprint can
21   * be used to detect changes in the authentication data across JVM restarts without exposing sensitive information.
22   */
23  public final class AuthenticationDigest
24  {
25  
26      private final MessageDigest digest;
27  
28      private final RepositorySystemSession session;
29  
30      private final RemoteRepository repository;
31  
32      private final Proxy proxy;
33  
34      /**
35       * Gets the fingerprint for the authentication of the specified repository.
36       * 
37       * @param session The repository system session during which the fingerprint is requested, must not be {@code null}.
38       * @param repository The repository whose authentication is to be fingerprinted, must not be {@code null}.
39       * @return The fingerprint of the repository authentication or an empty string if no authentication is configured,
40       *         never {@code null}.
41       */
42      public static String forRepository( RepositorySystemSession session, RemoteRepository repository )
43      {
44          String digest = "";
45          Authentication auth = repository.getAuthentication();
46          if ( auth != null )
47          {
48              AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, null );
49              auth.digest( authDigest );
50              digest = authDigest.digest();
51          }
52          return digest;
53      }
54  
55      /**
56       * Gets the fingerprint for the authentication of the specified repository's proxy.
57       * 
58       * @param session The repository system session during which the fingerprint is requested, must not be {@code null}.
59       * @param repository The repository whose proxy authentication is to be fingerprinted, must not be {@code null}.
60       * @return The fingerprint of the proxy authentication or an empty string if no proxy is present or if no proxy
61       *         authentication is configured, never {@code null}.
62       */
63      public static String forProxy( RepositorySystemSession session, RemoteRepository repository )
64      {
65          String digest = "";
66          Proxy proxy = repository.getProxy();
67          if ( proxy != null )
68          {
69              Authentication auth = proxy.getAuthentication();
70              if ( auth != null )
71              {
72                  AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, proxy );
73                  auth.digest( authDigest );
74                  digest = authDigest.digest();
75              }
76          }
77          return digest;
78      }
79  
80      private AuthenticationDigest( RepositorySystemSession session, RemoteRepository repository, Proxy proxy )
81      {
82          this.session = session;
83          this.repository = repository;
84          this.proxy = proxy;
85          digest = newDigest();
86      }
87  
88      private static MessageDigest newDigest()
89      {
90          try
91          {
92              return MessageDigest.getInstance( "SHA-1" );
93          }
94          catch ( NoSuchAlgorithmException e )
95          {
96              try
97              {
98                  return MessageDigest.getInstance( "MD5" );
99              }
100             catch ( NoSuchAlgorithmException ne )
101             {
102                 throw new IllegalStateException( ne );
103             }
104         }
105     }
106 
107     /**
108      * Gets the repository system session during which the authentication fingerprint is calculated.
109      * 
110      * @return The repository system session, never {@code null}.
111      */
112     public RepositorySystemSession getSession()
113     {
114         return session;
115     }
116 
117     /**
118      * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by
119      * this authentication digest does not apply to the repository's host but rather the proxy.
120      * 
121      * @return The repository to be contacted, never {@code null}.
122      */
123     public RemoteRepository getRepository()
124     {
125         return repository;
126     }
127 
128     /**
129      * Gets the proxy (if any) to be authenticated with.
130      * 
131      * @return The proxy or {@code null} if authenticating directly with the repository's host.
132      */
133     public Proxy getProxy()
134     {
135         return proxy;
136     }
137 
138     /**
139      * Updates the digest with the specified strings.
140      * 
141      * @param strings The strings to update the digest with, may be {@code null} or contain {@code null} elements.
142      */
143     public void update( String... strings )
144     {
145         if ( strings != null )
146         {
147             for ( String string : strings )
148             {
149                 if ( string != null )
150                 {
151                     try
152                     {
153                         digest.update( string.getBytes( "UTF-8" ) );
154                     }
155                     catch ( UnsupportedEncodingException e )
156                     {
157                         throw new IllegalStateException( e );
158                     }
159                 }
160             }
161         }
162     }
163 
164     /**
165      * Updates the digest with the specified characters.
166      * 
167      * @param chars The characters to update the digest with, may be {@code null}.
168      */
169     public void update( char... chars )
170     {
171         if ( chars != null )
172         {
173             for ( char c : chars )
174             {
175                 digest.update( (byte) ( c >> 8 ) );
176                 digest.update( (byte) ( c & 0xFF ) );
177             }
178         }
179     }
180 
181     /**
182      * Updates the digest with the specified bytes.
183      * 
184      * @param bytes The bytes to update the digest with, may be {@code null}.
185      */
186     public void update( byte... bytes )
187     {
188         if ( bytes != null )
189         {
190             digest.update( bytes );
191         }
192     }
193 
194     private String digest()
195     {
196         byte[] bytes = digest.digest();
197         StringBuilder buffer = new StringBuilder( bytes.length * 2 );
198         for ( byte aByte : bytes )
199         {
200             int b = aByte & 0xFF;
201             if ( b < 0x10 )
202             {
203                 buffer.append( '0' );
204             }
205             buffer.append( Integer.toHexString( b ) );
206         }
207         return buffer.toString();
208     }
209 
210 }