├── .gitignore ├── pom.xml └── src ├── main ├── java │ └── sample │ │ ├── config │ │ ├── DataConfig.java │ │ ├── WebMvcAppInitializer.java │ │ ├── WebMvcConfig.java │ │ ├── WebSecurityAppInitializer.java │ │ └── WebSecurityConfig.java │ │ ├── data │ │ ├── Message.java │ │ └── MessageRepository.java │ │ └── mvc │ │ └── MessageController.java ├── resources │ └── log4j.xml └── webapp │ ├── WEB-INF │ └── templates │ │ └── messages │ │ ├── form.html │ │ ├── list.html │ │ └── view.html │ ├── index.jsp │ └── resources │ ├── css │ └── bootstrap.min.css │ └── js │ ├── jquery-1.7.2.js │ └── jquery.validate.js └── test └── java ├── org └── springframework │ └── security │ └── test │ ├── context │ └── showcase │ │ ├── CustomUserDetails.java │ │ ├── WithMockCustomUser.java │ │ ├── WithMockCustomUserSecurityContextFactory.java │ │ ├── WithMockUserTests.java │ │ ├── WithUserDetailsTests.java │ │ └── service │ │ ├── HelloMessageService.java │ │ └── MessageService.java │ └── web │ └── servlet │ └── showcase │ ├── csrf │ ├── CsrfShowcaseTests.java │ ├── CustomCsrfShowcaseTests.java │ └── DefaultCsrfShowcaseTests.java │ ├── login │ ├── AuthenticationTests.java │ ├── CustomConfigAuthenticationTests.java │ └── CustomLoginRequestBuilderAuthenticationTests.java │ └── secured │ ├── DefaultfSecurityRequestsTests.java │ ├── SecurityRequestsTests.java │ ├── WithUserAuthenticationTests.java │ ├── WithUserClassLevelAuthenticationTests.java │ ├── WithUserDetailsAuthenticationTests.java │ └── WithUserDetailsClassLevelAuthenticationTests.java └── sample ├── config └── MockDataConfig.java ├── data └── mock │ └── MockConversionService.java ├── fest ├── Assertions.java └── MessageAssert.java ├── htmlunit └── MockMvcHtmlUnitCreateMessageTest.java ├── mockmvc └── MockMvcCreateMessageTest.java └── webdriver ├── MockMvcHtmlUnitDriverCreateMessageTest.java └── pages ├── AbstractPage.java ├── CreateMessagePage.java └── ViewMessagePage.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | .settings 4 | .classpath 5 | .project 6 | *.iml 7 | .idea -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | sample 6 | spring-security-test-blog 7 | 4.0.0.M1 8 | spring-security-test 9 | spring-security-test 10 | http://spring.io/spring-security 11 | war 12 | 13 | spring.io 14 | http://spring.io/ 15 | 16 | 17 | 18 | The Apache Software License, Version 2.0 19 | http://www.apache.org/licenses/LICENSE-2.0.txt 20 | repo 21 | 22 | 23 | 24 | 25 | rwinch 26 | Rob Winch 27 | rwinch@gopivotal.com 28 | 29 | 30 | 31 | scm:git:git://github.com/spring-projects/spring-security 32 | scm:git:git://github.com/spring-projects/spring-security 33 | https://github.com/spring-projects/spring-security 34 | 35 | 36 | 37 | 38 | maven-compiler-plugin 39 | 40 | 1.7 41 | 1.7 42 | 43 | 44 | 45 | maven-war-plugin 46 | 47 | false 48 | 49 | 50 | 51 | org.apache.tomcat.maven 52 | tomcat7-maven-plugin 53 | 2.2 54 | 55 | 56 | 57 | 58 | 59 | spring-snasphot 60 | https://repo.spring.io/libs-snapshot 61 | 62 | 63 | 64 | 65 | org.springframework.security 66 | spring-security-core 67 | 4.0.0.M1 68 | compile 69 | 70 | 71 | org.springframework.security 72 | spring-security-web 73 | 4.0.0.M1 74 | compile 75 | 76 | 77 | org.springframework.security 78 | spring-security-config 79 | 4.0.0.M1 80 | 81 | 82 | commons-logging 83 | commons-logging 84 | 1.1.3 85 | 86 | 87 | 88 | org.springframework 89 | spring-webmvc 90 | 4.0.2.RELEASE 91 | 92 | 93 | 94 | javax.servlet 95 | javax.servlet-api 96 | 3.0.1 97 | provided 98 | 99 | 100 | junit 101 | junit 102 | 4.11 103 | test 104 | 105 | 106 | org.easytesting 107 | fest-assert 108 | 1.4 109 | test 110 | 111 | 112 | org.springframework.security 113 | spring-security-test 114 | 4.0.0.M1 115 | 116 | 117 | org.springframework 118 | spring-test 119 | 4.0.2.RELEASE 120 | test 121 | 122 | 123 | 124 | org.spockframework 125 | spock-spring 126 | 0.7-groovy-2.0 127 | test 128 | 129 | 130 | org.springframework.security 131 | spring-security-web 132 | 4.0.0.M1 133 | compile 134 | 135 | 136 | org.seleniumhq.selenium 137 | selenium-htmlunit-driver 138 | 2.40.0 139 | test 140 | 141 | 142 | org.mockito 143 | mockito-all 144 | 1.9.5 145 | test 146 | 147 | 148 | org.springframework 149 | spring-context 150 | 4.0.2.RELEASE 151 | compile 152 | 153 | 154 | javax.validation 155 | validation-api 156 | 1.0.0.GA 157 | compile 158 | 159 | 160 | org.thymeleaf 161 | thymeleaf 162 | 2.1.2.RELEASE 163 | compile 164 | 165 | 166 | javax.servlet 167 | javax.servlet-api 168 | 3.0.1 169 | provided 170 | 171 | 172 | org.aspectj 173 | aspectjrt 174 | 1.6.10 175 | compile 176 | 177 | 178 | org.slf4j 179 | slf4j-log4j12 180 | 1.7.6 181 | compile 182 | 183 | 184 | org.springframework 185 | spring-test-mvc-htmlunit 186 | 1.0.0.BUILD-SNAPSHOT 187 | test 188 | 189 | 190 | org.thymeleaf 191 | thymeleaf-spring4 192 | 2.1.2.RELEASE 193 | compile 194 | 195 | 196 | org.hibernate 197 | hibernate-validator 198 | 4.1.0.Final 199 | compile 200 | 201 | 202 | org.gebish 203 | geb-spock 204 | 0.9.2 205 | test 206 | 207 | 208 | junit 209 | junit 210 | 4.8.2 211 | test 212 | 213 | 214 | org.easytesting 215 | fest-assert 216 | 1.4 217 | test 218 | 219 | 220 | org.springframework 221 | spring-webmvc 222 | 4.0.2.RELEASE 223 | compile 224 | 225 | 226 | org.springframework 227 | spring-tx 228 | 4.0.2.RELEASE 229 | compile 230 | 231 | 232 | org.springframework.data 233 | spring-data-jpa 234 | 1.5.1.RELEASE 235 | compile 236 | 237 | 238 | org.springframework.security 239 | spring-security-config 240 | 4.0.0.M1 241 | compile 242 | 243 | 244 | org.hibernate 245 | hibernate-entitymanager 246 | 4.3.4.Final 247 | compile 248 | 249 | 250 | org.spockframework 251 | spock-core 252 | 0.7-groovy-2.0 253 | test 254 | 255 | 256 | org.hsqldb 257 | hsqldb 258 | 2.3.2 259 | compile 260 | 261 | 262 | xml-apis 263 | xml-apis 264 | 1.4.01 265 | 266 | 267 | org.springframework.security 268 | spring-security-test 269 | 4.0.0.M1 270 | test 271 | 272 | 273 | org.hibernate.javax.persistence 274 | hibernate-jpa-2.0-api 275 | 1.0.1.Final 276 | compile 277 | 278 | 279 | org.codehaus.groovy 280 | groovy 281 | 2.2.2 282 | test 283 | 284 | 285 | org.easytesting 286 | fest-assert-core 287 | 2.0M10 288 | test 289 | 290 | 291 | org.seleniumhq.selenium 292 | selenium-support 293 | 2.40.0 294 | test 295 | 296 | 297 | org.springframework 298 | spring-test 299 | 4.0.2.RELEASE 300 | test 301 | 302 | 303 | 304 | -------------------------------------------------------------------------------- /src/main/java/sample/config/DataConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import javax.sql.DataSource; 19 | 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.context.annotation.DependsOn; 23 | import org.springframework.core.io.ClassPathResource; 24 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 25 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 26 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 27 | import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; 28 | import org.springframework.orm.jpa.JpaTransactionManager; 29 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 30 | import org.springframework.orm.jpa.vendor.Database; 31 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 32 | import sample.data.Message; 33 | import org.springframework.transaction.PlatformTransactionManager; 34 | import sample.data.MessageRepository; 35 | 36 | 37 | @Configuration 38 | @EnableJpaRepositories(basePackageClasses = MessageRepository.class) 39 | public class DataConfig { 40 | 41 | @Bean 42 | public DataSource dataSource() { 43 | EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); 44 | return builder.setType(EmbeddedDatabaseType.HSQL).build(); 45 | } 46 | 47 | @Bean 48 | public LocalContainerEntityManagerFactoryBean entityManagerFactory() { 49 | HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 50 | vendorAdapter.setDatabase(Database.HSQL); 51 | vendorAdapter.setGenerateDdl(true); 52 | 53 | LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); 54 | factory.setJpaVendorAdapter(vendorAdapter); 55 | factory.setPackagesToScan(Message.class.getPackage().getName()); 56 | factory.setDataSource(dataSource()); 57 | 58 | return factory; 59 | } 60 | 61 | @Bean 62 | public PlatformTransactionManager transactionManager() { 63 | JpaTransactionManager txManager = new JpaTransactionManager(); 64 | txManager.setEntityManagerFactory(entityManagerFactory().getObject()); 65 | return txManager; 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/sample/config/WebMvcAppInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 19 | 20 | /** 21 | * @author Rob Winch 22 | */ 23 | public class WebMvcAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 24 | @Override 25 | protected Class[] getRootConfigClasses() { 26 | return null; 27 | } 28 | 29 | @Override 30 | protected Class[] getServletConfigClasses() { 31 | return new Class[] { DataConfig.class, WebMvcConfig.class}; 32 | } 33 | 34 | @Override 35 | protected String[] getServletMappings() { 36 | return new String[] { "/"}; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/sample/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.ComponentScan; 21 | import org.springframework.core.Ordered; 22 | import org.springframework.data.repository.support.DomainClassConverter; 23 | import org.springframework.format.support.FormattingConversionService; 24 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 25 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 26 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 27 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 28 | import org.thymeleaf.spring4.SpringTemplateEngine; 29 | import org.thymeleaf.spring4.view.ThymeleafViewResolver; 30 | import org.thymeleaf.templateresolver.ServletContextTemplateResolver; 31 | import org.thymeleaf.templateresolver.TemplateResolver; 32 | import sample.mvc.MessageController; 33 | 34 | @EnableWebMvc 35 | @ComponentScan(basePackageClasses = MessageController.class) 36 | public class WebMvcConfig extends WebMvcConfigurerAdapter { 37 | 38 | @Autowired 39 | private FormattingConversionService mvcConversionService; 40 | 41 | @Override 42 | public void addViewControllers(ViewControllerRegistry registry) { 43 | registry.addViewController("/login").setViewName("login"); 44 | registry.setOrder(Ordered.HIGHEST_PRECEDENCE); 45 | } 46 | 47 | @Override 48 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 49 | registry 50 | .addResourceHandler("/resources/**") 51 | .addResourceLocations("/resources/") 52 | .setCachePeriod(31556926); 53 | registry.setOrder(Ordered.HIGHEST_PRECEDENCE); 54 | } 55 | 56 | @Bean 57 | public TemplateResolver templateResolver() { 58 | TemplateResolver result = new ServletContextTemplateResolver(); 59 | result.setPrefix("/WEB-INF/templates/"); 60 | result.setSuffix(".html"); 61 | result.setTemplateMode("HTML5"); 62 | return result; 63 | } 64 | 65 | @Bean 66 | public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) { 67 | SpringTemplateEngine templateEngine = new SpringTemplateEngine(); 68 | templateEngine.setTemplateResolver(templateResolver); 69 | return templateEngine; 70 | } 71 | 72 | @Bean 73 | public ThymeleafViewResolver viewResolver(SpringTemplateEngine templateEngine) { 74 | ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); 75 | viewResolver.setTemplateEngine(templateEngine); 76 | return viewResolver; 77 | } 78 | 79 | @Bean 80 | public DomainClassConverter domainClassConverter() { 81 | return new DomainClassConverter(mvcConversionService); 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/java/sample/config/WebSecurityAppInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; 19 | 20 | /** 21 | * @author Rob Winch 22 | */ 23 | public class WebSecurityAppInitializer extends AbstractSecurityWebApplicationInitializer { 24 | public WebSecurityAppInitializer() { 25 | super(WebSecurityConfig.class); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/sample/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.context.annotation.Configuration; 20 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 21 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 22 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 23 | 24 | /** 25 | * @author Rob Winch 26 | */ 27 | @EnableWebMvcSecurity 28 | @Configuration 29 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 30 | @Autowired 31 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 32 | auth 33 | .inMemoryAuthentication() 34 | .withUser("user").password("password").roles("USER"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/sample/data/Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.data; 14 | 15 | import java.util.Calendar; 16 | 17 | import javax.persistence.Entity; 18 | import javax.persistence.GeneratedValue; 19 | import javax.persistence.GenerationType; 20 | import javax.persistence.Id; 21 | import javax.persistence.Version; 22 | 23 | import org.hibernate.validator.constraints.NotEmpty; 24 | 25 | /** 26 | * 27 | * @author Rob Winch 28 | * 29 | */ 30 | @Entity 31 | public class Message { 32 | @Id 33 | @GeneratedValue(strategy = GenerationType.AUTO) 34 | private Long id; 35 | 36 | @NotEmpty(message = "Message is required.") 37 | private String text; 38 | 39 | @NotEmpty(message = "Summary is required.") 40 | private String summary; 41 | 42 | @Version 43 | private Calendar created = Calendar.getInstance(); 44 | 45 | public Long getId() { 46 | return id; 47 | } 48 | 49 | public void setId(Long id) { 50 | this.id = id; 51 | } 52 | 53 | public Calendar getCreated() { 54 | return created; 55 | } 56 | 57 | public void setCreated(Calendar created) { 58 | this.created = created; 59 | } 60 | 61 | public String getText() { 62 | return text; 63 | } 64 | 65 | public void setText(String text) { 66 | this.text = text; 67 | } 68 | 69 | public String getSummary() { 70 | return summary; 71 | } 72 | 73 | public void setSummary(String summary) { 74 | this.summary = summary; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/sample/data/MessageRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.data; 14 | 15 | import org.springframework.data.repository.CrudRepository; 16 | 17 | /** 18 | * 19 | * @author Rob Winch 20 | * 21 | */ 22 | public interface MessageRepository extends CrudRepository { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/sample/mvc/MessageController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.mvc; 14 | 15 | import javax.validation.Valid; 16 | 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.stereotype.Controller; 19 | import sample.data.Message; 20 | import sample.data.MessageRepository; 21 | import org.springframework.validation.BindingResult; 22 | import org.springframework.web.bind.annotation.ModelAttribute; 23 | import org.springframework.web.bind.annotation.PathVariable; 24 | import org.springframework.web.bind.annotation.RequestMapping; 25 | import org.springframework.web.bind.annotation.RequestMethod; 26 | import org.springframework.web.servlet.ModelAndView; 27 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 28 | 29 | /** 30 | * 31 | * @author Rob Winch 32 | * 33 | */ 34 | @Controller 35 | @RequestMapping("/messages/") 36 | public class MessageController { 37 | private MessageRepository messageRepository; 38 | 39 | @Autowired 40 | public MessageController(MessageRepository messageRepository) { 41 | this.messageRepository = messageRepository; 42 | } 43 | 44 | @RequestMapping 45 | public ModelAndView list() { 46 | Iterable messages = messageRepository.findAll(); 47 | return new ModelAndView("messages/list", "messages", messages); 48 | } 49 | 50 | @RequestMapping("{id}") 51 | public ModelAndView view(@PathVariable("id") 52 | Message message) { 53 | return new ModelAndView("messages/view", "message", message); 54 | } 55 | 56 | @RequestMapping(value = "form", method = RequestMethod.GET) 57 | public String createForm(@ModelAttribute 58 | Message message) { 59 | return "messages/form"; 60 | } 61 | 62 | @RequestMapping(method = RequestMethod.POST) 63 | public ModelAndView create(@Valid 64 | Message message, BindingResult result, RedirectAttributes redirect) { 65 | if (result.hasErrors()) { 66 | return new ModelAndView("messages/form"); 67 | } 68 | message = messageRepository.save(message); 69 | redirect.addFlashAttribute("globalMessage", "Successfully created a new message"); 70 | return new ModelAndView("redirect:/messages/{message.id}", "message.id", message.getId()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/messages/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Messages : Create 5 | 6 | 7 | 8 |
9 |

