The login page is the fist thing that most web application users encounter. Account creation is the gateway through which all new application users pass through before they can use a web application. This means that authentication (account creation, login and user data management) is a critical component for most web applications.
This article discusses the Amazon Web Services (AWS) Cognito service and how it can be used to build server side authentication for a Java web application constructed using the Spring framework.
The Java source code for the demonstration application described in this article is available on GitHub, under the Apache 2 software license.
Creating strong authentication software that can resist password attacks requires careful, informed, design. Authentication requires persistent storage of user information (passwords and user account information). This is often supported by a database that is available 24 hours a day, seven days a week (24/7). This database will incur an operating cost, regardless of how much it is used.
For the nderground social network, Topstone Software developed a custom authentication infrastructure that uses theRDS/Postgres database. In addition to the encrypted password and a unique "salt" value, for each user, this database hosts access and security information used by nderground's groups (the nderground Karass). The RDS/Postgres database was chosen over a NoSQL database like Amazon's DynamoDB for critical user information storage because Postgres is a transaction safe SQL database.
AWS Cognito simplifies application development by providing an authentication service. In addition to storing password and email information, Cognito can store standard and custom user account values. Cognito is a "serverless" service that does not require the deployment of a 24/7 database server like RDS/Postgres. Cognito's cost model is "pay as you go". Currently the first 50,000 monthly users (users who sign-in at least once in a month) are free.
The custom authentication software developed for nderground could be integrated into new Topstone Software web applications. However, this would incur the cost of a 24/7 RDS/Postgres server.
One of the architectural objectives for the Web applications designed and built by Topstone Software is cost that scales with the number of users. A application with only a few users should have a low cost, which increases as the user base and performance demands increase. Using AWS Cognito helps meet this architectural objective by removing the requirement for a database server to store user authentication information.
The different ways that Cognito can be applied can make the Amazon documentation difficult to understand. Documentation that describes an authentication task (for example, account creation and verification via email or SMS text message) describes a number of different use cases in the same section.
At the time this article was written, Amazon did not provide Java reference code for Cognito server side authentication. The AWS Java SDK documentation for the Cognito API has minimal documentation and it can be difficult to understand how to apply the API.
This article and the associated GitHub Java source code have been written to help Java software engineers integrate Cognito into a Java Web application.
Cognito can support one more more "user pools". Each "pool" contains the login and user information for a group of users. Production and test user pools can be created so that application testing does not impact the Cognito production user information.
Cognito also provides a user interface that allows management of users within a particular pool. This user interface is available the AWS console login, which can be protected with two factor authentication.
The AWS Cognito service provides support for a wide range of authentication features, many of which are not used in this demonstration application. For example, Cognito can support two factor authentication for high security applications and OAuth, which allows an application to authenticate using an OAuth provider like Google, Facebook or Twitter.
Cognito supports the steps needed to securely create an application account. This includes sending a temporary password to the user's email and temporary authentication using this password, which allows the user to create a permanent password.
Cognito also supports password reset for an existing account where the user has forgotten their password. Cognito will email the user a code, which can be used to create a new password.
The diagram below illustrates the web page flow for new accounts and forgotten passwords. In this demonstration application, the Spring code supports the control flow via Spring controller objects.
The Cognito demonstration application contains the basic components for application authentication and user management. This includes the server Java code that makes use of Cognito and the web pages associated with authentication. The code and web pages are open source, published under the Apache 2 software license
The Spring Tool Suite (release 3.9.4), which is based on Eclipse, was used to develop the application. The project files are included in the GitHub repository.
The application web pages are built using Java Server Pages - a server side rendering technology for building Java web applications. The pages use Bootstrap and Kube for device independent formatting and fonts.
This article assumes that the reader already has an Amazon Web Services account and has experience with other Amazon services.
The recommended approach for Amazon Services is that the minimal permissions possible should be used for an application. This compartmentalizes access and security. For example, to use DynamoDB you use DynamoDB permissions and for Cognito you use Cognito permissions.
I used the following steps to create IAM permissions that I used in the Cognito demo application.
The steps needed to create the Cognito User Pool used by the demo application are described here.
Authentication consists of much more than support for login. A screen show of the login page is shown below:
Users create an account by entering their proposed user name, email address and location. The location is an example of arbitrary information that can be associated with a user's Cognito information.
When this information is submitted to Cognito, the user will be emailed a temporary password. This assures that the email address entered by the user is valid.
When the user logs in using the temporary email address, the Java software in the page controller can check to see if the login used a temporary password. If this is the case, the user can be routed to a page that allows them to reset their password with a password of their choosing.
As the screen shot above shows, the user can also recover a forgotten user name or reset a forgotten password. Forgotten password reset takes place via a code that is emailed to the user.
Authentication software must also support changes for logged in users. The demo application page is shown below. This web page is a proxy for the main page for an application.
The Java API used for authentication in this application is outlined below:
This API abstracts Cognito operations so that Cognito dependencies are not introduced outside of the AuthenticationService class. In theory the AuthenticationService class could be replaced by another class that used another authentication infrastructure (e.g., the RDS/Postgres authentication infrastructure developed for the nderground social network).
In practice migrating away from Cognito once it is adopted would be problematic since the application users would have to recreate their accounts using the new infrastructure.