MSHARED-314 - Unsign jar still have some signatures in the manisfest


git-svn-id: https://svn.apache.org/repos/asf/maven/shared/trunk@1553841 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/maven/shared/jarsigner/JarSignerUtil.java b/src/main/java/org/apache/maven/shared/jarsigner/JarSignerUtil.java
index 9fc267c..f0b509e 100644
--- a/src/main/java/org/apache/maven/shared/jarsigner/JarSignerUtil.java
+++ b/src/main/java/org/apache/maven/shared/jarsigner/JarSignerUtil.java
@@ -28,6 +28,9 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
@@ -82,7 +85,7 @@
      * output JAR to retain as much metadata from the original JAR as possible.
      *
      * @param jarFile The JAR file to unsign, must not be <code>null</code>.
-     * @throws java.io.IOException
+     * @throws IOException
      */
     public static void unsignArchive( File jarFile )
         throws IOException
@@ -107,6 +110,18 @@
 
                 zos.putNextEntry( new ZipEntry( ze.getName() ) );
 
+                if ( isManifestFile( ze.getName() ) )
+                {
+
+                    // build a new manifest while removing all digest entries
+                    // see https://jira.codehaus.org/browse/MSHARED-314
+                    Manifest oldManifest = new Manifest( zis );
+                    Manifest newManifest = buildUnsignedManifest( oldManifest );
+                    newManifest.write( zos );
+
+                    continue;
+                }
+
                 IOUtil.copy( zis, zos );
             }
 
@@ -122,11 +137,48 @@
     }
 
     /**
+     * Build a new manifest from the given one removing any signing information inside it.
+     *
+     * This is done by removing any attributes containing some digest informations.
+     * If a entry has then no more attributes, then it will not be readd in the result manifest.
+     *
+     * @param manifest manifest to clean
+     * @return the build manifest with no digest attributes
+     * @since 1.3
+     */
+    protected static Manifest buildUnsignedManifest( Manifest manifest ) {
+
+        Manifest result = new Manifest( manifest );
+        result.getMainAttributes().clear();
+
+        for ( Map.Entry<String, Attributes> entry : manifest.getEntries().entrySet() )
+        {
+            Attributes oldAttributes = entry.getValue();
+            Attributes newAttributes = new Attributes();
+            for ( Map.Entry<Object, Object> objectEntry : oldAttributes.entrySet() )
+            {
+                String attributeKey = String.valueOf( objectEntry.getKey() );
+                if ( !attributeKey.contains( "-Digest" ) )
+                {
+                    // can add this attribute
+                    newAttributes.put( objectEntry.getKey(), objectEntry.getValue() );
+                }
+            }
+            if ( !newAttributes.isEmpty() )
+            {
+                // can add this entry
+                result.getEntries().put( entry.getKey(), newAttributes );
+            }
+        }
+        return result;
+    }
+
+    /**
      * Scans an archive for existing signatures.
      *
      * @param jarFile The archive to scan, must not be <code>null</code>.
      * @return <code>true</code>, if the archive contains at least one signature file; <code>false</code>, if the archive
-     *         does not contain any signature files.
+     * does not contain any signature files.
      * @throws IOException if scanning <code>jarFile</code> fails.
      */
     public static boolean isArchiveSigned( final File jarFile )
@@ -183,7 +235,7 @@
      * @param entryName The name of the JAR file entry to check, must not be <code>null</code>.
      * @return <code>true</code> if the entry is related to a signature, <code>false</code> otherwise.
      */
-    private static boolean isSignatureFile( String entryName )
+    protected static boolean isSignatureFile( String entryName )
     {
         boolean result = false;
         if ( entryName.regionMatches( true, 0, "META-INF", 0, 8 ) )
@@ -212,4 +264,22 @@
         }
         return result;
     }
+
+    protected static boolean isManifestFile( String entryName )
+    {
+        boolean result = false;
+        if ( entryName.regionMatches( true, 0, "META-INF", 0, 8 ) )
+        {
+            entryName = entryName.replace( '\\', '/' );
+
+            if ( entryName.indexOf( '/' ) == 8 && entryName.lastIndexOf( '/' ) == 8 )
+            {
+                if ( entryName.regionMatches( true, entryName.length() - 11, "MANIFEST.MF", 0, 11 ) )
+                {
+                    result = true;
+                }
+            }
+        }
+        return result;
+    }
 }
diff --git a/src/test/java/org/apache/maven/shared/jarsigner/JarSignerUtilTest.java b/src/test/java/org/apache/maven/shared/jarsigner/JarSignerUtilTest.java
index 885e3c4..9e3b579 100644
--- a/src/test/java/org/apache/maven/shared/jarsigner/JarSignerUtilTest.java
+++ b/src/test/java/org/apache/maven/shared/jarsigner/JarSignerUtilTest.java
@@ -23,6 +23,8 @@
 import org.apache.maven.shared.utils.io.FileUtils;
 
 import java.io.File;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 
 /**
  * Created on 11/8/13.
@@ -52,9 +54,28 @@
 
         assertTrue( JarSignerUtil.isArchiveSigned( target ) );
 
+        // check that manifest contains some digest attributes
+        JarFile originalJarFile = new JarFile( file );
+        Manifest originalManifest = originalJarFile.getManifest();
+        originalJarFile.close();
+
+        Manifest originalCleanManifest = JarSignerUtil.buildUnsignedManifest( originalManifest );
+        assertFalse( originalManifest.equals( originalCleanManifest ) );
+        assertTrue( originalCleanManifest.equals( JarSignerUtil.buildUnsignedManifest( originalCleanManifest ) ) );
+
         JarSignerUtil.unsignArchive( target );
 
         assertFalse( JarSignerUtil.isArchiveSigned( target ) );
 
+        // check that manifest has no digest entry
+        // see https://jira.codehaus.org/browse/MSHARED-314
+        JarFile jarFile = new JarFile( target );
+        Manifest manifest = jarFile.getManifest();
+        jarFile.close();
+        Manifest cleanManifest = JarSignerUtil.buildUnsignedManifest( manifest );
+        assertTrue( manifest.equals( cleanManifest ) );
+        assertTrue( manifest.equals( originalCleanManifest ) );
+
+
     }
 }