Messages : Create

10 |
11 |
12 |

Validation error

13 |
14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 | 26 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/messages/list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Messages : View all 6 | 7 | 8 | 9 |
10 |

Messages : View all

11 |
12 | Create Message 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
IDCreatedSummary
No messages
1July 11, 2012 2:17:16 PM CDTThe summary
33 |
34 | 35 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/templates/messages/view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Messages : View 6 | 7 | 8 | 9 |
10 |

Messages : View

11 |
Some Success message
12 | 13 |
14 |
ID
15 |
123
16 |
Date
17 |
July 11, 2012 2:17:16 PM CDT
18 |
Summary
19 |
A short summary...
20 |
Message
21 |
A detailed message that is longer than the summary.
22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | -------------------------------------------------------------------------------- /src/main/webapp/resources/js/jquery.validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jQuery Validation Plugin @VERSION 3 | * 4 | * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ 5 | * http://docs.jquery.com/Plugins/Validation 6 | * 7 | * Copyright (c) 2012 Jörn Zaefferer 8 | * 9 | * Dual licensed under the MIT and GPL licenses: 10 | * http://www.opensource.org/licenses/mit-license.php 11 | * http://www.gnu.org/licenses/gpl.html 12 | */ 13 | 14 | (function($) { 15 | 16 | $.extend($.fn, { 17 | // http://docs.jquery.com/Plugins/Validation/validate 18 | validate: function( options ) { 19 | 20 | // if nothing is selected, return nothing; can't chain anyway 21 | if (!this.length) { 22 | if (options && options.debug && window.console) { 23 | console.warn( "nothing selected, can't validate, returning nothing" ); 24 | } 25 | return; 26 | } 27 | 28 | // check if a validator for this form was already created 29 | var validator = $.data(this[0], 'validator'); 30 | if ( validator ) { 31 | return validator; 32 | } 33 | 34 | // Add novalidate tag if HTML5. 35 | this.attr('novalidate', 'novalidate'); 36 | 37 | validator = new $.validator( options, this[0] ); 38 | $.data(this[0], 'validator', validator); 39 | 40 | if ( validator.settings.onsubmit ) { 41 | 42 | this.validateDelegate( ":submit", "click", function(ev) { 43 | if ( validator.settings.submitHandler ) { 44 | validator.submitButton = ev.target; 45 | } 46 | // allow suppressing validation by adding a cancel class to the submit button 47 | if ( $(ev.target).hasClass('cancel') ) { 48 | validator.cancelSubmit = true; 49 | } 50 | }); 51 | 52 | // validate the form on submit 53 | this.submit( function( event ) { 54 | if ( validator.settings.debug ) { 55 | // prevent form submit to be able to see console output 56 | event.preventDefault(); 57 | } 58 | function handle() { 59 | var hidden; 60 | if ( validator.settings.submitHandler ) { 61 | if (validator.submitButton) { 62 | // insert a hidden input as a replacement for the missing submit button 63 | hidden = $("").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm); 64 | } 65 | validator.settings.submitHandler.call( validator, validator.currentForm, event ); 66 | if (validator.submitButton) { 67 | // and clean up afterwards; thanks to no-block-scope, hidden can be referenced 68 | hidden.remove(); 69 | } 70 | return false; 71 | } 72 | return true; 73 | } 74 | 75 | // prevent submit for invalid forms or custom submit handlers 76 | if ( validator.cancelSubmit ) { 77 | validator.cancelSubmit = false; 78 | return handle(); 79 | } 80 | if ( validator.form() ) { 81 | if ( validator.pendingRequest ) { 82 | validator.formSubmitted = true; 83 | return false; 84 | } 85 | return handle(); 86 | } else { 87 | validator.focusInvalid(); 88 | return false; 89 | } 90 | }); 91 | } 92 | 93 | return validator; 94 | }, 95 | // http://docs.jquery.com/Plugins/Validation/valid 96 | valid: function() { 97 | if ( $(this[0]).is('form')) { 98 | return this.validate().form(); 99 | } else { 100 | var valid = true; 101 | var validator = $(this[0].form).validate(); 102 | this.each(function() { 103 | valid &= validator.element(this); 104 | }); 105 | return valid; 106 | } 107 | }, 108 | // attributes: space seperated list of attributes to retrieve and remove 109 | removeAttrs: function(attributes) { 110 | var result = {}, 111 | $element = this; 112 | $.each(attributes.split(/\s/), function(index, value) { 113 | result[value] = $element.attr(value); 114 | $element.removeAttr(value); 115 | }); 116 | return result; 117 | }, 118 | // http://docs.jquery.com/Plugins/Validation/rules 119 | rules: function(command, argument) { 120 | var element = this[0]; 121 | 122 | if (command) { 123 | var settings = $.data(element.form, 'validator').settings; 124 | var staticRules = settings.rules; 125 | var existingRules = $.validator.staticRules(element); 126 | switch(command) { 127 | case "add": 128 | $.extend(existingRules, $.validator.normalizeRule(argument)); 129 | staticRules[element.name] = existingRules; 130 | if (argument.messages) { 131 | settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages ); 132 | } 133 | break; 134 | case "remove": 135 | if (!argument) { 136 | delete staticRules[element.name]; 137 | return existingRules; 138 | } 139 | var filtered = {}; 140 | $.each(argument.split(/\s/), function(index, method) { 141 | filtered[method] = existingRules[method]; 142 | delete existingRules[method]; 143 | }); 144 | return filtered; 145 | } 146 | } 147 | 148 | var data = $.validator.normalizeRules( 149 | $.extend( 150 | {}, 151 | $.validator.metadataRules(element), 152 | $.validator.classRules(element), 153 | $.validator.attributeRules(element), 154 | $.validator.staticRules(element) 155 | ), element); 156 | 157 | // make sure required is at front 158 | if (data.required) { 159 | var param = data.required; 160 | delete data.required; 161 | data = $.extend({required: param}, data); 162 | } 163 | 164 | return data; 165 | } 166 | }); 167 | 168 | // Custom selectors 169 | $.extend($.expr[":"], { 170 | // http://docs.jquery.com/Plugins/Validation/blank 171 | blank: function(a) {return !$.trim("" + a.value);}, 172 | // http://docs.jquery.com/Plugins/Validation/filled 173 | filled: function(a) {return !!$.trim("" + a.value);}, 174 | // http://docs.jquery.com/Plugins/Validation/unchecked 175 | unchecked: function(a) {return !a.checked;} 176 | }); 177 | 178 | // constructor for validator 179 | $.validator = function( options, form ) { 180 | this.settings = $.extend( true, {}, $.validator.defaults, options ); 181 | this.currentForm = form; 182 | this.init(); 183 | }; 184 | 185 | $.validator.format = function(source, params) { 186 | if ( arguments.length === 1 ) { 187 | return function() { 188 | var args = $.makeArray(arguments); 189 | args.unshift(source); 190 | return $.validator.format.apply( this, args ); 191 | }; 192 | } 193 | if ( arguments.length > 2 && params.constructor !== Array ) { 194 | params = $.makeArray(arguments).slice(1); 195 | } 196 | if ( params.constructor !== Array ) { 197 | params = [ params ]; 198 | } 199 | $.each(params, function(i, n) { 200 | source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); 201 | }); 202 | return source; 203 | }; 204 | 205 | $.extend($.validator, { 206 | 207 | defaults: { 208 | messages: {}, 209 | groups: {}, 210 | rules: {}, 211 | errorClass: "error", 212 | validClass: "valid", 213 | errorElement: "label", 214 | focusInvalid: true, 215 | errorContainer: $( [] ), 216 | errorLabelContainer: $( [] ), 217 | onsubmit: true, 218 | ignore: ":hidden", 219 | ignoreTitle: false, 220 | onfocusin: function(element, event) { 221 | this.lastActive = element; 222 | 223 | // hide error label and remove error class on focus if enabled 224 | if ( this.settings.focusCleanup && !this.blockFocusCleanup ) { 225 | if ( this.settings.unhighlight ) { 226 | this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); 227 | } 228 | this.addWrapper(this.errorsFor(element)).hide(); 229 | } 230 | }, 231 | onfocusout: function(element, event) { 232 | if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) { 233 | this.element(element); 234 | } 235 | }, 236 | onkeyup: function(element, event) { 237 | if ( element.name in this.submitted || element === this.lastElement ) { 238 | this.element(element); 239 | } 240 | }, 241 | onclick: function(element, event) { 242 | // click on selects, radiobuttons and checkboxes 243 | if ( element.name in this.submitted ) { 244 | this.element(element); 245 | } 246 | // or option elements, check parent select in that case 247 | else if (element.parentNode.name in this.submitted) { 248 | this.element(element.parentNode); 249 | } 250 | }, 251 | highlight: function(element, errorClass, validClass) { 252 | if (element.type === 'radio') { 253 | this.findByName(element.name).addClass(errorClass).removeClass(validClass); 254 | } else { 255 | $(element).addClass(errorClass).removeClass(validClass); 256 | } 257 | }, 258 | unhighlight: function(element, errorClass, validClass) { 259 | if (element.type === 'radio') { 260 | this.findByName(element.name).removeClass(errorClass).addClass(validClass); 261 | } else { 262 | $(element).removeClass(errorClass).addClass(validClass); 263 | } 264 | } 265 | }, 266 | 267 | // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults 268 | setDefaults: function(settings) { 269 | $.extend( $.validator.defaults, settings ); 270 | }, 271 | 272 | messages: { 273 | required: "This field is required.", 274 | remote: "Please fix this field.", 275 | email: "Please enter a valid email address.", 276 | url: "Please enter a valid URL.", 277 | date: "Please enter a valid date.", 278 | dateISO: "Please enter a valid date (ISO).", 279 | number: "Please enter a valid number.", 280 | digits: "Please enter only digits.", 281 | creditcard: "Please enter a valid credit card number.", 282 | equalTo: "Please enter the same value again.", 283 | accept: "Please enter a value with a valid extension.", 284 | maxlength: $.validator.format("Please enter no more than {0} characters."), 285 | minlength: $.validator.format("Please enter at least {0} characters."), 286 | rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."), 287 | range: $.validator.format("Please enter a value between {0} and {1}."), 288 | max: $.validator.format("Please enter a value less than or equal to {0}."), 289 | min: $.validator.format("Please enter a value greater than or equal to {0}.") 290 | }, 291 | 292 | autoCreateRanges: false, 293 | 294 | prototype: { 295 | 296 | init: function() { 297 | this.labelContainer = $(this.settings.errorLabelContainer); 298 | this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm); 299 | this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer ); 300 | this.submitted = {}; 301 | this.valueCache = {}; 302 | this.pendingRequest = 0; 303 | this.pending = {}; 304 | this.invalid = {}; 305 | this.reset(); 306 | 307 | var groups = (this.groups = {}); 308 | $.each(this.settings.groups, function(key, value) { 309 | $.each(value.split(/\s/), function(index, name) { 310 | groups[name] = key; 311 | }); 312 | }); 313 | var rules = this.settings.rules; 314 | $.each(rules, function(key, value) { 315 | rules[key] = $.validator.normalizeRule(value); 316 | }); 317 | 318 | function delegate(event) { 319 | var validator = $.data(this[0].form, "validator"), 320 | eventType = "on" + event.type.replace(/^validate/, ""); 321 | if (validator.settings[eventType]) { 322 | validator.settings[eventType].call(validator, this[0], event); 323 | } 324 | } 325 | $(this.currentForm) 326 | .validateDelegate("[type='text'], [type='password'], [type='file'], select, textarea, " + 327 | "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + 328 | "[type='email'], [type='datetime'], [type='date'], [type='month'], " + 329 | "[type='week'], [type='time'], [type='datetime-local'], " + 330 | "[type='range'], [type='color'] ", 331 | "focusin focusout keyup", delegate) 332 | .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate); 333 | 334 | if (this.settings.invalidHandler) { 335 | $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler); 336 | } 337 | }, 338 | 339 | // http://docs.jquery.com/Plugins/Validation/Validator/form 340 | form: function() { 341 | this.checkForm(); 342 | $.extend(this.submitted, this.errorMap); 343 | this.invalid = $.extend({}, this.errorMap); 344 | if (!this.valid()) { 345 | $(this.currentForm).triggerHandler("invalid-form", [this]); 346 | } 347 | this.showErrors(); 348 | return this.valid(); 349 | }, 350 | 351 | checkForm: function() { 352 | this.prepareForm(); 353 | for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) { 354 | this.check( elements[i] ); 355 | } 356 | return this.valid(); 357 | }, 358 | 359 | // http://docs.jquery.com/Plugins/Validation/Validator/element 360 | element: function( element ) { 361 | element = this.validationTargetFor( this.clean( element ) ); 362 | this.lastElement = element; 363 | this.prepareElement( element ); 364 | this.currentElements = $(element); 365 | var result = this.check( element ) !== false; 366 | if (result) { 367 | delete this.invalid[element.name]; 368 | } else { 369 | this.invalid[element.name] = true; 370 | } 371 | if ( !this.numberOfInvalids() ) { 372 | // Hide error containers on last error 373 | this.toHide = this.toHide.add( this.containers ); 374 | } 375 | this.showErrors(); 376 | return result; 377 | }, 378 | 379 | // http://docs.jquery.com/Plugins/Validation/Validator/showErrors 380 | showErrors: function(errors) { 381 | if(errors) { 382 | // add items to error list and map 383 | $.extend( this.errorMap, errors ); 384 | this.errorList = []; 385 | for ( var name in errors ) { 386 | this.errorList.push({ 387 | message: errors[name], 388 | element: this.findByName(name)[0] 389 | }); 390 | } 391 | // remove items from success list 392 | this.successList = $.grep( this.successList, function(element) { 393 | return !(element.name in errors); 394 | }); 395 | } 396 | if (this.settings.showErrors) { 397 | this.settings.showErrors.call( this, this.errorMap, this.errorList ); 398 | } else { 399 | this.defaultShowErrors(); 400 | } 401 | }, 402 | 403 | // http://docs.jquery.com/Plugins/Validation/Validator/resetForm 404 | resetForm: function() { 405 | if ( $.fn.resetForm ) { 406 | $( this.currentForm ).resetForm(); 407 | } 408 | this.submitted = {}; 409 | this.lastElement = null; 410 | this.prepareForm(); 411 | this.hideErrors(); 412 | this.elements().removeClass( this.settings.errorClass ); 413 | }, 414 | 415 | numberOfInvalids: function() { 416 | return this.objectLength(this.invalid); 417 | }, 418 | 419 | objectLength: function( obj ) { 420 | var count = 0; 421 | for ( var i in obj ) { 422 | count++; 423 | } 424 | return count; 425 | }, 426 | 427 | hideErrors: function() { 428 | this.addWrapper( this.toHide ).hide(); 429 | }, 430 | 431 | valid: function() { 432 | return this.size() === 0; 433 | }, 434 | 435 | size: function() { 436 | return this.errorList.length; 437 | }, 438 | 439 | focusInvalid: function() { 440 | if( this.settings.focusInvalid ) { 441 | try { 442 | $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []) 443 | .filter(":visible") 444 | .focus() 445 | // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 446 | .trigger("focusin"); 447 | } catch(e) { 448 | // ignore IE throwing errors when focusing hidden elements 449 | } 450 | } 451 | }, 452 | 453 | findLastActive: function() { 454 | var lastActive = this.lastActive; 455 | return lastActive && $.grep(this.errorList, function(n) { 456 | return n.element.name === lastActive.name; 457 | }).length === 1 && lastActive; 458 | }, 459 | 460 | elements: function() { 461 | var validator = this, 462 | rulesCache = {}; 463 | 464 | // select all valid inputs inside the form (no submit or reset buttons) 465 | return $(this.currentForm) 466 | .find("input, select, textarea") 467 | .not(":submit, :reset, :image, [disabled]") 468 | .not( this.settings.ignore ) 469 | .filter(function() { 470 | if ( !this.name && validator.settings.debug && window.console ) { 471 | console.error( "%o has no name assigned", this); 472 | } 473 | 474 | // select only the first element for each name, and only those with rules specified 475 | if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) { 476 | return false; 477 | } 478 | 479 | rulesCache[this.name] = true; 480 | return true; 481 | }); 482 | }, 483 | 484 | clean: function( selector ) { 485 | return $( selector )[0]; 486 | }, 487 | 488 | errors: function() { 489 | var errorClass = this.settings.errorClass.replace(' ', '.'); 490 | return $( this.settings.errorElement + "." + errorClass, this.errorContext ); 491 | }, 492 | 493 | reset: function() { 494 | this.successList = []; 495 | this.errorList = []; 496 | this.errorMap = {}; 497 | this.toShow = $([]); 498 | this.toHide = $([]); 499 | this.currentElements = $([]); 500 | }, 501 | 502 | prepareForm: function() { 503 | this.reset(); 504 | this.toHide = this.errors().add( this.containers ); 505 | }, 506 | 507 | prepareElement: function( element ) { 508 | this.reset(); 509 | this.toHide = this.errorsFor(element); 510 | }, 511 | 512 | elementValue: function( element ) { 513 | var val = $(element).val(); 514 | if( typeof val === 'string' ) { 515 | return val.replace(/\r/g, ""); 516 | } 517 | return val; 518 | }, 519 | 520 | check: function( element ) { 521 | element = this.validationTargetFor( this.clean( element ) ); 522 | 523 | var rules = $(element).rules(); 524 | var dependencyMismatch = false; 525 | var val = this.elementValue(element); 526 | var result; 527 | 528 | for (var method in rules ) { 529 | var rule = { method: method, parameters: rules[method] }; 530 | try { 531 | 532 | result = $.validator.methods[method].call( this, val, element, rule.parameters ); 533 | 534 | // if a method indicates that the field is optional and therefore valid, 535 | // don't mark it as valid when there are no other rules 536 | if ( result === "dependency-mismatch" ) { 537 | dependencyMismatch = true; 538 | continue; 539 | } 540 | dependencyMismatch = false; 541 | 542 | if ( result === "pending" ) { 543 | this.toHide = this.toHide.not( this.errorsFor(element) ); 544 | return; 545 | } 546 | 547 | if( !result ) { 548 | this.formatAndAdd( element, rule ); 549 | return false; 550 | } 551 | } catch(e) { 552 | if ( this.settings.debug && window.console ) { 553 | console.log("exception occured when checking element " + element.id + ", check the '" + rule.method + "' method", e); 554 | } 555 | throw e; 556 | } 557 | } 558 | if (dependencyMismatch) { 559 | return; 560 | } 561 | if ( this.objectLength(rules) ) { 562 | this.successList.push(element); 563 | } 564 | return true; 565 | }, 566 | 567 | // return the custom message for the given element and validation method 568 | // specified in the element's "messages" metadata 569 | customMetaMessage: function(element, method) { 570 | if (!$.metadata) { 571 | return; 572 | } 573 | var meta = this.settings.meta ? $(element).metadata()[this.settings.meta] : $(element).metadata(); 574 | return meta && meta.messages && meta.messages[method]; 575 | }, 576 | 577 | // return the custom message for the given element name and validation method 578 | customMessage: function( name, method ) { 579 | var m = this.settings.messages[name]; 580 | return m && (m.constructor === String ? m : m[method]); 581 | }, 582 | 583 | // return the first defined argument, allowing empty strings 584 | findDefined: function() { 585 | for(var i = 0; i < arguments.length; i++) { 586 | if (arguments[i] !== undefined) { 587 | return arguments[i]; 588 | } 589 | } 590 | return undefined; 591 | }, 592 | 593 | defaultMessage: function( element, method) { 594 | return this.findDefined( 595 | this.customMessage( element.name, method ), 596 | this.customMetaMessage( element, method ), 597 | // title is never undefined, so handle empty string as undefined 598 | !this.settings.ignoreTitle && element.title || undefined, 599 | $.validator.messages[method], 600 | "Warning: No message defined for " + element.name + "" 601 | ); 602 | }, 603 | 604 | formatAndAdd: function( element, rule ) { 605 | var message = this.defaultMessage( element, rule.method ), 606 | theregex = /\$?\{(\d+)\}/g; 607 | if ( typeof message === "function" ) { 608 | message = message.call(this, rule.parameters, element); 609 | } else if (theregex.test(message)) { 610 | message = $.validator.format(message.replace(theregex, '{$1}'), rule.parameters); 611 | } 612 | this.errorList.push({ 613 | message: message, 614 | element: element 615 | }); 616 | 617 | this.errorMap[element.name] = message; 618 | this.submitted[element.name] = message; 619 | }, 620 | 621 | addWrapper: function(toToggle) { 622 | if ( this.settings.wrapper ) { 623 | toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 624 | } 625 | return toToggle; 626 | }, 627 | 628 | defaultShowErrors: function() { 629 | var i, elements; 630 | for ( i = 0; this.errorList[i]; i++ ) { 631 | var error = this.errorList[i]; 632 | if ( this.settings.highlight ) { 633 | this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); 634 | } 635 | this.showLabel( error.element, error.message ); 636 | } 637 | if( this.errorList.length ) { 638 | this.toShow = this.toShow.add( this.containers ); 639 | } 640 | if (this.settings.success) { 641 | for ( i = 0; this.successList[i]; i++ ) { 642 | this.showLabel( this.successList[i] ); 643 | } 644 | } 645 | if (this.settings.unhighlight) { 646 | for ( i = 0, elements = this.validElements(); elements[i]; i++ ) { 647 | this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass ); 648 | } 649 | } 650 | this.toHide = this.toHide.not( this.toShow ); 651 | this.hideErrors(); 652 | this.addWrapper( this.toShow ).show(); 653 | }, 654 | 655 | validElements: function() { 656 | return this.currentElements.not(this.invalidElements()); 657 | }, 658 | 659 | invalidElements: function() { 660 | return $(this.errorList).map(function() { 661 | return this.element; 662 | }); 663 | }, 664 | 665 | showLabel: function(element, message) { 666 | var label = this.errorsFor( element ); 667 | if ( label.length ) { 668 | // refresh error/success class 669 | label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 670 | 671 | // check if we have a generated label, replace the message then 672 | if ( label.attr("generated") ) { 673 | label.html(message); 674 | } 675 | } else { 676 | // create label 677 | label = $("<" + this.settings.errorElement + "/>") 678 | .attr({"for": this.idOrName(element), generated: true}) 679 | .addClass(this.settings.errorClass) 680 | .html(message || ""); 681 | if ( this.settings.wrapper ) { 682 | // make sure the element is visible, even in IE 683 | // actually showing the wrapped element is handled elsewhere 684 | label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent(); 685 | } 686 | if ( !this.labelContainer.append(label).length ) { 687 | if ( this.settings.errorPlacement ) { 688 | this.settings.errorPlacement(label, $(element) ); 689 | } else { 690 | label.insertAfter(element); 691 | } 692 | } 693 | } 694 | if ( !message && this.settings.success ) { 695 | label.text(""); 696 | if ( typeof this.settings.success === "string" ) { 697 | label.addClass( this.settings.success ); 698 | } else { 699 | this.settings.success( label ); 700 | } 701 | } 702 | this.toShow = this.toShow.add(label); 703 | }, 704 | 705 | errorsFor: function(element) { 706 | var name = this.idOrName(element); 707 | return this.errors().filter(function() { 708 | return $(this).attr('for') === name; 709 | }); 710 | }, 711 | 712 | idOrName: function(element) { 713 | return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name); 714 | }, 715 | 716 | validationTargetFor: function(element) { 717 | // if radio/checkbox, validate first element in group instead 718 | if (this.checkable(element)) { 719 | element = this.findByName( element.name ).not(this.settings.ignore)[0]; 720 | } 721 | return element; 722 | }, 723 | 724 | checkable: function( element ) { 725 | return (/radio|checkbox/i).test(element.type); 726 | }, 727 | 728 | findByName: function( name ) { 729 | // select by name and filter by form for performance over form.find("[name=...]") 730 | var form = this.currentForm; 731 | return $(document.getElementsByName(name)).map(function(index, element) { 732 | return element.form === form && element.name === name && element || null; 733 | }); 734 | }, 735 | 736 | getLength: function(value, element) { 737 | switch( element.nodeName.toLowerCase() ) { 738 | case 'select': 739 | return $("option:selected", element).length; 740 | case 'input': 741 | if( this.checkable( element) ) { 742 | return this.findByName(element.name).filter(':checked').length; 743 | } 744 | } 745 | return value.length; 746 | }, 747 | 748 | depend: function(param, element) { 749 | return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true; 750 | }, 751 | 752 | dependTypes: { 753 | "boolean": function(param, element) { 754 | return param; 755 | }, 756 | "string": function(param, element) { 757 | return !!$(param, element.form).length; 758 | }, 759 | "function": function(param, element) { 760 | return param(element); 761 | } 762 | }, 763 | 764 | optional: function(element) { 765 | var val = this.elementValue(element); 766 | return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch"; 767 | }, 768 | 769 | startRequest: function(element) { 770 | if (!this.pending[element.name]) { 771 | this.pendingRequest++; 772 | this.pending[element.name] = true; 773 | } 774 | }, 775 | 776 | stopRequest: function(element, valid) { 777 | this.pendingRequest--; 778 | // sometimes synchronization fails, make sure pendingRequest is never < 0 779 | if (this.pendingRequest < 0) { 780 | this.pendingRequest = 0; 781 | } 782 | delete this.pending[element.name]; 783 | if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 784 | $(this.currentForm).submit(); 785 | this.formSubmitted = false; 786 | } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) { 787 | $(this.currentForm).triggerHandler("invalid-form", [this]); 788 | this.formSubmitted = false; 789 | } 790 | }, 791 | 792 | previousValue: function(element) { 793 | return $.data(element, "previousValue") || $.data(element, "previousValue", { 794 | old: null, 795 | valid: true, 796 | message: this.defaultMessage( element, "remote" ) 797 | }); 798 | } 799 | 800 | }, 801 | 802 | classRuleSettings: { 803 | required: {required: true}, 804 | email: {email: true}, 805 | url: {url: true}, 806 | date: {date: true}, 807 | dateISO: {dateISO: true}, 808 | number: {number: true}, 809 | digits: {digits: true}, 810 | creditcard: {creditcard: true} 811 | }, 812 | 813 | addClassRules: function(className, rules) { 814 | if ( className.constructor === String ) { 815 | this.classRuleSettings[className] = rules; 816 | } else { 817 | $.extend(this.classRuleSettings, className); 818 | } 819 | }, 820 | 821 | classRules: function(element) { 822 | var rules = {}; 823 | var classes = $(element).attr('class'); 824 | if ( classes ) { 825 | $.each(classes.split(' '), function() { 826 | if (this in $.validator.classRuleSettings) { 827 | $.extend(rules, $.validator.classRuleSettings[this]); 828 | } 829 | }); 830 | } 831 | return rules; 832 | }, 833 | 834 | attributeRules: function(element) { 835 | var rules = {}; 836 | var $element = $(element); 837 | 838 | for (var method in $.validator.methods) { 839 | var value; 840 | 841 | // support for in both html5 and older browsers 842 | if (method === 'required') { 843 | value = $element.get(0).getAttribute(method); 844 | // Some browsers return an empty string for the required attribute 845 | // and non-HTML5 browsers might have required="" markup 846 | if (value === "") { 847 | value = true; 848 | } else if (value === "false") { 849 | value = false; 850 | } 851 | // force non-HTML5 browsers to return bool 852 | value = !!value; 853 | } else { 854 | value = $element.attr(method); 855 | } 856 | 857 | if (value) { 858 | rules[method] = value; 859 | } else if ($element[0].getAttribute("type") === method) { 860 | rules[method] = true; 861 | } 862 | } 863 | 864 | // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs 865 | if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) { 866 | delete rules.maxlength; 867 | } 868 | 869 | return rules; 870 | }, 871 | 872 | metadataRules: function(element) { 873 | if (!$.metadata) { 874 | return {}; 875 | } 876 | 877 | var meta = $.data(element.form, 'validator').settings.meta; 878 | return meta ? 879 | $(element).metadata()[meta] : 880 | $(element).metadata(); 881 | }, 882 | 883 | staticRules: function(element) { 884 | var rules = {}; 885 | var validator = $.data(element.form, 'validator'); 886 | if (validator.settings.rules) { 887 | rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {}; 888 | } 889 | return rules; 890 | }, 891 | 892 | normalizeRules: function(rules, element) { 893 | // handle dependency check 894 | $.each(rules, function(prop, val) { 895 | // ignore rule when param is explicitly false, eg. required:false 896 | if (val === false) { 897 | delete rules[prop]; 898 | return; 899 | } 900 | if (val.param || val.depends) { 901 | var keepRule = true; 902 | switch (typeof val.depends) { 903 | case "string": 904 | keepRule = !!$(val.depends, element.form).length; 905 | break; 906 | case "function": 907 | keepRule = val.depends.call(element, element); 908 | break; 909 | } 910 | if (keepRule) { 911 | rules[prop] = val.param !== undefined ? val.param : true; 912 | } else { 913 | delete rules[prop]; 914 | } 915 | } 916 | }); 917 | 918 | // evaluate parameters 919 | $.each(rules, function(rule, parameter) { 920 | rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter; 921 | }); 922 | 923 | // clean number parameters 924 | $.each(['minlength', 'maxlength', 'min', 'max'], function() { 925 | if (rules[this]) { 926 | rules[this] = Number(rules[this]); 927 | } 928 | }); 929 | $.each(['rangelength', 'range'], function() { 930 | if (rules[this]) { 931 | rules[this] = [Number(rules[this][0]), Number(rules[this][1])]; 932 | } 933 | }); 934 | 935 | if ($.validator.autoCreateRanges) { 936 | // auto-create ranges 937 | if (rules.min && rules.max) { 938 | rules.range = [rules.min, rules.max]; 939 | delete rules.min; 940 | delete rules.max; 941 | } 942 | if (rules.minlength && rules.maxlength) { 943 | rules.rangelength = [rules.minlength, rules.maxlength]; 944 | delete rules.minlength; 945 | delete rules.maxlength; 946 | } 947 | } 948 | 949 | // To support custom messages in metadata ignore rule methods titled "messages" 950 | if (rules.messages) { 951 | delete rules.messages; 952 | } 953 | 954 | return rules; 955 | }, 956 | 957 | // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 958 | normalizeRule: function(data) { 959 | if( typeof data === "string" ) { 960 | var transformed = {}; 961 | $.each(data.split(/\s/), function() { 962 | transformed[this] = true; 963 | }); 964 | data = transformed; 965 | } 966 | return data; 967 | }, 968 | 969 | // http://docs.jquery.com/Plugins/Validation/Validator/addMethod 970 | addMethod: function(name, method, message) { 971 | $.validator.methods[name] = method; 972 | $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name]; 973 | if (method.length < 3) { 974 | $.validator.addClassRules(name, $.validator.normalizeRule(name)); 975 | } 976 | }, 977 | 978 | methods: { 979 | 980 | // http://docs.jquery.com/Plugins/Validation/Methods/required 981 | required: function(value, element, param) { 982 | // check if dependency is met 983 | if ( !this.depend(param, element) ) { 984 | return "dependency-mismatch"; 985 | } 986 | if ( element.nodeName.toLowerCase() === "select" ) { 987 | // could be an array for select-multiple or a string, both are fine this way 988 | var val = $(element).val(); 989 | return val && val.length > 0; 990 | } 991 | if ( this.checkable(element) ) { 992 | return this.getLength(value, element) > 0; 993 | } 994 | return $.trim(value).length > 0; 995 | }, 996 | 997 | // http://docs.jquery.com/Plugins/Validation/Methods/remote 998 | remote: function(value, element, param) { 999 | if ( this.optional(element) ) { 1000 | return "dependency-mismatch"; 1001 | } 1002 | 1003 | var previous = this.previousValue(element); 1004 | if (!this.settings.messages[element.name] ) { 1005 | this.settings.messages[element.name] = {}; 1006 | } 1007 | previous.originalMessage = this.settings.messages[element.name].remote; 1008 | this.settings.messages[element.name].remote = previous.message; 1009 | 1010 | param = typeof param === "string" && {url:param} || param; 1011 | 1012 | if ( this.pending[element.name] ) { 1013 | return "pending"; 1014 | } 1015 | if ( previous.old === value ) { 1016 | return previous.valid; 1017 | } 1018 | 1019 | previous.old = value; 1020 | var validator = this; 1021 | this.startRequest(element); 1022 | var data = {}; 1023 | data[element.name] = value; 1024 | $.ajax($.extend(true, { 1025 | url: param, 1026 | mode: "abort", 1027 | port: "validate" + element.name, 1028 | dataType: "json", 1029 | data: data, 1030 | success: function(response) { 1031 | validator.settings.messages[element.name].remote = previous.originalMessage; 1032 | var valid = response === true; 1033 | if ( valid ) { 1034 | var submitted = validator.formSubmitted; 1035 | validator.prepareElement(element); 1036 | validator.formSubmitted = submitted; 1037 | validator.successList.push(element); 1038 | validator.showErrors(); 1039 | } else { 1040 | var errors = {}; 1041 | var message = response || validator.defaultMessage( element, "remote" ); 1042 | errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message; 1043 | validator.showErrors(errors); 1044 | } 1045 | previous.valid = valid; 1046 | validator.stopRequest(element, valid); 1047 | } 1048 | }, param)); 1049 | return "pending"; 1050 | }, 1051 | 1052 | // http://docs.jquery.com/Plugins/Validation/Methods/minlength 1053 | minlength: function(value, element, param) { 1054 | var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1055 | return this.optional(element) || length >= param; 1056 | }, 1057 | 1058 | // http://docs.jquery.com/Plugins/Validation/Methods/maxlength 1059 | maxlength: function(value, element, param) { 1060 | var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1061 | return this.optional(element) || length <= param; 1062 | }, 1063 | 1064 | // http://docs.jquery.com/Plugins/Validation/Methods/rangelength 1065 | rangelength: function(value, element, param) { 1066 | var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element); 1067 | return this.optional(element) || ( length >= param[0] && length <= param[1] ); 1068 | }, 1069 | 1070 | // http://docs.jquery.com/Plugins/Validation/Methods/min 1071 | min: function( value, element, param ) { 1072 | return this.optional(element) || value >= param; 1073 | }, 1074 | 1075 | // http://docs.jquery.com/Plugins/Validation/Methods/max 1076 | max: function( value, element, param ) { 1077 | return this.optional(element) || value <= param; 1078 | }, 1079 | 1080 | // http://docs.jquery.com/Plugins/Validation/Methods/range 1081 | range: function( value, element, param ) { 1082 | return this.optional(element) || ( value >= param[0] && value <= param[1] ); 1083 | }, 1084 | 1085 | // http://docs.jquery.com/Plugins/Validation/Methods/email 1086 | email: function(value, element) { 1087 | // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/ 1088 | return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value); 1089 | }, 1090 | 1091 | // http://docs.jquery.com/Plugins/Validation/Methods/url 1092 | url: function(value, element) { 1093 | // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 1094 | return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value); 1095 | }, 1096 | 1097 | // http://docs.jquery.com/Plugins/Validation/Methods/date 1098 | date: function(value, element) { 1099 | return this.optional(element) || !/Invalid|NaN/.test(new Date(value)); 1100 | }, 1101 | 1102 | // http://docs.jquery.com/Plugins/Validation/Methods/dateISO 1103 | dateISO: function(value, element) { 1104 | return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value); 1105 | }, 1106 | 1107 | // http://docs.jquery.com/Plugins/Validation/Methods/number 1108 | number: function(value, element) { 1109 | return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value); 1110 | }, 1111 | 1112 | // http://docs.jquery.com/Plugins/Validation/Methods/digits 1113 | digits: function(value, element) { 1114 | return this.optional(element) || /^\d+$/.test(value); 1115 | }, 1116 | 1117 | // http://docs.jquery.com/Plugins/Validation/Methods/creditcard 1118 | // based on http://en.wikipedia.org/wiki/Luhn 1119 | creditcard: function(value, element) { 1120 | if ( this.optional(element) ) { 1121 | return "dependency-mismatch"; 1122 | } 1123 | // accept only spaces, digits and dashes 1124 | if (/[^0-9 \-]+/.test(value)) { 1125 | return false; 1126 | } 1127 | var nCheck = 0, 1128 | nDigit = 0, 1129 | bEven = false; 1130 | 1131 | value = value.replace(/\D/g, ""); 1132 | 1133 | for (var n = value.length - 1; n >= 0; n--) { 1134 | var cDigit = value.charAt(n); 1135 | nDigit = parseInt(cDigit, 10); 1136 | if (bEven) { 1137 | if ((nDigit *= 2) > 9) { 1138 | nDigit -= 9; 1139 | } 1140 | } 1141 | nCheck += nDigit; 1142 | bEven = !bEven; 1143 | } 1144 | 1145 | return (nCheck % 10) === 0; 1146 | }, 1147 | 1148 | // http://docs.jquery.com/Plugins/Validation/Methods/accept 1149 | accept: function(value, element, param) { 1150 | param = typeof param === "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif"; 1151 | return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i")); 1152 | }, 1153 | 1154 | // http://docs.jquery.com/Plugins/Validation/Methods/equalTo 1155 | equalTo: function(value, element, param) { 1156 | // bind to the blur event of the target in order to revalidate whenever the target field is updated 1157 | // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 1158 | var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() { 1159 | $(element).valid(); 1160 | }); 1161 | return value === target.val(); 1162 | } 1163 | 1164 | } 1165 | 1166 | }); 1167 | 1168 | // deprecated, use $.validator.format instead 1169 | $.format = $.validator.format; 1170 | 1171 | }(jQuery)); 1172 | 1173 | // ajax mode: abort 1174 | // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 1175 | // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 1176 | (function($) { 1177 | var pendingRequests = {}; 1178 | // Use a prefilter if available (1.5+) 1179 | if ( $.ajaxPrefilter ) { 1180 | $.ajaxPrefilter(function(settings, _, xhr) { 1181 | var port = settings.port; 1182 | if (settings.mode === "abort") { 1183 | if ( pendingRequests[port] ) { 1184 | pendingRequests[port].abort(); 1185 | } 1186 | pendingRequests[port] = xhr; 1187 | } 1188 | }); 1189 | } else { 1190 | // Proxy ajax 1191 | var ajax = $.ajax; 1192 | $.ajax = function(settings) { 1193 | var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, 1194 | port = ( "port" in settings ? settings : $.ajaxSettings ).port; 1195 | if (mode === "abort") { 1196 | if ( pendingRequests[port] ) { 1197 | pendingRequests[port].abort(); 1198 | } 1199 | return (pendingRequests[port] = ajax.apply(this, arguments)); 1200 | } 1201 | return ajax.apply(this, arguments); 1202 | }; 1203 | } 1204 | }(jQuery)); 1205 | 1206 | // provides cross-browser focusin and focusout events 1207 | // IE has native support, in other browsers, use event caputuring (neither bubbles) 1208 | 1209 | // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation 1210 | // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 1211 | (function($) { 1212 | // only implement if not provided by jQuery core (since 1.4) 1213 | // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs 1214 | if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) { 1215 | $.each({ 1216 | focus: 'focusin', 1217 | blur: 'focusout' 1218 | }, function( original, fix ){ 1219 | $.event.special[fix] = { 1220 | setup:function() { 1221 | this.addEventListener( original, handler, true ); 1222 | }, 1223 | teardown:function() { 1224 | this.removeEventListener( original, handler, true ); 1225 | }, 1226 | handler: function(e) { 1227 | var args = arguments; 1228 | args[0] = $.event.fix(e); 1229 | args[0].type = fix; 1230 | return $.event.handle.apply(this, args); 1231 | } 1232 | }; 1233 | function handler(e) { 1234 | e = $.event.fix(e); 1235 | e.type = fix; 1236 | return $.event.handle.call(this, e); 1237 | } 1238 | }); 1239 | } 1240 | $.extend($.fn, { 1241 | validateDelegate: function(delegate, type, handler) { 1242 | return this.bind(type, function(event) { 1243 | var target = $(event.target); 1244 | if (target.is(delegate)) { 1245 | return handler.apply(target, arguments); 1246 | } 1247 | }); 1248 | } 1249 | }); 1250 | }(jQuery)); -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/CustomUserDetails.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 org.springframework.security.test.context.showcase; 17 | 18 | import org.springframework.security.core.GrantedAuthority; 19 | import org.springframework.security.core.authority.AuthorityUtils; 20 | import org.springframework.security.core.userdetails.UserDetails; 21 | 22 | import java.util.Collection; 23 | 24 | /** 25 | * @author Rob Winch 26 | */ 27 | public class CustomUserDetails implements UserDetails { 28 | private final String name; 29 | private final String username; 30 | private final Collection authorities; 31 | 32 | public CustomUserDetails(String name, String username) { 33 | this.name = name; 34 | this.username = username; 35 | this.authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); 36 | } 37 | 38 | @Override 39 | public Collection getAuthorities() { 40 | return authorities; 41 | } 42 | 43 | @Override 44 | public String getPassword() { 45 | return null; 46 | } 47 | 48 | @Override 49 | public String getUsername() { 50 | return username; 51 | } 52 | 53 | @Override 54 | public boolean isAccountNonExpired() { 55 | return true; 56 | } 57 | 58 | @Override 59 | public boolean isAccountNonLocked() { 60 | return true; 61 | } 62 | 63 | @Override 64 | public boolean isCredentialsNonExpired() { 65 | return true; 66 | } 67 | 68 | @Override 69 | public boolean isEnabled() { 70 | return true; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "CustomUserDetails{" + 76 | "username='" + username + '\'' + 77 | '}'; 78 | } 79 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/WithMockCustomUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.context.showcase; 17 | 18 | import org.springframework.security.test.context.support.WithSecurityContext; 19 | 20 | /** 21 | * @author Rob Winch 22 | */ 23 | @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class) 24 | public @interface WithMockCustomUser { 25 | /** 26 | * The username to be used. The default is rob 27 | * @return 28 | */ 29 | String username() default "rob"; 30 | 31 | /** 32 | * The roles to use. The default is "USER". A {@link org.springframework.security.core.GrantedAuthority} will 33 | * be created for each value within roles. Each value in roles will 34 | * automatically be prefixed with "ROLE_". For example, the default will 35 | * result in "ROLE_USER" being used. 36 | * 37 | * @return 38 | */ 39 | String[] roles() default { "USER" }; 40 | 41 | /** 42 | * The name of the user 43 | * @return 44 | */ 45 | String name() default "Rob Winch"; 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/WithMockCustomUserSecurityContextFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 org.springframework.security.test.context.showcase; 17 | 18 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 19 | import org.springframework.security.core.Authentication; 20 | import org.springframework.security.core.GrantedAuthority; 21 | import org.springframework.security.core.authority.AuthorityUtils; 22 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 23 | import org.springframework.security.core.context.SecurityContext; 24 | import org.springframework.security.core.context.SecurityContextHolder; 25 | import org.springframework.security.test.context.support.WithSecurityContextFactory; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | /** 31 | * @author Rob Winch 32 | */ 33 | public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory { 34 | @Override 35 | public SecurityContext createSecurityContext(WithMockCustomUser customUser) { 36 | SecurityContext context = SecurityContextHolder.createEmptyContext(); 37 | 38 | CustomUserDetails principal = new CustomUserDetails(customUser.name(), customUser.username()); 39 | Authentication auth = 40 | new UsernamePasswordAuthenticationToken(principal, "password", principal.getAuthorities()); 41 | context.setAuthentication(auth); 42 | return context; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/WithMockUserTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 org.springframework.security.test.context.showcase; 17 | 18 | import static org.fest.assertions.Assertions.assertThat; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.context.annotation.ComponentScan; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; 26 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 27 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 28 | import org.springframework.security.test.context.showcase.service.HelloMessageService; 29 | import org.springframework.security.test.context.showcase.service.MessageService; 30 | import org.springframework.security.test.context.support.WithMockUser; 31 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 32 | import org.springframework.test.context.ContextConfiguration; 33 | import org.springframework.test.context.TestExecutionListeners; 34 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 35 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 36 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 37 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 38 | import org.springframework.test.context.web.ServletTestExecutionListener; 39 | 40 | /** 41 | * @author Rob Winch 42 | */ 43 | 44 | @RunWith(SpringJUnit4ClassRunner.class) 45 | @ContextConfiguration 46 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 47 | DependencyInjectionTestExecutionListener.class, 48 | DirtiesContextTestExecutionListener.class, 49 | TransactionalTestExecutionListener.class, 50 | WithSecurityContextTestExcecutionListener.class}) 51 | public class WithMockUserTests { 52 | @Autowired 53 | private MessageService messageService; 54 | 55 | @Test(expected = AuthenticationCredentialsNotFoundException.class) 56 | public void getMessageUnauthenticated() { 57 | messageService.getMessage(); 58 | } 59 | 60 | @Test 61 | @WithMockUser 62 | public void getMessageWithMockUser() { 63 | String message = messageService.getMessage(); 64 | assertThat(message).contains("user"); 65 | } 66 | 67 | @Test 68 | @WithMockUser("customUsername") 69 | public void getMessageWithMockUserCustomUsername() { 70 | String message = messageService.getMessage(); 71 | assertThat(message).contains("customUsername"); 72 | } 73 | 74 | @Test 75 | @WithMockUser(username="admin",roles={"USER","ADMIN"}) 76 | public void getMessageWithMockUserCustomUser() { 77 | String message = messageService.getMessage(); 78 | assertThat(message).contains("admin").contains("ROLE_USER").contains("ROLE_ADMIN"); 79 | } 80 | 81 | @Configuration 82 | @EnableGlobalMethodSecurity(prePostEnabled = true) 83 | @ComponentScan(basePackageClasses = HelloMessageService.class) 84 | static class Config { 85 | @Autowired 86 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 87 | auth 88 | .inMemoryAuthentication() 89 | .withUser("user").password("password").roles("USER"); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/WithUserDetailsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 org.springframework.security.test.context.showcase; 17 | 18 | import static org.fest.assertions.Assertions.assertThat; 19 | 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.ComponentScan; 25 | import org.springframework.context.annotation.Configuration; 26 | import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; 27 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 28 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 29 | import org.springframework.security.core.context.SecurityContextHolder; 30 | import org.springframework.security.core.userdetails.UserDetails; 31 | import org.springframework.security.core.userdetails.UserDetailsService; 32 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 33 | import org.springframework.security.test.context.showcase.service.HelloMessageService; 34 | import org.springframework.security.test.context.showcase.service.MessageService; 35 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 36 | import org.springframework.security.test.context.support.WithUserDetails; 37 | import org.springframework.test.context.ContextConfiguration; 38 | import org.springframework.test.context.TestExecutionListeners; 39 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 40 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 41 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 42 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 43 | import org.springframework.test.context.web.ServletTestExecutionListener; 44 | 45 | /** 46 | * @author Rob Winch 47 | */ 48 | 49 | @RunWith(SpringJUnit4ClassRunner.class) 50 | @ContextConfiguration 51 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 52 | DependencyInjectionTestExecutionListener.class, 53 | DirtiesContextTestExecutionListener.class, 54 | TransactionalTestExecutionListener.class, 55 | WithSecurityContextTestExcecutionListener.class}) 56 | public class WithUserDetailsTests { 57 | @Autowired 58 | private MessageService messageService; 59 | 60 | @Test(expected = AuthenticationCredentialsNotFoundException.class) 61 | public void getMessageUnauthenticated() { 62 | messageService.getMessage(); 63 | } 64 | 65 | @Test 66 | @WithUserDetails 67 | public void getMessageWithUserDetails() { 68 | String message = messageService.getMessage(); 69 | assertThat(message).contains("user"); 70 | assertThat(getPrincipal()).isInstanceOf(CustomUserDetails.class); 71 | } 72 | 73 | @Test 74 | @WithUserDetails("customUsername") 75 | public void getMessageWithUserDetailsCustomUsername() { 76 | String message = messageService.getMessage(); 77 | assertThat(message).contains("customUsername"); 78 | assertThat(getPrincipal()).isInstanceOf(CustomUserDetails.class); 79 | } 80 | 81 | @Configuration 82 | @EnableGlobalMethodSecurity(prePostEnabled = true) 83 | @ComponentScan(basePackageClasses = HelloMessageService.class) 84 | static class Config { 85 | @Autowired 86 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 87 | auth 88 | .userDetailsService(userDetailsService()); 89 | } 90 | 91 | @Bean 92 | public UserDetailsService userDetailsService() { 93 | return new CustomUserDetailsService(); 94 | } 95 | } 96 | 97 | private Object getPrincipal() { 98 | return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 99 | } 100 | 101 | static class CustomUserDetailsService implements UserDetailsService { 102 | 103 | @Override 104 | public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { 105 | return new CustomUserDetails("name", username); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/service/HelloMessageService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 org.springframework.security.test.context.showcase.service; 17 | 18 | import org.springframework.security.access.prepost.PreAuthorize; 19 | import org.springframework.security.core.Authentication; 20 | import org.springframework.security.core.context.SecurityContextHolder; 21 | import org.springframework.stereotype.Component; 22 | 23 | /** 24 | * @author Rob Winch 25 | */ 26 | @Component 27 | public class HelloMessageService implements MessageService { 28 | 29 | @PreAuthorize("authenticated") 30 | public String getMessage() { 31 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 32 | return "Hello " + authentication; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/context/showcase/service/MessageService.java: -------------------------------------------------------------------------------- 1 | package org.springframework.security.test.context.showcase.service; 2 | 3 | import org.springframework.security.access.prepost.PreAuthorize; 4 | 5 | /** 6 | * @author Rob Winch 7 | */ 8 | public interface MessageService { 9 | String getMessage(); 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CsrfShowcaseTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.csrf; 17 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 20 | 21 | import javax.servlet.Filter; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.context.annotation.Configuration; 28 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 29 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 30 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 31 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 32 | import org.springframework.test.context.ContextConfiguration; 33 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 34 | import org.springframework.test.context.web.WebAppConfiguration; 35 | import org.springframework.test.web.servlet.MockMvc; 36 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 37 | import org.springframework.web.context.WebApplicationContext; 38 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 39 | 40 | @RunWith(SpringJUnit4ClassRunner.class) 41 | @ContextConfiguration 42 | @WebAppConfiguration 43 | public class CsrfShowcaseTests { 44 | 45 | @Autowired 46 | private WebApplicationContext context; 47 | 48 | @Autowired 49 | private Filter springSecurityFilterChain; 50 | 51 | private MockMvc mvc; 52 | 53 | @Before 54 | public void setup() { 55 | mvc = MockMvcBuilders 56 | .webAppContextSetup(context) 57 | .addFilters(springSecurityFilterChain) 58 | .build(); 59 | } 60 | 61 | @Test 62 | public void postWithCsrfWorks() throws Exception { 63 | mvc 64 | .perform(post("/").with(csrf())) 65 | .andExpect(status().isNotFound()); 66 | } 67 | 68 | @Test 69 | public void postWithCsrfWorksWithPut() throws Exception { 70 | mvc 71 | .perform(put("/").with(csrf())) 72 | .andExpect(status().isNotFound()); 73 | } 74 | 75 | @Test 76 | public void postWithNoCsrfForbidden() throws Exception { 77 | mvc 78 | .perform(post("/")) 79 | .andExpect(status().isForbidden()); 80 | } 81 | 82 | @Configuration 83 | @EnableWebMvcSecurity 84 | @EnableWebMvc 85 | static class Config extends WebSecurityConfigurerAdapter { 86 | 87 | @Override 88 | protected void configure(HttpSecurity http) throws Exception { 89 | } 90 | 91 | @Autowired 92 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 93 | auth 94 | .inMemoryAuthentication() 95 | .withUser("user").password("password").roles("USER"); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.csrf; 17 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 20 | 21 | import javax.servlet.Filter; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 30 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 31 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 32 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 33 | import org.springframework.security.web.csrf.CsrfTokenRepository; 34 | import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; 35 | import org.springframework.test.context.ContextConfiguration; 36 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 37 | import org.springframework.test.context.web.WebAppConfiguration; 38 | import org.springframework.test.web.servlet.MockMvc; 39 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 40 | import org.springframework.web.context.WebApplicationContext; 41 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 42 | 43 | @RunWith(SpringJUnit4ClassRunner.class) 44 | @ContextConfiguration 45 | @WebAppConfiguration 46 | public class CustomCsrfShowcaseTests { 47 | 48 | @Autowired 49 | private WebApplicationContext context; 50 | 51 | @Autowired 52 | private Filter springSecurityFilterChain; 53 | 54 | @Autowired 55 | private CsrfTokenRepository repository; 56 | 57 | private MockMvc mvc; 58 | 59 | @Before 60 | public void setup() { 61 | mvc = MockMvcBuilders 62 | .webAppContextSetup(context) 63 | .defaultRequest(get("/").with(csrf())) 64 | .addFilters(springSecurityFilterChain) 65 | .build(); 66 | } 67 | 68 | @Test 69 | public void postWithCsrfWorks() throws Exception { 70 | mvc 71 | .perform(post("/").with(csrf())) 72 | .andExpect(status().isNotFound()); 73 | } 74 | 75 | @Test 76 | public void postWithCsrfWorksWithPut() throws Exception { 77 | mvc 78 | .perform(put("/").with(csrf())) 79 | .andExpect(status().isNotFound()); 80 | } 81 | 82 | @Configuration 83 | @EnableWebMvcSecurity 84 | @EnableWebMvc 85 | static class Config extends WebSecurityConfigurerAdapter { 86 | 87 | @Override 88 | protected void configure(HttpSecurity http) throws Exception { 89 | http 90 | .csrf() 91 | .csrfTokenRepository(repo()); 92 | } 93 | 94 | @Autowired 95 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 96 | auth 97 | .inMemoryAuthentication() 98 | .withUser("user").password("password").roles("USER"); 99 | } 100 | 101 | @Bean 102 | public CsrfTokenRepository repo() { 103 | HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository(); 104 | repo.setParameterName("custom_csrf"); 105 | return repo; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/DefaultCsrfShowcaseTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.csrf; 17 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 18 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 20 | 21 | import javax.servlet.Filter; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.context.annotation.Configuration; 28 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 29 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 30 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 31 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 32 | import org.springframework.test.context.ContextConfiguration; 33 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 34 | import org.springframework.test.context.web.WebAppConfiguration; 35 | import org.springframework.test.web.servlet.MockMvc; 36 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 37 | import org.springframework.web.context.WebApplicationContext; 38 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 39 | 40 | @RunWith(SpringJUnit4ClassRunner.class) 41 | @ContextConfiguration 42 | @WebAppConfiguration 43 | public class DefaultCsrfShowcaseTests { 44 | 45 | @Autowired 46 | private WebApplicationContext context; 47 | 48 | @Autowired 49 | private Filter springSecurityFilterChain; 50 | 51 | private MockMvc mvc; 52 | 53 | @Before 54 | public void setup() { 55 | mvc = MockMvcBuilders 56 | .webAppContextSetup(context) 57 | .defaultRequest(get("/").with(csrf())) 58 | .addFilters(springSecurityFilterChain) 59 | .build(); 60 | } 61 | 62 | @Test 63 | public void postWithCsrfWorks() throws Exception { 64 | mvc 65 | .perform(post("/")) 66 | .andExpect(status().isNotFound()); 67 | } 68 | 69 | @Test 70 | public void postWithCsrfWorksWithPut() throws Exception { 71 | mvc 72 | .perform(put("/")) 73 | .andExpect(status().isNotFound()); 74 | } 75 | 76 | @Configuration 77 | @EnableWebMvcSecurity 78 | @EnableWebMvc 79 | static class Config extends WebSecurityConfigurerAdapter { 80 | 81 | @Override 82 | protected void configure(HttpSecurity http) throws Exception { 83 | } 84 | 85 | @Autowired 86 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 87 | auth 88 | .inMemoryAuthentication() 89 | .withUser("user").password("password").roles("USER"); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.login; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 22 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 23 | 24 | import javax.servlet.Filter; 25 | 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 32 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 33 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 34 | import org.springframework.test.context.ContextConfiguration; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | import org.springframework.test.context.web.WebAppConfiguration; 37 | import org.springframework.test.web.servlet.MockMvc; 38 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 39 | import org.springframework.web.context.WebApplicationContext; 40 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 41 | 42 | @RunWith(SpringJUnit4ClassRunner.class) 43 | @ContextConfiguration 44 | @WebAppConfiguration 45 | public class AuthenticationTests { 46 | 47 | @Autowired 48 | private WebApplicationContext context; 49 | 50 | @Autowired 51 | private Filter springSecurityFilterChain; 52 | 53 | private MockMvc mvc; 54 | 55 | @Before 56 | public void setup() { 57 | mvc = MockMvcBuilders 58 | .webAppContextSetup(context) 59 | .addFilters(springSecurityFilterChain) 60 | .build(); 61 | } 62 | 63 | @Test 64 | public void requiresAuthentication() throws Exception { 65 | mvc 66 | .perform(get("/")) 67 | .andExpect(status().isMovedTemporarily()); 68 | } 69 | 70 | @Test 71 | public void httpBasicAuthenticationSuccess() throws Exception { 72 | mvc 73 | .perform(get("/secured/butnotfound").with(httpBasic("user","password"))) 74 | .andExpect(status().isNotFound()) 75 | .andExpect(authenticated().withUsername("user")); 76 | } 77 | 78 | @Test 79 | public void authenticationSuccess() throws Exception { 80 | mvc 81 | .perform(formLogin()) 82 | .andExpect(status().isMovedTemporarily()) 83 | .andExpect(redirectedUrl("/")) 84 | .andExpect(authenticated().withUsername("user")); 85 | } 86 | 87 | @Test 88 | public void authenticationFailed() throws Exception { 89 | mvc 90 | .perform(formLogin().user("user").password("invalid")) 91 | .andExpect(status().isMovedTemporarily()) 92 | .andExpect(redirectedUrl("/login?error")) 93 | .andExpect(unauthenticated()); 94 | } 95 | 96 | @Configuration 97 | @EnableWebMvcSecurity 98 | @EnableWebMvc 99 | static class Config extends WebSecurityConfigurerAdapter { 100 | @Autowired 101 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 102 | auth 103 | .inMemoryAuthentication() 104 | .withUser("user").password("password").roles("USER"); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.login; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*; 19 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 20 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 22 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 23 | 24 | import javax.servlet.Filter; 25 | 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.springframework.beans.factory.annotation.Autowired; 30 | import org.springframework.context.annotation.Bean; 31 | import org.springframework.context.annotation.Configuration; 32 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 33 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 34 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 35 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 36 | import org.springframework.security.web.context.HttpSessionSecurityContextRepository; 37 | import org.springframework.security.web.context.SecurityContextRepository; 38 | import org.springframework.test.context.ContextConfiguration; 39 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 40 | import org.springframework.test.context.web.WebAppConfiguration; 41 | import org.springframework.test.web.servlet.MockMvc; 42 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 43 | import org.springframework.web.context.WebApplicationContext; 44 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 45 | 46 | @RunWith(SpringJUnit4ClassRunner.class) 47 | @ContextConfiguration 48 | @WebAppConfiguration 49 | public class CustomConfigAuthenticationTests { 50 | 51 | @Autowired 52 | private WebApplicationContext context; 53 | 54 | @Autowired 55 | private Filter springSecurityFilterChain; 56 | 57 | @Autowired 58 | private SecurityContextRepository securityContextRepository; 59 | 60 | private MockMvc mvc; 61 | 62 | @Before 63 | public void setup() { 64 | mvc = MockMvcBuilders 65 | .webAppContextSetup(context) 66 | .defaultRequest(get("/")) 67 | .addFilters(springSecurityFilterChain) 68 | .build(); 69 | } 70 | 71 | @Test 72 | public void authenticationSuccess() throws Exception { 73 | mvc 74 | .perform(formLogin("/authenticate").user("user","user").password("pass","password")) 75 | .andExpect(status().isMovedTemporarily()) 76 | .andExpect(redirectedUrl("/")) 77 | .andExpect(authenticated().withUsername("user")); 78 | } 79 | 80 | 81 | @Test 82 | public void withUserSuccess() throws Exception { 83 | mvc 84 | .perform(get("/").with(user("user"))) 85 | .andExpect(status().isNotFound()) 86 | .andExpect(authenticated().withUsername("user")); 87 | } 88 | 89 | @Test 90 | public void authenticationFailed() throws Exception { 91 | mvc 92 | .perform(formLogin("/authenticate").user("user","notfound").password("pass","invalid")) 93 | .andExpect(status().isMovedTemporarily()) 94 | .andExpect(redirectedUrl("/authenticate?error")) 95 | .andExpect(unauthenticated()); 96 | } 97 | 98 | @Configuration 99 | @EnableWebMvcSecurity 100 | @EnableWebMvc 101 | static class Config extends WebSecurityConfigurerAdapter { 102 | 103 | @Override 104 | protected void configure(HttpSecurity http) throws Exception { 105 | http 106 | .authorizeRequests() 107 | .anyRequest().authenticated() 108 | .and() 109 | .securityContext() 110 | .securityContextRepository(securityContextRepository()) 111 | .and() 112 | .formLogin() 113 | .usernameParameter("user") 114 | .passwordParameter("pass") 115 | .loginPage("/authenticate"); 116 | } 117 | 118 | @Autowired 119 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 120 | auth 121 | .inMemoryAuthentication() 122 | .withUser("user").password("password").roles("USER"); 123 | } 124 | 125 | @Bean 126 | public SecurityContextRepository securityContextRepository() { 127 | HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository(); 128 | repo.setSpringSecurityContextKey("CUSTOM"); 129 | return repo; 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.login; 17 | 18 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 20 | 21 | import javax.servlet.Filter; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.context.annotation.Configuration; 28 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 29 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 30 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 31 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 32 | import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders; 33 | import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.FormLoginRequestBuilder; 34 | import org.springframework.test.context.ContextConfiguration; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | import org.springframework.test.context.web.WebAppConfiguration; 37 | import org.springframework.test.web.servlet.MockMvc; 38 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 39 | import org.springframework.web.context.WebApplicationContext; 40 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 41 | 42 | @RunWith(SpringJUnit4ClassRunner.class) 43 | @ContextConfiguration 44 | @WebAppConfiguration 45 | public class CustomLoginRequestBuilderAuthenticationTests { 46 | 47 | @Autowired 48 | private WebApplicationContext context; 49 | 50 | @Autowired 51 | private Filter springSecurityFilterChain; 52 | 53 | private MockMvc mvc; 54 | 55 | @Before 56 | public void setup() { 57 | mvc = MockMvcBuilders 58 | .webAppContextSetup(context) 59 | .addFilters(springSecurityFilterChain) 60 | .build(); 61 | } 62 | 63 | @Test 64 | public void authenticationSuccess() throws Exception { 65 | mvc 66 | .perform(login()) 67 | .andExpect(status().isMovedTemporarily()) 68 | .andExpect(redirectedUrl("/")) 69 | .andExpect(authenticated().withUsername("user")); 70 | } 71 | 72 | @Test 73 | public void authenticationFailed() throws Exception { 74 | mvc 75 | .perform(login().user("notfound").password("invalid")) 76 | .andExpect(status().isMovedTemporarily()) 77 | .andExpect(redirectedUrl("/authenticate?error")) 78 | .andExpect(unauthenticated()); 79 | } 80 | 81 | static FormLoginRequestBuilder login() { 82 | return SecurityMockMvcRequestBuilders 83 | .formLogin("/authenticate") 84 | .userParameter("user") 85 | .passwordParam("pass"); 86 | } 87 | 88 | @Configuration 89 | @EnableWebMvcSecurity 90 | @EnableWebMvc 91 | static class Config extends WebSecurityConfigurerAdapter { 92 | 93 | @Override 94 | protected void configure(HttpSecurity http) throws Exception { 95 | http 96 | .authorizeRequests() 97 | .anyRequest().authenticated() 98 | .and() 99 | .formLogin() 100 | .usernameParameter("user") 101 | .passwordParameter("pass") 102 | .loginPage("/authenticate"); 103 | } 104 | 105 | @Autowired 106 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 107 | auth 108 | .inMemoryAuthentication() 109 | .withUser("user").password("password").roles("USER"); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Configuration; 30 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 31 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 32 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 33 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 34 | import org.springframework.test.context.ContextConfiguration; 35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 36 | import org.springframework.test.context.web.WebAppConfiguration; 37 | import org.springframework.test.web.servlet.MockMvc; 38 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 39 | import org.springframework.web.context.WebApplicationContext; 40 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 41 | 42 | @RunWith(SpringJUnit4ClassRunner.class) 43 | @ContextConfiguration 44 | @WebAppConfiguration 45 | public class DefaultfSecurityRequestsTests { 46 | 47 | @Autowired 48 | private WebApplicationContext context; 49 | 50 | @Autowired 51 | private Filter springSecurityFilterChain; 52 | 53 | private MockMvc mvc; 54 | 55 | @Before 56 | public void setup() { 57 | mvc = MockMvcBuilders 58 | .webAppContextSetup(context) 59 | .defaultRequest(get("/").with(user("user").roles("ADMIN"))) 60 | .addFilters(springSecurityFilterChain) 61 | .build(); 62 | } 63 | 64 | @Test 65 | public void requestProtectedUrlWithUser() throws Exception { 66 | mvc 67 | .perform(get("/")) 68 | // Ensure we got past Security 69 | .andExpect(status().isNotFound()) 70 | // Ensure it appears we are authenticated with user 71 | .andExpect(authenticated().withUsername("user")); 72 | } 73 | 74 | @Test 75 | public void requestProtectedUrlWithAdmin() throws Exception { 76 | mvc 77 | .perform(get("/admin")) 78 | // Ensure we got past Security 79 | .andExpect(status().isNotFound()) 80 | // Ensure it appears we are authenticated with user 81 | .andExpect(authenticated().withUsername("user")); 82 | } 83 | 84 | @Configuration 85 | @EnableWebMvcSecurity 86 | @EnableWebMvc 87 | static class Config extends WebSecurityConfigurerAdapter { 88 | 89 | @Override 90 | protected void configure(HttpSecurity http) throws Exception { 91 | http 92 | .authorizeRequests() 93 | .antMatchers("/admin/**").hasRole("ADMIN") 94 | .anyRequest().authenticated() 95 | .and() 96 | .formLogin(); 97 | } 98 | 99 | @Autowired 100 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 101 | auth 102 | .inMemoryAuthentication() 103 | .withUser("user").password("password").roles("USER"); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Bean; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.security.authentication.TestingAuthenticationToken; 32 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 33 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 34 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 35 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 36 | import org.springframework.security.core.Authentication; 37 | import org.springframework.security.core.userdetails.UserDetails; 38 | import org.springframework.security.core.userdetails.UserDetailsService; 39 | import org.springframework.test.context.ContextConfiguration; 40 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 41 | import org.springframework.test.context.web.WebAppConfiguration; 42 | import org.springframework.test.web.servlet.MockMvc; 43 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 44 | import org.springframework.web.context.WebApplicationContext; 45 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 46 | 47 | @RunWith(SpringJUnit4ClassRunner.class) 48 | @ContextConfiguration 49 | @WebAppConfiguration 50 | public class SecurityRequestsTests { 51 | 52 | @Autowired 53 | private WebApplicationContext context; 54 | 55 | @Autowired 56 | private Filter springSecurityFilterChain; 57 | 58 | @Autowired 59 | private UserDetailsService userDetailsService; 60 | 61 | private MockMvc mvc; 62 | 63 | @Before 64 | public void setup() { 65 | mvc = MockMvcBuilders 66 | .webAppContextSetup(context) 67 | .addFilters(springSecurityFilterChain) 68 | .build(); 69 | } 70 | 71 | @Test 72 | public void requestProtectedUrlWithUser() throws Exception { 73 | mvc 74 | .perform(get("/").with(user("user"))) 75 | // Ensure we got past Security 76 | .andExpect(status().isNotFound()) 77 | // Ensure it appears we are authenticated with user 78 | .andExpect(authenticated().withUsername("user")); 79 | } 80 | 81 | @Test 82 | public void requestProtectedUrlWithAdmin() throws Exception { 83 | mvc 84 | .perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN"))) 85 | // Ensure we got past Security 86 | .andExpect(status().isNotFound()) 87 | // Ensure it appears we are authenticated with admin 88 | .andExpect(authenticated().withUsername("admin")); 89 | } 90 | 91 | @Test 92 | public void requestProtectedUrlWithUserDetails() throws Exception { 93 | UserDetails userDetails = userDetailsService.loadUserByUsername("user"); 94 | mvc 95 | .perform(get("/").with(user(userDetails))) 96 | // Ensure we got past Security 97 | .andExpect(status().isNotFound()) 98 | // Ensure it appears we are authenticated with user 99 | .andExpect(authenticated().withAuthenticationPrincipal(userDetails)); 100 | } 101 | 102 | @Test 103 | public void requestProtectedUrlWithAuthentication() throws Exception { 104 | Authentication authentication = new TestingAuthenticationToken("test", "notused", "ROLE_USER"); 105 | mvc 106 | .perform(get("/").with(authentication(authentication))) 107 | // Ensure we got past Security 108 | .andExpect(status().isNotFound()) 109 | // Ensure it appears we are authenticated with user 110 | .andExpect(authenticated().withAuthentication(authentication)); 111 | } 112 | 113 | @Configuration 114 | @EnableWebMvcSecurity 115 | @EnableWebMvc 116 | static class Config extends WebSecurityConfigurerAdapter { 117 | 118 | @Override 119 | protected void configure(HttpSecurity http) throws Exception { 120 | http 121 | .authorizeRequests() 122 | .antMatchers("/admin/**").hasRole("ADMIN") 123 | .anyRequest().authenticated() 124 | .and() 125 | .formLogin(); 126 | } 127 | 128 | @Autowired 129 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 130 | auth 131 | .inMemoryAuthentication() 132 | .withUser("user").password("password").roles("USER"); 133 | } 134 | 135 | @Override 136 | @Bean 137 | public UserDetailsService userDetailsServiceBean() throws Exception { 138 | return super.userDetailsServiceBean(); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Configuration; 30 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 31 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 32 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 33 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 34 | import org.springframework.security.test.context.support.WithMockUser; 35 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 36 | import org.springframework.test.context.ContextConfiguration; 37 | import org.springframework.test.context.TestExecutionListeners; 38 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 39 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 40 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 41 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 42 | import org.springframework.test.context.web.ServletTestExecutionListener; 43 | import org.springframework.test.context.web.WebAppConfiguration; 44 | import org.springframework.test.web.servlet.MockMvc; 45 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 46 | import org.springframework.web.context.WebApplicationContext; 47 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 48 | 49 | @RunWith(SpringJUnit4ClassRunner.class) 50 | @ContextConfiguration 51 | @WebAppConfiguration 52 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 53 | DependencyInjectionTestExecutionListener.class, 54 | DirtiesContextTestExecutionListener.class, 55 | TransactionalTestExecutionListener.class, 56 | WithSecurityContextTestExcecutionListener.class}) 57 | public class WithUserAuthenticationTests { 58 | 59 | @Autowired 60 | private WebApplicationContext context; 61 | 62 | @Autowired 63 | private Filter springSecurityFilterChain; 64 | 65 | private MockMvc mvc; 66 | 67 | @Before 68 | public void setup() { 69 | mvc = MockMvcBuilders 70 | .webAppContextSetup(context) 71 | .addFilters(springSecurityFilterChain) 72 | .defaultRequest(get("/").with(testSecurityContext())) 73 | .build(); 74 | } 75 | 76 | @Test 77 | @WithMockUser 78 | public void requestProtectedUrlWithUser() throws Exception { 79 | mvc 80 | .perform(get("/")) 81 | // Ensure we got past Security 82 | .andExpect(status().isNotFound()) 83 | // Ensure it appears we are authenticated with user 84 | .andExpect(authenticated().withUsername("user")); 85 | } 86 | 87 | @Test 88 | @WithMockUser(roles="ADMIN") 89 | public void requestProtectedUrlWithAdmin() throws Exception { 90 | mvc 91 | .perform(get("/admin")) 92 | // Ensure we got past Security 93 | .andExpect(status().isNotFound()) 94 | // Ensure it appears we are authenticated with user 95 | .andExpect(authenticated().withUsername("user").withRoles("ADMIN")); 96 | } 97 | 98 | @Configuration 99 | @EnableWebMvcSecurity 100 | @EnableWebMvc 101 | static class Config extends WebSecurityConfigurerAdapter { 102 | 103 | @Override 104 | protected void configure(HttpSecurity http) throws Exception { 105 | http 106 | .authorizeRequests() 107 | .antMatchers("/admin/**").hasRole("ADMIN") 108 | .anyRequest().authenticated() 109 | .and() 110 | .formLogin(); 111 | } 112 | 113 | @Autowired 114 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 115 | auth 116 | .inMemoryAuthentication() 117 | .withUser("user").password("password").roles("USER"); 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Configuration; 30 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 31 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 32 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 33 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 34 | import org.springframework.security.test.context.support.WithMockUser; 35 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 36 | import org.springframework.test.context.ContextConfiguration; 37 | import org.springframework.test.context.TestExecutionListeners; 38 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 39 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 40 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 41 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 42 | import org.springframework.test.context.web.ServletTestExecutionListener; 43 | import org.springframework.test.context.web.WebAppConfiguration; 44 | import org.springframework.test.web.servlet.MockMvc; 45 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 46 | import org.springframework.web.context.WebApplicationContext; 47 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 48 | 49 | @RunWith(SpringJUnit4ClassRunner.class) 50 | @ContextConfiguration 51 | @WebAppConfiguration 52 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 53 | DependencyInjectionTestExecutionListener.class, 54 | DirtiesContextTestExecutionListener.class, 55 | TransactionalTestExecutionListener.class, 56 | WithSecurityContextTestExcecutionListener.class}) 57 | @WithMockUser(roles="ADMIN") 58 | public class WithUserClassLevelAuthenticationTests { 59 | 60 | @Autowired 61 | private WebApplicationContext context; 62 | 63 | @Autowired 64 | private Filter springSecurityFilterChain; 65 | 66 | private MockMvc mvc; 67 | 68 | @Before 69 | public void setup() { 70 | mvc = MockMvcBuilders 71 | .webAppContextSetup(context) 72 | .addFilters(springSecurityFilterChain) 73 | .defaultRequest(get("/").with(testSecurityContext())) 74 | .build(); 75 | } 76 | 77 | @Test 78 | public void requestProtectedUrlWithUser() throws Exception { 79 | mvc 80 | .perform(get("/")) 81 | // Ensure we got past Security 82 | .andExpect(status().isNotFound()) 83 | // Ensure it appears we are authenticated with user 84 | .andExpect(authenticated().withUsername("user")); 85 | } 86 | 87 | @Test 88 | public void requestProtectedUrlWithAdmin() throws Exception { 89 | mvc 90 | .perform(get("/admin")) 91 | // Ensure we got past Security 92 | .andExpect(status().isNotFound()) 93 | // Ensure it appears we are authenticated with user 94 | .andExpect(authenticated().withUsername("user").withRoles("ADMIN")); 95 | } 96 | 97 | @Configuration 98 | @EnableWebMvcSecurity 99 | @EnableWebMvc 100 | static class Config extends WebSecurityConfigurerAdapter { 101 | 102 | @Override 103 | protected void configure(HttpSecurity http) throws Exception { 104 | http 105 | .authorizeRequests() 106 | .antMatchers("/admin/**").hasRole("ADMIN") 107 | .anyRequest().authenticated() 108 | .and() 109 | .formLogin(); 110 | } 111 | 112 | @Autowired 113 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 114 | auth 115 | .inMemoryAuthentication() 116 | .withUser("user").password("password").roles("USER"); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Bean; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 32 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 33 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 34 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 35 | import org.springframework.security.core.userdetails.UserDetailsService; 36 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 37 | import org.springframework.security.test.context.support.WithUserDetails; 38 | import org.springframework.test.context.ContextConfiguration; 39 | import org.springframework.test.context.TestExecutionListeners; 40 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 41 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 42 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 43 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 44 | import org.springframework.test.context.web.ServletTestExecutionListener; 45 | import org.springframework.test.context.web.WebAppConfiguration; 46 | import org.springframework.test.web.servlet.MockMvc; 47 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 48 | import org.springframework.web.context.WebApplicationContext; 49 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 50 | 51 | @RunWith(SpringJUnit4ClassRunner.class) 52 | @ContextConfiguration 53 | @WebAppConfiguration 54 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 55 | DependencyInjectionTestExecutionListener.class, 56 | DirtiesContextTestExecutionListener.class, 57 | TransactionalTestExecutionListener.class, 58 | WithSecurityContextTestExcecutionListener.class}) 59 | public class WithUserDetailsAuthenticationTests { 60 | 61 | @Autowired 62 | private WebApplicationContext context; 63 | 64 | @Autowired 65 | private Filter springSecurityFilterChain; 66 | 67 | private MockMvc mvc; 68 | 69 | @Before 70 | public void setup() { 71 | mvc = MockMvcBuilders 72 | .webAppContextSetup(context) 73 | .addFilters(springSecurityFilterChain) 74 | .defaultRequest(get("/").with(testSecurityContext())) 75 | .build(); 76 | } 77 | 78 | @Test 79 | @WithUserDetails 80 | public void requestProtectedUrlWithUser() throws Exception { 81 | mvc 82 | .perform(get("/")) 83 | // Ensure we got past Security 84 | .andExpect(status().isNotFound()) 85 | // Ensure it appears we are authenticated with user 86 | .andExpect(authenticated().withUsername("user")); 87 | } 88 | 89 | @Test 90 | @WithUserDetails("admin") 91 | public void requestProtectedUrlWithAdmin() throws Exception { 92 | mvc 93 | .perform(get("/admin")) 94 | // Ensure we got past Security 95 | .andExpect(status().isNotFound()) 96 | // Ensure it appears we are authenticated with user 97 | .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER")); 98 | } 99 | 100 | @Configuration 101 | @EnableWebMvcSecurity 102 | @EnableWebMvc 103 | static class Config extends WebSecurityConfigurerAdapter { 104 | 105 | @Override 106 | protected void configure(HttpSecurity http) throws Exception { 107 | http 108 | .authorizeRequests() 109 | .antMatchers("/admin/**").hasRole("ADMIN") 110 | .anyRequest().authenticated() 111 | .and() 112 | .formLogin(); 113 | } 114 | 115 | @Bean 116 | @Override 117 | public UserDetailsService userDetailsServiceBean() throws Exception { 118 | return super.userDetailsServiceBean(); 119 | } 120 | 121 | @Autowired 122 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 123 | auth 124 | .inMemoryAuthentication() 125 | .withUser("user").password("password").roles("USER").and() 126 | .withUser("admin").password("password").roles("USER","ADMIN"); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of 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, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.security.test.web.servlet.showcase.secured; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 19 | import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 22 | 23 | import javax.servlet.Filter; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.context.annotation.Bean; 30 | import org.springframework.context.annotation.Configuration; 31 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 32 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 33 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 34 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 35 | import org.springframework.security.core.userdetails.UserDetailsService; 36 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 37 | import org.springframework.security.test.context.support.WithUserDetails; 38 | import org.springframework.test.context.ContextConfiguration; 39 | import org.springframework.test.context.TestExecutionListeners; 40 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 41 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 42 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 43 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 44 | import org.springframework.test.context.web.ServletTestExecutionListener; 45 | import org.springframework.test.context.web.WebAppConfiguration; 46 | import org.springframework.test.web.servlet.MockMvc; 47 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 48 | import org.springframework.web.context.WebApplicationContext; 49 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 50 | 51 | @RunWith(SpringJUnit4ClassRunner.class) 52 | @ContextConfiguration 53 | @WebAppConfiguration 54 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 55 | DependencyInjectionTestExecutionListener.class, 56 | DirtiesContextTestExecutionListener.class, 57 | TransactionalTestExecutionListener.class, 58 | WithSecurityContextTestExcecutionListener.class}) 59 | @WithUserDetails("admin") 60 | public class WithUserDetailsClassLevelAuthenticationTests { 61 | 62 | @Autowired 63 | private WebApplicationContext context; 64 | 65 | @Autowired 66 | private Filter springSecurityFilterChain; 67 | 68 | private MockMvc mvc; 69 | 70 | @Before 71 | public void setup() { 72 | mvc = MockMvcBuilders 73 | .webAppContextSetup(context) 74 | .addFilters(springSecurityFilterChain) 75 | .defaultRequest(get("/").with(testSecurityContext())) 76 | .build(); 77 | } 78 | 79 | @Test 80 | public void requestRootUrlWithAdmin() throws Exception { 81 | mvc 82 | .perform(get("/")) 83 | // Ensure we got past Security 84 | .andExpect(status().isNotFound()) 85 | // Ensure it appears we are authenticated with user 86 | .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER")); 87 | } 88 | 89 | @Test 90 | public void requestProtectedUrlWithAdmin() throws Exception { 91 | mvc 92 | .perform(get("/admin")) 93 | // Ensure we got past Security 94 | .andExpect(status().isNotFound()) 95 | // Ensure it appears we are authenticated with user 96 | .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER")); 97 | } 98 | 99 | @Configuration 100 | @EnableWebMvcSecurity 101 | @EnableWebMvc 102 | static class Config extends WebSecurityConfigurerAdapter { 103 | 104 | @Override 105 | protected void configure(HttpSecurity http) throws Exception { 106 | http 107 | .authorizeRequests() 108 | .antMatchers("/admin/**").hasRole("ADMIN") 109 | .anyRequest().authenticated() 110 | .and() 111 | .formLogin(); 112 | } 113 | 114 | @Bean 115 | @Override 116 | public UserDetailsService userDetailsServiceBean() throws Exception { 117 | return super.userDetailsServiceBean(); 118 | } 119 | 120 | @Autowired 121 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 122 | auth 123 | .inMemoryAuthentication() 124 | .withUser("user").password("password").roles("USER").and() 125 | .withUser("admin").password("password").roles("USER","ADMIN"); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /src/test/java/sample/config/MockDataConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.config; 17 | 18 | import org.mockito.invocation.InvocationOnMock; 19 | import org.mockito.stubbing.Answer; 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.context.annotation.Scope; 23 | import org.springframework.core.convert.ConversionService; 24 | import org.springframework.core.convert.converter.ConverterRegistry; 25 | import sample.data.Message; 26 | import sample.data.MessageRepository; 27 | import sample.data.mock.MockConversionService; 28 | 29 | import java.util.Calendar; 30 | import java.util.Locale; 31 | 32 | import static org.mockito.Matchers.any; 33 | import static org.mockito.Matchers.anyLong; 34 | import static org.mockito.Mockito.mock; 35 | import static org.mockito.Mockito.when; 36 | 37 | /** 38 | * @author Rob Winch 39 | */ 40 | @Configuration 41 | public class MockDataConfig { 42 | 43 | @Bean 44 | public MessageRepository messageRepository() { 45 | final Message message = createMessage(); 46 | MessageRepository messages = mock(MessageRepository.class); 47 | when(messages.save(any(Message.class))).thenAnswer(new Answer() { 48 | @Override 49 | public Message answer(InvocationOnMock invocation) throws Throwable { 50 | Object[] args = invocation.getArguments(); 51 | Message result = (Message) args[0]; 52 | result.setId(message.getId()); 53 | result.setCreated(message.getCreated()); 54 | return result; 55 | } 56 | }); 57 | when(messages.findOne(anyLong())).thenReturn(message); 58 | return messages; 59 | } 60 | 61 | @Bean 62 | public MockConversionService conversionService(T conversionService) { 63 | return new MockConversionService(conversionService); 64 | } 65 | 66 | @Bean 67 | public Message createMessage() { 68 | Calendar created = Calendar.getInstance(Locale.ENGLISH); 69 | // we need to clear out the milliseconds since we are not interested in being that precise 70 | created.set(Calendar.MILLISECOND, 0); 71 | created.getTime().setTime(1397672456000L); 72 | Message message = new Message(); 73 | message.setCreated(created); 74 | message.setId(123L); 75 | message.setSummary("Spring Rocks"); 76 | message.setText("In case you didn't know, Spring Rocks!"); 77 | return message; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/sample/data/mock/MockConversionService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.data.mock; 14 | 15 | import java.io.Serializable; 16 | import java.util.Collection; 17 | import java.util.Collections; 18 | import java.util.Set; 19 | 20 | import org.springframework.context.ApplicationContext; 21 | import org.springframework.context.ApplicationContextAware; 22 | import org.springframework.core.GenericTypeResolver; 23 | import org.springframework.core.convert.ConversionService; 24 | import org.springframework.core.convert.TypeDescriptor; 25 | import org.springframework.core.convert.converter.ConditionalGenericConverter; 26 | import org.springframework.core.convert.converter.ConverterRegistry; 27 | import org.springframework.data.repository.CrudRepository; 28 | import org.springframework.data.repository.support.DomainClassConverter; 29 | import sample.mvc.MessageController; 30 | 31 | /** 32 | * Allows using Mock {@link CrudRepository} instances (i.e. using Mockito) and still support converting from a String to 33 | * a domain object. This is used internally by Spring on methods like 34 | * {@link MessageController#view(sample.data.Message)} 35 | * 36 | * @author Rob Winch 37 | * 38 | * @param 39 | * @see DomainClassConverter 40 | */ 41 | public class MockConversionService implements ApplicationContextAware, 42 | ConditionalGenericConverter { 43 | @SuppressWarnings("rawtypes") 44 | private Collection repositories; 45 | 46 | private final T conversionService; 47 | 48 | public MockConversionService(T conversionService) { 49 | this.conversionService = conversionService; 50 | } 51 | 52 | public Set getConvertibleTypes() { 53 | return Collections.singleton(new ConvertiblePair(Object.class, Object.class)); 54 | } 55 | 56 | public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { 57 | CrudRepository repo = getRepository(targetType.getType(), sourceType.getType()); 58 | return repo == null ? null : repo.findOne((Serializable) source); 59 | } 60 | 61 | public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { 62 | return getRepository(targetType.getType(), sourceType.getType()) != null; 63 | } 64 | 65 | public void setApplicationContext(ApplicationContext context) { 66 | this.repositories = context.getBeansOfType(CrudRepository.class).values(); 67 | this.conversionService.addConverter(this); 68 | } 69 | 70 | private CrudRepository getRepository(Class domainClass, Class idClass) { 71 | for (CrudRepository repository : repositories) { 72 | Class[] typeArgs = GenericTypeResolver.resolveTypeArguments(repository.getClass(), CrudRepository.class); 73 | if (domainClass.equals(typeArgs[0]) && conversionService.canConvert(typeArgs[1], idClass)) { 74 | return repository; 75 | } 76 | } 77 | return null; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/sample/fest/Assertions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.fest; 17 | 18 | import sample.data.Message; 19 | 20 | /** 21 | * @author Rob Winch 22 | */ 23 | public class Assertions extends org.fest.assertions.Assertions { 24 | 25 | public static MessageAssert assertThat(Message message) { 26 | return new MessageAssert(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/sample/fest/MessageAssert.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.fest; 17 | 18 | import org.fest.assertions.ObjectAssert; 19 | import org.springframework.test.util.MatcherAssertionErrors; 20 | import sample.data.Message; 21 | 22 | import java.util.Calendar; 23 | 24 | import static org.fest.assertions.Assertions.assertThat; 25 | 26 | /** 27 | * @author Rob Winch 28 | */ 29 | public class MessageAssert extends ObjectAssert { 30 | 31 | public MessageAssert(Message message) { 32 | super(message); 33 | } 34 | 35 | @Override 36 | public MessageAssert isEqualTo(Object expected) { 37 | isEqualToIgnoringGeneratedFields(expected); 38 | Message expectedMessage = (Message) expected; 39 | Message actualMessage = (Message) actual; 40 | assertThat(actualMessage.getId()).isEqualTo(expectedMessage.getId()); 41 | assertThat(actualMessage.getCreated()).isEqualTo(expectedMessage.getCreated()); 42 | return this; 43 | } 44 | 45 | public MessageAssert isEqualToIgnoringGeneratedFields(Object expected) { 46 | assertThat(expected).isInstanceOf(Message.class); 47 | Message expectedMessage = (Message) expected; 48 | Message actualMessage = (Message) actual; 49 | assertThat(actualMessage.getSummary()).isEqualTo(expectedMessage.getSummary()); 50 | assertThat(actualMessage.getText()).isEqualTo(expectedMessage.getText()); 51 | return this; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/sample/htmlunit/MockMvcHtmlUnitCreateMessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.htmlunit; 17 | 18 | import static org.fest.assertions.Assertions.assertThat; 19 | 20 | import java.io.IOException; 21 | 22 | import javax.servlet.Filter; 23 | 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.security.test.context.support.WithMockUser; 30 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 31 | import org.springframework.test.context.ContextConfiguration; 32 | import org.springframework.test.context.TestExecutionListeners; 33 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 34 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 35 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 36 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 37 | import org.springframework.test.context.web.ServletTestExecutionListener; 38 | import org.springframework.test.context.web.WebAppConfiguration; 39 | import org.springframework.test.web.servlet.MockMvc; 40 | import org.springframework.test.web.servlet.htmlunit.MockMvcWebConnection; 41 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 42 | import org.springframework.web.context.WebApplicationContext; 43 | 44 | import sample.config.MockDataConfig; 45 | import sample.config.WebMvcConfig; 46 | import sample.config.WebSecurityConfig; 47 | 48 | import com.gargoylesoftware.htmlunit.WebClient; 49 | import com.gargoylesoftware.htmlunit.html.HtmlForm; 50 | import com.gargoylesoftware.htmlunit.html.HtmlPage; 51 | import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; 52 | import com.gargoylesoftware.htmlunit.html.HtmlTextArea; 53 | import com.gargoylesoftware.htmlunit.html.HtmlTextInput; 54 | 55 | /** 56 | * @author Rob Winch 57 | */ 58 | @RunWith(SpringJUnit4ClassRunner.class) 59 | @ContextConfiguration(classes = {WebMvcConfig.class, WebSecurityConfig.class, MockDataConfig.class}) 60 | @WebAppConfiguration 61 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 62 | DependencyInjectionTestExecutionListener.class, 63 | DirtiesContextTestExecutionListener.class, 64 | TransactionalTestExecutionListener.class, 65 | WithSecurityContextTestExcecutionListener.class}) 66 | @WithMockUser 67 | public class MockMvcHtmlUnitCreateMessageTest { 68 | @Autowired 69 | private Filter springSecurityFilterChain; 70 | 71 | @Autowired 72 | private WebApplicationContext context; 73 | 74 | private WebClient webClient; 75 | 76 | @Before 77 | public void setup() { 78 | MockMvc mockMvc = MockMvcBuilders 79 | .webAppContextSetup(context) 80 | .addFilters(springSecurityFilterChain) 81 | .build(); 82 | webClient = new WebClient(); 83 | webClient.setWebConnection(new MockMvcWebConnection(mockMvc)); 84 | } 85 | 86 | @After 87 | public void cleanup() { 88 | this.webClient.closeAllWindows(); 89 | } 90 | 91 | @Test 92 | public void createMessage() throws IOException { 93 | // Load the Create Message Form 94 | HtmlPage createMsgFormPage = webClient.getPage("http://localhost/mail/messages/form"); 95 | // Submit the create message form 96 | HtmlForm form = createMsgFormPage.getHtmlElementById("messageForm"); 97 | HtmlTextInput summaryInput = createMsgFormPage.getHtmlElementById("summary"); 98 | summaryInput.setValueAttribute("Spring Rocks"); 99 | HtmlTextArea textInput = createMsgFormPage.getHtmlElementById("text"); 100 | textInput.setText("In case you didn't know, Spring Rocks!"); 101 | HtmlSubmitInput submit = form.getOneHtmlElementByAttribute("input", "type", "submit"); 102 | HtmlPage newMessagePage = submit.click(); 103 | 104 | // verify we successfully created a message and displayed the newly create message 105 | assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123"); 106 | String id = newMessagePage.getHtmlElementById("id").getTextContent(); 107 | assertThat(id).isEqualTo("123"); 108 | String summary = newMessagePage.getHtmlElementById("summary").getTextContent(); 109 | assertThat(summary).isEqualTo("Spring Rocks"); 110 | String text = newMessagePage.getHtmlElementById("text").getTextContent(); 111 | assertThat(text).isEqualTo("In case you didn't know, Spring Rocks!"); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/test/java/sample/mockmvc/MockMvcCreateMessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 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 sample.mockmvc; 17 | 18 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; 19 | 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath; 25 | 26 | import javax.servlet.Filter; 27 | 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.springframework.beans.factory.annotation.Autowired; 32 | import org.springframework.security.test.context.support.WithMockUser; 33 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 34 | import org.springframework.test.context.ContextConfiguration; 35 | import org.springframework.test.context.TestExecutionListeners; 36 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 37 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 38 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 39 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 40 | import org.springframework.test.context.web.ServletTestExecutionListener; 41 | import org.springframework.test.context.web.WebAppConfiguration; 42 | import org.springframework.test.web.servlet.MockMvc; 43 | import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; 44 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 45 | import org.springframework.web.context.WebApplicationContext; 46 | 47 | import sample.config.MockDataConfig; 48 | import sample.config.WebMvcConfig; 49 | import sample.config.WebSecurityConfig; 50 | 51 | /** 52 | * @author Rob Winch 53 | */ 54 | @RunWith(SpringJUnit4ClassRunner.class) 55 | @ContextConfiguration(classes = {WebMvcConfig.class, WebSecurityConfig.class, MockDataConfig.class}) 56 | @WebAppConfiguration 57 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 58 | DependencyInjectionTestExecutionListener.class, 59 | DirtiesContextTestExecutionListener.class, 60 | TransactionalTestExecutionListener.class, 61 | WithSecurityContextTestExcecutionListener.class}) 62 | @WithMockUser 63 | public class MockMvcCreateMessageTest { 64 | @Autowired 65 | private Filter springSecurityFilterChain; 66 | 67 | @Autowired 68 | private WebApplicationContext context; 69 | 70 | private MockMvc mockMvc; 71 | 72 | @Before 73 | public void setup() { 74 | this.mockMvc = MockMvcBuilders 75 | .webAppContextSetup(context) 76 | .defaultRequest(get("/").with(testSecurityContext())) 77 | .addFilters(springSecurityFilterChain) 78 | .build(); 79 | } 80 | 81 | @Test 82 | public void createMessage() throws Exception { 83 | MockHttpServletRequestBuilder createMessage = post("/messages/") 84 | .param("summary", "Spring Rocks") 85 | .param("text", "In case you didn't know, Spring Rocks!") 86 | .with(csrf()); 87 | 88 | mockMvc.perform(createMessage) 89 | .andExpect(status().is3xxRedirection()) 90 | .andExpect(redirectedUrl("/messages/123")); 91 | } 92 | 93 | @Test 94 | public void createMessageForm() throws Exception { 95 | mockMvc.perform(get("/messages/form")) 96 | .andExpect(xpath("//input[@name='summary']").exists()) 97 | .andExpect(xpath("//textarea[@name='text']").exists()); 98 | } 99 | 100 | @Test 101 | public void createMessageFormSubmit() throws Exception { 102 | String summaryParamName = "summary"; 103 | String textParamName = "text"; 104 | mockMvc.perform(get("/messages/form")) 105 | .andExpect(xpath("//input[@name='" + summaryParamName + "']").exists()) 106 | .andExpect(xpath("//textarea[@name='" + textParamName + "']").exists()); 107 | 108 | MockHttpServletRequestBuilder createMessage = post("/messages/") 109 | .param(summaryParamName, "Spring Rocks") 110 | .param(textParamName, "In case you didn't know, Spring Rocks!") 111 | .with(csrf()); 112 | 113 | mockMvc.perform(createMessage) 114 | .andExpect(status().is3xxRedirection()) 115 | .andExpect(redirectedUrl("/messages/123")); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/sample/webdriver/MockMvcHtmlUnitDriverCreateMessageTest.java: -------------------------------------------------------------------------------- 1 | package sample.webdriver; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.openqa.selenium.WebDriver; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.security.test.context.support.WithMockUser; 10 | import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.TestExecutionListeners; 13 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 14 | import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 15 | import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 16 | import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 17 | import org.springframework.test.context.web.ServletTestExecutionListener; 18 | import org.springframework.test.context.web.WebAppConfiguration; 19 | import org.springframework.test.web.servlet.MockMvc; 20 | import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriver; 21 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 22 | import org.springframework.web.context.WebApplicationContext; 23 | 24 | import sample.config.MockDataConfig; 25 | import sample.config.WebMvcConfig; 26 | import sample.config.WebSecurityConfig; 27 | import sample.data.Message; 28 | import sample.webdriver.pages.CreateMessagePage; 29 | import sample.webdriver.pages.ViewMessagePage; 30 | 31 | import java.text.ParseException; 32 | 33 | import javax.servlet.Filter; 34 | 35 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext; 36 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 37 | import static sample.fest.Assertions.assertThat; 38 | 39 | /** 40 | * An end to end test that validates the {@link CreateMessagePage}. A few things to notice: 41 | * 42 | *
    43 | *
  • You will see that all the tests are the same as {@link WebDriverCreateMessageITest}. This shows how little difference 44 | * there is in how you would write the tests.
  • 45 | *
  • The only difference is how we initialize our {@link WebDriver}
  • 46 | *
  • We do not need to run the web application on a server for this test since we are using 47 | * {@link org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriver}
  • 48 | *
