View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.mailet.crypto.mailet;
23  
24  import org.apache.mailet.Mail;
25  
26  import javax.mail.MessagingException;
27  import javax.mail.internet.MimeBodyPart;
28  import javax.mail.internet.MimeMessage;
29  import javax.mail.internet.MimeMultipart;
30  
31  import java.io.IOException;
32  
33  /**
34   * <p>Puts a <I>server-side</I> SMIME signature on a message.
35   * It is a concrete subclass of {@link Sign}, with very few modifications to it,
36   * to specialize for SMIME.</p>
37   *
38   *  <P>Handles the following init parameters (will comment only the differences from {@link AbstractSign}):</P>
39   * <ul>
40   * <li>&lt;debug&gt;.</li>
41   * <li>&lt;keyStoreFileName&gt;.</li>
42   * <li>&lt;keyStorePassword&gt;.</li>
43   * <li>&lt;keyAlias&gt;.</li>
44   * <li>&lt;keyAliasPassword&gt;.</li>
45   * <li>&lt;keyStoreType&gt;.</li>
46   * <li>&lt;postmasterSigns&gt;. The default is <CODE>true</CODE>.</li>
47   * <li>&lt;rebuildFrom&gt;. The default is <CODE>true</CODE>.</li>
48   * <li>&lt;signerName&gt;.</li>
49   * <li>&lt;explanationText&gt;. There is a default explanation string template in English,
50   * displaying also all the headers of the original message (see {@link #getExplanationText}).</li>
51   * </ul>
52   * @version CVS $Revision: 744748 $ $Date: 2009-02-15 20:38:04 +0000 (Sun, 15 Feb 2009) $
53   * @since 2.3.0
54   */
55  public class SMIMESign extends Sign {
56      
57      /**
58       * Return a string describing this mailet.
59       *
60       * @return a string describing this mailet
61       */
62      public String getMailetInfo() {
63          return "SMIME Signature Mailet";
64      }
65      
66      /**
67       *
68       */
69      protected  String[] getAllowedInitParameters() {
70          String[] allowedArray = {
71              "debug",
72              "keyStoreFileName",
73              "keyStorePassword",
74              "keyStoreType",
75              "keyAlias",
76              "keyAliasPassword",
77              "signerName",
78              "postmasterSigns",
79              "rebuildFrom",
80              "explanationText"
81          };
82          return allowedArray;
83      }
84      
85       /* ******************************************************************** */
86      /* ****************** Begin of setters and getters ******************** */
87      /* ******************************************************************** */    
88      
89      /**
90       * Gets text offering an explanation.
91       * If the <CODE>&lt;explanationText&gt;</CODE> init parameter is missing
92       * returns the following default explanation template string:
93       * <pre><code>
94       * The message this file is attached to has been signed on the server by
95       *     "[signerName]" <[signerAddress]>
96       * to certify that the sender is known and truly has the following address (reverse-path):
97       *     [reversePath]
98       * and that the original message has the following message headers:
99       *
100      * [headers]
101      *
102      * The signature envelopes this attachment too.
103      * Please check the signature integrity.
104      *
105      *     "[signerName]" <[signerAddress]>
106      * </code></pre>
107      */
108     public String getExplanationText() {
109         String explanationText = super.getExplanationText();
110         if (explanationText == null) {
111             explanationText = "The message this file is attached to has been signed on the server by\r\n"
112             + "\t\"[signerName]\" <[signerAddress]>"
113             + "\r\nto certify that the sender is known and truly has the following address (reverse-path):\r\n"
114             + "\t[reversePath]"
115             + "\r\nand that the original message has the following message headers:\r\n"
116             + "\r\n[headers]"
117             + "\r\n\r\nThe signature envelopes this attachment too."
118             + "\r\nPlease check the signature integrity."
119             + "\r\n\r\n"
120             + "\t\"[signerName]\" <[signerAddress]>";
121         }
122         
123         return explanationText;
124     }
125     
126     /**
127      * Initializer for property keyHolderClass.
128      * Hardcodes it to {@link org.apache.james.mailet.crypto.SMIMEKeyHolder}.
129      */
130     protected void initKeyHolderClass() throws MessagingException {
131         String keyHolderClassName = "org.apache.james.security.SMIMEKeyHolder";
132         try {
133             setKeyHolderClass(Class.forName(keyHolderClassName));
134         } catch (ClassNotFoundException cnfe) {
135             throw new MessagingException(keyHolderClassName + "does not exist.");
136         }
137         if (isDebug()) {
138             log("keyHolderClass: " + getKeyHolderClass());
139         }
140     }
141     
142     /**
143      * If the <CODE>&lt;postmasterSigns&gt;</CODE> init parameter is missing sets it to <I>true</I>.
144      */
145     protected void initPostmasterSigns() {
146         setPostmasterSigns((getInitParameter("postmasterSigns") == null) ? true : new Boolean(getInitParameter("postmasterSigns")).booleanValue());
147     }
148     
149     /**
150      * If the <CODE>&lt;rebuildFrom&gt;</CODE> init parameter is missing sets it to <I>true</I>.
151      */
152     protected void initRebuildFrom() throws MessagingException {
153         setRebuildFrom((getInitParameter("rebuildFrom") == null) ? true : new Boolean(getInitParameter("rebuildFrom")).booleanValue());
154         if (isDebug()) {
155             if (isRebuildFrom()) {
156                 log("Will modify the \"From:\" header.");
157             } else {
158                 log("Will leave the \"From:\" header unchanged.");
159             }
160         }
161     }
162     
163     /* ******************************************************************** */
164     /* ****************** End of setters and getters ********************** */
165     /* ******************************************************************** */
166     
167     /**
168      * A text file with the massaged contents of {@link #getExplanationText}
169      * is attached to the original message.
170      */    
171     protected MimeBodyPart getWrapperBodyPart(Mail mail) throws MessagingException, IOException {
172         
173         String explanationText = getExplanationText();
174         
175         // if there is no explanation text there should be no wrapping
176         if (explanationText == null) {
177             return null;
178         }
179 
180             MimeMessage originalMessage = mail.getMessage();
181 
182             MimeBodyPart messagePart = new MimeBodyPart();
183             MimeBodyPart signatureReason = new MimeBodyPart();
184             
185             String contentType = originalMessage.getContentType();
186             Object content = originalMessage.getContent();
187             
188             if (contentType != null && content != null) {
189             messagePart.setContent(content, contentType);
190             } else {
191                 throw new MessagingException("Either the content type or the content is null");
192             }
193             
194             String headers = getMessageHeaders(originalMessage);
195             
196             signatureReason.setText(getReplacedExplanationText(getExplanationText(),
197                                                                getSignerName(),
198                                                                getKeyHolder().getSignerAddress(),
199                                                                mail.getSender().toString(),
200                                                                headers));
201             
202             signatureReason.setFileName("SignatureExplanation.txt");
203             
204             MimeMultipart wrapperMultiPart = new MimeMultipart();
205             
206             wrapperMultiPart.addBodyPart(messagePart);
207             wrapperMultiPart.addBodyPart(signatureReason);
208             
209             MimeBodyPart wrapperBodyPart = new MimeBodyPart();
210             
211             wrapperBodyPart.setContent(wrapperMultiPart);
212             
213             return wrapperBodyPart;
214     }
215         
216 }
217