You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2010/09/18 01:28:57 UTC

svn commit: r998369 - in /james/jdkim/trunk/mailets/src: main/java/org/apache/james/jdkim/mailets/ test/java/org/apache/james/jdkim/mailets/

Author: bago
Date: Fri Sep 17 23:28:57 2010
New Revision: 998369

URL: http://svn.apache.org/viewvc?rev=998369&view=rev
Log:
Added DKIMVerify mailet (JDKIM-24)
Extracted common code from DKIMSign. Like DKIMSign we don't use jdkim mime4j parser but instead rely on javamail mimemessage for the needed header parsing.
The mailet simply adds a mail attribute: some more code/mailet will be needed to add headers.

Added:
    james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java   (with props)
    james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java   (with props)
    james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java   (with props)
Modified:
    james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
    james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java

Modified: james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java?rev=998369&r1=998368&r2=998369&view=diff
==============================================================================
--- james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java (original)
+++ james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java Fri Sep 17 23:28:57 2010
@@ -26,11 +26,9 @@ import java.security.NoSuchAlgorithmExce
 import java.security.PrivateKey;
 import java.security.spec.InvalidKeySpecException;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 
 import javax.mail.Header;
 import javax.mail.MessagingException;
@@ -81,46 +79,6 @@ import org.apache.mailet.base.GenericMai
  */
 public class DKIMSign extends GenericMailet {
 
-    /**
-     * An adapter to let DKIMSigner read headers from MimeMessage
-     */
-    private final class MimeMessageHeaders implements Headers {
-
-        private Map<String, List<String>> headers;
-        private List<String> fields;
-
-        @SuppressWarnings("unchecked")
-        public MimeMessageHeaders(MimeMessage message)
-                throws MessagingException {
-            headers = new HashMap<String, List<String>>();
-            fields = new LinkedList<String>();
-            for (Enumeration<String> e = message.getAllHeaderLines(); e
-                    .hasMoreElements();) {
-                String head = (String) e.nextElement();
-                int p = head.indexOf(':');
-                if (p <= 0)
-                    throw new MessagingException("Bad header line: " + head);
-                String headerName = head.substring(0, p).trim();
-                String headerNameLC = headerName.toLowerCase();
-                fields.add(headerName);
-                List<String> strings = (List<String>) headers.get(headerNameLC);
-                if (strings == null) {
-                    strings = new LinkedList<String>();
-                    headers.put(headerNameLC, strings);
-                }
-                strings.add(head);
-            }
-        }
-
-        public List<String> getFields() {
-            return fields;
-        }
-
-        public List<String> getFields(String name) {
-            return headers.get(name);
-        }
-    }
-
     private String signatureTemplate;
     private PrivateKey privateKey;
 

Added: james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java?rev=998369&view=auto
==============================================================================
--- james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java (added)
+++ james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java Fri Sep 17 23:28:57 2010
@@ -0,0 +1,94 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.jdkim.mailets;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.jdkim.DKIMVerifier;
+import org.apache.james.jdkim.api.BodyHasher;
+import org.apache.james.jdkim.api.Headers;
+import org.apache.james.jdkim.api.SignatureRecord;
+import org.apache.james.jdkim.exceptions.FailException;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.GenericMailet;
+
+/**
+ * This mailet verify a message using the DKIM protocol
+ * 
+ * Sample configuration:
+ * <pre><code>
+ * &lt;mailet match=&quot;All&quot; class=&quot;DKIMVerify&quot;&gt;
+ * &lt;/mailet&gt;
+ * </code></pre>
+ */
+public class DKIMVerify extends GenericMailet {
+
+    public static final String DKIM_AUTH_RESULT_ATTRIBUTE = "jDKIM.AUTHRESULT";
+    
+    protected DKIMVerifier verifier = null;
+
+    @Override
+    public void init() throws MessagingException {
+        verifier = new DKIMVerifier();
+    }
+    
+    public void service(Mail mail) throws MessagingException {
+        try {
+            MimeMessage message = mail.getMessage();
+            Headers headers = new MimeMessageHeaders(message);
+            BodyHasher bh = verifier.newBodyHasher(headers);
+            try {
+                if (bh != null) {
+                    message.writeTo(new HeaderSkippingOutputStream(bh
+                            .getOutputStream()));
+                    bh.getOutputStream().close();
+                }
+                
+            } catch (IOException e) {
+                throw new MessagingException("Exception calculating bodyhash: "
+                        + e.getMessage(), e);
+            }
+            List<SignatureRecord> res = verifier.verify(bh);
+            if (res == null || res.isEmpty()) {
+                // neutral
+                mail.setAttribute(DKIM_AUTH_RESULT_ATTRIBUTE, "neutral (no signatures)");
+            } else {
+                // pass
+                StringBuilder msg = new StringBuilder();
+                msg.append("pass");
+                for (SignatureRecord rec : res) {
+                    msg.append(" (");
+                    msg.append("identity ");
+                    msg.append(rec.getIdentity().toString());
+                    msg.append(")");
+                }
+                mail.setAttribute(DKIM_AUTH_RESULT_ATTRIBUTE, msg.toString());
+            }
+        } catch (FailException e) {
+            // fail
+            mail.setAttribute(DKIM_AUTH_RESULT_ATTRIBUTE, "fail ("+(e.getRelatedRecordIdentity() != null ? "identity "+ e.getRelatedRecordIdentity() + ": " : "")+e.getMessage()+")");
+        }
+        
+    }
+}

Propchange: james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMVerify.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java?rev=998369&view=auto
==============================================================================
--- james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java (added)
+++ james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java Fri Sep 17 23:28:57 2010
@@ -0,0 +1,71 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.jdkim.mailets;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.jdkim.api.Headers;
+
+/**
+ * An adapter to let DKIMSigner read headers from MimeMessage
+ */
+final class MimeMessageHeaders implements Headers {
+
+    private Map<String, List<String>> headers;
+    private List<String> fields;
+
+    @SuppressWarnings("unchecked")
+    public MimeMessageHeaders(MimeMessage message)
+            throws MessagingException {
+        headers = new HashMap<String, List<String>>();
+        fields = new LinkedList<String>();
+        for (Enumeration<String> e = message.getAllHeaderLines(); e
+                .hasMoreElements();) {
+            String head = (String) e.nextElement();
+            int p = head.indexOf(':');
+            if (p <= 0)
+                throw new MessagingException("Bad header line: " + head);
+            String headerName = head.substring(0, p).trim();
+            String headerNameLC = headerName.toLowerCase();
+            fields.add(headerName);
+            List<String> strings = (List<String>) headers.get(headerNameLC);
+            if (strings == null) {
+                strings = new LinkedList<String>();
+                headers.put(headerNameLC, strings);
+            }
+            strings.add(head);
+        }
+    }
+
+    public List<String> getFields() {
+        return fields;
+    }
+
+    public List<String> getFields(String name) {
+        return headers.get(name.toLowerCase());
+    }
+}
\ No newline at end of file

Propchange: james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/MimeMessageHeaders.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java?rev=998369&r1=998368&r2=998369&view=diff
==============================================================================
--- james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java (original)
+++ james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java Fri Sep 17 23:28:57 2010
@@ -132,12 +132,12 @@ public class DKIMSignTest extends TestCa
         ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
         mail.getMessage().writeTo(rawMessage);
         String res = rawMessage.toString();
-
+        
         MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
                 "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
                 "selector", "example.com");
         try {
-            List<SignatureRecord> sr = new DKIMVerifier(mockPublicKeyRecordRetriever)
+            new DKIMVerifier(mockPublicKeyRecordRetriever)
                     .verify(new ByteArrayInputStream(res.getBytes()));
             fail("Expecting signature to be ignored");
         } catch (PermFailException e) {

Added: james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java?rev=998369&view=auto
==============================================================================
--- james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java (added)
+++ james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java Fri Sep 17 23:28:57 2010
@@ -0,0 +1,119 @@
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+package org.apache.james.jdkim.mailets;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+import junit.framework.TestCase;
+
+import org.apache.james.jdkim.DKIMVerifier;
+import org.apache.james.jdkim.MockPublicKeyRecordRetriever;
+import org.apache.james.jdkim.exceptions.FailException;
+import org.apache.mailet.Mail;
+import org.apache.mailet.Mailet;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailContext;
+import org.apache.mailet.base.test.FakeMailetConfig;
+
+public class DKIMVerifyTest extends TestCase {
+
+    public void testDKIMVerifyPass() throws MessagingException, IOException,
+            FailException {
+        String message = "DKIM-Signature: v=1; d=example.com; t=1284762805; b=ZFfwSIzTQM7k9syRnl9VfQh0/dr99euvBe1gn/DiTrnEZjxyjzQBD2MMvowVdbHpPMtSjtCtehU9zZ3urXmj5iHKujpEkP92FEKinzElkQ2eT2zoxdg1zByPHsKPX+KjrBespAJcO2k052aOK5kIBFxpQumP4aiW7ZklBKSWMBk=; s=selector; a=rsa-sha256; bh=rHOD7fd9xnNxK7OSl5ellpQVF14NNFbOIizqtUMhnio=; h=from:to:received:received;\r\n"
+            + "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
+
+        Mail mail = process(message);
+        
+        String attr = (String) mail.getAttribute(DKIMVerify.DKIM_AUTH_RESULT_ATTRIBUTE);
+        assertNotNull(attr);
+        assertTrue(attr.startsWith("pass"));
+    }
+
+    public void testDKIMVerifyFail() throws MessagingException, IOException,
+            FailException {
+        // altered message body
+        String message = "DKIM-Signature: v=1; d=example.com; t=1284762805; b=ZFfwSIzTQM7k9syRnl9VfQh0/dr99euvBe1gn/DiTrnEZjxyjzQBD2MMvowVdbHpPMtSjtCtehU9zZ3urXmj5iHKujpEkP92FEKinzElkQ2eT2zoxdg1zByPHsKPX+KjrBespAJcO2k052aOK5kIBFxpQumP4aiW7ZklBKSWMBk=; s=selector; a=rsa-sha256; bh=rHOD7fd9xnNxK7OSl5ellpQVF14NNFbOIizqtUMhnio=; h=from:to:received:received;\r\n"
+            + "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova altered\r\n";
+
+        Mail mail = process(message);
+        
+        String attr = (String) mail.getAttribute(DKIMVerify.DKIM_AUTH_RESULT_ATTRIBUTE);
+        assertNotNull(attr);
+        assertTrue(attr.startsWith("fail"));
+    }
+
+    public void testDKIMVerifyFailInvalid() throws MessagingException, IOException,
+            FailException {
+        // invalid version v=2
+        String message = "DKIM-Signature: v=2; d=example.com; t=1284762805; b=ZFfwSIzTQM7k9syRnl9VfQh0/dr99euvBe1gn/DiTrnEZjxyjzQBD2MMvowVdbHpPMtSjtCtehU9zZ3urXmj5iHKujpEkP92FEKinzElkQ2eT2zoxdg1zByPHsKPX+KjrBespAJcO2k052aOK5kIBFxpQumP4aiW7ZklBKSWMBk=; s=selector; a=rsa-sha256; bh=rHOD7fd9xnNxK7OSl5ellpQVF14NNFbOIizqtUMhnio=; h=from:to:received:received;\r\n"
+            + "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
+
+        Mail mail = process(message);
+        
+        String attr = (String) mail.getAttribute(DKIMVerify.DKIM_AUTH_RESULT_ATTRIBUTE);
+        assertNotNull(attr);
+        assertTrue(attr.startsWith("fail"));
+    }
+
+    public void testDKIMVerifyNeutral() throws MessagingException, IOException,
+            FailException {
+        // no signatures!
+        String message = ""
+            + "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova altered\r\n";
+
+        Mail mail = process(message);
+        
+        String attr = (String) mail.getAttribute(DKIMVerify.DKIM_AUTH_RESULT_ATTRIBUTE);
+        assertNotNull(attr);
+        assertTrue(attr.startsWith("neutral"));
+    }
+
+    private Mail process(String message) throws MessagingException {
+        Mailet mailet = new DKIMVerify() {
+
+            @Override
+            public void init() throws MessagingException {
+                verifier = new DKIMVerifier(new MockPublicKeyRecordRetriever(
+                        "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
+                        "selector", "example.com"));
+            }
+            
+        };
+
+        FakeMailetConfig mci = new FakeMailetConfig("Test",
+                new FakeMailContext());
+
+        mailet.init(mci);
+
+        Mail mail = new FakeMail();
+        mail.setMessage(new MimeMessage(Session
+                .getDefaultInstance(new Properties()),
+                new ByteArrayInputStream(message.getBytes())));
+
+        mailet.service(mail);
+        return mail;
+    }
+}

Propchange: james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMVerifyTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org