001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.kaptcha.components; 014 015import org.apache.tapestry5.ComponentResources; 016import org.apache.tapestry5.Link; 017import org.apache.tapestry5.MarkupWriter; 018import org.apache.tapestry5.StreamResponse; 019import org.apache.tapestry5.annotations.Persist; 020import org.apache.tapestry5.annotations.SupportsInformalParameters; 021import org.apache.tapestry5.ioc.annotations.Inject; 022import org.apache.tapestry5.kaptcha.services.KaptchaProducer; 023import org.apache.tapestry5.services.HttpError; 024import org.apache.tapestry5.services.Response; 025 026import javax.imageio.ImageIO; 027import javax.servlet.http.HttpServletResponse; 028import java.awt.image.BufferedImage; 029import java.io.ByteArrayInputStream; 030import java.io.ByteArrayOutputStream; 031import java.io.IOException; 032import java.io.InputStream; 033 034/** 035 * Part of a Captcha based authentication scheme; a KaptchaImage generates a new 036 * text image whenever it <em>renders</em> and can provide the previously 037 * rendered text subsequently (it is stored persistently in the session). 038 * 039 * The component renders an {@code <img>} tag, including width and height attributes. Other attributes 040 * come from informal parameters. 041 * 042 * @tapestrydoc 043 * @since 5.3 044 */ 045@SupportsInformalParameters 046public class KaptchaImage 047{ 048 049 @Persist 050 private String captchaText; 051 052 @Inject 053 private KaptchaProducer producer; 054 055 @Inject 056 private ComponentResources resources; 057 058 @Inject 059 private Response response; 060 061 public String getCaptchaText() 062 { 063 return captchaText; 064 } 065 066 void setupRender() 067 { 068 captchaText = producer.createText(); 069 } 070 071 boolean beginRender(MarkupWriter writer) 072 { 073 Link link = resources.createEventLink("image"); 074 075 writer.element("img", 076 077 "src", link.toURI(), 078 079 "width", producer.getWidth(), 080 081 "height", producer.getHeight()); 082 083 resources.renderInformalParameters(writer); 084 085 writer.end(); 086 087 return false; 088 } 089 090 Object onImage() throws IOException 091 { 092 if (captchaText == null) 093 { 094 return new HttpError(HttpServletResponse.SC_NOT_FOUND, "Session expired."); 095 } 096 097 return new StreamResponse() 098 { 099 @Override 100 public String getContentType() 101 { 102 return "image/jpeg"; 103 } 104 105 @Override 106 public InputStream getStream() throws IOException 107 { 108 BufferedImage image = producer.createImage(captchaText); 109 110 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 111 112 ImageIO.write(image, "jpg", baos); 113 114 return new ByteArrayInputStream(baos.toByteArray()); 115 } 116 117 @Override 118 public void prepareResponse(Response response) 119 { 120 response.setDateHeader("Expires", 0); 121 // Set standard HTTP/1.1 no-cache headers. 122 response.addHeader("Cache-Control", "no-store, no-cache, must-revalidate"); 123 // Set IE extended HTTP/1.1 no-cache headers (use addHeader). 124 response.addHeader("Cache-Control", "post-check=0, pre-check=0"); 125 // Set standard HTTP/1.0 no-cache header. 126 response.setHeader("Pragma", "no-cache"); 127 } 128 }; 129 130 } 131}