You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LoginForm.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright 2011 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.IOException;
  18. import java.io.Serializable;
  19. import java.lang.reflect.Method;
  20. import java.util.HashMap;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import com.vaadin.server.ConnectorResource;
  24. import com.vaadin.server.ExternalResource;
  25. import com.vaadin.server.VaadinRequest;
  26. import com.vaadin.server.VaadinResponse;
  27. import com.vaadin.server.VaadinService;
  28. import com.vaadin.server.VaadinServletService;
  29. import com.vaadin.shared.ApplicationConstants;
  30. /**
  31. * LoginForm is a Vaadin component to handle common problem among Ajax
  32. * applications: browsers password managers don't fill dynamically created forms
  33. * like all those UI elements created by Vaadin.
  34. * <p>
  35. * For developer it is easy to use: add component to a desired place in you UI
  36. * and add LoginListener to validate form input. Behind the curtain LoginForm
  37. * creates an iframe with static html that browsers detect.
  38. * <p>
  39. * Login form is by default 100% width and height, so consider using it inside a
  40. * sized {@link Panel} or {@link Window}.
  41. * <p>
  42. * Login page html can be overridden by replacing protected getLoginHTML method.
  43. * As the login page is actually an iframe, styles must be handled manually. By
  44. * default component tries to guess the right place for theme css.
  45. *
  46. * @since 5.3
  47. * @deprecated As of 7.0. This component no longer fulfills its duty reliably in
  48. * the supported browsers and a {@link VerticalLayout} with two
  49. * {@link TextField}s can be used instead.
  50. */
  51. @Deprecated
  52. public class LoginForm extends CustomComponent {
  53. private String usernameCaption = "Username";
  54. private String passwordCaption = "Password";
  55. private String loginButtonCaption = "Login";
  56. private Embedded iframe = new Embedded();
  57. @Override
  58. public boolean handleConnectorRequest(VaadinRequest request,
  59. VaadinResponse response, String path) throws IOException {
  60. String method = VaadinServletService.getCurrentServletRequest()
  61. .getMethod();
  62. if (!path.equals("login")) {
  63. return super.handleConnectorRequest(request, response, path);
  64. }
  65. String responseString = null;
  66. if (method.equalsIgnoreCase("post")) {
  67. responseString = handleLogin(request);
  68. } else {
  69. responseString = getLoginHTML();
  70. }
  71. if (responseString != null) {
  72. response.setContentType("text/html; charset=utf-8");
  73. response.setCacheTime(-1);
  74. response.getWriter().write(responseString);
  75. return true;
  76. } else {
  77. return false;
  78. }
  79. }
  80. private String handleLogin(VaadinRequest request) {
  81. // Ensure UI.getCurrent() works in listeners
  82. Map<String, String[]> parameters = VaadinService.getCurrentRequest()
  83. .getParameterMap();
  84. HashMap<String, String> params = new HashMap<String, String>();
  85. // expecting single params
  86. for (Iterator<String> it = parameters.keySet().iterator(); it.hasNext();) {
  87. String key = it.next();
  88. String value = (parameters.get(key))[0];
  89. params.put(key, value);
  90. }
  91. LoginEvent event = new LoginEvent(LoginForm.this, params);
  92. fireEvent(event);
  93. return "<html><body>Login form handled."
  94. + "<script type='text/javascript'>parent.parent.vaadin.forceSync();"
  95. + "</script></body></html>";
  96. }
  97. public LoginForm() {
  98. iframe.setType(Embedded.TYPE_BROWSER);
  99. iframe.setSizeFull();
  100. setSizeFull();
  101. setCompositionRoot(iframe);
  102. addStyleName("v-loginform");
  103. }
  104. @Override
  105. public void beforeClientResponse(boolean initial) {
  106. // Generate magic URL now when UI id and connectorId are known
  107. iframe.setSource(new ExternalResource(
  108. ApplicationConstants.APP_PROTOCOL_PREFIX
  109. + ApplicationConstants.APP_PATH + '/'
  110. + ConnectorResource.CONNECTOR_PATH + '/'
  111. + getUI().getUIId() + '/' + getConnectorId() + "/login"));
  112. super.beforeClientResponse(initial);
  113. }
  114. /**
  115. * Returns byte array containing login page html. If you need to override
  116. * the login html, use the default html as basis. Login page sets its target
  117. * with javascript.
  118. *
  119. * @return byte array containing login page html
  120. */
  121. protected String getLoginHTML() {
  122. return "<!DOCTYPE html>\n"
  123. + "<html>"
  124. + "<head><script type='text/javascript'>"
  125. + "var setTarget = function() {"
  126. + "var uri = window.location;"
  127. + "var f = document.getElementById('loginf');"
  128. + "document.forms[0].action = uri;document.forms[0].username.focus();};"
  129. + ""
  130. + "var styles = window.parent.document.styleSheets;"
  131. + "for(var j = 0; j < styles.length; j++) {\n"
  132. + "if(styles[j].href) {"
  133. + "var stylesheet = document.createElement('link');\n"
  134. + "stylesheet.setAttribute('rel', 'stylesheet');\n"
  135. + "stylesheet.setAttribute('type', 'text/css');\n"
  136. + "stylesheet.setAttribute('href', styles[j].href);\n"
  137. + "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"
  138. + "}"
  139. + "}\n"
  140. + "function submitOnEnter(e) { var keycode = e.keyCode || e.which;"
  141. + " if (keycode == 13) {document.forms[0].submit();} } \n"
  142. + "</script>"
  143. + "</head><body onload='setTarget();' style='margin:0;padding:0; background:transparent;' class=\""
  144. + ApplicationConstants.GENERATED_BODY_CLASSNAME
  145. + "\">"
  146. + "<div class='v-app v-app-loginpage' style=\"background:transparent;\">"
  147. + "<iframe name='logintarget' style='width:0;height:0;"
  148. + "border:0;margin:0;padding:0;display:block'></iframe>"
  149. + "<form id='loginf' target='logintarget' onkeypress=\"submitOnEnter(event)\" method=\"post\">"
  150. + "<div>"
  151. + usernameCaption
  152. + "</div><div >"
  153. + "<input class='v-textfield v-widget' style='display:block;' type='text' name='username'></div>"
  154. + "<div>"
  155. + passwordCaption
  156. + "</div>"
  157. + "<div><input class='v-textfield v-widget' style='display:block;' type='password' name='password'></div>"
  158. + "<div><div onclick=\"document.forms[0].submit();\" tabindex=\"0\" class=\"v-button\" role=\"button\" ><span class=\"v-button-wrap\"><span class=\"v-button-caption\">"
  159. + loginButtonCaption
  160. + "</span></span></div></div></form></div>" + "</body></html>";
  161. }
  162. /**
  163. * This event is sent when login form is submitted.
  164. */
  165. public static class LoginEvent extends Event {
  166. private Map<String, String> params;
  167. private LoginEvent(Component source, Map<String, String> params) {
  168. super(source);
  169. this.params = params;
  170. }
  171. /**
  172. * Access method to form values by field names.
  173. *
  174. * @param name
  175. * @return value in given field
  176. */
  177. public String getLoginParameter(String name) {
  178. if (params.containsKey(name)) {
  179. return params.get(name);
  180. } else {
  181. return null;
  182. }
  183. }
  184. }
  185. /**
  186. * Login listener is a class capable to listen LoginEvents sent from
  187. * LoginBox
  188. */
  189. public interface LoginListener extends Serializable {
  190. /**
  191. * This method is fired on each login form post.
  192. *
  193. * @param event
  194. */
  195. public void onLogin(LoginForm.LoginEvent event);
  196. }
  197. private static final Method ON_LOGIN_METHOD;
  198. private static final String UNDEFINED_HEIGHT = "140px";
  199. private static final String UNDEFINED_WIDTH = "200px";
  200. static {
  201. try {
  202. ON_LOGIN_METHOD = LoginListener.class.getDeclaredMethod("onLogin",
  203. new Class[] { LoginEvent.class });
  204. } catch (final java.lang.NoSuchMethodException e) {
  205. // This should never happen
  206. throw new java.lang.RuntimeException(
  207. "Internal error finding methods in LoginForm");
  208. }
  209. }
  210. /**
  211. * Adds LoginListener to handle login logic
  212. *
  213. * @param listener
  214. */
  215. public void addLoginListener(LoginListener listener) {
  216. addListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
  217. }
  218. /**
  219. * @deprecated As of 7.0, replaced by
  220. * {@link #addLoginListener(LoginListener)}
  221. **/
  222. @Deprecated
  223. public void addListener(LoginListener listener) {
  224. addLoginListener(listener);
  225. }
  226. /**
  227. * Removes LoginListener
  228. *
  229. * @param listener
  230. */
  231. public void removeLoginListener(LoginListener listener) {
  232. removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD);
  233. }
  234. /**
  235. * @deprecated As of 7.0, replaced by
  236. * {@link #removeLoginListener(LoginListener)}
  237. **/
  238. @Deprecated
  239. public void removeListener(LoginListener listener) {
  240. removeLoginListener(listener);
  241. }
  242. @Override
  243. public void setWidth(float width, Unit unit) {
  244. super.setWidth(width, unit);
  245. if (iframe != null) {
  246. if (width < 0) {
  247. iframe.setWidth(UNDEFINED_WIDTH);
  248. } else {
  249. iframe.setWidth("100%");
  250. }
  251. }
  252. }
  253. @Override
  254. public void setHeight(float height, Unit unit) {
  255. super.setHeight(height, unit);
  256. if (iframe != null) {
  257. if (height < 0) {
  258. iframe.setHeight(UNDEFINED_HEIGHT);
  259. } else {
  260. iframe.setHeight("100%");
  261. }
  262. }
  263. }
  264. /**
  265. * Returns the caption for the user name field.
  266. *
  267. * @return String
  268. */
  269. public String getUsernameCaption() {
  270. return usernameCaption;
  271. }
  272. /**
  273. * Sets the caption to show for the user name field. The caption cannot be
  274. * changed after the form has been shown to the user.
  275. *
  276. * @param usernameCaption
  277. */
  278. public void setUsernameCaption(String usernameCaption) {
  279. this.usernameCaption = usernameCaption;
  280. }
  281. /**
  282. * Returns the caption for the password field.
  283. *
  284. * @return String
  285. */
  286. public String getPasswordCaption() {
  287. return passwordCaption;
  288. }
  289. /**
  290. * Sets the caption to show for the password field. The caption cannot be
  291. * changed after the form has been shown to the user.
  292. *
  293. * @param passwordCaption
  294. */
  295. public void setPasswordCaption(String passwordCaption) {
  296. this.passwordCaption = passwordCaption;
  297. }
  298. /**
  299. * Returns the caption for the login button.
  300. *
  301. * @return String
  302. */
  303. public String getLoginButtonCaption() {
  304. return loginButtonCaption;
  305. }
  306. /**
  307. * Sets the caption (button text) to show for the login button. The caption
  308. * cannot be changed after the form has been shown to the user.
  309. *
  310. * @param loginButtonCaption
  311. */
  312. public void setLoginButtonCaption(String loginButtonCaption) {
  313. this.loginButtonCaption = loginButtonCaption;
  314. }
  315. }