Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
package dk.portalprotect.nodb.plugins;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import dk.itp.security.authentication.googleauth.GoogleAuthAuthenticationPlugin;
import dk.itp.security.passticket.PTException;
import dk.itp.security.passticket.User;
import dk.itp.security.passticket.server.AuthErrorCodes;
import dk.itp.security.utils.Base64;

/**
 * Demonstration on how to create your own TOTP Authentication plugin
 *  
 * @author Kim Rasmussen
 *
 * <pre>
 * Ceptor - http://ceptor.io
 * Copyright(c) 2018, Asseco Denmark A/S, All rights reserved.
 * 
 * This source code is confidential.
 * </pre>
 */
public class TOTPAuthenticationExample extends GoogleAuthAuthenticationPlugin {
	static Logger cat = LoggerFactory.getLogger(TOTPAuthenticationExample.class.getName());
	static final int DEFAULT_AUTHLEVEL = 10;

	public int getAuthenticationLevel() {
		return DEFAULT_AUTHLEVEL;
	}

	/**
	 * Generate new secret, or return PNG using QR code
	 */
	public String newToken(User user, String inputToken) throws PTException {
		String secret = "";

		try {
			if (!user.isLoggedOn) {
				// TODO: Here you can change the logic for registration / signing up new users
				throw new PTException("Not authenticated, cannot register new TOTP device", AuthErrorCodes.ERROR_NOTAUTHENTICATED, "Cannot register new OTP device until authenticated");
			}
			secret = (String)user.getStateObject("saved_totp_secret");
			if (secret == null) {
				// Create a new 
				secret = super.generateSecretSharedKey();
				user.setStateObject("saved_totp_secret", secret);
			}

			if (inputToken.equals("PNG"))
				return new String(Base64.encode(getQRPNG(secret, user.userid)), "UTF-8");
			else if (inputToken.equals("secret"))
				return secret;
			else
				throw new PTException("Invalid token");
		} catch(PTException e) {
			throw e;
		} catch(Exception e) {
			cat.error("Got exception trying to create new token for user " + user.userid, e);
			throw new PTException("Error trying to create new security token for user", AuthErrorCodes.ERROR_GENERALERROR, "Unknown error trying to create new token");
		}
	}

	public void login(User user, String userid, Object credentials) throws PTException {
		if (credentials instanceof String) {
			// TODO: Verify userid and password and lookup the shared secret, store the secret for use on next call
			//user.setStateObject("saved_totp_secret", secret_found_in_userstore);

			user.setStateObject("totp_password_verified", Boolean.TRUE);
			throw new PTException("Need OTP", AuthErrorCodes.ERROR_NEED_OTP, "Need OTP code");
		}

		if (credentials instanceof String[]) {
			String[] creds = (String[])credentials;

			String secret = (String)user.getStateObject("saved_totp_secret");

			long code = 0;
			try {
				if (creds.length == 2) {
					// Assume we are called with password and OTP - supporting login using userid + password + OTP all in one dialog

					// TODO: Verify password, lookup secret
					//String password = creds[0];

					// secret = secret_found_in_userstore;

					code = Long.parseLong(creds[1]);
				} else {
					// Assume we are just called with the OTP, supporting 2nd step login using authenticator code

					// Verify that we we called first
					if (!Boolean.TRUE.equals(user.getStateObject("totp_password_verified"))) {
						throw new PTException("Called with OTP without verifying first using userid+password");
					}

					code = Long.parseLong(creds[0]);
				}
			} catch(NumberFormatException e) {
				throw new PTException("Password does not match", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid credentials", e);
			}

			// Check the google authenticator code
			try {
				if (!verifyCode(secret, code)) {
					throw new PTException("OTP does not match", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid credentials");
				}
			} catch (InvalidKeyException | NoSuchAlgorithmException e) {
				throw new PTException("OTP does not match", AuthErrorCodes.ERROR_INVALIDCREDENTIALS, "Invalid credentials", e);
			}

			user.userid = userid;
			user.isLoggedOn = true;
		} else {
			cat.error("Cannot login, unsupported type of credentials");
			throw new PTException("Unsupported type of credentials - cannot login", AuthErrorCodes.ERROR_GENERALERROR, "Unsupported type of credentials");
		}
	}
}

...