Source Code Cross Referenced for SMIMEAbstractSign.java in  » Web-Mail » james-2.3.1 » org » apache » james » transport » mailets » smime » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Mail » james 2.3.1 » org.apache.james.transport.mailets.smime 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /****************************************************************
002:         * Licensed to the Apache Software Foundation (ASF) under one   *
003:         * or more contributor license agreements.  See the NOTICE file *
004:         * distributed with this work for additional information        *
005:         * regarding copyright ownership.  The ASF licenses this file   *
006:         * to you under the Apache License, Version 2.0 (the            *
007:         * "License"); you may not use this file except in compliance   *
008:         * with the License.  You may obtain a copy of the License at   *
009:         *                                                              *
010:         *   http://www.apache.org/licenses/LICENSE-2.0                 *
011:         *                                                              *
012:         * Unless required by applicable law or agreed to in writing,   *
013:         * software distributed under the License is distributed on an  *
014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015:         * KIND, either express or implied.  See the License for the    *
016:         * specific language governing permissions and limitations      *
017:         * under the License.                                           *
018:         ****************************************************************/package org.apache.james.transport.mailets.smime;
019:
020:        import org.apache.james.security.KeyHolder;
021:        import org.apache.james.security.SMIMEAttributeNames;
022:        import org.apache.mailet.GenericMailet;
023:        import org.apache.mailet.Mail;
024:        import org.apache.mailet.MailAddress;
025:        import org.apache.mailet.RFC2822Headers;
026:
027:        import javax.mail.MessagingException;
028:        import javax.mail.Session;
029:        import javax.mail.internet.InternetAddress;
030:        import javax.mail.internet.MimeBodyPart;
031:        import javax.mail.internet.MimeMessage;
032:        import javax.mail.internet.MimeMultipart;
033:        import javax.mail.internet.ParseException;
034:
035:        import java.io.IOException;
036:        import java.util.ArrayList;
037:        import java.util.Collection;
038:        import java.util.Enumeration;
039:        import java.util.HashSet;
040:        import java.util.Iterator;
041:
042:        /**
043:         * <P>Abstract mailet providing common SMIME signature services.<BR>
044:         * It can be subclassed to make authoring signing mailets simple.<BR>
045:         * By extending it and overriding one or more of the following methods a new behaviour can
046:         * be quickly created without the author having to address any issue other than
047:         * the relevant one:</P>
048:         * <ul>
049:         * <li>{@link #initDebug}, {@link #setDebug} and {@link #isDebug} manage the debugging mode.</li>
050:         * <li>{@link #initExplanationText}, {@link #setExplanationText} and {@link #getExplanationText} manage the text of
051:         * an attachment that will be added to explain the meaning of this server-side signature.</li>
052:         * <li>{@link #initKeyHolder}, {@link #setKeyHolder} and {@link #getKeyHolder} manage the {@link KeyHolder} object that will
053:         * contain the keys and certificates and will do the crypto work.</li>
054:         * <li>{@link #initPostmasterSigns}, {@link #setPostmasterSigns} and {@link #isPostmasterSigns}
055:         * determines whether messages originated by the Postmaster will be signed or not.</li>
056:         * <li>{@link #initRebuildFrom}, {@link #setRebuildFrom} and {@link #isRebuildFrom}
057:         * determines whether the "From:" header will be rebuilt to neutralize the wrong behaviour of
058:         * some MUAs like Microsoft Outlook Express.</li>
059:         * <li>{@link #initSignerName}, {@link #setSignerName} and {@link #getSignerName} manage the name
060:         * of the signer to be shown in the explanation text.</li>
061:         * <li>{@link #isOkToSign} controls whether the mail can be signed or not.</li>
062:         * <li>The abstract method {@link #getWrapperBodyPart} returns the massaged {@link javax.mail.internet.MimeBodyPart}
063:         * that will be signed, or null if the message has to be signed "as is".</li>
064:         * </ul>
065:         *
066:         * <P>Handles the following init parameters:</P>
067:         * <ul>
068:         * <li>&lt;debug&gt;: if <CODE>true</CODE> some useful information is logged.
069:         * The default is <CODE>false</CODE>.</li>
070:         * <li>&lt;keyStoreFileName&gt;: the {@link java.security.KeyStore} full file name.</li>
071:         * <li>&lt;keyStorePassword&gt;: the <CODE>KeyStore</CODE> password.
072:         *      If given, it is used to check the integrity of the keystore data,
073:         *      otherwise, if null, the integrity of the keystore is not checked.</li>
074:         * <li>&lt;keyAlias&gt;: the alias name to use to search the Key using {@link java.security.KeyStore#getKey}.
075:         * The default is to look for the first and only alias in the keystore;
076:         * if zero or more than one is found a {@link java.security.KeyStoreException} is thrown.</li>
077:         * <li>&lt;keyAliasPassword&gt;: the alias password. The default is to use the <CODE>KeyStore</CODE> password.
078:         *      At least one of the passwords must be provided.</li>
079:         * <li>&lt;keyStoreType&gt;: the type of the keystore. The default will use {@link java.security.KeyStore#getDefaultType}.</li>
080:         * <li>&lt;postmasterSigns&gt;: if <CODE>true</CODE> the message will be signed even if the sender is the Postmaster.
081:         * The default is <CODE>false</CODE>.</li></li>
082:         * <li>&lt;rebuildFrom&gt;: If <CODE>true</CODE> will modify the "From:" header.
083:         * For more info see {@link #isRebuildFrom}.
084:         * The default is <CODE>false</CODE>.</li>
085:         * <li>&lt;signerName&gt;: the name of the signer to be shown in the explanation text.
086:         * The default is to use the "CN=" property of the signing certificate.</li>
087:         * <li>&lt;explanationText&gt;: the text of an explanation of the meaning of this server-side signature.
088:         * May contain the following substitution patterns (see also {@link #getReplacedExplanationText}):
089:         * <CODE>[signerName]</CODE>, <CODE>[signerAddress]</CODE>, <CODE>[reversePath]</CODE>, <CODE>[headers]</CODE>.
090:         * It should be included in the signature.
091:         * The actual presentation of the text depends on the specific concrete mailet subclass:
092:         * see for example {@link SMIMESign}.
093:         * The default is to not have any explanation text.</li>
094:         * </ul>
095:         * @version CVS $Revision: 494012 $ $Date: 2007-01-08 11:23:58 +0100 (Mo, 08 Jan 2007) $
096:         * @since 2.2.1
097:         */
098:        public abstract class SMIMEAbstractSign extends GenericMailet {
099:
100:            private static final String HEADERS_PATTERN = "[headers]";
101:
102:            private static final String SIGNER_NAME_PATTERN = "[signerName]";
103:
104:            private static final String SIGNER_ADDRESS_PATTERN = "[signerAddress]";
105:
106:            private static final String REVERSE_PATH_PATTERN = "[reversePath]";
107:
108:            /**
109:             * Holds value of property debug.
110:             */
111:            private boolean debug;
112:
113:            /**
114:             * Holds value of property explanationText.
115:             */
116:            private String explanationText;
117:
118:            /**
119:             * Holds value of property keyHolder.
120:             */
121:            private KeyHolder keyHolder;
122:
123:            /**
124:             * Holds value of property postmasterSigns.
125:             */
126:            private boolean postmasterSigns;
127:
128:            /**
129:             * Holds value of property rebuildFrom.
130:             */
131:            private boolean rebuildFrom;
132:
133:            /**
134:             * Holds value of property signerName.
135:             */
136:            private String signerName;
137:
138:            /**
139:             * Gets the expected init parameters.
140:             * @return An array containing the parameter names allowed for this mailet.
141:             */
142:            protected abstract String[] getAllowedInitParameters();
143:
144:            /* ******************************************************************** */
145:            /* ****************** Begin of setters and getters ******************** */
146:            /* ******************************************************************** */
147:
148:            /**
149:             * Initializer for property debug.
150:             */
151:            protected void initDebug() {
152:                setDebug((getInitParameter("debug") == null) ? false
153:                        : new Boolean(getInitParameter("debug")).booleanValue());
154:            }
155:
156:            /**
157:             * Getter for property debug.
158:             * @return Value of property debug.
159:             */
160:            public boolean isDebug() {
161:                return this .debug;
162:            }
163:
164:            /**
165:             * Setter for property debug.
166:             * @param debug New value of property debug.
167:             */
168:            public void setDebug(boolean debug) {
169:                this .debug = debug;
170:            }
171:
172:            /**
173:             * Initializer for property explanationText.
174:             */
175:            protected void initExplanationText() {
176:                setExplanationText(getInitParameter("explanationText"));
177:                if (isDebug()) {
178:                    log("Explanation text:\r\n" + getExplanationText());
179:                }
180:            }
181:
182:            /**
183:             * Getter for property explanationText.
184:             * Text to be used in the SignatureExplanation.txt file.
185:             * @return Value of property explanationText.
186:             */
187:            public String getExplanationText() {
188:                return this .explanationText;
189:            }
190:
191:            /**
192:             * Setter for property explanationText.
193:             * @param explanationText New value of property explanationText.
194:             */
195:            public void setExplanationText(String explanationText) {
196:                this .explanationText = explanationText;
197:            }
198:
199:            /**
200:             * Initializer for property keyHolder.
201:             */
202:            protected void initKeyHolder() throws Exception {
203:                String keyStoreFileName = getInitParameter("keyStoreFileName");
204:                if (keyStoreFileName == null) {
205:                    throw new MessagingException(
206:                            "<keyStoreFileName> parameter missing.");
207:                }
208:
209:                String keyStorePassword = getInitParameter("keyStorePassword");
210:                if (keyStorePassword == null) {
211:                    throw new MessagingException(
212:                            "<keyStorePassword> parameter missing.");
213:                }
214:                String keyAliasPassword = getInitParameter("keyAliasPassword");
215:                if (keyAliasPassword == null) {
216:                    keyAliasPassword = keyStorePassword;
217:                    if (isDebug()) {
218:                        log("<keyAliasPassword> parameter not specified: will default to the <keyStorePassword> parameter.");
219:                    }
220:                }
221:
222:                String keyStoreType = getInitParameter("keyStoreType");
223:                if (keyStoreType == null) {
224:                    if (isDebug()) {
225:                        log("<type> parameter not specified: will default to \""
226:                                + KeyHolder.getDefaultType() + "\".");
227:                    }
228:                }
229:
230:                String keyAlias = getInitParameter("keyAlias");
231:                if (keyAlias == null) {
232:                    if (isDebug()) {
233:                        log("<keyAlias> parameter not specified: will look for the first one in the keystore.");
234:                    }
235:                }
236:
237:                if (isDebug()) {
238:                    StringBuffer logBuffer = new StringBuffer(1024).append(
239:                            "KeyStore related parameters:").append(
240:                            "  keyStoreFileName=").append(keyStoreFileName)
241:                            .append(", keyStoreType=").append(keyStoreType)
242:                            .append(", keyAlias=").append(keyAlias).append(" ");
243:                    log(logBuffer.toString());
244:                }
245:
246:                // Certificate preparation
247:                setKeyHolder(new KeyHolder(keyStoreFileName, keyStorePassword,
248:                        keyAlias, keyAliasPassword, keyStoreType));
249:
250:                if (isDebug()) {
251:                    log("Subject Distinguished Name: "
252:                            + getKeyHolder().getSignerDistinguishedName());
253:                }
254:
255:                if (getKeyHolder().getSignerAddress() == null) {
256:                    throw new MessagingException(
257:                            "Signer address missing in the certificate.");
258:                }
259:            }
260:
261:            /**
262:             * Getter for property keyHolder.
263:             * It is <CODE>protected</CODE> instead of <CODE>public</CODE> for security reasons.
264:             * @return Value of property keyHolder.
265:             */
266:            protected KeyHolder getKeyHolder() {
267:                return this .keyHolder;
268:            }
269:
270:            /**
271:             * Setter for property keyHolder.
272:             * It is <CODE>protected</CODE> instead of <CODE>public</CODE> for security reasons.
273:             * @param keyHolder New value of property keyHolder.
274:             */
275:            protected void setKeyHolder(KeyHolder keyHolder) {
276:                this .keyHolder = keyHolder;
277:            }
278:
279:            /**
280:             * Initializer for property postmasterSigns.
281:             */
282:            protected void initPostmasterSigns() {
283:                setPostmasterSigns((getInitParameter("postmasterSigns") == null) ? false
284:                        : new Boolean(getInitParameter("postmasterSigns"))
285:                                .booleanValue());
286:            }
287:
288:            /**
289:             * Getter for property postmasterSigns.
290:             * If true will sign messages signed by the postmaster.
291:             * @return Value of property postmasterSigns.
292:             */
293:            public boolean isPostmasterSigns() {
294:                return this .postmasterSigns;
295:            }
296:
297:            /**
298:             * Setter for property postmasterSigns.
299:             * @param postmasterSigns New value of property postmasterSigns.
300:             */
301:            public void setPostmasterSigns(boolean postmasterSigns) {
302:                this .postmasterSigns = postmasterSigns;
303:            }
304:
305:            /**
306:             * Initializer for property rebuildFrom.
307:             */
308:            protected void initRebuildFrom() throws MessagingException {
309:                setRebuildFrom((getInitParameter("rebuildFrom") == null) ? false
310:                        : new Boolean(getInitParameter("rebuildFrom"))
311:                                .booleanValue());
312:                if (isDebug()) {
313:                    if (isRebuildFrom()) {
314:                        log("Will modify the \"From:\" header.");
315:                    } else {
316:                        log("Will leave the \"From:\" header unchanged.");
317:                    }
318:                }
319:            }
320:
321:            /**
322:             * Getter for property rebuildFrom.
323:             * If true will modify the "From:" header.
324:             * <P>The modification is as follows:
325:             * assuming that the signer mail address in the signer certificate is <I>trusted-server@xxx.com&gt;</I>
326:             * and that <I>From: "John Smith" <john.smith@xxx.com></I>
327:             * we will get <I>From: "John Smith" <john.smith@xxx.com>" &lt;trusted-server@xxx.com&gt;</I>.</P>
328:             * <P>If the "ReplyTo:" header is missing or empty it will be set to the original "From:" header.</P>
329:             * <P>Such modification is necessary to achieve a correct behaviour
330:             * with some mail clients (e.g. Microsoft Outlook Express).</P>
331:             * @return Value of property rebuildFrom.
332:             */
333:            public boolean isRebuildFrom() {
334:                return this .rebuildFrom;
335:            }
336:
337:            /**
338:             * Setter for property rebuildFrom.
339:             * @param rebuildFrom New value of property rebuildFrom.
340:             */
341:            public void setRebuildFrom(boolean rebuildFrom) {
342:                this .rebuildFrom = rebuildFrom;
343:            }
344:
345:            /**
346:             * Initializer for property signerName.
347:             */
348:            protected void initSignerName() {
349:                setSignerName(getInitParameter("signerName"));
350:                if (getSignerName() == null) {
351:                    if (getKeyHolder() == null) {
352:                        throw new RuntimeException(
353:                                "initKeyHolder() must be invoked before initSignerName()");
354:                    }
355:                    setSignerName(getKeyHolder().getSignerCN());
356:                    if (isDebug()) {
357:                        log("<signerName> parameter not specified: will use the certificate signer \"CN=\" attribute.");
358:                    }
359:                }
360:            }
361:
362:            /**
363:             * Getter for property signerName.
364:             * @return Value of property signerName.
365:             */
366:            public String getSignerName() {
367:                return this .signerName;
368:            }
369:
370:            /**
371:             * Setter for property signerName.
372:             * @param signerName New value of property signerName.
373:             */
374:            public void setSignerName(String signerName) {
375:                this .signerName = signerName;
376:            }
377:
378:            /* ******************************************************************** */
379:            /* ****************** End of setters and getters ********************** */
380:            /* ******************************************************************** */
381:
382:            /**
383:             * Mailet initialization routine.
384:             */
385:            public void init() throws MessagingException {
386:
387:                // check that all init parameters have been declared in allowedInitParameters
388:                checkInitParameters(getAllowedInitParameters());
389:
390:                try {
391:                    initDebug();
392:                    if (isDebug()) {
393:                        log("Initializing");
394:                    }
395:
396:                    initKeyHolder();
397:                    initSignerName();
398:                    initPostmasterSigns();
399:                    initRebuildFrom();
400:                    initExplanationText();
401:
402:                } catch (MessagingException me) {
403:                    throw me;
404:                } catch (Exception e) {
405:                    log("Exception thrown", e);
406:                    throw new MessagingException("Exception thrown", e);
407:                } finally {
408:                    if (isDebug()) {
409:                        StringBuffer logBuffer = new StringBuffer(1024).append(
410:                                "Other parameters:").append(", signerName=")
411:                                .append(getSignerName()).append(
412:                                        ", postmasterSigns=").append(
413:                                        postmasterSigns).append(
414:                                        ", rebuildFrom=").append(rebuildFrom)
415:                                .append(" ");
416:                        log(logBuffer.toString());
417:                    }
418:                }
419:
420:            }
421:
422:            /**
423:             * Service does the hard work, and signs
424:             *
425:             * @param mail the mail to sign
426:             * @throws MessagingException if a problem arises signing the mail
427:             */
428:            public void service(Mail mail) throws MessagingException {
429:
430:                try {
431:                    if (!isOkToSign(mail)) {
432:                        return;
433:                    }
434:
435:                    MimeBodyPart wrapperBodyPart = getWrapperBodyPart(mail);
436:
437:                    MimeMessage originalMessage = mail.getMessage();
438:
439:                    // do it
440:                    MimeMultipart signedMimeMultipart;
441:                    if (wrapperBodyPart != null) {
442:                        signedMimeMultipart = getKeyHolder().generate(
443:                                wrapperBodyPart);
444:                    } else {
445:                        signedMimeMultipart = getKeyHolder().generate(
446:                                originalMessage);
447:                    }
448:
449:                    MimeMessage newMessage = new MimeMessage(Session
450:                            .getDefaultInstance(System.getProperties(), null));
451:                    Enumeration headerEnum = originalMessage
452:                            .getAllHeaderLines();
453:                    while (headerEnum.hasMoreElements()) {
454:                        newMessage.addHeaderLine((String) headerEnum
455:                                .nextElement());
456:                    }
457:
458:                    newMessage.setSender(new InternetAddress(getKeyHolder()
459:                            .getSignerAddress(), getSignerName()));
460:
461:                    if (isRebuildFrom()) {
462:                        // builds a new "mixed" "From:" header
463:                        InternetAddress modifiedFromIA = new InternetAddress(
464:                                getKeyHolder().getSignerAddress(), mail
465:                                        .getSender().toString());
466:                        newMessage.setFrom(modifiedFromIA);
467:
468:                        // if the original "ReplyTo:" header is missing sets it to the original "From:" header
469:                        newMessage.setReplyTo(originalMessage.getReplyTo());
470:                    }
471:
472:                    newMessage.setContent(signedMimeMultipart,
473:                            signedMimeMultipart.getContentType());
474:                    String messageId = originalMessage.getMessageID();
475:                    newMessage.saveChanges();
476:                    if (messageId != null) {
477:                        newMessage.setHeader(RFC2822Headers.MESSAGE_ID,
478:                                messageId);
479:                    }
480:
481:                    mail.setMessage(newMessage);
482:
483:                    // marks this mail as server-signed
484:                    mail.setAttribute(SMIMEAttributeNames.SMIME_SIGNING_MAILET,
485:                            this .getClass().getName());
486:                    // it is valid for us by definition (signed here by us)
487:                    mail.setAttribute(
488:                            SMIMEAttributeNames.SMIME_SIGNATURE_VALIDITY,
489:                            "valid");
490:
491:                    // saves the trusted server signer address
492:                    // warning: should be same as the mail address in the certificate, but it is not guaranteed
493:                    mail.setAttribute(SMIMEAttributeNames.SMIME_SIGNER_ADDRESS,
494:                            getKeyHolder().getSignerAddress());
495:
496:                    if (isDebug()) {
497:                        log("Message signed, reverse-path: " + mail.getSender()
498:                                + ", Id: " + messageId);
499:                    }
500:
501:                } catch (MessagingException me) {
502:                    log("MessagingException found - could not sign!", me);
503:                    throw me;
504:                } catch (Exception e) {
505:                    log("Exception found", e);
506:                    throw new MessagingException(
507:                            "Exception thrown - could not sign!", e);
508:                }
509:
510:            }
511:
512:            /**
513:             * <P>Checks if the mail can be signed.</P>
514:             * <P>Rules:</P>
515:             * <OL>
516:             * <LI>The reverse-path != null (it is not a bounce).</LI>
517:             * <LI>The sender user must have been SMTP authenticated.</LI>
518:             * <LI>Either:</LI>
519:             * <UL>
520:             * <LI>The reverse-path is the postmaster address and {@link #isPostmasterSigns} returns <I>true</I></LI>
521:             * <LI>or the reverse-path == the authenticated user
522:             * and there is at least one "From:" address == reverse-path.</LI>.
523:             * </UL>
524:             * <LI>The message has not already been signed (mimeType != <I>multipart/signed</I>
525:             * and != <I>application/pkcs7-mime</I>).</LI>
526:             * </OL>
527:             * @param mail The mail object to check.
528:             * @return True if can be signed.
529:             */
530:            protected boolean isOkToSign(Mail mail) throws MessagingException {
531:
532:                MailAddress reversePath = mail.getSender();
533:
534:                // Is it a bounce?
535:                if (reversePath == null) {
536:                    return false;
537:                }
538:
539:                String authUser = (String) mail
540:                        .getAttribute("org.apache.james.SMTPAuthUser");
541:                // was the sender user SMTP authorized?
542:                if (authUser == null) {
543:                    return false;
544:                }
545:
546:                // The sender is the postmaster?
547:                if (getMailetContext().getPostmaster().equals(reversePath)) {
548:                    // should not sign postmaster sent messages?
549:                    if (!isPostmasterSigns()) {
550:                        return false;
551:                    }
552:                } else {
553:                    // is the reverse-path user different from the SMTP authorized user?
554:                    if (!reversePath.getUser().equals(authUser)) {
555:                        return false;
556:                    }
557:                    // is there no "From:" address same as the reverse-path?
558:                    if (!fromAddressSameAsReverse(mail)) {
559:                        return false;
560:                    }
561:                }
562:
563:                // if already signed return false
564:                MimeMessage mimeMessage = mail.getMessage();
565:                if (mimeMessage.isMimeType("multipart/signed")
566:                        || mimeMessage.isMimeType("application/pkcs7-mime")) {
567:                    return false;
568:                }
569:
570:                return true;
571:            }
572:
573:            /**
574:             * Creates the {@link javax.mail.internet.MimeBodyPart} that will be signed.
575:             * For example, may attach a text file explaining the meaning of the signature,
576:             * or an XML file containing information that can be checked by other MTAs.
577:             * @param mail The mail to massage.
578:             * @return The massaged MimeBodyPart to sign, or null to have the whole message signed "as is".
579:             */
580:            protected abstract MimeBodyPart getWrapperBodyPart(Mail mail)
581:                    throws MessagingException, IOException;
582:
583:            /**
584:             * Checks if there are unallowed init parameters specified in the configuration file
585:             * against the String[] allowedInitParameters.
586:             */
587:            private void checkInitParameters(String[] allowedArray)
588:                    throws MessagingException {
589:                // if null then no check is requested
590:                if (allowedArray == null) {
591:                    return;
592:                }
593:
594:                Collection allowed = new HashSet();
595:                Collection bad = new ArrayList();
596:
597:                for (int i = 0; i < allowedArray.length; i++) {
598:                    allowed.add(allowedArray[i]);
599:                }
600:
601:                Iterator iterator = getInitParameterNames();
602:                while (iterator.hasNext()) {
603:                    String parameter = (String) iterator.next();
604:                    if (!allowed.contains(parameter)) {
605:                        bad.add(parameter);
606:                    }
607:                }
608:
609:                if (bad.size() > 0) {
610:                    throw new MessagingException(
611:                            "Unexpected init parameters found: "
612:                                    + arrayToString(bad.toArray()));
613:                }
614:            }
615:
616:            /**
617:             * Utility method for obtaining a string representation of an array of Objects.
618:             */
619:            private final String arrayToString(Object[] array) {
620:                if (array == null) {
621:                    return "null";
622:                }
623:                StringBuffer sb = new StringBuffer(1024);
624:                sb.append("[");
625:                for (int i = 0; i < array.length; i++) {
626:                    if (i > 0) {
627:                        sb.append(",");
628:                    }
629:                    sb.append(array[i]);
630:                }
631:                sb.append("]");
632:                return sb.toString();
633:            }
634:
635:            /**
636:             * Utility method that checks if there is at least one address in the "From:" header
637:             * same as the <i>reverse-path</i>.
638:             * @param mail The mail to check.
639:             * @return True if an address is found, false otherwise.
640:             */
641:            protected final boolean fromAddressSameAsReverse(Mail mail) {
642:
643:                MailAddress reversePath = mail.getSender();
644:
645:                if (reversePath == null) {
646:                    return false;
647:                }
648:
649:                try {
650:                    InternetAddress[] fromArray = (InternetAddress[]) mail
651:                            .getMessage().getFrom();
652:                    if (fromArray != null) {
653:                        for (int i = 0; i < fromArray.length; i++) {
654:                            MailAddress mailAddress = null;
655:                            try {
656:                                mailAddress = new MailAddress(fromArray[i]);
657:                            } catch (ParseException pe) {
658:                                log("Unable to parse a \"FROM\" header address: "
659:                                        + fromArray[i].toString()
660:                                        + "; ignoring.");
661:                                continue;
662:                            }
663:                            if (mailAddress.equals(reversePath)) {
664:                                return true;
665:                            }
666:                        }
667:                    }
668:                } catch (MessagingException me) {
669:                    log("Unable to parse the \"FROM\" header; ignoring.");
670:                }
671:
672:                return false;
673:
674:            }
675:
676:            /**
677:             * Utility method for obtaining a string representation of the Message's headers
678:             * @param message The message to extract the headers from.
679:             * @return The string containing the headers.
680:             */
681:            protected final String getMessageHeaders(MimeMessage message)
682:                    throws MessagingException {
683:                Enumeration heads = message.getAllHeaderLines();
684:                StringBuffer headBuffer = new StringBuffer(1024);
685:                while (heads.hasMoreElements()) {
686:                    headBuffer.append(heads.nextElement().toString()).append(
687:                            "\r\n");
688:                }
689:                return headBuffer.toString();
690:            }
691:
692:            /**
693:             * Prepares the explanation text making substitutions in the <I>explanationText</I> template string.
694:             * Utility method that searches for all occurrences of some pattern strings
695:             * and substitute them with the appropriate params.
696:             * @param explanationText The template string for the explanation text.
697:             * @param signerName The string that will replace the <CODE>[signerName]</CODE> pattern.
698:             * @param signerAddress The string that will replace the <CODE>[signerAddress]</CODE> pattern.
699:             * @param reversePath The string that will replace the <CODE>[reversePath]</CODE> pattern.
700:             * @param headers The string that will replace the <CODE>[headers]</CODE> pattern.
701:             * @return The actual explanation text string with all replacements done.
702:             */
703:            protected final String getReplacedExplanationText(
704:                    String explanationText, String signerName,
705:                    String signerAddress, String reversePath, String headers) {
706:
707:                String replacedExplanationText = explanationText;
708:
709:                replacedExplanationText = getReplacedString(
710:                        replacedExplanationText, SIGNER_NAME_PATTERN,
711:                        signerName);
712:                replacedExplanationText = getReplacedString(
713:                        replacedExplanationText, SIGNER_ADDRESS_PATTERN,
714:                        signerAddress);
715:                replacedExplanationText = getReplacedString(
716:                        replacedExplanationText, REVERSE_PATH_PATTERN,
717:                        reversePath);
718:                replacedExplanationText = getReplacedString(
719:                        replacedExplanationText, HEADERS_PATTERN, headers);
720:
721:                return replacedExplanationText;
722:            }
723:
724:            /**
725:             * Searches the <I>template</I> String for all occurrences of the <I>pattern</I> string
726:             * and creates a new String substituting them with the <I>actual</I> String.
727:             * @param template The template String to work on.
728:             * @param pattern The string to search for the replacement.
729:             * @param actual The actual string to use for the replacement.
730:             */
731:            private String getReplacedString(String template, String pattern,
732:                    String actual) {
733:                if (actual != null) {
734:                    StringBuffer sb = new StringBuffer(template.length());
735:                    int fromIndex = 0;
736:                    int index;
737:                    while ((index = template.indexOf(pattern, fromIndex)) >= 0) {
738:                        sb.append(template.substring(fromIndex, index));
739:                        sb.append(actual);
740:                        fromIndex = index + pattern.length();
741:                    }
742:                    if (fromIndex < template.length()) {
743:                        sb.append(template.substring(fromIndex));
744:                    }
745:                    return sb.toString();
746:                } else {
747:                    return new String(template);
748:                }
749:            }
750:
751:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.