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><debug>.</li>
41 * <li><keyStoreFileName>.</li>
42 * <li><keyStorePassword>.</li>
43 * <li><keyAlias>.</li>
44 * <li><keyAliasPassword>.</li>
45 * <li><keyStoreType>.</li>
46 * <li><postmasterSigns>. The default is <CODE>true</CODE>.</li>
47 * <li><rebuildFrom>. The default is <CODE>true</CODE>.</li>
48 * <li><signerName>.</li>
49 * <li><explanationText>. 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><explanationText></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><postmasterSigns></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><rebuildFrom></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