0

I have already developed a standalone app and now i would like to perform authentication

One of the ways would be to use a servlet but i would like my application to be standalone app which doesnt need to communicate with the server.

So my login code is

    //loads the login screen
    @Override
public void start(Stage primaryStage) throws IOException {
    Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
    primaryStage.setTitle("Login screen");
    Scene loginscene = new Scene(root,700, 700);
   loginscene.setOnKeyPressed(new EventHandler<KeyEvent>() {
       @Override
       public void handle(KeyEvent event) {
           switch (event.getCode()){
               case ENTER:{
                   onLogin();
               }
           }
       }
   });
    primaryStage.setScene(loginscene);
    primaryStage.initStyle(StageStyle.UNDECORATED);
     primaryStage.getIcons().add(new Image("file:icon.png"));
     primaryStage.centerOnScreen();
    primaryStage.setResizable(false);
    primaryStage.show();
}

The login method is

onLOgin(){

   //here am stuck on how to proceed

  }

Does anyone has a clue on how i should proceed. App can connect directly to a mysql or mssql database hence the password can be stored there but i want store it in a hashed form so that a user cannot directly see the password

How do i handle such a situation.Am still new to java.

Piro
  • 1,367
  • 2
  • 19
  • 40
Geoff
  • 6,277
  • 23
  • 87
  • 197
  • `doesnt need to communicate with the server` so fully local app - I have to set authentication on every PC it is used and there is no data shared between them? Is PIN code enough? – Piro Feb 14 '18 at 13:00
  • `For the app the javafx can connect directly to a mysql or mssql database hence the password can be stored there but i want store it in a hashed form so that a user cannot directly see the password.` This is probably what you should do. When creating the user, store his hashed password in some form of database. When the user tries to login, you hash the password he has entered and compare it to the one in the database. You can find lots of password hashing tutorials online. – Markus Köbele Feb 14 '18 at 15:23

1 Answers1

1

When developing authentication I followed this guide. It describes how passwords are hacked and what you need to do to protect user passwords. Provides some good tips on hashing process. In short:

  • store only hash of your password (and salt, see below)
  • Use existing hashing functions - they are better than inventing own hashing
  • hash with salt - salt is random so even same passwords will have different hashes
  • salt has to generated for every password change

So in database you need 2 - 3 columns

  • login name
  • password hash
  • salt (if not combined into password hash)

Authentication will create hash from provided password (and stored salt) and compare it to stored hash (under specified login name). Error message for invalid login name or password should be same (invalid user name or password) so it is not easy to find user names.

Under the hood my authentication method looks like this:

public User authenticate(String login, String password) {
    final User user = UserService.getInstance().getUser(login);
    if(user != null) {
        //check password
        byte[] passwordHash = PasswordManipulator.instance.hash(password, user.getPasswordSalt());
        if(Arrays.equals(passwordHash, user.getPasswordHash())) {
            return user;
        }
        else {
            // invalid password, we return no user
            return null;
        }
    }
    return null;
}

returning null means either login or password is invalid. UserService simply reads user table and return it as User object.

PasswordManipulator looks like this:

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class PasswordManipulator {
private static final int SaltLength = 32;
private static final int IterationCount = 65536;
private static final int KeyLength = 256;
private final SecureRandom random = new SecureRandom();
SecretKeyFactory factory = null;

public static final PasswordManipulator instance = new PasswordManipulator();

private PasswordManipulator() {

}

public byte[] createSalt() {
    byte[] salt = new byte[SaltLength];
    random.nextBytes(salt);
    return salt;
}

public byte[] hash(String password, byte[] salt) {
    init();
    if(password == null || password.isEmpty()) {
        throw new IllegalArgumentException("Password is null or empty");
    }
    if(salt == null ) {
        throw new IllegalArgumentException("Salt is null!");
    }
    if(salt.length != SaltLength) {
        throw new IllegalArgumentException("Salt length is not valid. Expected length is " + SaltLength + ", but length is " + salt.length);
    }
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, IterationCount, KeyLength);
    try {
        byte[] hash = factory.generateSecret(spec).getEncoded();
        return hash;
    } catch (InvalidKeySpecException e) {
        throw new IllegalArgumentException("Failed to create password hash", e);
    }
}

private void init(){
    if(factory == null) {
        try {
            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Cannot init " + this.getClass(), e);
        }
    }
}

}

You probably need some database to embed into your application, or have other way of database setup on client. Check this comparison of embedded databases. To connect to database use standard JDBC way.

Question is what will you do if user will forget password. Standard way is to use email for password recovery (and user login to be equal to email or email to be required user information), but that require online connection. Maybe have some password recovery backup questions that user has to answer correctly. Or if you have some form of administrative user, administrative user could reset passwords for standard users.

There are also other ways of authentication like using Active directory, but you need some infrastructure already set up to connect to it.

Piro
  • 1,367
  • 2
  • 19
  • 40