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> signature on a message.
35 * It is a concrete subclass of {@link AbstractSign}, with very few modifications to it.</p>
36 * <p>A text file with an explanation text is attached to the original message,
37 * and the resulting message with all its attachments is signed.
38 * The resulting appearence of the message is almost unchanged: only an extra attachment
39 * and the signature are added.</p>
40 *<p>The kind of signuture depends on the value of the <keyHolderClass> init parameter.
41 *
42 * <P>Handles the following init parameters (will comment only the differences from {@link AbstractSign}):</P>
43 * <ul>
44 * <li><keyHolderClass>: Sets the class of the KeyHolder object that will handle the cryptography functions,
45 * for example org.apache.james.security.SMIMEKeyHolder for SMIME.</li>
46 * <li><debug>.</li>
47 * <li><keyStoreFileName>.</li>
48 * <li><keyStorePassword>.</li>
49 * <li><keyAlias>.</li>
50 * <li><keyAliasPassword>.</li>
51 * <li><keyStoreType>.</li>
52 * <li><postmasterSigns>. The default is <CODE>true</CODE>.</li>
53 * <li><rebuildFrom>. The default is <CODE>true</CODE>.</li>
54 * <li><signerName>.</li>
55 * <li><explanationText>. There is a default explanation string template in English,
56 * displaying also all the headers of the original message (see {@link #getExplanationText}).</li>
57 * </ul>
58 * @version CVS $Revision: 744745 $ $Date: 2009-02-15 20:30:17 +0000 (Sun, 15 Feb 2009) $
59 * @since 2.2.1
60 */
61 public class Sign extends AbstractSign {
62
63 /**
64 * Return a string describing this mailet.
65 *
66 * @return a string describing this mailet
67 */
68 public String getMailetInfo() {
69 return "Signature Mailet";
70 }
71
72 /**
73 *
74 */
75 protected String[] getAllowedInitParameters() {
76 String[] allowedArray = {
77 "keyHolderClass",
78 "debug",
79 "keyStoreFileName",
80 "keyStorePassword",
81 "keyStoreType",
82 "keyAlias",
83 "keyAliasPassword",
84 "signerName",
85 "postmasterSigns",
86 "rebuildFrom",
87 "explanationText"
88 };
89 return allowedArray;
90 }
91
92 /* ******************************************************************** */
93 /* ****************** Begin of setters and getters ******************** */
94 /* ******************************************************************** */
95
96 /**
97 * Gets text offering an explanation.
98 * If the <CODE><explanationText></CODE> init parameter is missing
99 * returns the following default explanation template string:
100 * <pre><code>
101 * The message this file is attached to has been signed on the server by
102 * "[signerName]" <[signerAddress]>
103 * to certify that the sender is known and truly has the following address (reverse-path):
104 * [reversePath]
105 * and that the original message has the following message headers:
106 *
107 * [headers]
108 *
109 * The signature envelopes this attachment too.
110 * Please check the signature integrity.
111 *
112 * "[signerName]" <[signerAddress]>
113 * </code></pre>
114 */
115 public String getExplanationText() {
116 String explanationText = super.getExplanationText();
117 if (explanationText == null) {
118 explanationText = "The message this file is attached to has been signed on the server by\r\n"
119 + "\t\"[signerName]\" <[signerAddress]>"
120 + "\r\nto certify that the sender is known and truly has the following address (reverse-path):\r\n"
121 + "\t[reversePath]"
122 + "\r\nand that the original message has the following message headers:\r\n"
123 + "\r\n[headers]"
124 + "\r\n\r\nThe signature envelopes this attachment too."
125 + "\r\nPlease check the signature integrity."
126 + "\r\n\r\n"
127 + "\t\"[signerName]\" <[signerAddress]>";
128 }
129
130 return explanationText;
131 }
132
133 /**
134 * If the <CODE><postmasterSigns></CODE> init parameter is missing sets it to <I>true</I>.
135 */
136 protected void initPostmasterSigns() {
137 setPostmasterSigns((getInitParameter("postmasterSigns") == null) ? true : new Boolean(getInitParameter("postmasterSigns")).booleanValue());
138 }
139
140 /**
141 * If the <CODE><rebuildFrom></CODE> init parameter is missing sets it to <I>true</I>.
142 */
143 protected void initRebuildFrom() throws MessagingException {
144 setRebuildFrom((getInitParameter("rebuildFrom") == null) ? true : new Boolean(getInitParameter("rebuildFrom")).booleanValue());
145 if (isDebug()) {
146 if (isRebuildFrom()) {
147 log("Will modify the \"From:\" header.");
148 } else {
149 log("Will leave the \"From:\" header unchanged.");
150 }
151 }
152 }
153
154 /* ******************************************************************** */
155 /* ****************** End of setters and getters ********************** */
156 /* ******************************************************************** */
157
158 /**
159 * A text file with the massaged contents of {@link #getExplanationText}
160 * is attached to the original message.
161 */
162 protected MimeBodyPart getWrapperBodyPart(Mail mail) throws MessagingException, IOException {
163
164 String explanationText = getExplanationText();
165
166 // if there is no explanation text there should be no wrapping
167 if (explanationText == null) {
168 return null;
169 }
170
171 MimeMessage originalMessage = mail.getMessage();
172
173 MimeBodyPart messagePart = new MimeBodyPart();
174 MimeBodyPart signatureReason = new MimeBodyPart();
175
176 String contentType = originalMessage.getContentType();
177 Object content = originalMessage.getContent();
178
179 if (contentType != null && content != null) {
180 messagePart.setContent(content, contentType);
181 } else {
182 throw new MessagingException("Either the content type or the content is null");
183 }
184
185 String headers = getMessageHeaders(originalMessage);
186
187 signatureReason.setText(getReplacedExplanationText(getExplanationText(),
188 getSignerName(),
189 getKeyHolder().getSignerAddress(),
190 mail.getSender().toString(),
191 headers));
192
193 signatureReason.setFileName("SignatureExplanation.txt");
194
195 MimeMultipart wrapperMultiPart = new MimeMultipart();
196
197 wrapperMultiPart.addBodyPart(messagePart);
198 wrapperMultiPart.addBodyPart(signatureReason);
199
200 MimeBodyPart wrapperBodyPart = new MimeBodyPart();
201
202 wrapperBodyPart.setContent(wrapperMultiPart);
203
204 return wrapperBodyPart;
205 }
206
207 }
208