49 | * 50 | * @author Rob Winch 51 | * 52 | */ 53 | @RunWith(SpringJUnit4ClassRunner.class) 54 | @ContextConfiguration(classes = {WebMvcConfig.class, WebSecurityConfig.class, MockDataConfig.class}) 55 | @WebAppConfiguration 56 | @TestExecutionListeners(listeners={ServletTestExecutionListener.class, 57 | DependencyInjectionTestExecutionListener.class, 58 | DirtiesContextTestExecutionListener.class, 59 | TransactionalTestExecutionListener.class, 60 | WithSecurityContextTestExcecutionListener.class}) 61 | @WithMockUser 62 | public class MockMvcHtmlUnitDriverCreateMessageTest { 63 | @Autowired 64 | private Filter springSecurityFilterChain; 65 | 66 | @Autowired 67 | private WebApplicationContext context; 68 | 69 | @Autowired 70 | private Message expectedMessage; 71 | 72 | private WebDriver driver; 73 | 74 | @Before 75 | public void setup() { 76 | MockMvc mockMvc = MockMvcBuilders 77 | .webAppContextSetup(context) 78 | .addFilters(springSecurityFilterChain) 79 | .build(); 80 | driver = new MockMvcHtmlUnitDriver(mockMvc, true); 81 | } 82 | 83 | @After 84 | public void destroy() { 85 | if(driver != null) { 86 | driver.close(); 87 | } 88 | } 89 | 90 | @Test 91 | public void missingFieldWithJavascriptValidationDisplaysError() { 92 | CreateMessagePage messagePage = CreateMessagePage.to(driver); 93 | messagePage = messagePage.createMessage(CreateMessagePage.class, "", ""); 94 | assertThat(messagePage.getErrors()).isEqualTo("This field is required."); 95 | } 96 | 97 | @Test 98 | public void missingFieldServerSideValidationDisplaysError() { 99 | CreateMessagePage messagePage = CreateMessagePage.to(driver); 100 | messagePage = messagePage.createMessage(CreateMessagePage.class, "Summary", ""); 101 | assertThat(messagePage.getErrors()).isEqualTo("Message is required."); 102 | } 103 | 104 | @Test 105 | public void successfullyCreateMessage() throws ParseException { 106 | String expectedSummary = expectedMessage.getSummary(); 107 | String expectedText = expectedMessage.getText(); 108 | 109 | CreateMessagePage page = CreateMessagePage.to(driver); 110 | 111 | ViewMessagePage viewMessagePage = page.createMessage(ViewMessagePage.class, expectedSummary, expectedText); 112 | assertThat(viewMessagePage.getMessage()).isEqualTo(expectedMessage); 113 | assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new message"); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/sample/webdriver/pages/AbstractPage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.webdriver.pages; 14 | 15 | import org.openqa.selenium.WebDriver; 16 | import org.openqa.selenium.WebElement; 17 | import org.openqa.selenium.support.FindBy; 18 | 19 | /** 20 | * Represents the common elements in a page within the message application. 21 | * 22 | * @author Rob Winch 23 | * 24 | */ 25 | public class AbstractPage { 26 | protected WebDriver driver; 27 | 28 | @FindBy(css = "label.error, .alert-error") 29 | private WebElement errors; 30 | 31 | public AbstractPage(WebDriver driver) { 32 | setDriver(driver); 33 | } 34 | 35 | public void setDriver(WebDriver driver) { 36 | this.driver = driver; 37 | } 38 | 39 | public String getErrors() { 40 | return errors.getText(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/sample/webdriver/pages/CreateMessagePage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.webdriver.pages; 14 | 15 | import org.openqa.selenium.WebDriver; 16 | import org.openqa.selenium.WebElement; 17 | import org.openqa.selenium.support.FindBy; 18 | import org.openqa.selenium.support.PageFactory; 19 | import sample.data.Message; 20 | 21 | /** 22 | * Represents the page where a {@link Message} is created. 23 | * 24 | * @author Rob Winch 25 | * 26 | */ 27 | public class CreateMessagePage extends AbstractPage { 28 | private WebElement summary; 29 | 30 | private WebElement text; 31 | 32 | @FindBy(css = "input[type=submit]") 33 | private WebElement submit; 34 | 35 | public CreateMessagePage(WebDriver driver) { 36 | super(driver); 37 | } 38 | 39 | public T createMessage(Class resultPage, String summary, String details) { 40 | this.summary.sendKeys(summary); 41 | this.text.sendKeys(details); 42 | this.submit.click(); 43 | return PageFactory.initElements(driver, resultPage); 44 | } 45 | 46 | public static CreateMessagePage to(WebDriver driver) { 47 | driver.get("http://localhost:9990/mail/messages/form"); 48 | return PageFactory.initElements(driver, CreateMessagePage.class); 49 | } 50 | } -------------------------------------------------------------------------------- /src/test/java/sample/webdriver/pages/ViewMessagePage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package sample.webdriver.pages; 14 | 15 | import org.openqa.selenium.WebDriver; 16 | import org.openqa.selenium.WebElement; 17 | import org.openqa.selenium.support.FindBy; 18 | import sample.data.Message; 19 | 20 | import java.text.DateFormat; 21 | import java.text.ParseException; 22 | import java.util.Calendar; 23 | import java.util.Locale; 24 | 25 | /** 26 | * Represents the page where the {@link Message} details can be viewed. 27 | * 28 | * @author Rob Winch 29 | * 30 | */ 31 | public class ViewMessagePage extends AbstractPage { 32 | @FindBy(className = "alert-success") 33 | private WebElement success; 34 | 35 | private WebElement id; 36 | 37 | private WebElement created; 38 | 39 | private WebElement summary; 40 | 41 | private WebElement text; 42 | 43 | public ViewMessagePage(WebDriver driver) { 44 | super(driver); 45 | } 46 | 47 | public String getSuccess() { 48 | return success.getText(); 49 | } 50 | 51 | public Long getId() { 52 | return Long.parseLong(id.getText()); 53 | } 54 | 55 | public Calendar getCreated() throws ParseException { 56 | Calendar result = Calendar.getInstance(); 57 | DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.ENGLISH); 58 | result.setTime(format.parse(created.getText())); 59 | return result; 60 | } 61 | 62 | public String getSummary() { 63 | return summary.getText(); 64 | } 65 | 66 | public String getText() { 67 | return text.getText(); 68 | } 69 | 70 | public Message getMessage() throws ParseException { 71 | Message message = new Message(); 72 | message.setId(getId()); 73 | message.setCreated(getCreated()); 74 | message.setSummary(getSummary()); 75 | message.setText(getText()); 76 | return message; 77 | } 78 | } 79 | --------------------------------------------------------------------------------