Package io.conducive.server.db.impl

Source Code of io.conducive.server.db.impl.UserDAOImpl

package io.conducive.server.db.impl;

import io.conducive.server.bind.DBFile;
import io.conducive.server.db.UserDAO;
import io.conducive.server.db.exception.DuplicateUserException;
import io.conducive.shared.model.User;
import static com.google.common.base.Preconditions.*;
import static com.google.common.hash.Hashing.*;
import org.mapdb.*;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.File;
import java.util.*;

@Singleton
public class UserDAOImpl extends AbstractMapDBDao implements UserDAO {

    private final static int EXP = 17;

    @Inject
    public UserDAOImpl(@DBFile File dbFile, DB db) {
        super(dbFile, db);
    }

    @Override
    public User getUser(final String username, final String password, final String salt) {
        checkNotNull(username, "Username should not be null");
        checkNotNull(password, "Password should not be null");

        final User user = users().get(username);
        if (user != null) {
            if (stretch(password, salt, EXP).equals(user.getHash())) {
                // don't surface the hash
                return new User(username);
            }
        }
        return null;
    }

    @Override
    public void createUser(final User user)
        throws DuplicateUserException
    {
        checkNotNull(user.getUsername(), "Username should not be null");
        checkNotNull(user.getHash(), "Password should not be null");
        checkNotNull(user.getSalt(), "Salt should not be null");

        if (users().containsKey(user.getUsername())) {
            throw new DuplicateUserException();
        }

        // hash from client is already stretched. stretch some more. distance from what is stored vs password is
        // 2^(LoginView.EXP + UserDAOImpl.EXP), i.e. 2^29
        logger.info("Stretching");
        User toStore = new User(user.getUsername(), stretch(user.getHash(), user.getSalt(), EXP));
        toStore.setSalt(user.getSalt());
        logger.info("Done stretching");
        users().put(user.getUsername(), toStore);
        // save to disk
        commit();
    }

    private NavigableMap<String, User> users() {
        return oneToOne("users");
    }

    public static String hash(final String password) {
        try {
            return sha256().hashBytes(password.getBytes("UTF-8")).toString();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * Lifted from "Cryptographic Engineering" - make it more expensive to crack a password by repeatedly hashing
     * with salt.
     *
     * TODO use scrypt once we have time.
     *
     * The effort to crack the password is increased by 2^exp. Salt can be public, as can exp.
     * @param password
     * @param salt
     * @param exp
     * @return
     */
    public static String stretch(String password, String salt, int exp) {
        String hash = hash(password + salt);
        for (int i = 0; i < Math.pow(2, exp); i++) {
            hash = hash(hash + password + salt);
        }
        return hash;
    }
}
TOP

Related Classes of io.conducive.server.db.impl.UserDAOImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.