|
| 1 | +# 1. Introduction |
| 2 | +Nowadays many applications expose business functionality as REST services. These services |
| 3 | +can be consumed not only within the enterprise where they were created but from outside as |
| 4 | +well because REST is platform-agnostic and almost every development platform currently |
| 5 | +provides some way of consuming REST services. When creating REST services it is common to |
| 6 | +incorporate some sort of security for every REST API endpoint. This ensures that each API |
| 7 | +endpoint is only invoked by clients that are authorised and intended to use that endpoint. |
| 8 | +This prevents information leakage and malicious use of the application by internal and |
| 9 | +external users. |
| 10 | + |
| 11 | +Spring Security is a flexible framework for implementing security requirements for web |
| 12 | +based applications. It is therefore not uncommon for developers to use Spring Security to |
| 13 | +enforce security restrictions on REST API endpoints. One of the challenges encountered |
| 14 | +when using Spring Security to secure REST API endpoints stems from the requirement to |
| 15 | +support stateless REST clients. In this context, *stateless* means that the client does |
| 16 | +not provide any information with REST requests that would allow the server to determine the |
| 17 | +identity of the user associated with the client. This is a challenge because Spring Security |
| 18 | +(and any other security framework) requires some sort of state information in order to |
| 19 | +authenticate and authorize application users. In the absence of an in-built state |
| 20 | +transmission mechanism, a custom mechanism needs to be evolved to support stateless REST |
| 21 | +and similar scenarios. |
| 22 | + |
| 23 | +# 2. Overview |
| 24 | +This application uses the following architecture to demonstrate how the default Spring |
| 25 | +Security configuration can be used to secure a standard web application and another |
| 26 | +configuration to secure a stateless REST API. |
| 27 | + |
| 28 | + =================== =================== |
| 29 | + | | | | |
| 30 | + | W e b L a y e r | | A P I L a y e r | |
| 31 | + | | | | |
| 32 | + =================== =================== |
| 33 | + |
| 34 | + ============================================= |
| 35 | + | | |
| 36 | + | B u s i n e s s L o g i c L a y e r | |
| 37 | + | | |
| 38 | + ============================================= |
| 39 | + |
| 40 | +The *Business Logic* layer is responsible for performing all business operations. It is |
| 41 | +secured using Spring Security annotations. The *Web* and *API* layers call the *Business |
| 42 | +Logic* layer as and when required. This means, both these layers need to authenticate |
| 43 | +users correctly and consistently so that users can use either of these layers to get access |
| 44 | +to the data and business functionality provided by the *Business Logic* layer. |
| 45 | + |
| 46 | +# 3. Design |
| 47 | +The *Web* layer uses the default Spring Security configuration and takes advantage of form |
| 48 | +login capability provided by Spring Security. The following configuration for the *Web* |
| 49 | +layer enables this configuration. |
| 50 | + |
| 51 | + <security:http access-denied-page="/" auto-config="true" use-expressions="true"> |
| 52 | + <security:form-login /> |
| 53 | + </security:http> |
| 54 | + |
| 55 | +With this configuration, Spring Security uses HTTP sessions to store user credentials in |
| 56 | +between requests. |
| 57 | + |
| 58 | +The *API* layer cannot use the default configuration because all communication between this |
| 59 | +layer and its clients has been assumed to be stateless. Spring Security configuration for |
| 60 | +this layer is therefore slightly more involved and is shown below. |
| 61 | + |
| 62 | + <bean class="org.example.api.security.APIAuthenticationEntryPoint" id="apiAuthenticationEntryPoint" /> |
| 63 | + <bean class="org.example.api.security.EhcacheSecurityContextRepository" id="apiSecurityContextRepository" /> |
| 64 | + <security:authentication-manager alias="authenticationManager" erase-credentials="false"> |
| 65 | + <security:authentication-provider ref="authenticationProvider" /> |
| 66 | + </security:authentication-manager> |
| 67 | + <security:http auto-config="true" create-session="stateless" entry-point-ref="apiAuthenticationEntryPoint" security-context-repository-ref="apiSecurityContextRepository" use-expressions="true" /> |
| 68 | + |
| 69 | +The class `APIAuthenticationEntryPoint` simply rejects all requests that are unauthenticated |
| 70 | +but were expected to be. This ensures that unauthenticated users cannot invoke API endpoints. |
| 71 | +The class `EhcacheSecurityContextRepository` leverages the modular architecture of Spring |
| 72 | +Security to store authentication information in an expirable Ehcache. It implements the |
| 73 | +Spring Security interface `SecurityContextRepository`, whose other implementation |
| 74 | +`HttpSessionSecurityContextRepository` is the default implementation used by Spring Security. |
| 75 | +Of course, it is not mandatory to use Ehcache. Any other caching solution could be used to |
| 76 | +store user credentials in between REST calls. |
| 77 | + |
| 78 | +#4. Running the application |
| 79 | +The following pre-requisites apply to this application. |
| 80 | + |
| 81 | +1. Java Development Kit (JDK) 6.0 or higher; |
| 82 | +1. Apache Maven 3.0.4 or higher. |
| 83 | + |
| 84 | +Once these have been installed and the code checked out, the `web` application can be run |
| 85 | +as `mvn clean package tomcat7:run -pl common,data,domain,service,transfer,web`. This starts an |
| 86 | +embedded Tomcat instance on local port `8888`. The application can then be accessed using |
| 87 | +any web browser on [http://localhost:8888](http://localhost:8888). When accessed for the first |
| 88 | +time, the application will present a login screen with instructions on logging in. |
| 89 | +Successfully logging in as an *Admin* user provides access to a list of users for the system. |
| 90 | +This functionality is not accessible to normal users (try accessing it as a normal user). |
| 91 | + |
| 92 | +Similarly, the `api` application can be run as |
| 93 | +`mvn clean package tomcat7:run -pl api,common,data,domain,service,transfer`. This starts |
| 94 | +an embedded Tomcat instance on local port `9999`. The application can then be accessed |
| 95 | +using a REST client, such as the *Postman* extension for Google Chrome on |
| 96 | +`http://localhost:9999`. There are two REST endpoints - `http://localhost:9999/authenticate` |
| 97 | +to authenticate clients and `http://localhost:9999/users` to access the user list. |
| 98 | +First, make a *POST* request to `http://localhost:9999/authenticate` with two form parameters |
| 99 | +`username` (same as the one used for the web application) and `password` (set to *password* |
| 100 | +for all users). Note the text token returned by this call. Then, make a *GET* request to |
| 101 | +`http://localhost:9999/users`, including the value of the text token retrieved on the |
| 102 | +previous call as an HTTP header `X-API-TOKEN`. This should return the list of users similar |
| 103 | +to how it was displayed for the web application. |
| 104 | + |
| 105 | +# 5. License |
| 106 | +This sample application and its associated source code in its entirety is being made |
| 107 | +available under the following licensing terms. |
| 108 | + |
| 109 | + Copyright (C) 2014 |
| 110 | + |
| 111 | + Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 112 | + this software and associated documentation files (the "Software"), to deal in the |
| 113 | + Software without restriction, including without limitation the rights to use, copy, |
| 114 | + modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, |
| 115 | + and to permit persons to whom the Software is furnished to do so, subject to the |
| 116 | + following conditions: |
| 117 | + |
| 118 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
| 119 | + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
| 120 | + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 121 | + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 122 | + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE |
| 123 | + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
0 commit comments