Thursday, April 27, 2017

Creating Strong Password using Stream API of Java 9


Creating a strong password has never been so easy in Java when Stream API is used. Stream API is introduced in Java SE 8 and has changed the way we think and develop in Java together with the functional programming and lambda expressions. Java 9 will improve the Stream API with new convenience methods. Stream API is basically designed to work with collections in functional style. I would like to exemplify this new way of thinking simply by creating a strong password: 

package com.example.java9.features;

import java.security.SecureRandom;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public final class StrongPasswordApplication {
    private static final List<String> CHARACTER_TABLE= List.of(
        "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
        "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
        "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 
        "0", "1", "2", "3", "4", "5", "6","7","8","9",
        "_", "-", "$", "@", "#", "?", "%" 
    );
    public static String create(int length){
        return new SecureRandom()
                .ints(0,CHARACTER_TABLE.size())
                .limit(length)
                .boxed()
                .map( CHARACTER_TABLE::get )                
                .collect(Collectors.joining());
    }    
}

There are new methods added to the Stream interface in Java 9: dropWhile, takeWhile, ofNullable. Now, we allow the application programmer to define what strong password is and create a password that conforms that definition:

package com.example.java9.features;

import java.security.SecureRandom;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class RandomPasswordApplication {

    private static final List<String> CHARACTER_TABLE = List.of(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
            "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
            "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "_", "-", "$", "@", "#", "&", "%", "/", "\\", "?",
            "*", "+", "!", ".", ",", ";", "~", "'", "\"", "<", ">"
    );

    public static void main(String[] args) {
        IntStream.range(8, 15)
                .boxed()
                .map(RandomPasswordApplication::createpassword)
                .map(password -> String.format("Password [length=%d] is %s", password.length(), password))
                .forEach(System.out::println);
    }

    public static String createpassword(int length) {
        final StrongPassword strongness = new StrongPassword.Builder()
                .minimumNumberOfDigits(1)
                .minimumNumberOfSpecialCharacters(1)
                .minimumNumberOfCapitalLetters(1)
                .minimumLength(length)
                .build();
        return new SecureRandom()
                .ints(0, CHARACTER_TABLE.size())
                .boxed()
                .map(CHARACTER_TABLE::get)
                .takeWhile(strongness::isWeek)
                .collect(Collectors.joining());
    }

}

StrongPassword class defines the strongness of the password:

package com.example.java9.features;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class StrongPassword {

    private final int minimumNumberOfDigits;
    private final int minimumNumberOfCapitalLetters;
    private final int minimumNumberOfSpecialCharacters;
    private final int minimumLength;
    private int length;
    private int numberOfDigits;
    private int numberOfSpecialCharacters;
    private int numberOfCapitalLetters;

    private StrongPassword(Builder builder) {
        this.minimumNumberOfDigits = builder.minimumNumberOfDigits;
        this.minimumNumberOfCapitalLetters = builder.minimumNumberOfCapitalLetters;
        this.minimumNumberOfSpecialCharacters = builder.minimumNumberOfSpecialCharacters;
        this.minimumLength = builder.minimumLength;
    }

    public boolean isWeek(String s) {
        final boolean isWeekPassword = (length < minimumLength)
                || (numberOfDigits < minimumNumberOfDigits)
                || (numberOfSpecialCharacters < minimumNumberOfSpecialCharacters)
                || (numberOfCapitalLetters < minimumNumberOfCapitalLetters);
        length++;
        if (Character.isDigit(s.charAt(0))) {
            numberOfDigits++;
        } else if (!Character.isLetter(s.charAt(0))) {
            numberOfSpecialCharacters++;
        } else if (s.equals(s.toUpperCase())) {
            numberOfCapitalLetters++;
        }
        return isWeekPassword;
    }

    public static class Builder {

        private int minimumNumberOfDigits;
        private int minimumNumberOfCapitalLetters;
        private int minimumNumberOfSpecialCharacters;
        private int minimumLength;

        public Builder minimumNumberOfDigits(int minimumNumberOfDigits) {
            this.minimumNumberOfDigits = minimumNumberOfDigits;
            return this;
        }

        public Builder minimumNumberOfCapitalLetters(int minimumNumberOfCapitalLetters) {
            this.minimumNumberOfCapitalLetters = minimumNumberOfCapitalLetters;
            return this;
        }

        public Builder minimumNumberOfSpecialCharacters(int minimumNumberOfSpecialCharacters) {
            this.minimumNumberOfSpecialCharacters = minimumNumberOfSpecialCharacters;
            return this;
        }

        public Builder minimumLength(int minimumLength) {
            this.minimumLength = minimumLength;
            return this;
        }

        public StrongPassword build() {
            return new StrongPassword(this);
        }
    }
}

One example output of the execution is given below:

Password [length=8] is k@\D%b16
Password [length=9] is "+fORbi9f
Password [length=10] is D35g,'7zKN
Password [length=11] is PJTnpN~YN1o
Password [length=12] is 2AD!H"xGhBZd
Password [length=13] is b+A9-Ovzc+,RD
Password [length=14] is *@Nj\89nW7ep5B

You could retrieve the code from this URL as NetBeans IDE Dev (Build 2017-06-14-0001project.