From 2e26648afd79a2fe4ef473f66a19a16cc94998df Mon Sep 17 00:00:00 2001 From: eugenp Date: Mon, 8 Dec 2014 12:06:23 +0200 Subject: [PATCH] cleanup work in apache fop --- .../baeldung/java/ApacheFOPHeroldTest.java | 33 +- .../src/test/resources/final_output.pdf | Bin 29522 -> 136822 bytes apache-fop/src/test/resources/input.xml | 1263 ++++++++++++++--- apache-fop/src/test/resources/output-doha.xml | 313 ---- .../src/test/resources/output-eugen.xml | 312 ---- 5 files changed, 1062 insertions(+), 859 deletions(-) delete mode 100644 apache-fop/src/test/resources/output-doha.xml delete mode 100644 apache-fop/src/test/resources/output-eugen.xml diff --git a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldTest.java b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldTest.java index 18550cbd0e..5e3c2c472b 100644 --- a/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldTest.java +++ b/apache-fop/src/test/java/org/baeldung/java/ApacheFOPHeroldTest.java @@ -11,8 +11,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; -import java.text.Normalizer; -import java.util.regex.Pattern; import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -35,11 +33,11 @@ import org.w3c.dom.Document; public class ApacheFOPHeroldTest { private String[] inputUrls = {// @formatter:off "http://www.baeldung.com/2011/10/20/bootstraping-a-web-application-with-spring-3-1-and-java-based-configuration-part-1/", - // "http://www.baeldung.com/2011/10/25/building-a-restful-web-service-with-spring-3-1-and-java-based-configuration-part-2/", - // "http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/", - // "http://www.baeldung.com/spring-security-basic-authentication", - // "http://www.baeldung.com/spring-security-digest-authentication", - //"http://www.baeldung.com/2011/11/20/basic-and-digest-authentication-for-a-restful-service-with-spring-security-3-1/", + "http://www.baeldung.com/2011/10/25/building-a-restful-web-service-with-spring-3-1-and-java-based-configuration-part-2/", + "http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/", + "http://www.baeldung.com/spring-security-basic-authentication", + "http://www.baeldung.com/spring-security-digest-authentication", + "http://www.baeldung.com/2011/11/20/basic-and-digest-authentication-for-a-restful-service-with-spring-security-3-1/", //"http://www.baeldung.com/spring-httpmessageconverter-rest", //"http://www.baeldung.com/2011/11/06/restful-web-service-discoverability-part-4/", //"http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/", @@ -56,6 +54,8 @@ public class ApacheFOPHeroldTest { private String xmlInput = "src/test/resources/input.xml"; private String xmlOutput = "src/test/resources/output.xml"; + // tests + @Test public void whenTransformFromHeroldToPDF_thenCorrect() throws Exception { final int len = inputUrls.length; @@ -78,7 +78,7 @@ public class ApacheFOPHeroldTest { final DocBookTransformer transformer = new DocBookTransformer(); transformer.setScript(script); - transformer.convert(getInputStream(input), new FileOutputStream(xmlInput ,append)); + transformer.convert(getInputStream(input), new FileOutputStream(xmlInput, append)); } private Document fromXMLFileToFO() throws Exception { @@ -115,19 +115,20 @@ public class ApacheFOPHeroldTest { return url.openStream(); } - private void fixXML(final String input, final String output) throws IOException{ + private void fixXML(final String input, final String output) throws IOException { final BufferedReader reader = new BufferedReader(new FileReader(input)); final FileWriter writer = new FileWriter(output); String line = reader.readLine(); int count = 0; - while(line != null){ - line = line.replaceAll("[^\\x00-\\x7F]", ""); - - if(line.contains("info>")){ + while (line != null) { + line = line.replaceAll("”", "\""); + line = line.replaceAll("“", "\""); + // line = line.replaceAll("[^\\x00-\\x7F]", ""); + + if (line.contains("info>")) { writer.write(line.replace("info>", "section>")); - } - else if(!((line.startsWith(" 4)){ - writer.write(line.replaceAll("xml:id=\"", "xml:id=\""+count)); + } else if (!((line.startsWith(" 4)) { + writer.write(line.replaceAll("xml:id=\"", "xml:id=\"" + count)); } writer.write("\n"); diff --git a/apache-fop/src/test/resources/final_output.pdf b/apache-fop/src/test/resources/final_output.pdf index d895015df0636296b9b2761d3a8637dd93d4aac2..0b12b4f2ae54a45bdc57a1c43c9e3352387bf475 100644 GIT binary patch literal 136822 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 literal 29522 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. The Maven pom.xml -     2.1. Justification of the cglib dependency +     2.1. Justification of the cglib dependency -     2.2. The cglib dependency in Spring 3.2 and beyond +     2.2. The cglib dependency in Spring 3.2 and beyond 3. The Java based web configuration -    3.1. The web.xml +    3.1. The web.xml 4. Conclusion @@ -159,9 +159,9 @@ End Shortcoder content public class AppConfig{ @Bean -   public static PropertySourcesPlaceholderConfigurer properties() { -   return new PropertySourcesPlaceholderConfigurer(); -   } +   public static PropertySourcesPlaceholderConfigurer properties() { +   return new PropertySourcesPlaceholderConfigurer(); +   } } First, the @Configuration annotation – this is the main artifact used by the Java based Spring configuration; it is itself meta-annotated with @Component, which makes the annotated classes standard beans and as such, also candidates for component scanning. The main purpose of @Configuration classes is to be sources of bean definitions for the Spring IoC Container. For a more detailed description, see the official docs. Then, @ImportResource is used to import the existing XML based Spring configuration. This may be configuration which is still being migrated from XML to Java, or simply legacy configuration that you wish to keep. Either way, importing it into the Container is essential for a successful migration, allowing small steps without to much risk. The equivalent XML annotation that is replaced is: @@ -172,7 +172,7 @@ public class AppConfig{ excludeFilters = { @ComponentScan.Filter( Configuration.class ) } The @Configuration classes should not be autodiscovered because they are already specified and used by the Container – allowing them to be rediscovered and introduced into the Spring context will result in the following error: Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘webConfig’ for bean class [org.rest.spring.AppConfig] conflicts with existing, non-compatible bean definition of same name and class [org.rest.spring.AppConfig] - And finally, using the @Bean annotation to configure the properties support – PropertySourcesPlaceholderConfigurer is initialized in a @Bean annotated method, indicating it will produce a Spring bean managed by the Container. This new configuration has replaced the following XML: + And finally, using the @Bean annotation to configure the properties support – PropertySourcesPlaceholderConfigurer is initialized in a @Bean annotated method, indicating it will produce a Spring bean managed by the Container. This new configuration has replaced the following XML: <context:property-placeholder location="classpath:persistence.properties, classpath:web.properties" ignore-unresolvable="true"/> @@ -182,12 +182,12 @@ ignore-unresolvable="true"/> <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns=" http://java.sun.com/xml/ns/javaee" -     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -    xsi:schemaLocation=" +     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" +     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +    xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -    id="rest" version="3.0"> +    id="rest" version="3.0"> <context-param> <param-name>contextClass</param-name> @@ -245,6 +245,7 @@ ignore-unresolvable="true"/> +   @@ -310,6 +311,673 @@ WP SyntaxHighlighter Ver.1.7.3 End +
+ + Build a REST API with Spring 4 and Java Config + + + + + + Return to Content + + + + + + Contents + + + Table of Contents + + + 1. Overview + + + 2. Understanding REST in Spring + + + 3. The Java configuration + + + 4. Testing the Spring context + + + 5. The Controller + + + 6. Mapping the HTTP response codes + + + 7. Additional Maven dependencies + + + 8. Conclusion + + + If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! + + +   + +
+ <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> + + + 1. Overview + + + 2. Understanding REST in Spring + + + 3. The Java configuration + + + 4. Testing the Spring context + + + 5. The Controller + + + 6. Mapping the HTTP response codes + + +     6.1. Unmapped requests + + +     6.2. Valid, mapped requests + + +     6.3. Client error + + +     6.4. Using @ExceptionHandler + + + 7. Additional Maven dependencies + + + 8. Conclusion + + +
+ <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> + This article shows how to set up REST in Spring – the Controller and HTTP response codes, configuration of payload marshalling and content negotiation. +
+
+ <anchor xml:id="dbdoclet.2_Understanding_REST_in_Spring"/><emphasis role="bold">2. Understanding REST in Spring</emphasis> + The Spring framework supports 2 ways of creating RESTful services: + + + using MVC with ModelAndView + + + using HTTP message converters + + + The ModelAndView approach is older and much better documented, but also more verbose and configuration heavy. It tries to shoehorn the REST paradigm into the old model, which is not without problems. The Spring team understood this and provided first-class REST support starting with Spring 3.0. + The new approach, based on HttpMessageConverterand annotations, is much more lightweight and easy to implement. Configuration is minimal and it provides sensible defaults for what you would expect from a RESTful service. It is however newer and a a bit on the light side concerning documentation; what’s , the reference doesn’t go out of it’s way to make the distinction and the tradeoffs between the two approaches as clear as they should be. Nevertheless, this is the way RESTful services should be build after Spring 3.0. +
+
+ <anchor xml:id="dbdoclet.3_The_Java_configuration"/><emphasis role="bold">3. The Java configuration</emphasis> + + @Configuration +@EnableWebMvc +public class WebConfig{ + // +} + The new @EnableWebMvc annotation does a number of useful things – specifically, in the case of REST, it detect the existence of Jackson and JAXB 2 on the classpath and automatically creates and registers default JSON and XML converters. The functionality of the annotation is equivalent to the XML version: + <mvc:annotation-driven /> + This is a shortcut, and though it may be useful in many situations, it’s not perfect. When more complex configuration is needed, remove the annotation and extend WebMvcConfigurationSupport directly. +
+
+ <anchor xml:id="dbdoclet.4_Testing_the_Spring_context"/><emphasis role="bold">4. Testing the Spring context</emphasis> + Starting with Spring 3.1, we get first-class testing support for @Configuration classes: + @RunWith( SpringJUnit4ClassRunner.class ) +@ContextConfiguration( classes = { ApplicationConfig.class, PersistenceConfig.class }, + loader = AnnotationConfigContextLoader.class ) +public class SpringTest{ + + @Test + public void whenSpringContextIsInstantiated_thenNoExceptions(){ + // When + } +} + The Java configuration classes are simply specified with the @ContextConfiguration annotation and the new AnnotationConfigContextLoader loads the bean definitions from the @Configuration classes. + Notice that the WebConfig configuration class was not included in the test because it needs to run in a Servlet context, which is not provided. +
+
+ <anchor xml:id="dbdoclet.5_The_Controller"/><emphasis role="bold">5. The Controller</emphasis> + The @Controller is the central artifact in the entire Web Tier of the RESTful API. For the purpose of this post, the controller is modeling a simple REST resource – Foo: + @Controller +@RequestMapping( value = "/foos" ) +class FooController{ + + @Autowired + IFooService service; + + @RequestMapping( method = RequestMethod.GET ) + @ResponseBody + public List< Foo > findAll(){ + return service.findAll(); + } + + @RequestMapping( value = "/{id}", method = RequestMethod.GET ) + @ResponseBody + public Foo findOne( @PathVariable( "id" ) Long id ){ + return RestPreconditions.checkFound( service.findOne( id ) ); + } + + @RequestMapping( method = RequestMethod.POST ) + @ResponseStatus( HttpStatus.CREATED ) + @ResponseBody + public Long create( @RequestBody Foo resource ){ + Preconditions.checkNotNull( resource ); + return service.create( resource ); + } + + @RequestMapping( value = "/{id}", method = RequestMethod.PUT ) + @ResponseStatus( HttpStatus.OK ) + public void update( @PathVariable( "id" ) Long id, @RequestBody Foo resource ){ + Preconditions.checkNotNull( resource ); + RestPreconditions.checkNotNull( service.getById( resource.getId() ) ); + service.update( resource ); + } + + @RequestMapping( value = "/{id}", method = RequestMethod.DELETE ) + @ResponseStatus( HttpStatus.OK ) + public void delete( @PathVariable( "id" ) Long id ){ + service.deleteById( id ); + } + +} + You may have noticed I’m using a very simple, guava style RestPreconditions utility: + public class RestPreconditions { + public static <T> T checkFound(final T resource) { + if (resource == null) { + throw new MyResourceNotFoundException(); + } + return resource; + } +} + The Controller implementation is non-public – this is because it doesn’t need to be. Usually the controller is the last in the chain of dependencies – it receives HTTP requests from the Spring front controller (the DispathcerServlet) and simply delegate them forward to a service layer. If there is no use case where the controller has to be injected or manipulated through a direct reference, then I prefer not to declare it as public. + The request mappings are straightforward – as with any controller, the actual value of the mapping as well as the HTTP method are used to determine the target method for the request. @RequestBody will bind the parameters of the method to the body of the HTTP request, whereas @ResponseBody does the same for the response and return type. They also ensure that the resource will be marshalled and unmarshalled using the correct HTTP converter. Content negotiation will take place to choose which one of the active converters will be used, based mostly on the Accept header, although other HTTP headers may be used to determine the representation as well. +
+
+ <anchor xml:id="dbdoclet.6_Mapping_the_HTTP_response_codes"/><emphasis role="bold">6. Mapping the HTTP response codes</emphasis> + The status codes of the HTTP response are one of the most important parts of the REST service, and the subject can quickly become very complex. Getting these right can be what makes or breaks the service. +
+ <emphasis role="bold">6.1. Unmapped requests</emphasis> + If Spring MVC receives a request which doesn’t have a mapping, it considers the request not to be allowed and returns a 405 METHOD NOT ALLOWED back to the client. It is also good practice to include the Allow HTTP header when returning a 405 to the client, in order to specify which operations are allowed. This is the standard behavior of Spring MVC and does not require any additional configuration. +
+
+ <emphasis role="bold">6.2. Valid, mapped requests</emphasis> + For any request that does have a mapping, Spring MVC considers the request valid and responds with 200 OK if no other status code is specified otherwise. It is because of this that controller declares different @ResponseStatus for the create, update and delete actions but not for get, which should indeed return the default 200 OK. +
+
+ <emphasis role="bold">6.3. Client error</emphasis> + In case of a client error, custom exceptions are defined and mapped to the appropriate error codes. Simply throwing these exceptions from any of the layers of the web tier will ensure Spring maps the corresponding status code on the HTTP response. + @ResponseStatus( value = HttpStatus.BAD_REQUEST ) +public class BadRequestException extends RuntimeException{ + // +} +@ResponseStatus( value = HttpStatus.NOT_FOUND ) +public class ResourceNotFoundException extends RuntimeException{ + // +} + These exceptions are part of the REST API and, as such, should only be used in the appropriate layers corresponding to REST; if for instance a DAO/DAL layer exist, it should not use the exceptions directly. Note also that these are not checked exceptions but runtime exceptions – in line with Spring practices and idioms. +
+
+ <emphasis role="bold">6.4. Using @ExceptionHandler</emphasis> + Another option to map custom exceptions on specific status codes is to use the @ExceptionHandler annotation in the controller. The problem with that approach is that the annotation only applies to the controller in which it is defined, not to the entire Spring Container, which means that it needs to be declared in each controller individually. This quickly becomes cumbersome, especially in more complex applications which many controllers. There are a few JIRA issues opened with Spring at this time to handle this and other related limitations: SPR-8124, SPR-7278, SPR-8406. +
+
+
+ <anchor xml:id="dbdoclet.7_Additional_Maven_dependencies"/><emphasis role="bold">7. Additional Maven dependencies</emphasis><emphasis role="bold"></emphasis> + In addition to the spring-webmvc dependency required for the standard web application, we’ll need to set up content marshalling and unmarshalling for the REST API: + <dependencies> + <dependency> +   <groupId>com.fasterxml.jackson.core</groupId> +    <artifactId>jackson-databind</artifactId> +   <version>${jackson.version}</version> + </dependency> + <dependency> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + <version>${jaxb-api.version}</version> + <scope>runtime</scope> + </dependency> +</dependencies> + +<properties> + <jackson.version>2.4.0</jackson.version> + <jaxb-api.version>2.2.11</jaxb-api.version> +</properties> + These are the libraries used to convert the representation of the REST resource to either JSON or XML. +
+
+ <anchor xml:id="dbdoclet.8_Conclusion"/><emphasis role="bold">8. Conclusion</emphasis> + This tutorial illustrated how to implement and configure a REST Service using Spring 4 and Java based configuration, discussing HTTP response codes, basic Content Negotiation and marshaling. + In the next articles of the series I will focus on Discoverability of the API, advanced content negotiation and working with additional representations of a Resource. + The implementation of this Spring REST API Tutorial can be downloaded as a working sample project. + This is an Eclipse based project, so it should be easy to import and run as it is. + + + + + + + + + + java, REST, Spring, testing + + + + + + + + + + + © 2014 Baeldung. All Rights Reserved. + + + + + + + + + +
+
+
+ +
+ + Spring Security for a REST API + + + + + + Return to Content + + + + + + Contents + + + Table of Contents + + + 1. Overview + + + 2. Spring Security in the web.xml + + + 3. The Security Configuration + + + 4. Maven and other trouble + + + 5. Conclusion + + + + + +
+ <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> + + + 1. Overview + + + 2. Introducing Spring Security in the web.xml + + + 3. The Security Configuration + + +     3.1. The basics + + +     3.2. The Entry Point + + +     3.3. The Login + + +     3.4. Authentication should return 200 instead of 301 + + +     3.5. Failed Authentication should return 401 instead of 302 + + +     3.6. The Authentication Manager and Provider + + +     3.7. Finally – Authentication against the running REST Service + + + 4. Maven and other trouble + + + 5. Conclusion + + +
+ <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> + This tutorial shows how to Secure a REST Service using Spring and Spring Security 3.1 with Java based configuration. The article will focus on how to set up the Security Configuration specifically for the REST API using a Login and Cookie approach. +
+
+ <anchor xml:id="dbdoclet.2_Spring_Security_in_the_webxml"/><emphasis role="bold">2. Spring Security in the web.xml</emphasis> + The architecture of Spring Security is based entirely on Servlet Filters and, as such, comes before Spring MVC in regards to the processing of HTTP requests. Keeping this in mind, to begin with, a filter needs to be declared in the web.xml of the application: + <filter> + <filter-name>springSecurityFilterChain</filter-name> + <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> +</filter> +<filter-mapping> + <filter-name>springSecurityFilterChain</filter-name> + <url-pattern>/*</url-pattern> +</filter-mapping> + The filter must necessarily be named ‘springSecurityFilterChain’  to match the default bean created by Spring Security in the container. + Note that the defined filter is not the actual class implementing the security logic but a DelegatingFilterProxy with the purpose of delegating the Filter’s methods to an internal bean. This is done so that the target bean can still benefit from the Spring context lifecycle and flexibility. + The URL pattern used to configure the Filter is /* even though the entire web service is mapped to /api/* so that the security configuration has the option to secure other possible mappings as well, if required. +
+
+ <anchor xml:id="dbdoclet.3_The_Security_Configuration"/><emphasis role="bold">3. The Security Configuration</emphasis> + <?xml version="1.0" encoding="UTF-8"?> +<beans:beans + xmlns="http://www.springframework.org/schema/security" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:beans="http://www.springframework.org/schema/beans" + xmlns:sec="http://www.springframework.org/schema/security" + xsi:schemaLocation=" + http://www.springframework.org/schema/security + http://www.springframework.org/schema/security/spring-security-3.2.xsd + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> + + <http entry-point-ref="restAuthenticationEntryPoint"> + <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN"/> + + <form-login + authentication-success-handler-ref="mySuccessHandler" + authentication-failure-handler-ref="myFailureHandler" + /> + + <logout /> + </http> + + <beans:bean id="mySuccessHandler" + class="org.rest.security.MySavedRequestAwareAuthenticationSuccessHandler"/> + <beans:bean id="myFailureHandler" + class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/> + + <authentication-manager alias="authenticationManager"> + <authentication-provider> + <user-service> + <user name="temporary" password="temporary" authorities="ROLE_ADMIN"/> + <user name="user" password="user" authorities="ROLE_USER"/> + </user-service> + </authentication-provider> + </authentication-manager> + +</beans:beans> + Most of the configuration is done using the security namespace – for this to be enabled, the schema locations must be defined and pointed to the correct 3.1 or 3.2 XSD versions. The namespace is designed so that it expresses the common uses of Spring Security while still providing hooks raw beans to accommodate more advanced scenarios. >> Signup for my upcoming Video Course on Building a REST API with Spring 4 +
+ <emphasis role="bold">3.1. The <http> element</emphasis> + The <http> element is the main container element for HTTP security configuration. In the current implementation, it only secured a single mapping: /api/admin/**. Note that the mapping is relative to the root context of the web application, not to the rest Servlet; this is because the entire security configuration lives in the root Spring context and not in the child context of the Servlet. +
+
+ <emphasis role="bold">3.2. The Entry Point</emphasis> + In a standard web application, the authentication process may be automatically triggered when the client tries to access a secured resource without being authenticated – this is usually done by redirecting to a login page so that the user can enter credentials. However, for a REST Web Service this behavior doesn’t make much sense – Authentication should only be done by a request to the correct URI and all other requests should simply fail with a 401 UNAUTHORIZED status code if the user is not authenticated. + Spring Security handles this automatic triggering of the authentication process with the concept of an Entry Point – this is a required part of the configuration, and can be injected via the entry-point-ref attribute of the <http> element. Keeping in mind that this functionality doesn’t make sense in the context of the REST Service, the new custom entry point is defined to simply return 401 whenever it is triggered: + @Component( "restAuthenticationEntryPoint" ) +public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{ + + @Override + public void commence( HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException ) throws IOException{ + response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" ); + } +} + A quick sidenote here is that the 401 is sent without the WWW-Authenticate header, as required by the HTTP Spec – we can of course set the value manually if we need to. +
+
+ <emphasis role="bold">3.3. The Login Form for REST</emphasis> + There are multiple ways to do Authentication for a REST API – one of the default Spring Security provides is Form Login – which uses an authentication processing filter – org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter. + The <form-login> element will create this filter and will also allow us to set our custom authentication success handler on it. This can also be done manually by using the <custom-filter> element to register a filter at the position FORM_LOGIN_FILTER – but the namespace support is flexible enough. + Note that for a standard web application, the auto-config attribute of the <http> element is shorthand syntax for some useful security configuration. While this may be appropriate for some very simple configurations, it doesn’t fit and should not be used for a REST API. +
+
+ <emphasis role="bold">3.4. Authentication should return 200 instead of 301</emphasis> + By default, form login will answer a successful authentication request with a 301 MOVED PERMANENTLY status code; this makes sense in the context of an actual login form which needs to redirect after login. For a RESTful web service however, the desired response for a successful authentication should be 200 OK. + This is done by injecting a custom authentication success handler in the form login filter, to replace the default one. The new handler implements the exact same login as the default org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler with one notable difference – the redirect logic is removed: + public class MySavedRequestAwareAuthenticationSuccessHandler + extends SimpleUrlAuthenticationSuccessHandler { + + private RequestCache requestCache = new HttpSessionRequestCache(); + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws ServletException, IOException { + SavedRequest savedRequest = requestCache.getRequest(request, response); + + if (savedRequest == null) { + clearAuthenticationAttributes(request); + return; + } + String targetUrlParam = getTargetUrlParameter(); + if (isAlwaysUseDefaultTargetUrl() || + (targetUrlParam != null && + StringUtils.hasText(request.getParameter(targetUrlParam)))) { + requestCache.removeRequest(request, response); + clearAuthenticationAttributes(request); + return; + } + + clearAuthenticationAttributes(request); + } + + public void setRequestCache(RequestCache requestCache) { + this.requestCache = requestCache; + } +} +
+
+ <emphasis role="bold">3.5. Failed Authentication should return 401 instead of 302</emphasis> + Similarly – we configured the authentication failure handler – same way we did with the success handler. + Luckily – in this case, we don’t need to actually define a new class for this handler – the standard implementation – SimpleUrlAuthenticationFailureHandler – does just fine. + The only difference is that – now that we’re defining this explicitly in our XML config – it’s not going to get a default defaultFailureUrl from Spring – and so it won’t redirect. +
+
+ <emphasis role="bold">3.6. The Authentication Manager and Provider</emphasis> + The authentication process uses an in-memory provider to perform authentication – this is meant to simplify the configuration as a production implementation of these artifacts is outside the scope of this post. +
+
+ <emphasis role="bold">3.7 Finally – Authentication against the running REST Service</emphasis> + Now let’s see how we can authenticate against the REST API – the URL for login is /j_spring_security_check – and a simple curl command performing login would be: + curl -i -X POST -d j_username=user -d j_password=userPass +http://localhost:8080/spring-security-rest/j_spring_security_check + This request will return the Cookie which will then be used by any subsequent request against the REST Service. + We can use curl to authentication and store the cookie it receives in a file: + curl -i -X POST -d j_username=user -d j_password=userPass -c /opt/cookies.txt +http://localhost:8080/spring-security-rest/j_spring_security_check + Then we can use the cookie from the file to do further authenticated requests: + curl -i --header "Accept:application/json" -X GET -b /opt/cookies.txt +http://localhost:8080/spring-security-rest/api/foos + This authenticated request will correctly result in a 200 OK: + HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Content-Type: application/json;charset=UTF-8 +Transfer-Encoding: chunked +Date: Wed, 24 Jul 2013 20:31:13 GMT + +[{"id":0,"name":"JbidXc"}] +
+
+
+ <anchor xml:id="dbdoclet.4_Maven_and_other_trouble"/><emphasis role="bold">4. Maven and other trouble</emphasis> + The Spring core dependencies necessary for a web application and for the REST Service have been discussed in detail. For security, we’ll need to add: spring-security-web and spring-security-config – all of these have also been covered in the Maven for Spring Security tutorial. + It’s worth paying close attention to the way Maven will resolve the older Spring dependencies – the resolution strategy will start causing problems once the security artifacts are added to the pom. To address this problem, some of the core dependencies will need to be overridden in order to keep them at the right version. +
+
+ <anchor xml:id="dbdoclet.5_Conclusion"/><emphasis role="bold">5. Conclusion</emphasis> + This post covered the basic security configuration and implementation for a RESTful Service using Spring Security 3.1, discussing the web.xml, the security configuration, the HTTP status codes for the authentication process and the Maven resolution of the security artifacts. + The implementation of this Spring Security REST Tutorial can be downloaded as a working sample project.This is an Eclipse based project, so it should be easy to import and run as it is. + + + + + + + + + + REST, security, Spring + + + + + + + + + + + © 2014 Baeldung. All Rights Reserved. + + + + + + + + + +
+
+
+
Spring Security Basic Authentication @@ -456,7 +1124,7 @@ public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoi
<anchor xml:id="dbdoclet.6_Conclusion"/><emphasis role="bold">6. Conclusion</emphasis> In this example we secured an MVC application with Spring Security and Basic Authentication. We discussed the XML configuration and we consumed the application with simple curl commands. Finally took control of the exact error message format – moving from the standard HTML error page to a custom text or json format. - The implementation of this Spring tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is. When the project runs locally, the sample html can be accessed at: + The implementation of this Spring tutorial can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is. When the project runs locally, the sample html can be accessed at: http://localhost:8080/spring-security-mvc-basic-auth/homepage.html -
- <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. Page as Resource vs Page as Representation - - - 3. The Controller - - - 4. Discoverability for REST pagination - - - 5. Test Driving Pagination - - - 6. Test Driving Pagination Discoverability - - - 7. Getting All Resources - - - 8. REST Paging with Range HTTP headers - - - 9. Conclusion - - -
- <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - This tutorial will focus on the implementation of pagination in a REST API, using Spring MVC and Spring Data. +
+ <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> + This tutorial shows how to set up, configure and customize Digest Authentication with Spring. Similar to the previous article covering Basic Authentication, we’re going to built on top of the Spring MVC tutorial, and secure the application with the Digest Auth mechanism provided by Spring Security. +
+ <anchor xml:id="dbdoclet.2_The_Security_XML_Configuration"/><emphasis role="bold">2. The Security XML Configuration</emphasis> + First thing to understand about the configuration is that, while Spring Security does have full out of the box support for the Digest authentication mechanism, this support is not as well integrated into the namespace as Basic Authentication was. + In this case, we need to manually define the raw beans that are going to make up the security configuration – the DigestAuthenticationFilter and the DigestAuthenticationEntryPoint: + <?xml version="1.0" encoding="UTF-8"?> +<beans:beans xmlns="http://www.springframework.org/schema/security" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:beans="http://www.springframework.org/schema/beans" + xsi:schemaLocation=" + http://www.springframework.org/schema/security + http://www.springframework.org/schema/security/spring-security-3.1.xsd + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> + +    <beans:bean id="digestFilter" + class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> +        <beans:property name="userDetailsService" ref="userService" /> +        <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" /> +    </beans:bean> +    <beans:bean id="digestEntryPoint"  + class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"> +        <beans:property name="realmName" value="Contacts Realm via Digest Authentication" /> +        <beans:property name="key" value="acegi" /> +    </beans:bean> + + <!-- the security namespace configuration --> + <http use-expressions="true" entry-point-ref="digestEntryPoint"> + <intercept-url pattern="/**" access="isAuthenticated()" /> + + <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" /> + </http> + + <authentication-manager> + <authentication-provider> + <user-service id="userService"> + <user name="user1" password="user1Pass" authorities="ROLE_USER" /> + </user-service> + </authentication-provider> + </authentication-manager> + +</beans:beans> + Next, we need to integrate these beans into the overall security configuration – and in this case, the namespace is still flexible enough to allow us to do that. + The first part of this is pointing to the custom entry point bean, via the entry-point-ref attribute of the main <http> element. + The second part is adding the newly defined digest filter into the security filter chain. Since this filter is functionally equivalent to the BasicAuthenticationFilter, we are using the same relative position in the chain – this is specified by the BASIC_AUTH_FILTER alias in the overall Spring Security Standard Filters. + Finally, notice that the Digest Filter is configured to point to the user service bean – and here, the namespace is again very useful as it allows us to specify a bean name for the default user service created by the <user-service> element: + <user-service id="userService">
-
- <anchor xml:id="dbdoclet.2_Page_as_Resource_vs_Page_as_Representation"/><emphasis role="bold">2. Page as Resource vs Page as Representation</emphasis> - The first question when designing pagination in the context of a RESTful architecture is whether to consider the page an actual Resource or just a Representation of Resources. - Treating the page itself as a resource introduces a host of problems such as no longer being able to uniquely identify resources between calls. This, coupled with the fact that, in the persistence layer, the page is not proper entity but a holder that is constructed when necessary, makes the choice straightforward: the page is part of the representation. - The next question in the pagination design in the context of REST is where to include the paging information: - - - in the URI path: /foo/page/1 - - - the URI query: /foo?page=1 - - - Keeping in mind that a page is not a Resource, encoding the page information in the URI is no longer an option. - We are going to use the standard way of solving this problem by encoding the paging information in a URI query. +
+ <anchor xml:id="dbdoclet.3_Consuming_the_Secured_Application"/><emphasis role="bold">3. Consuming the Secured Application</emphasis> + We’re going to be using the curl command to consume the secured application and understand how a client can interact with it. + Let’s start by requesting the homepage – without providing security credentials in the request: + curl -i http://localhost/spring-security-mvc-digest-auth/homepage.html + As expected, we get back a response with a 401 Unauthorized status code: + HTTP/1.1 401 Unauthorized +Server: Apache-Coyote/1.1 +Set-Cookie: JSESSIONID=CF0233C...; Path=/spring-security-mvc-digest-auth/; HttpOnly +WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth", + nonce="MTM3MzYzODE2NTg3OTo3MmYxN2JkOWYxZTc4MzdmMzBiN2Q0YmY0ZTU0N2RkZg==" +Content-Type: text/html;charset=utf-8 +Content-Length: 1061 +Date: Fri, 12 Jul 2013 14:04:25 GMT + If this request were sent by the browser, the authentication challenge would prompt the user for credentials using a simple user/password dialog. + Let’s now provide the correct credentials and send the request again: + curl -i --digest --user + user1:user1Pass http://localhost/spring-security-mvc-digest-auth/homepage.html + Notice that we are enabling Digest Authentication for the curl command via the –digest flag. + The first response from the server will be the same – the 401 Unauthorized – but the challenge will now be interpreted and acted upon by a second request – which will succeed with a 200 OK: + HTTP/1.1 401 Unauthorized +Server: Apache-Coyote/1.1 +Set-Cookie: JSESSIONID=A961E0D...; Path=/spring-security-mvc-digest-auth/; HttpOnly +WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="auth", + nonce="MTM3MzYzODgyOTczMTo3YjM4OWQzMGU0YTgwZDg0YmYwZjRlZWJjMDQzZWZkOA==" +Content-Type: text/html;charset=utf-8 +Content-Length: 1061 +Date: Fri, 12 Jul 2013 14:15:29 GMT + +HTTP/1.1 200 OK +Server: Apache-Coyote/1.1 +Set-Cookie: JSESSIONID=55F996B...; Path=/spring-security-mvc-digest-auth/; HttpOnly +Content-Type: text/html;charset=ISO-8859-1 +Content-Language: en-US +Content-Length: 90 +Date: Fri, 12 Jul 2013 14:15:29 GMT + +<html> +<head></head> + +<body> + <h1>This is the homepage</h1> +</body> +</html> + A final note on this interaction is that a client can preemptively send the correct Authorization header with the first request, and thus entirely avoid the server security challenge and the second request.
-
- <anchor xml:id="dbdoclet.3_The_Controller"/><emphasis role="bold">3. The Controller</emphasis> - Now, for the  implementation – the Spring MVC Controller for pagination is straightforward: - @RequestMapping( value = "admin/foo",params = { "page", "size" },method = GET ) -@ResponseBody -public List< Foo > findPaginated( - @RequestParam( "page" ) int page, @RequestParam( "size" ) int size, - UriComponentsBuilder uriBuilder, HttpServletResponse response ){ - - Page< Foo > resultPage = service.findPaginated( page, size ); - if( page > resultPage.getTotalPages() ){ - throw new ResourceNotFoundException(); - } - eventPublisher.publishEvent( new PaginatedResultsRetrievedEvent< Foo > - ( Foo.class, uriBuilder, response, page, resultPage.getTotalPages(), size ) ); - - return resultPage.getContent(); -} - The two query parameters are injected into the Controller method via @RequestParam. - We’re also injecting both the Http Response and the UriComponentsBuilder to help with Discoverability – which we are decoupling via a custom event. If that is not a goal of the API, you can simply remove the custom event and be done. - Finally – note that the focus of this article is only the REST and the web layer – to go deeper into the data access part of pagination you can check out this article about Pagination with Spring Data. -
-
- <anchor xml:id="dbdoclet.4_Discoverability_for_REST_pagination"/><emphasis role="bold">4. Discoverability for REST pagination</emphasis> - Withing the scope of pagination, satisfying the HATEOAS constraint of REST means enabling the client of the API to discover the next and previous pages based on the current page in the navigation. For this purpose, we’re going to use the Link HTTP header, coupled with the official “next“, “prev“, “first” and “last” link relation types. - In REST, Discoverability is a cross cutting concern, applicable not only to specific operations but to types of operations. For example, each time a Resource is created, the URI of that Resource should be discoverable by the client. Since this requirement is relevant for the creation of ANY Resource, it should be dealt with separately and decoupled from the main Controller flow. - With Spring, this decoupling is done with Events, as was thoroughly discussed in the previous article focusing on Discoverability of a REST Service. In the case of pagination, the event – PaginatedResultsRetrievedEvent – is fired in the controller layer, and discoverability is implemented with a custom listener for this event: - void addLinkHeaderOnPagedResourceRetrieval( - UriComponentsBuilder uriBuilder, HttpServletResponse response, - Class clazz, int page, int totalPages, int size ){ - - String resourceName = clazz.getSimpleName().toString().toLowerCase(); - uriBuilder.path( "/admin/" + resourceName ); - - StringBuilder linkHeader = new StringBuilder(); - if( hasNextPage( page, totalPages ) ){ - String uriNextPage = constructNextPageUri( uriBuilder, page, size ); - linkHeader.append( createLinkHeader( uriNextPage, "next" ) ); - } - if( hasPreviousPage( page ) ){ - String uriPrevPage = constructPrevPageUri( uriBuilder, page, size ); - appendCommaIfNecessary( linkHeader ); - linkHeader.append( createLinkHeader( uriPrevPage, "prev" ) ); - } - if( hasFirstPage( page ) ){ - String uriFirstPage = constructFirstPageUri( uriBuilder, size ); - appendCommaIfNecessary( linkHeader ); - linkHeader.append( createLinkHeader( uriFirstPage, "first" ) ); - } - if( hasLastPage( page, totalPages ) ){ - String uriLastPage = constructLastPageUri( uriBuilder, totalPages, size ); - appendCommaIfNecessary( linkHeader ); - linkHeader.append( createLinkHeader( uriLastPage, "last" ) ); - } - response.addHeader( "Link", linkHeader.toString() ); -} - In short, the listener checks if the navigation allows for a next, previous, first and last pages and – if it does – adds the relevant URIs to the Link HTTP Header. - Note that, for brevity, I included only a partial code sample and the full code here. -
-
- <anchor xml:id="dbdoclet.5_Test_Driving_Pagination"/><emphasis role="bold">5. Test Driving Pagination</emphasis> - Both the main logic of pagination and discoverability are covered by small, focused integration tests; as in the previous article, the rest-assured library is used to consume the REST service and to verify the results. - These are a few example of pagination integration tests; for a full test suite, check out the github project (link at the end of the article): - @Test -public void whenResourcesAreRetrievedPaged_then200IsReceived(){ - Response response = givenAuth().get( paths.getFooURL() + "?page=0&size=2" ); - - assertThat( response.getStatusCode(), is( 200 ) ); -} -@Test -public void whenPageOfResourcesAreRetrievedOutOfBounds_then404IsReceived(){ - String url = getFooURL() + "?page=" + randomNumeric(5) + "&size=2"; -   Response response = givenAuth().get(url); - - assertThat( response.getStatusCode(), is( 404 ) ); -} -@Test -public void givenResourcesExist_whenFirstPageIsRetrieved_thenPageContainsResources(){ - createResource(); - - Response response = givenAuth().get( paths.getFooURL() + "?page=0&size=2" ); - - assertFalse( response.body().as( List.class ).isEmpty() ); -} -
-
- <anchor xml:id="dbdoclet.6_Test_Driving_Pagination_Discoverability"/><emphasis role="bold">6. Test Driving Pagination Discoverability</emphasis> - Testing that pagination is discoverable by a client is relatively straightforward, although there is a lot of ground to cover. The tests are focused on the position of the current page in navigation and the different URIs that should be discoverable from each position: - @Test -public void whenFirstPageOfResourcesAreRetrieved_thenSecondPageIsNext(){ - Response response = givenAuth().get( getFooURL()+"?page=0&size=2" ); - - String uriToNextPage = extractURIByRel( response.getHeader( "Link" ), "next" ); - assertEquals( getFooURL()+"?page=1&size=2", uriToNextPage ); -} -@Test -public void whenFirstPageOfResourcesAreRetrieved_thenNoPreviousPage(){ - Response response = givenAuth().get( getFooURL()+"?page=0&size=2" ); - - String uriToPrevPage = extractURIByRel( response.getHeader( "Link" ), "prev" ); - assertNull( uriToPrevPage ); -} -@Test -public void whenSecondPageOfResourcesAreRetrieved_thenFirstPageIsPrevious(){ - Response response = givenAuth().get( getFooURL()+"?page=1&size=2" ); - - String uriToPrevPage = extractURIByRel( response.getHeader( "Link" ), "prev" ); - assertEquals( getFooURL()+"?page=0&size=2", uriToPrevPage ); -} -@Test -public void whenLastPageOfResourcesIsRetrieved_thenNoNextPageIsDiscoverable(){ - Response first = givenAuth().get( getFooURL()+"?page=0&size=2" ); - String uriToLastPage = extractURIByRel( first.getHeader( "Link" ), "last" ); - - Response response = givenAuth().get( uriToLastPage ); - - String uriToNextPage = extractURIByRel( response.getHeader( "Link" ), "next" ); - assertNull( uriToNextPage ); -} - Note that the full low level code for extractURIByRel – responsible for extracting the URIs by rel relation is here. -
-
- <anchor xml:id="dbdoclet.7_Getting_All_Resources"/><emphasis role="bold">7. Getting All Resources</emphasis> - On the same topic of pagination and discoverability, the choice must be made if a client is allowed to retrieve all the Resources in the system at once, or if the client MUST ask for them paginated. If the choice is made that the client cannot retrieve all Resources with a single request, and pagination is not optional but required, then several options are available for the response to a get all request. One option is to return a 404 (Not Found) and use the Link header to make the first page discoverable: -
- Link=<http://localhost:8080/rest/api/admin/foo?page=0&size=2>; rel=”first“, <http://localhost:8080/rest/api/admin/foo?page=103&size=2>; rel=”last -
- Another option is to return redirect – 303 (See Other) – to the first page. A more conservative route would be to simply return to the client a 405 (Method Not Allowed) for the GET request. -
-
- <anchor xml:id="dbdoclet.8_REST_Paging_with_Range_HTTP_headers"/><emphasis role="bold">8. REST Paging with Range HTTP headers</emphasis> - A relatively different way of implementing pagination is to work with the HTTP Range headersRange, Content-Range, If-Range, Accept-Ranges – and HTTP status codes – 206 (Partial Content), 413 (Request Entity Too Large), 416 (Requested Range Not Satisfiable). One view on this approach is that the HTTP Range extensions were not intended for pagination, and that they should be managed by the Server, not by the Application. Implementing pagination based on the HTTP Range header extensions is nevertheless technically possible, although not nearly as common as the implementation discussed in this article. +
+ <anchor xml:id="dbdoclet.4_The_Maven_Dependencies"/><emphasis role="bold">4. The Maven Dependencies</emphasis> + The security dependencies are discussed in depth in the Spring Security Maven tutorial. In short, we will need to define spring-security-web and spring-security-config as dependencies in our pom.xml.
- <anchor xml:id="dbdoclet.9_Conclusion"/><emphasis role="bold">9. Conclusion</emphasis> - This tutorial illustrated how to implement Pagination in a REST API using Spring, and discussed how to set up and test Discoverability. - If you want to go in depth on pagination in the persistence level, check out my JPA or Hibernate pagination tutorials. - The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is. + <anchor xml:id="dbdoclet.5_Conclusion"/><emphasis role="bold">5. Conclusion</emphasis> + In this tutorial we introduce security into a simple Spring MVC project by leveraging the Digest Authentication support in the framework. + The implementation of these examples can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is. + When the project runs locally, the homepage html can be accessed at (or, with minimal Tomcat configuration, on port 80): + http://localhost:8080/spring-security-mvc-digest-auth/homepage.html + Finally, there is no reason an application needs to choose between Basic and Digest authentication – both can be set up simultaneously on the same URI structure, in such a way that the client can pick between the two mechanisms when consuming the web application. @@ -797,7 +1368,263 @@ End OptinSkin - HATEOAS, java, REST, testing + security, Spring + + + + + + + + + + + © 2014 Baeldung. All Rights Reserved. + + + + + + + +
+
+
+ +
+ + Basic and Digest Authentication for a REST Service with Spring Security + + + + + + Return to Content + + + + + + Contents + + + Table of Contents + + + 1. Overview + + + 2. Configuration of Basic Authentication + + + 3. Configuration of Digest Authentication + + + 4. Supporting both authentication protocols in the same RESTful service + + + 5. Testing both scenarios + + + 6. Conclusion + + + If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! + + + +
+ <anchor xml:id="Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> + + + 1. Overview + + + 2. Configuration of Basic Authentication + + +     2.1. Satisfying the stateless constraint – getting rid of sessions + + + 3. Configuration of Digest Authentication + + + 4. Supporting both authentication protocols in the same RESTful service + + +     4.1. Anonymous request + + +     4.2. Request with authentication credentials + + + 5. Testing both scenarios + + + 6. Conclusion + + +
+ <anchor xml:id="dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> + This article discusses how to set up both Basic and Digest Authentication on the same URI structure of a REST API. In a previous article, we discussed another method of securing the REST Service – form based authentication, so Basic and Digest authentication is the natural alternative, as well as the more RESTful one. +
+
+ <anchor xml:id="dbdoclet.2_Configuration_of_Basic_Authentication"/><emphasis role="bold">2. Configuration of Basic Authentication</emphasis> + The main reason that form based authentication is not ideal for a RESTful Service is that Spring Security will make use of Sessions – this is of course state on the server, so the statelessness constraints in REST is practically ignored. + We’ll start by setting up Basic Authentication – first we remove the old custom entry point and filter from the main <http> security element: + <http create-session="stateless"> + <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" /> + + <http-basic /> +</http> + Note how support for basic authentication has been added with a single configuration line – <http-basic /> – which handles the creation and wiring of both the BasicAuthenticationFilter and the BasicAuthenticationEntryPoint. +
+ <emphasis role="bold">2.1. Satisfying the stateless constraint – getting rid of sessions</emphasis> + One of the main constraints of the RESTful architectural style is that the client-server communication is fully stateless, as the original dissertation reads: +
+     5.1.3 Stateless + We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client. +
+ The concept of Session on the server is one with a long history in Spring Security, and removing it entirely has been difficult until now, especially when configuration was done by using the namespace. However, Spring Security 3.1 augments the namespace configuration with a new stateless option for session creation, which effectively guarantees that no session will be created or used by Spring. What this new option does is completely removes all session related filters from the security filter chain, ensuring that authentication is performed for each request. +
+
+
+ <anchor xml:id="dbdoclet.3_Configuration_of_Digest_Authentication"/><emphasis role="bold">3. Configuration of Digest Authentication</emphasis> + Starting with the previous configuration, the filter and entry point necessary to set up digest authentication will be defined as beans. Then, the digest entry point will override the one created by <http-basic> behind the scenes. Finally, the custom digest filter will be introduced in the security filter chain using the after semantics of the security namespace to position it directly after the basic authentication filter. + <http create-session="stateless" entry-point-ref="digestEntryPoint"> + <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" /> + + <http-basic /> + <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" /> +</http> + +<beans:bean id="digestFilter" class= + "org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> + <beans:property name="userDetailsService" ref="userService" /> + <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" /> +</beans:bean> + +<beans:bean id="digestEntryPoint" class= + "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint"> + <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/> + <beans:property name="key" value="acegi" /> +</beans:bean> + +<authentication-manager> + <authentication-provider> + <user-service id="userService"> + <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" /> + <user name="user" password="user" authorities="ROLE_USER" /> + </user-service> + </authentication-provider> +</authentication-manager> + Unfortunately there is no support in the security namespace to automatically configure the digest authentication the way basic authentication can be configured with <http-basic>. Because of that, the necessary beans had to be defined and wired manually into the security configuration. +
+
+ <anchor xml:id="dbdoclet.4_Supporting_both_authentication_protocols_in_the_same_RESTful_service"/><emphasis role="bold">4. Supporting both authentication protocols in the same RESTful service</emphasis> + Basic or Digest authentication alone can be easily implemented in Spring Security 3.x; it is supporting both of them for the same RESTful web service, on the same URI mappings that introduces a new level of complexity into the configuration and testing of the service. +
+ <emphasis role="bold">4.1. Anonymous request</emphasis> + With both basic and digest filters in the security chain, the way a anonymous request – a request containing no authentication credentials (Authorization HTTP header) – is processed by Spring Security is – the two authentication filters will find no credentials and will continue execution of the filter chain. Then, seeing how the request wasn’t authenticated, an AccessDeniedException is thrown and caught in the ExceptionTranslationFilter, which commences the digest entry point, prompting the client for credentials. + The responsibilities of both the basic and digest filters are very narrow – they will continue to execute the security filter chain if they are unable to identify the type of authentication credentials in the request. It is because of this that Spring Security can have the flexibility to be configured with support for multiple authentication protocols on the same URI. + When a request is made containing the correct authentication credentials – either basic or digest – that protocol will be rightly used. However, for an anonymous request, the client will get prompted only for digest authentication credentials. This is because the digest entry point is configured as the main and single entry point of the Spring Security chain; as such digest authentication can be considered the default. +
+
+ <emphasis role="bold">4.2. Request with authentication credentials</emphasis> + A request with credentials for Basic authentication will be identified by the Authorization header starting with the prefix “Basic”. When processing such a request, the credentials will be decoded in the basic authentication filter and the request will be authorized. Similarly, a request with credentials for Digest authentication will use the prefix “Digest”  for it’s Authorization header. +
+
+
+ <anchor xml:id="dbdoclet.5_Testing_both_scenarios"/><emphasis role="bold">5. Testing both scenarios</emphasis> + The tests will consume the REST service by creating a new resource after authenticating with either basic or digest: + @Test +public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){ + // Given + // When + Response response = given() + .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD ) + .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) + .post( paths.getFooURL() ); + + // Then + assertThat( response.getStatusCode(), is( 201 ) ); +} +@Test +public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){ + // Given + // When + Response response = given() + .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD ) + .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) ) + .post( paths.getFooURL() ); + + // Then + assertThat( response.getStatusCode(), is( 201 ) ); +} + Note that the test using basic authentication adds credentials to the request preemptively, regardless if the server has challenged for authentication or not. This is to ensure that the server doesn’t need to challenge the client for credentials, because if it did, the challenge would be for Digest credentials, since that is the default. +
+
+ <anchor xml:id="dbdoclet.6_Conclusion"/><emphasis role="bold">6. Conclusion</emphasis> + This article covered the configuration and implementation of both Basic and Digest authentication for a RESTful service, using mostly Spring Security 3.0 namespace support as well as some new features added by Spring Security 3.1. + For the full implementation, check out the github project. + + + + + + + + + + REST, security, Spring diff --git a/apache-fop/src/test/resources/output-doha.xml b/apache-fop/src/test/resources/output-doha.xml deleted file mode 100644 index 9b390534f0..0000000000 --- a/apache-fop/src/test/resources/output-doha.xml +++ /dev/null @@ -1,313 +0,0 @@ - -
-
- Bootstrap a Web Application with Spring 4 -
- - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. The Maven pom.xml - - - 3. The Java based Web Configuration - - - 4. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="50Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. The Maven pom.xml - - -     2.1. Justification of the cglib dependency - - -     2.2. The cglib dependency in Spring 3.2 and beyond - - - 3. The Java based web configuration - - -    3.1. The web.xml - - - 4. Conclusion - - -
- <anchor xml:id="75dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - The tutorial illustrates how to Bootstrap a Web Application with Spring and also discusses how to make the jump from XML to Java without having to completely migrate the entire XML configuration. -
-
- <anchor xml:id="79dbdoclet.2_The_Maven_pomxml"/><emphasis role="bold">2. The Maven pom.xml</emphasis> - <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://maven.apache.org/POM/4.0.0 - http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org</groupId> - <artifactId>rest</artifactId> - <version>0.0.1-SNAPSHOT</version> - <packaging>war</packaging> - - <dependencies> - - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-webmvc</artifactId> - <version>${spring.version}</version> - <exclusions> - <exclusion> - <artifactId>commons-logging</artifactId> - <groupId>commons-logging</groupId> - </exclusion> - </exclusions> - </dependency> - - </dependencies> - - <build> - <finalName>rest</finalName> - - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.6</source> - <target>1.6</target> - <encoding>UTF-8</encoding> - </configuration> - </plugin> - </plugins> - </build> - - <properties> - <spring.version>4.0.5.RELEASE</spring.version> - </properties> - -</project> -
- <emphasis role="bold">2.1. The cglib dependency before Spring 3.2</emphasis> - You may wonder why cglib is a dependency – it turns out there is a valid reason to include it – the entire configuration cannot function without it. If removed, Spring will throw: - Caused by: java.lang.IllegalStateException: CGLIB is required to process @Configuration classes. Either add CGLIB to the classpath or remove the following @Configuration bean definitions - The reason this happens is explained by the way Spring deals with @Configuration classes. These classes are effectively beans, and because of this they need to be aware of the Context, and respect scope and other bean semantics. This is achieved by dynamically creating a cglib proxy with this awareness for each @Configuration class, hence the cglib dependency. - Also, because of this, there are a few restrictions for Configuration annotated classes: - - - Configuration classes should not be final - - - They should have a constructor with no arguments - - -
-
- <emphasis role="bold">2.2. The cglib dependency in Spring 3.2 and beyond</emphasis> - Starting with Spring 3.2, it is no longer necessary to add cglib as an explicit dependency. This is because Spring is in now inlining cglib – which will ensure that all class based proxying functionality will work out of the box with Spring 3.2. - The new cglib code is placed under the Spring package: org.springframework.cglib (replacing the original net.sf.cglib). The reason for the package change is to avoid conflicts with any cglib versions already existing on the classpath. - Also, the new cglib 3.0 is now used, upgraded from the older 2.2 dependency (see this JIRA issue for more details). - Finally, now that Spring 4.0 is out in the wild, changes like this one (removing the cglib dependency) are to be expected with Java 8 just around the corner – you can watch this Spring Jira to keep track of the Spring support, and the Java 8 Resources page to keep tabs on the that. -
-
-
- <anchor xml:id="153dbdoclet.3_The_Java_based_Web_Configuration"/><emphasis role="bold">3. The Java based Web Configuration</emphasis> - @Configuration -@ImportResource( { "classpath*:/rest_config.xml" } ) -@ComponentScan( basePackages = "org.rest" ) -@PropertySource({ "classpath:rest.properties", "classpath:web.properties" }) -public class AppConfig{ - - @Bean -   public static PropertySourcesPlaceholderConfigurer properties() { -   return new PropertySourcesPlaceholderConfigurer(); -   } -} - First, the @Configuration annotation – this is the main artifact used by the Java based Spring configuration; it is itself meta-annotated with @Component, which makes the annotated classes standard beans and as such, also candidates for component scanning. The main purpose of @Configuration classes is to be sources of bean definitions for the Spring IoC Container. For a more detailed description, see the official docs. - Then, @ImportResource is used to import the existing XML based Spring configuration. This may be configuration which is still being migrated from XML to Java, or simply legacy configuration that you wish to keep. Either way, importing it into the Container is essential for a successful migration, allowing small steps without to much risk. The equivalent XML annotation that is replaced is: - <import resource=”classpath*:/rest_config.xml” /> - Moving on to @ComponentScan – this configures the component scanning directive, effectively replacing the XML: - <context:component-scan base-package="org.rest" /> - As of Spring 3.1, the @Configuration are excluded from classpath scanning by default – see this JIRA issue. Before Spring 3.1 though, these classes should have been excluded explicitly: - excludeFilters = { @ComponentScan.Filter( Configuration.class ) } - The @Configuration classes should not be autodiscovered because they are already specified and used by the Container – allowing them to be rediscovered and introduced into the Spring context will result in the following error: - Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘webConfig’ for bean class [org.rest.spring.AppConfig] conflicts with existing, non-compatible bean definition of same name and class [org.rest.spring.AppConfig] - And finally, using the @Bean annotation to configure the properties support – PropertySourcesPlaceholderConfigurer is initialized in a @Bean annotated method, indicating it will produce a Spring bean managed by the Container. This new configuration has replaced the following XML: - <context:property-placeholder -location="classpath:persistence.properties, classpath:web.properties" -ignore-unresolvable="true"/> - For a more in depth discussion on why it was necessary to manually register the PropertySourcesPlaceholderConfigurer bean, see the Properties with Spring Tutorial. -
- <emphasis role="bold">3.1. The web.xml</emphasis> - <?xml version="1.0" encoding="UTF-8"?> -<web-app xmlns=" - http://java.sun.com/xml/ns/javaee" -     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -    xsi:schemaLocation=" - http://java.sun.com/xml/ns/javaee - http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -    id="rest" version="3.0"> - - <context-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </context-param> - <context-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.root</param-value> - </context-param> - <listener> - <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> - </listener> - - <servlet> - <servlet-name>rest</servlet-name> - <servlet-class> - org.springframework.web.servlet.DispatcherServlet - </servlet-class> - <init-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </init-param> - <init-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.rest</param-value> - </init-param> - <load-on-startup>1</load-on-startup> - </servlet> - <servlet-mapping> - <servlet-name>rest</servlet-name> - <url-pattern>/api/*</url-pattern> - </servlet-mapping> - - <welcome-file-list> - <welcome-file /> - </welcome-file-list> - -</web-app> - First, the root context is defined and configured to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext. The newer AnnotationConfigWebApplicationContext accepts @Configuration annotated classes as input for the Container configuration and is needed in order to set up the Java based context. Unlike XmlWebApplicationContext, it assumes no default configuration class locations, so the “contextConfigLocation”init-param for the Servlet must be set. This will point to the java package where the @Configuration classes are located; the fully qualified name(s) of the classes are also supported. - Next, the DispatcherServlet is configured to use the same kind of context, with the only difference that it’s loading configuration classes out of a different package. - Other than this, the web.xml doesn’t really change from a XML to a Java based configuration. -
-
-
- <anchor xml:id="238dbdoclet.4_Conclusion"/><emphasis role="bold">4. Conclusion</emphasis> - The presented approach allows for a smooth migration of the Spring configuration from XML to Java, mixing the old and the new. This is important for older projects, which may have a lot of XML based configuration that cannot be migrated all at once. - This way, in a migration, the XML beans can be ported in small increments. - In the next article on REST with Spring, I cover setting up MVC in the project, configuration of the HTTP status codes, payload marshalling and content negotiation. - The implementation of this Bootstrap a Spring Web App Tutorial can be downloaded as a working sample project. - This is an Eclipse based project, so it should be easy to import and run as it is. - -   - - - - - - - - - java, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
- -
\ No newline at end of file diff --git a/apache-fop/src/test/resources/output-eugen.xml b/apache-fop/src/test/resources/output-eugen.xml deleted file mode 100644 index a953f54c54..0000000000 --- a/apache-fop/src/test/resources/output-eugen.xml +++ /dev/null @@ -1,312 +0,0 @@ - -
-
- Bootstrap a Web Application with Spring 4 -
- - - - - Return to Content - - - - - - Contents - - - Table of Contents - - - 1. Overview - - - 2. The Maven pom.xml - - - 3. The Java based Web Configuration - - - 4. Conclusion - - - If you're new here, you may want to get my "REST APIs with Spring" eBook. Thanks for visiting! - - - -
- <anchor xml:id="50Table_of_Contents"/><emphasis role="bold">Table of Contents</emphasis> - - - 1. Overview - - - 2. The Maven pom.xml - - -     2.1. Justification of the cglib dependency - - -     2.2. The cglib dependency in Spring 3.2 and beyond - - - 3. The Java based web configuration - - -    3.1. The web.xml - - - 4. Conclusion - - -
- <anchor xml:id="75dbdoclet.1_Overview"/><emphasis role="bold">1. Overview</emphasis> - The tutorial illustrates how to Bootstrap a Web Application with Spring and also discusses how to make the jump from XML to Java without having to completely migrate the entire XML configuration. -
-
- <anchor xml:id="79dbdoclet.2_The_Maven_pomxml"/><emphasis role="bold">2. The Maven pom.xml</emphasis> - <project xmlns="http://maven.apache.org/POM/4.0.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" - http://maven.apache.org/POM/4.0.0 - http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>org</groupId> - <artifactId>rest</artifactId> - <version>0.0.1-SNAPSHOT</version> - <packaging>war</packaging> - - <dependencies> - - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-webmvc</artifactId> - <version>${spring.version}</version> - <exclusions> - <exclusion> - <artifactId>commons-logging</artifactId> - <groupId>commons-logging</groupId> - </exclusion> - </exclusions> - </dependency> - - </dependencies> - - <build> - <finalName>rest</finalName> - - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.6</source> - <target>1.6</target> - <encoding>UTF-8</encoding> - </configuration> - </plugin> - </plugins> - </build> - - <properties> - <spring.version>4.0.5.RELEASE</spring.version> - </properties> - -</project> -
- <emphasis role="bold">2.1. The cglib dependency before Spring 3.2</emphasis> - You may wonder why cglib is a dependency – it turns out there is a valid reason to include it – the entire configuration cannot function without it. If removed, Spring will throw: - Caused by: java.lang.IllegalStateException: CGLIB is required to process @Configuration classes. Either add CGLIB to the classpath or remove the following @Configuration bean definitions - The reason this happens is explained by the way Spring deals with @Configuration classes. These classes are effectively beans, and because of this they need to be aware of the Context, and respect scope and other bean semantics. This is achieved by dynamically creating a cglib proxy with this awareness for each @Configuration class, hence the cglib dependency. - Also, because of this, there are a few restrictions for Configuration annotated classes: - - - Configuration classes should not be final - - - They should have a constructor with no arguments - - -
-
- <emphasis role="bold">2.2. The cglib dependency in Spring 3.2 and beyond</emphasis> - Starting with Spring 3.2, it is no longer necessary to add cglib as an explicit dependency. This is because Spring is in now inlining cglib – which will ensure that all class based proxying functionality will work out of the box with Spring 3.2. - The new cglib code is placed under the Spring package: org.springframework.cglib (replacing the original net.sf.cglib). The reason for the package change is to avoid conflicts with any cglib versions already existing on the classpath. - Also, the new cglib 3.0 is now used, upgraded from the older 2.2 dependency (see this JIRA issue for more details). - Finally, now that Spring 4.0 is out in the wild, changes like this one (removing the cglib dependency) are to be expected with Java 8 just around the corner – you can watch this Spring Jira to keep track of the Spring support, and the Java 8 Resources page to keep tabs on the that. -
-
-
- <anchor xml:id="153dbdoclet.3_The_Java_based_Web_Configuration"/><emphasis role="bold">3. The Java based Web Configuration</emphasis> - @Configuration -@ImportResource( { "classpath*:/rest_config.xml" } ) -@ComponentScan( basePackages = "org.rest" ) -@PropertySource({ "classpath:rest.properties", "classpath:web.properties" }) -public class AppConfig{ - - @Bean -   public static PropertySourcesPlaceholderConfigurer properties() { -   return new PropertySourcesPlaceholderConfigurer(); -   } -} - First, the @Configuration annotation – this is the main artifact used by the Java based Spring configuration; it is itself meta-annotated with @Component, which makes the annotated classes standard beans and as such, also candidates for component scanning. The main purpose of @Configuration classes is to be sources of bean definitions for the Spring IoC Container. For a more detailed description, see the official docs. - Then, @ImportResource is used to import the existing XML based Spring configuration. This may be configuration which is still being migrated from XML to Java, or simply legacy configuration that you wish to keep. Either way, importing it into the Container is essential for a successful migration, allowing small steps without to much risk. The equivalent XML annotation that is replaced is: - <import resource=?classpath*:/rest_config.xml? /> - Moving on to @ComponentScan – this configures the component scanning directive, effectively replacing the XML: - <context:component-scan base-package="org.rest" /> - As of Spring 3.1, the @Configuration are excluded from classpath scanning by default – see this JIRA issue. Before Spring 3.1 though, these classes should have been excluded explicitly: - excludeFilters = { @ComponentScan.Filter( Configuration.class ) } - The @Configuration classes should not be autodiscovered because they are already specified and used by the Container – allowing them to be rediscovered and introduced into the Spring context will result in the following error: - Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘webConfig’ for bean class [org.rest.spring.AppConfig] conflicts with existing, non-compatible bean definition of same name and class [org.rest.spring.AppConfig] - And finally, using the @Bean annotation to configure the properties support – PropertySourcesPlaceholderConfigurer is initialized in a @Bean annotated method, indicating it will produce a Spring bean managed by the Container. This new configuration has replaced the following XML: - <context:property-placeholder -location="classpath:persistence.properties, classpath:web.properties" -ignore-unresolvable="true"/> - For a more in depth discussion on why it was necessary to manually register the PropertySourcesPlaceholderConfigurer bean, see the Properties with Spring Tutorial. -
- <emphasis role="bold">3.1. The web.xml</emphasis> - <?xml version="1.0" encoding="UTF-8"?> -<web-app xmlns=" - http://java.sun.com/xml/ns/javaee" -     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -    xsi:schemaLocation=" - http://java.sun.com/xml/ns/javaee - http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" -    id="rest" version="3.0"> - - <context-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </context-param> - <context-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.root</param-value> - </context-param> - <listener> - <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> - </listener> - - <servlet> - <servlet-name>rest</servlet-name> - <servlet-class> - org.springframework.web.servlet.DispatcherServlet - </servlet-class> - <init-param> - <param-name>contextClass</param-name> - <param-value> - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - </param-value> - </init-param> - <init-param> - <param-name>contextConfigLocation</param-name> - <param-value>org.rest.spring.rest</param-value> - </init-param> - <load-on-startup>1</load-on-startup> - </servlet> - <servlet-mapping> - <servlet-name>rest</servlet-name> - <url-pattern>/api/*</url-pattern> - </servlet-mapping> - - <welcome-file-list> - <welcome-file /> - </welcome-file-list> - -</web-app> - First, the root context is defined and configured to use AnnotationConfigWebApplicationContext instead of the default XmlWebApplicationContext. The newer AnnotationConfigWebApplicationContext accepts @Configuration annotated classes as input for the Container configuration and is needed in order to set up the Java based context. Unlike XmlWebApplicationContext, it assumes no default configuration class locations, so the “contextConfigLocation?init-param for the Servlet must be set. This will point to the java package where the @Configuration classes are located; the fully qualified name(s) of the classes are also supported. - Next, the DispatcherServlet is configured to use the same kind of context, with the only difference that it’s loading configuration classes out of a different package. - Other than this, the web.xml doesn’t really change from a XML to a Java based configuration. -
-
-
- <anchor xml:id="238dbdoclet.4_Conclusion"/><emphasis role="bold">4. Conclusion</emphasis> - The presented approach allows for a smooth migration of the Spring configuration from XML to Java, mixing the old and the new. This is important for older projects, which may have a lot of XML based configuration that cannot be migrated all at once. - This way, in a migration, the XML beans can be ported in small increments. - In the next article on REST with Spring, I cover setting up MVC in the project, configuration of the HTTP status codes, payload marshalling and content negotiation. - The implementation of this Bootstrap a Spring Web App Tutorial can be downloaded as a working sample project. - This is an Eclipse based project, so it should be easy to import and run as it is. - - - - - - - - - - java, Spring - - - - - - - - - - - © 2014 Baeldung. All Rights Reserved. - - - - - - - -
-
- -
\ No newline at end of file