Authentication and Authorization: create users, handle login, protect pages

Subsections

User Login

Login both with normal or ajax request

User Registration

Registering new users

Description

The Yada Framework uses Spring Security to implement authentication (identifying the current user) and authorization (limiting access to web pages according to the user role). The YadaWebSecurity library must be added to the classpath in order for this to work.

Cross Site Request Forgery (CSRF) prevention is currently disabled by default

Setup

The WebConfig class must extend YadaWebSecurityConfig instead of YadaWebConfig:

@ComponentScan(basePackages = { "com.example.web" })
public class WebConfig extends YadaWebSecurityConfig {

The required YadaWebSecurity entities must also be added to persistence.xml in order to create the DB schema:

<persistence-unit name="yadaPersistenceUnit">
	<class>net.yadaframework.security.persistence.entity.YadaSocialCredentials</class>
	<class>net.yadaframework.security.persistence.entity.YadaUserCredentials</class>
	<class>net.yadaframework.security.persistence.entity.YadaUserProfile</class>
	<class>net.yadaframework.security.persistence.entity.YadaRegistrationRequest</class>
	<class>net.yadaframework.security.persistence.entity.YadaAutoLoginToken</class>

Some security parameters must be configured in conf.webapp.prod.xml:

<config>
	<security>
		<sessionTimeoutMinutes>240</sessionTimeoutMinutes> (1)
		<passwordLength min='5' max='128' /> (2)
		<encodePassword>true</encodePassword> (3)
		<maxFailedAttempts>10</maxFailedAttempts> (4)
		<failedAttemptsLockoutMinutes>10</failedAttemptsLockoutMinutes> (5)
		<autologinExpirationHours>48</autologinExpirationHours> (6)
		<roles> (7)
			<role>
				<id>8</id>
				<key>ADMIN</key>
			</role>
			<role>
				<id>2</id>
				<key>USER</key>
			</role>
		</roles>
	</security>
1 this value must be the same used in the web.xml <session-config><session-timeout> tag and is for checking session expiration
2 values for password validation
3 when true, passwords are encrypted in the database
4 the number of consecutive failed login attempts before an account is locked out
5 the number of minutes to wait for a locked out account before a new login attempt can be made
6 the validity time of autologin links
7 list of roles that users can have

The list of roles defines an id and a key for every role a user can have in the application. A user can have more than one role. Role ids are just integer numbers with no special meaning, but they must be unique. Role keys can be any word that reminds of the activity the user can perform on the site. In this example, "USER" is any user with no particular privileges, and "ADMIN" is a site administrator. Role names should be specific to the application domain. For example, a "MANAGER" could handle users, a "GUEST" could have limited access, a "TEACHER" could see the score editing form. It’s important not to change either the id or the key once the application goes to production because these values are stored in the database.

User Profile

Every web application handles a specific kind of user with different attributes like name, address, age etc. All user attributes are known as a "user profile". The Yada Framework provides the YadaUserProfile class with basic attributes like firstName or avatar image. The web application must subclass it with its own UserProfile class in order to add application-specific attributes:

@Entity
public class UserProfile extends YadaUserProfile {
	@Column(length = 32)
	String nickname; // This is an example of UserProfile customization

The user login name is always the email address. Together with the password it is stored in the userCredentials attribute of YadaUserProfile, of type YadaUserCredentials.

Root user

Usually, in a web application, users either register themselves or are added by an administrator. In any case, there must be an initial user with administrator rights that is already in the database when the application starts for the first time. This can be implemented by subclassing YadaUserSetup in any bean, for example a "Setup" bean:

@Component
public class Setup extends YadaUserSetup<UserProfile> {

Just by doing this, the users defined in the configuration will be created, if not there already, at each application startup. This configuration in conf.webapp.prod.xml creates one "admin" user (but it doesn’t have to be just one):

<config>
	<setup>
		<users>
			<user>
				<nickname>admin</nickname> <!-- This is an example of UserProfile customization -->
				<email>admin@EXAMPLE.com</email>
				<password>changeit</password>
				<locale>en_US</locale>
				<timezone>Europe/Rome</timezone>
				<role>USER</role>
				<role>ADMIN</role>
			</user>
		</users>
	</setup>

The xml user definition can contain all attributes defined in the application-specific UserProfile class: they will be set using reflection.

When a <password> is not provided, the user will be created with a random password that can only be known if <encodePassword> is false by reading the database directly. When the password is encoded, the only way of performing login is by resetting the password using the password recovery procedure that must have been implemented.

Sensitive data like the password of a production user or of a email provider can be stored in a server-specific file that by default is located in /srv/???/bin/security.properties. This file can hold name=value pairs like a normal java properties file, and the values can be used via variable interpolation inside the xml configuration file.

For example, if the security.properties file contains rootuser_password = somesecret then the conf.webapp.prod.xml file can have <password>${rootuser_password}</password>

Do not use dots in variable names or interpolation won’t work.

To delete all users (for development test):

delete from YadaUserCredentials_roles;
delete yup, yuc FROM YadaUserProfile yup join YadaUserCredentials yuc on yup.userCredentials_id = yuc.id;

Authorization

The SecurityConfig class is where the application endpoints are protected so that only specific roles can access specific pages. The default implementation allows users with "ADMIN" role to access the /admin path and with "USER" role to access the /user path. This can of course be changed as needed.

- Credentials expiration. See YadaAuthenticationFailureHandler.onAuthenticationFailure()
- Multiple SecurityConfig
- UserProfileDao