View Javadoc

1   /**
2    *
3    * Copyright 2005 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.geronimo.system.configuration;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileReader;
22  import java.io.FileWriter;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.LineNumberReader;
26  import java.io.OutputStream;
27  import java.security.MessageDigest;
28  import java.security.NoSuchAlgorithmException;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  
33  /**
34   * Utility methods for dealing with checksums (hashes) of files in the
35   * configuration store.
36   *
37   * @version $Rev: 410741 $ $Date: 2006-05-31 21:35:48 -0700 (Wed, 31 May 2006) $
38   */
39  public class ConfigurationStoreUtil {
40      private static final Log log = LogFactory.getLog(ConfigurationStoreUtil.class);
41  
42      public static void writeChecksumFor(File file) throws IOException {
43          // check if the sum already exists
44          File sumFile = new File(file.getParentFile(), file.getName() + ".sha1");
45          if (sumFile.exists()) {
46              throw new IOException("Sum file already exists");
47          }
48  
49          // calculate the checksum
50          String actualChecksum;
51          try {
52              actualChecksum = calculateChecksum(file, "SHA-1");
53          } catch (NoSuchAlgorithmException e) {
54              throw new IOException("SHA-1 algorithm not available");
55          }
56  
57          // write it
58          FileWriter writer = new FileWriter(sumFile);
59          try {
60              writer.write(actualChecksum);
61          } finally {
62              try {
63                  writer.close();
64              } catch (IOException ignored) {
65              }
66          }
67      }
68  
69      public static boolean verifyChecksum(File file) {
70          String expectedChecksum = getExpectedChecksum(file);
71          if (expectedChecksum == null) {
72              // log message already printed
73              return false;
74          }
75  
76          String actualChecksum = getActualChecksum(file);
77          if (actualChecksum == null) {
78              // log message already printed
79              return false;
80          }
81  
82  
83          if (!actualChecksum.equals(expectedChecksum)) {
84              log.warn("Configuration file was modified: " + file.getAbsolutePath());
85              return false;
86          }
87  
88          return true;
89      }
90  
91      public static String getExpectedChecksum(File file) {
92          File sumFile = new File(file.getParentFile(), file.getName() + ".sha1");
93          if (!sumFile.exists()) {
94              log.warn("Checksum file not found: " + sumFile.getAbsolutePath());
95              return null;
96          }
97          if (!sumFile.canRead()) {
98              log.warn("Checksum file is not readable: " + sumFile.getAbsolutePath());
99              return null;
100         }
101         LineNumberReader lineNumberReader = null;
102         try {
103             lineNumberReader = new LineNumberReader(new FileReader(sumFile));
104             String expectedChecksum = lineNumberReader.readLine();
105             if (expectedChecksum == null) {
106                 log.error("Checksum file was empty: " + sumFile.getAbsolutePath());
107                 return null;
108             }
109             return expectedChecksum.trim();
110         } catch (IOException e) {
111             log.error("Unable to read checksum file: " + sumFile.getAbsolutePath(), e);
112         } finally {
113             if (lineNumberReader != null) {
114                 try {
115                     lineNumberReader.close();
116                 } catch (IOException ignored) {
117                 }
118             }
119 
120         }
121         return null;
122     }
123 
124     public static String getActualChecksum(File file) {
125         return getActualChecksum(file, "SHA-1");
126     }
127     public static String getActualChecksum(File file, String algorithm) {
128         try {
129             return calculateChecksum(file, algorithm);
130         } catch (Exception e) {
131             log.error("Unable to calculate checksum for configuration file: " + file.getAbsolutePath(), e);
132         }
133         return null;
134     }
135 
136     private static String calculateChecksum(File file, String algorithm) throws NoSuchAlgorithmException, IOException {
137 
138         InputStream stream = null;
139         try {
140             stream = new FileInputStream(file);
141             
142             MessageDigest digester = MessageDigest.getInstance(algorithm);
143             digester.reset();
144 
145             byte buf[] = new byte[4096];
146             int len = 0;
147 
148             while ((len = stream.read(buf, 0, 1024)) != -1) {
149                 digester.update(buf, 0, len);
150             }
151 
152             String actualChecksum = encode(digester.digest());
153             return actualChecksum;
154         } finally {
155             try {
156                 if (stream != null)
157                     stream.close();
158             } catch (IOException ignored) {
159             }
160         }
161     }
162 
163     private static String encode(byte[] binaryData) {
164         if (binaryData.length != 16 && binaryData.length != 20) {
165             int bitLength = binaryData.length * 8;
166             throw new IllegalArgumentException("Unrecognised length for binary data: " + bitLength + " bits");
167         }
168 
169         String retValue = "";
170 
171         for (int i = 0; i < binaryData.length; i++) {
172             String t = Integer.toHexString(binaryData[i] & 0xff);
173 
174             if (t.length() == 1) {
175                 retValue += ("0" + t);
176             } else {
177                 retValue += t;
178             }
179         }
180 
181         return retValue.trim();
182     }
183 
184     public static class ChecksumOutputStream extends OutputStream {
185         private final OutputStream out;
186         private MessageDigest digester;
187 
188         public ChecksumOutputStream(OutputStream out) throws IOException {
189             this.out = out;
190             try {
191                 digester = MessageDigest.getInstance("SHA-1");
192                 digester.reset();
193             } catch (NoSuchAlgorithmException e) {
194                 throw new IOException("SHA-1 algorithm not available");
195             }
196         }
197 
198         public String getChecksum() {
199             String actualChecksum = encode(digester.digest());
200             return actualChecksum;
201         }
202 
203         public void write(int b) throws IOException {
204             digester.update((byte) b);
205             out.write(b);
206         }
207 
208         public void write(byte[] b) throws IOException {
209             digester.update(b);
210             out.write(b);
211         }
212 
213         public void write(byte[] b, int off, int len) throws IOException {
214             digester.update(b, off, len);
215             out.write(b, off, len);
216         }
217 
218         public void flush() throws IOException {
219             out.flush();
220         }
221 
222         public void close() throws IOException {
223             out.close();
224         }
225     }
226 }