Strategies for securing REST services
OAuth 2.0
Basics of the Spring Security framework
Implementing QuickPoll security
Traditional web applications requiring security typically use username/passwords for identification purposes. REST services pose interesting security problems as they can be consumed by a variety of clients such as browsers and mobile devices. They can also be consumed by other services, and this machine-to-machine communication might not have any human interaction. It is also not uncommon for clients to consume REST services on behalf of a user. In this chapter, we will explore the different authentication/authorization approaches that can be used while working with REST services. Then we will look at using some of these approaches to secure our QuickPoll application.
Securing REST Services
Session-based security
HTTP Basic authentication
Digest authentication
Certificate-based security
XAuth
OAuth
Session-Based Security
Frameworks such as Spring Security provide all the necessary plumbing to develop applications using this security model. This approach is very appealing to developers that are adding REST services to existing Spring Web applications. The REST services will retrieve the user identity from the session to perform authorization checks and serve resources accordingly. However, this approach violates the statelessness REST constraint. Also, because the server holds the client’s state, this approach is not scalable. Ideally, the client should hold the state and server should be stateless.
HTTP Basic Authentication
Using a login form to capture a username and password is possible when there is human interaction involved. However, this might not be possible when we have services talking to other services. HTTP Basic authentication provides a mechanism that allows clients to send authentication information using both interactive and noninteractive fashions.
Because the client includes the authentication information in each request, the server becomes stateless. It is important to remember that the client is simply encoding the information and not encrypting it. Hence, on non-SSL/TLS connections, it is possible to conduct a man-in-the-middle attack and steal the password.
Digest Authentication
A qop value "auth" indicates that the digest is used for authentication purposes.
A value "auth-int" indicates that digest will be used for authentication and request integrity.
The Digest authentication approach is more secure than the Basic authentication, as the password is never sent in clear text. However, on non-SSL/TLS communications, it is still possible for snoopers to retrieve the digest and replay the request. One way to address this problem is to limit server-generated nonces to one-time use only. Also, because the server has to generate the digest for verification, it needs to have access to the plain text version of the password. Hence, it can’t employ more secure one-way encryption algorithms such as bcrypt and can become more vulnerable to server side attacks.
Certificate-Based Security
The certificate-based security model relies on certificates to verify a party’s identity. In an SSL/TLS-based communication, a client such as a browser often verifies the server’s identity using certificates to ensure that the server is what it claims to be. This model can be extended to perform mutual authentication where a server can request a client certificate as part of an SSL/TLS handshake and verify a client’s identity.
The certificate-based security model eliminates the need to send over a shared secret, making it more secure over username/password models. However, deployments and maintenance of certificates can be expensive and typically are used for large systems.
XAuth
As REST APIs became popular, the number of third-party applications that use those APIs also grew significantly. These applications need a username and password in order to interact with REST services and perform actions on behalf of users. This poses a huge security problem as third-party applications now have access to usernames and passwords. A security breach in the third-party application can compromise user information. Also, if the user changes his credentials, he needs to remember to go and update all of these third-party applications. Finally, this mechanism doesn’t allow the user to revoke his authorization to the third-party application. The only option for revoking in this case would be to change his password.
Applications such as Twitter allow third-party applications to access their REST API using an XAuth scheme. However, even with XAuth, a third-party application needs to capture a username and password, leaving the possibility of misuse. Considering the simplicity involved in XAuth, it might be a good candidate when the same organization develops the client as well as the REST API.
OAuth 2.0
The Open Authorization or OAuth is a framework for accessing protected resources on behalf of a user without storing a password. The OAuth protocol was first introduced in 2007 and was superseded by OAuth 2.0, which was introduced in 2010. In this book, we will be reviewing OAuth 2.0 and general principles.
Resource owner—A resource owner is the user that wants to give access to portions of their account or resources. For example, a resource owner could be a Twitter or a Facebook user.
Client—A client is an application that wants access to a user’s resources. This could be a third-party app such as Klout (https://klout.com/) that wants to access a user’s Twitter account.
Authorization server—An authorization server verifies the user’s identity and grants the client a token to access the user’s resources.
Resource server—A resource server hosts protected user resources. For example, this would be Twitter API to access tweets and timelines and so on.
Before a client can participate in the “OAuth dance” shown in Figure 8-6, it must register itself with the authorization server. For most public APIs such as Facebook and Twitter, this involves filling out an application form and providing information about the client such as application name, base domain, and website. On successful registration, the client will receive a Client ID and a Client secret. The Client ID is used to uniquely identify the Client and is available publicly. These client credentials play an important part in the OAuth interactions, which we will discuss in just a minute.
The usage of HTTPS is mandatory for any production OAuth 2.0 interactions, and, hence, the URI begins with https. The CLIENT_ID is used to provide the client’s identity to the authorization server. The scope parameter provides a comma-separated set of scopes/roles that the client needs.
On receiving the access token, the client will request a protected resource from the resource server passing in the access token it obtained. The resource server validates the access token and serves the protected resource.
OAuth Client Profiles
One of the strengths of OAuth 2.0 is its support for a variety of client profiles such as “web application,” “native application,” and “user agent/browser application.” The authorization code flow discussed earlier (often referred to as authorization grant type ) is applicable to “web application” clients that have a web-based user interface and a server side backend. This allows the client to store the authorization code in a secure backend and reuse it for future interactions. Other client profiles have their own flows that determine the interaction between the four OAuth 2.0 players.
A pure JavaScript-based application or a native application can’t store authorization codes securely. Hence, for such clients, the callback from the authorization server doesn’t include an authorization code. Instead, an implicit grant-type approach is taken and an access token is directly handed over to the client, which is then used for requesting protected resources. Applications falling under this client profile will not have a client secret and are simply identified using the client ID.
OAuth 2.0 also supports an authorization flow, referred to as password grant type that is similar to XAuth discussed in the previous section. In this flow, the user supplies his credentials to the client application directly. He is never redirected to the authorization server. The client passes these credentials to the authorization server and receives an access token for requesting protected resources.
OAuth 1.0 introduced several implementation complexities especially around the cryptographic requirements for signing requests with client credentials. OAuth 2.0 simplified this by eliminating signatures and requiring HTTPS for all interactions. However, because many of OAuth 2’s features are optional, the specification has resulted in non-interoperable implementations.
Refresh Tokens versus Access Tokens
The lifetime of access tokens can be limited and clients should be prepared for the possibility of a token no longer working. To prevent the need for the resource owner to repeatedly authenticate, the OAuth 2.0 specification has provided a notion of refresh tokens. An authorization server can optionally issue a refresh token when it generates an access token. The client stores this refresh token, and when an access token expires, it contacts the authorization server for a fresh set of access token as well as refresh token. Specification allows generation of refresh tokens for authorization and password grant-type flows. Considering the lack of security with the “implicit grant type,” refresh tokens are prohibited for such client profiles.
Spring Security Overview
To implement security in the QuickPoll application, we will be using another popular Spring subproject, namely, Spring Security. Before we move forward with the implementation, let’s understand Spring Security and the different components that make up the framework.
Spring Security, formerly known as Acegi Security, is a framework for securing Java-based applications. It provides an out-of-the-box integration to a variety of authentication systems such as LDAP, Kerberos, OpenID, OAuth, and so on. With minimal configuration, it can be easily extended to work with any custom authentication and authorization systems. The framework also implements security best practices and has inbuilt features to protect against attacks such as CSRF, or Cross-Site Request Forgery, session fixation, and so on.
- 1.
The process begins with a user requesting a protected resource on a Spring-secured web application.
- 2.
The request goes through a series of Spring Security filters referred to as a “filter chain” that identify an org.springframework.security.web.AuthenticationEntryPoint to service the request. The AuthenticationEntryPoint will respond to the client with a request to authentication. This is done, for example, by sending a login page to the user.
- 3.
On receiving authentication information from the user such as a username/password, a org.springframework.security.core.Authentication object is created. The Authentication interface is shown in Listing 8-1, and its implementation plays a dual role in Spring Security. They represent a token for an authentication request or a fully authenticated principal after authentication is successfully completed. The isAuthenticated method can be used to determine the current role played by an Authentication instance. In case of a username/password authentication, the getPrincipal method returns the username and the getCredentials returns the password. The getUserDetails method contains additional information such as IP address and so on.
Authentication API
- 4.
As a next step, the authentication request token is presented to an org.springframework.security.authentication.AuthenticationManager. The AuthenticationManager, as shown in Listing 8-2, contains an authenticate method that takes an authentication request token and returns a fully populated Authentication instance. Spring provides an out-of-the-box implementation of AuthenticationManager called ProviderManager.
AuthenticationManager API
- 5.
In order to perform authentication, the ProviderManager needs to compare the submitted user information with a backend user store such as LDAP or database. ProviderManager delegates this responsibility to a series of org.springframework.security.authentication.AuthenticationProvider. These AuthenticationProviders use an org.springframework.security.core.userdetails.UserDetailsService to retrieve user information from backend stores. Listing 8-3 shows the UserDetailsService API.
UserDetailsService API
- 6.
The AuthenticationProvider compares the submitted credentials with the information in the backend system, and on successful verification, the org.springframework.security.core.userdetails.UserDetails object is used to build a fully populated Authentication instance.
- 7.
The Authentication instance is then put into an org.springframework.security.core.context.SecurityContextHolder. The SecurityContextHolder , as the name suggests, simply associates the logged-in user’s context with the current thread of execution so that it is readily available across user requests or operations. In a web-based application, the logged-in user’s context is typically stored in the user’s HTTP session.
- 8.
Spring Security then performs an authorization check using an org.springframework.security.access.intercept.AbstractSecurityInterceptor and its implementations org.springframework.security.web.access.intercept.FilterSecurityInterceptor and org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor. The FilterSecurityInterceptor is used for URL-based authorization and MethodSecurityInterceptor is used for method invocation authorization.
- 9.
The AbstractSecurityInterceptor relies on security configuration and a set of org.springframework.security.access.AccessDecisionManagers to decide if the user is authorized or not. On successful authorization, the user is given access to the protected resource.
To keep things simple, I have purposefully omitted some Spring Security classes in these steps. For a complete review of Spring Security and the authentication/authorization steps, please refer to Pro Spring Security (Apress, 2019).
Now that you have a basic understanding of Spring Security’s authentication/authorization flow as well as some of its components, let’s look at integrating Spring Security into our QuickPoll application.
Securing QuickPoll
Registered users can create and access polls. This allows us to keep track of accounts, usage, and so on.
Polls can be deleted only by users with admin privileges
In this chapter, we will continue building on the work that we did on the QuickPoll application in the previous chapters. Alternatively, a starter project is available for you to use inside the Chapter8starter folder of the downloaded source code. In this chapter, we will secure QuickPoll using Basic authentication. Then we will add OAuth 2.0 support to QuickPoll. Hence, the Chapter8final folder contains two folders: quick-poll-ch8-final-basic-auth and quick-poll-ch8-final. The quick-poll-ch8-final-basic-auth contains the solution with Basic authentication added to QuickPoll. The quick-poll-ch8-final contains the completed solution with both Basic authentication and OAuth 2.0 added. We understand that not all projects need OAuth 2.0 support. Hence, splitting the final solution into two projects allows you to examine and use features/code that you need. Please refer to the solutions under the final folder for complete listings containing getters/setters and additional imports. The downloaded Chapter8 folder also contains an exported Postman collection containing REST API requests associated with this chapter.
Spring Starter POM
Enter the username and password found in your console into the Postmaster login window and hit Log In. Spring Security will validate the entered credentials and allow the request to be completed.
cURL
Up to this point, we have been using Postman for testing our QuickPoll application. In this chapter, we will be using a command line tool named cURL in conjunction with Postman. cURL is a popular open-source tool used for interacting with servers and transferring data with URL syntax. It comes installed in most operating system distributions. If cURL is not available on your system, follow the instructions at http://curl.haxx.se/download.html to download and install cURL on your machine. Refer to Appendix A for instructions on installing cURL on a Windows machine.
In this command, the –v option requests cURL to run in the debug mode (verbose). The –u option allows us to specify the username and password needed for Basic authentication. A full list of cURL options is available at http://curl.haxx.se/docs/manual.html.
User Infrastructure Setup
Although Spring Boot has simplified Spring Security integration significantly, we would like to customize security behavior so that it uses application users instead of Spring Boot’s generic user. We also would like to apply the security to the v3 PollController, leaving other endpoints to be accessed anonymously. Before we look at customizing Spring Security, let’s set up the infrastructure needed for creating/updating QuickPoll application users.
User Class
UserRepository Interface
Test User Data
Test User Information
Username | Password | Is admin |
---|---|---|
Mickey | Cheese | No |
Minnie | Red01 | No |
Donald | Quack | No |
Daisy | Quack2 | No |
Clarabelle | Moo | No |
Admin | Admin | Yes |
UserDetailsService Implementation
UserDetailsService Implementation for QuickPoll
The QuickPollUserDetailsService class makes use of UserRepository to retrieve User information from the database. It then checks if the retrieved user has administrative rights and constructs an admin GrantedAuthority, namely, ROLE_ADMIN. The Spring Security infrastructure expects the loadUserByUsername method to return an instance of type UserDetails. Hence, the QuickPollUserDetailsService class creates the o.s.s.c.u.User instance and populates it with the data retrieved from the database. The o.s.s.c.u.User is a concrete implementation of the UserDetails interface. If the QuickPollUserDetailsService can’t find a user in the database for the passed-in username, it will throw a UsernameNotFoundException exception.
Customizing Spring Security
Security Configuration for QuickPoll
The SecurityConfig class declares a userDetailsService property, which gets injected with a QuickPollUserDetailsService instance at runtime. It also overrides a super class’s configure method that takes an AuthenticationManagerBuilder as parameter. The AuthenticationManagerBuilder is a helper class implementing the Builder pattern that provides an easy way of assembling an AuthenticationManager. In our method implementation, we use the AuthenticationManagerBuilder to add the UserDetailsService instance. Because we have encrypted the passwords stored in the database using BCrypt algorithm, we provide an instance of BCryptPasswordEncoder. The authentication manager framework will use the password encoder to compare the plain string provided by the user with the encrypted hash stored in the database.
Securing URI
New Config Method in SecurityConfig
The HttpSecurity parameter passed into the config method in Listing 8-10 allows us to specify the URI that should be secured or unsecured. We begin the method implementation by requesting Spring Security to not create an HTTP session and not store logged-in user’s SecurityContext in the session. This is achieved using the SessionCreationPolicy.STATELESS creation policy. We then use antMatchers to provide Ant-style URI expressions that we don’t want Spring Security protecting. Using the permitAll method , we are specifying that the API versions 1 and 2 and Swagger UI should be available anonymously. The next antMatchers along with authenticated method specifies that Spring Security should only allow authenticated users to access V3 Polls API. Finally, we enable HTTP Basic authentication and set the realm name to “Quick Poll.” Restart QuickPoll application and you should be prompted for authentication only on the /v3/polls resources.
Cross-Site Request Forgery, or CSRF (http://en.wikipedia.org/wiki/Cross-site_request_forgery), is a type of security vulnerability whereby a malicious website forces the end user to execute unwanted commands on a different website in which they are currently authenticated. Spring Security by default enables CSRF protection and highly recommends using it for requests submitted by a user via a browser. For services that are used by nonbrowser clients, the CSRF can be disabled. By implementing custom RequestMatchers, it is possible to disable CSRF only for certain URLs or HTTP methods.
To keep things simple and manageable for this book, we have disabled CSRF protection.
EnableGlobalMethodSecurity Annotation Added
PreAuthorize Annotation Added
Output of cURL Delete
Summary
Security is an important aspect of any enterprise application. In this chapter, we reviewed strategies for securing REST services. We also took a deeper look into OAuth 2 and reviewed its different components. We then used Spring Security to implement Basic authentication in our QuickPoll application. In the next chapter, we will use Spring’s RestTemplate to build REST clients. We will also use the Spring MVC Test framework to perform unit and integration testing on REST controllers.