// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/HashProvider.java
// public interface HashProvider {
//     boolean validateHash(final String password, final PrincipalDetail principalDetail);
// 
//     boolean canHandle(String hashConfig);
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/PrincipalDetail.java
// @Value
// public class PrincipalDetail {
//     private final String username;
//     private final String passwordHash;
//     private final String salt;
//     private final String hashConfiguration;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/Constants.java
// public class Constants {
//     public static final String PLUGIN_ID = "strongauth";
// }
// 
// Path: src/main/java/com/thoughtworks/util/Functional.java
// public static <T, U> Optional<U> flatMap(Optional<? extends T> maybeValue, final Function<T, Optional<U>> transformation) {
//     return maybeValue.isPresent() ? transformation.apply(maybeValue.get()) : Optional.<U>absent();
// }


import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.thoughtworks.go.plugin.api.logging.Logger;
import com.thoughtworks.go.strongauth.authentication.HashProvider;
import com.thoughtworks.go.strongauth.authentication.PrincipalDetail;
import com.thoughtworks.go.strongauth.util.Constants;
import lombok.Value;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.thoughtworks.util.Functional.flatMap;
import static java.lang.Integer.parseInt;
package com.thoughtworks.go.strongauth.authentication.hash;




public class PBESpecHashProvider implements HashProvider {
    public final String pluginId = Constants.PLUGIN_ID;
    private static final Logger LOGGER = Logger.getLoggerFor(PBESpecHashProvider.class);

    private static final Pattern HASH_CONFIG_PATTERN = Pattern.compile("^(\\w+)\\((\\d+), (\\d+)\\)$");

    @Override
    public boolean validateHash(final String password, final PrincipalDetail principalDetail) {
        Optional<HashConfig> maybeHashConfig = parseHashConfig(principalDetail.getHashConfiguration());
        return maybeHashConfig.transform(new Function<HashConfig, Boolean>() {
            @Override
            public Boolean apply(HashConfig hashConfig) {
                PBEKeySpec spec = new PBEKeySpec(
                        password.toCharArray(),
// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/HashProvider.java
// public interface HashProvider {
//     boolean validateHash(final String password, final PrincipalDetail principalDetail);
// 
//     boolean canHandle(String hashConfig);
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/PrincipalDetail.java
// @Value
// public class PrincipalDetail {
//     private final String username;
//     private final String passwordHash;
//     private final String salt;
//     private final String hashConfiguration;
// }
// 
// Path: src/main/java/com/thoughtworks/go/strongauth/util/Constants.java
// public class Constants {
//     public static final String PLUGIN_ID = "strongauth";
// }
// 
// Path: src/main/java/com/thoughtworks/util/Functional.java
// public static <T, U> Optional<U> flatMap(Optional<? extends T> maybeValue, final Function<T, Optional<U>> transformation) {
//     return maybeValue.isPresent() ? transformation.apply(maybeValue.get()) : Optional.<U>absent();
// }


// Path: src/main/java/com/thoughtworks/go/strongauth/authentication/hash/PBESpecHashProvider.java
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.thoughtworks.go.plugin.api.logging.Logger;
import com.thoughtworks.go.strongauth.authentication.HashProvider;
import com.thoughtworks.go.strongauth.authentication.PrincipalDetail;
import com.thoughtworks.go.strongauth.util.Constants;
import lombok.Value;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.thoughtworks.util.Functional.flatMap;
import static java.lang.Integer.parseInt;

package com.thoughtworks.go.strongauth.authentication.hash;




public class PBESpecHashProvider implements HashProvider {
    public final String pluginId = Constants.PLUGIN_ID;
    private static final Logger LOGGER = Logger.getLoggerFor(PBESpecHashProvider.class);

    private static final Pattern HASH_CONFIG_PATTERN = Pattern.compile("^(\\w+)\\((\\d+), (\\d+)\\)$");

    @Override
    public boolean validateHash(final String password, final PrincipalDetail principalDetail) {
        Optional<HashConfig> maybeHashConfig = parseHashConfig(principalDetail.getHashConfiguration());
        return maybeHashConfig.transform(new Function<HashConfig, Boolean>() {
            @Override
            public Boolean apply(HashConfig hashConfig) {
                PBEKeySpec spec = new PBEKeySpec(
                        password.toCharArray(),
                        Base64.decodeBase64(principalDetail.getSalt()),