1   package ch.qos.logback.classic.net;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertNotNull;
5   import static org.junit.Assert.assertTrue;
6   
7   import java.io.ByteArrayOutputStream;
8   import java.util.List;
9   import java.util.Random;
10  
11  import javax.mail.Part;
12  import javax.mail.internet.MimeMessage;
13  import javax.mail.internet.MimeMultipart;
14  
15  import org.dom4j.io.SAXReader;
16  import org.junit.After;
17  import org.junit.Before;
18  import org.junit.Ignore;
19  import org.junit.Test;
20  import org.subethamail.smtp.AuthenticationHandler;
21  import org.subethamail.smtp.AuthenticationHandlerFactory;
22  import org.subethamail.smtp.auth.LoginAuthenticationHandler;
23  import org.subethamail.smtp.auth.LoginFailedException;
24  import org.subethamail.smtp.auth.PlainAuthenticationHandler;
25  import org.subethamail.smtp.auth.PluginAuthenticationHandler;
26  import org.subethamail.smtp.auth.UsernamePasswordValidator;
27  import org.subethamail.smtp.server.MessageListenerAdapter;
28  import org.subethamail.wiser.Wiser;
29  import org.subethamail.wiser.WiserMessage;
30  
31  import ch.qos.logback.classic.Logger;
32  import ch.qos.logback.classic.LoggerContext;
33  import ch.qos.logback.classic.PatternLayout;
34  import ch.qos.logback.classic.html.HTMLLayout;
35  import ch.qos.logback.classic.html.XHTMLEntityResolver;
36  import ch.qos.logback.classic.spi.LoggingEvent;
37  import ch.qos.logback.core.CoreConstants;
38  import ch.qos.logback.core.Layout;
39  import ch.qos.logback.core.util.StatusPrinter;
40  
41  public class SMTPAppender_SubethaSMTPTest {
42  
43    int diff = 1024 + new Random().nextInt(10000);
44    Wiser wiser;
45  
46    SMTPAppender smtpAppender;
47    LoggerContext lc = new LoggerContext();
48  
49    static final String TEST_SUBJECT = "test subject";
50    static final String HEADER = "HEADER\n";
51    static final String FOOTER = "FOOTER\n";
52  
53    @Before
54    public void setUp() throws Exception { 
55      wiser = new Wiser();
56      wiser.setPort(diff); 
57      wiser.getServer();
58      wiser.start();
59      //StartTLSCommand s;
60      buildSMTPAppender();
61    }
62  
63    void buildSMTPAppender() throws Exception {
64      smtpAppender = new SMTPAppender();
65      smtpAppender.setContext(lc);
66      smtpAppender.setName("smtp");
67      smtpAppender.setFrom("user@host.dom");
68      smtpAppender.setSMTPHost("localhost");
69      smtpAppender.setSMTPPort(diff);
70      smtpAppender.setSubject(TEST_SUBJECT);
71      smtpAppender.addTo("noreply@qos.ch");
72    }
73  
74    private Layout<LoggingEvent> buildPatternLayout(LoggerContext lc) {
75      PatternLayout layout = new PatternLayout();
76      layout.setContext(lc);
77      layout.setFileHeader(HEADER);
78      layout.setPattern("%-4relative [%thread] %-5level %logger %class - %msg%n");
79      layout.setFileFooter(FOOTER);
80      layout.start();
81      return layout;
82    }
83  
84    private Layout<LoggingEvent> buildHTMLLayout(LoggerContext lc) {
85      HTMLLayout layout = new HTMLLayout();
86      layout.setContext(lc);
87      // layout.setFileHeader(HEADER);
88      layout.setPattern("%level%class%msg");
89      // layout.setFileFooter(FOOTER);
90      layout.start();
91      return layout;
92    }
93  
94    @After
95    public void tearDown() throws Exception {
96    }
97  
98    private static String getWholeMessage(Part msg) {
99      try {
100       ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
101       msg.writeTo(bodyOut);
102       return bodyOut.toString("US-ASCII").trim();
103     } catch (Exception e) {
104       throw new RuntimeException(e);
105     }
106   }
107   
108   private static String getBody(Part msg) {
109     String all = getWholeMessage(msg);
110     int i = all.indexOf("\r\n\r\n");
111     return all.substring(i + 4, all.length());
112 }
113 
114   @Test
115   public void smoke() throws Exception {
116     smtpAppender.setLayout(buildPatternLayout(lc));
117     smtpAppender.start();
118     Logger logger = lc.getLogger("test");
119     logger.addAppender(smtpAppender);
120     logger.debug("hello");
121     logger.error("en error", new Exception("an exception"));
122     List<WiserMessage> wiserMsgList = wiser.getMessages();
123     
124     assertNotNull(wiserMsgList);
125     assertEquals(1, wiserMsgList.size());
126     WiserMessage wm = wiserMsgList.get(0);
127     // http://jira.qos.ch/browse/LBCLASSIC-67
128     MimeMessage mm = wm.getMimeMessage();
129     assertEquals(TEST_SUBJECT, mm.getSubject());
130 
131     MimeMultipart mp = (MimeMultipart) mm.getContent();
132     String body = getBody(mp.getBodyPart(0));
133     System.out.println("["+body);
134     assertTrue(body.startsWith(HEADER.trim()));
135     assertTrue(body.endsWith(FOOTER.trim()));
136   }
137 
138   @Test
139   public void html() throws Exception {
140     smtpAppender.setLayout(buildHTMLLayout(lc));
141     smtpAppender.start();
142     Logger logger = lc.getLogger("test");
143     logger.addAppender(smtpAppender);
144     logger.debug("hello");
145     logger.error("en error", new Exception("an exception"));
146     
147     List<WiserMessage> wiserMsgList = wiser.getMessages();
148     
149     assertNotNull(wiserMsgList);
150     assertEquals(1, wiserMsgList.size());
151     WiserMessage wm = wiserMsgList.get(0);
152     MimeMessage mm = wm.getMimeMessage();
153     assertEquals(TEST_SUBJECT, mm.getSubject());
154 
155     MimeMultipart mp = (MimeMultipart) mm.getContent();
156 
157     // verify strict adherence to xhtml1-strict.dtd
158     SAXReader reader = new SAXReader();
159     reader.setValidation(true);
160     reader.setEntityResolver(new XHTMLEntityResolver());
161     reader.read(mp.getBodyPart(0).getInputStream());
162     // System.out.println(GreenMailUtil.getBody(mp.getBodyPart(0)));
163   }
164 
165   @Test
166   /**
167    * Checks that even when many events are processed, the output is still
168    * conforms to xhtml-strict.dtd.
169    * 
170    * Note that SMTPAppender only keeps only 500 or so (=buffer size) events. So
171    * the generated output will be rather short.
172    */
173   public void htmlLong() throws Exception {
174     smtpAppender.setLayout(buildHTMLLayout(lc));
175     smtpAppender.start();
176     Logger logger = lc.getLogger("test");
177     logger.addAppender(smtpAppender);
178     for (int i = 0; i < CoreConstants.TABLE_ROW_LIMIT * 3; i++) {
179       logger.debug("hello " + i);
180     }
181     logger.error("en error", new Exception("an exception"));
182     List<WiserMessage> wiserMsgList = wiser.getMessages();
183     
184     assertNotNull(wiserMsgList);
185     assertEquals(1, wiserMsgList.size());
186     WiserMessage wm = wiserMsgList.get(0);
187     MimeMessage mm = wm.getMimeMessage();
188     assertEquals(TEST_SUBJECT, mm.getSubject());
189 
190     MimeMultipart mp = (MimeMultipart) mm.getContent();
191 
192     // verify strict adherence to xhtml1-strict.dtd
193     SAXReader reader = new SAXReader();
194     reader.setValidation(true);
195     reader.setEntityResolver(new XHTMLEntityResolver());
196     reader.read(mp.getBodyPart(0).getInputStream());
197   }
198   
199   @Test
200   public void authenticated() throws Exception {
201     MessageListenerAdapter mla = (MessageListenerAdapter)wiser.getServer().getMessageHandlerFactory();
202     mla.setAuthenticationHandlerFactory(new TrivialAuthHandlerFactory());
203 
204     smtpAppender.setUsername("x");
205     smtpAppender.setPassword("x");
206     
207     smtpAppender.setLayout(buildPatternLayout(lc));
208     smtpAppender.start();
209     Logger logger = lc.getLogger("test");
210     logger.addAppender(smtpAppender);
211     logger.debug("hello");
212     logger.error("en error", new Exception("an exception"));
213 
214     List<WiserMessage> wiserMsgList = wiser.getMessages();
215 
216     assertNotNull(wiserMsgList);
217     assertEquals(1, wiserMsgList.size());
218     WiserMessage wm = wiserMsgList.get(0);
219     // http://jira.qos.ch/browse/LBCLASSIC-67
220     MimeMessage mm = wm.getMimeMessage();
221     assertEquals(TEST_SUBJECT, mm.getSubject());
222 
223     MimeMultipart mp = (MimeMultipart) mm.getContent();
224     String body = getBody(mp.getBodyPart(0));
225     assertTrue(body.startsWith(HEADER.trim()));
226     assertTrue(body.endsWith(FOOTER.trim()));
227   }
228   
229   @Test
230   @Ignore 
231   // Unfortunately, there seems to be a problem with SubethaSMTP's implementation
232   // of startTLS. The same SMTPAppender code works fine when tested with gmail.
233   public void authenticatedSSL() throws Exception {
234     MessageListenerAdapter mla = (MessageListenerAdapter)wiser.getServer().getMessageHandlerFactory();
235     mla.setAuthenticationHandlerFactory(new TrivialAuthHandlerFactory());
236     
237     smtpAppender.setSTARTTLS(true);
238     smtpAppender.setUsername("xx");
239     smtpAppender.setPassword("xx");    
240   
241     smtpAppender.setLayout(buildPatternLayout(lc));
242     smtpAppender.start();
243     Logger logger = lc.getLogger("test");
244     logger.addAppender(smtpAppender);
245     logger.debug("hello");
246     logger.error("en error", new Exception("an exception"));
247 
248     StatusPrinter.print(lc);
249     List<WiserMessage> wiserMsgList = wiser.getMessages();
250 
251     assertNotNull(wiserMsgList);
252     assertEquals(1, wiserMsgList.size());
253   }
254   
255   @Test
256   @Ignore
257   public void authenticatedGmailStartTLS() throws Exception {
258     smtpAppender.setSMTPHost("smtp.gmail.com");
259     smtpAppender.setSMTPPort(587);
260     
261     smtpAppender.addTo("XXX@gmail.com");
262     smtpAppender.setSTARTTLS(true);
263     smtpAppender.setUsername("XXX@gmail.com");
264     smtpAppender.setPassword("XXX");    
265   
266     smtpAppender.setLayout(buildPatternLayout(lc));
267     smtpAppender.start();
268     Logger logger = lc.getLogger("authenticatedGmailSTARTTLS");
269     logger.addAppender(smtpAppender);
270     logger.debug("hello");
271     logger.error("en error", new Exception("an exception"));
272 
273     StatusPrinter.print(lc);
274   }
275   
276   @Test
277   @Ignore
278   public void authenticatedGmail_SSL() throws Exception {
279     smtpAppender.setSMTPHost("smtp.gmail.com");
280     smtpAppender.setSMTPPort(465);
281     
282     smtpAppender.addTo("XXX@gmail.com");
283     smtpAppender.setSSL(true);
284     smtpAppender.setUsername("XXX@gmail.com");
285     smtpAppender.setPassword("XXX");    
286   
287     smtpAppender.setLayout(buildPatternLayout(lc));
288     smtpAppender.start();
289     Logger logger = lc.getLogger("authenticatedGmail_SSL");
290     logger.addAppender(smtpAppender);
291     logger.debug("hello");
292     logger.error("en error", new Exception("an exception"));
293 
294     StatusPrinter.print(lc);
295   }
296   
297   public class TrivialAuthHandlerFactory implements AuthenticationHandlerFactory {
298     public AuthenticationHandler create() {
299       PluginAuthenticationHandler ret = new PluginAuthenticationHandler();
300       UsernamePasswordValidator validator = new UsernamePasswordValidator() {
301         public void login(String username, String password)
302             throws LoginFailedException {
303           if(!username.equals(password)) {
304             throw new LoginFailedException("username="+username+", password="+password);
305           }
306         }
307       };
308       ret.addPlugin(new PlainAuthenticationHandler(validator));
309       ret.addPlugin(new LoginAuthenticationHandler(validator));
310       return ret;
311     }
312   }
313 
314 }