Reset Password for SUSI Accounts Using Verification Link

In this blog, I will discuss how the SUSI server interprets the verification link sent to your email id to reset SUSI account password. The email one receives to reset password looks like this :  

http://api.susi.ai/apps/resetpass/index.html?token={30 character long token}

*Original link contains a token of length of 30 characters. The link has been tampered for security purpose.

Taking a close look at the reset link, one would find it easy to decode. It simply contains path to an application on current SUSI Accounts hosting. Name of the application is “resetpass” for Reset Password. But what about the token in the link?

As soon as a user clicks on the link, the app is called and token is passed as a GET parameter. The app in background makes a call to the server where the token is evaluated for whether the token is hashed against some user’s email id and has not expired yet. Below is code of first step the client does which is to make a simple ajax call on Ready state.

$(document).ready(function()
{
	var passerr = false, confirmerr = false, tokenerr = false;

	// get password parameters
	var regex;
	var urltoken = getParameter('token');

	$.ajax(	"/aaa/recoverpassword.json", {
		data: { getParameters: true, token: urltoken },
		dataType: 'json',
		success: function (response) {
			regex = response.regex;
			var regexTooltip = response.regexTooltip;
			$('#pass').tooltip({'trigger':'focus', 'placement': 'left', 'title': regexTooltip});
			$('#status-box').text(response.message);
			tokenerr = false;
		},
		error: function (xhr, ajaxOptions, thrownError) {
			$('#status-box').text(thrownError);
			$('#status-box').addClass("error");
			$('#pass').prop( "disabled", true );
			$('#confirmpass').prop( "disabled", true );
			$('#resetbut').prop( "disabled", true );
			tokenerr = true;
		},
	});

As you can see the call is made to /aaa/recoverypassword.json end point with token as the request parameter. Now, the client has to just evaluate the JSON response and render the message for user accordingly. If this request returns an error then the error message is shown and the entries are disabled to enter the password. Otherwise, user email id is shown with green text and user can now enter new password and confirm it.

In next step, client simply evaluates the password and sends a query to server to reset it. Let us now look at how server functions and processes such requests.

//check if a token is already present
if (call.get("getParameters", false)) {
			if (call.get("token", null) != null && !call.get("token", null).isEmpty()) {
				ClientCredential credentialcheck = new ClientCredential(ClientCredential.Type.resetpass_token,
						call.get("token", null));
				if (DAO.passwordreset.has(credentialcheck.toString())) {
					Authentication authentication = new Authentication(credentialcheck, DAO.passwordreset);
					if (authentication.checkExpireTime()) {
						String passwordPattern = DAO.getConfig("users.password.regex", "^(?=.*\\d).{6,64}$");
						String passwordPatternTooltip = DAO.getConfig("users.password.regex.tooltip",
								"Enter a combination of atleast six characters");
						result.put("message", "Email ID: " + authentication.getIdentity().getName());
						result.put("regex", passwordPattern);
						result.put("regexTooltip", passwordPatternTooltip);
						result.put("accepted", true);
						return new ServiceResponse(result);
					}
					authentication.delete();
					throw new APIException(422, "Expired token");
				}
				throw new APIException(422, "Invalid token");
			} else {
				throw new APIException(422, "No token specified");
			}
		}

In the above code snippet, server evaluates the received token on the basis of three parameters. First it checks whether the token is provided or not. If not, it throws APIException with error code 422 and a message “No token specified”. If it passes the check, next it checks if the token passed is valid or not. If the token is invalid, it throws different APIException with same error code but different message “Invalid token”. Finally it checks whether the token is expired or not {life of each token is 7 days. After that, server marks it as expired}.

If all checks pass, the server finds the valid email id against which the token was hashed and sends it to user in JSON format. Now let us see how the final reset  password call is handled at the server.

If the token is valid  and still has life, user will be asked to enter new password and confirm it. Client locally checks whether new password and confirm password are same or not. It will now make a call to the below given servlet.

/aaa/resetpassword.json

Till now, server has already made the client identity using the token. Next it will check if the password matches regular expression or not. If not, it sends  an error message “Invalid Password” with error code 400.

if (DAO.hasAuthentication(emailcred)) {
			Authentication emailauth = DAO.getAuthentication(emailcred);
			String salt = createRandomString(20);
			emailauth.remove("salt");
			emailauth.remove("passwordHash");
			emailauth.put("salt", salt);
			emailauth.put("passwordHash", getHash(newpass, salt));
		}

Above code snippet shows what happens when new password matches the conditions of regular expression. The server will generate a random string of 20 characters and use it as the new salt to hash the password. It updates the salt and password hash for the particular user. Next time whenever user makes a login request, server will use the new salt-hash pair to authorise the user. Below given is a flowchart for better understanding.

Resources