package com.hwlcn.security.authc.credential; import com.hwlcn.security.authc.AuthenticationInfo; import com.hwlcn.security.authc.AuthenticationToken; import com.hwlcn.security.crypto.hash.Hash; public class PasswordMatcher implements CredentialsMatcher { private PasswordService passwordService; public PasswordMatcher() { this.passwordService = new DefaultPasswordService(); } public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { PasswordService service = ensurePasswordService(); Object submittedPassword = getSubmittedPassword(token); Object storedCredentials = getStoredPassword(info); assertStoredCredentialsType(storedCredentials); if (storedCredentials instanceof Hash) { Hash hashedPassword = (Hash)storedCredentials; HashingPasswordService hashingService = assertHashingPasswordService(service); return hashingService.passwordsMatch(submittedPassword, hashedPassword); } String formatted = (String)storedCredentials; return passwordService.passwordsMatch(submittedPassword, formatted); } private HashingPasswordService assertHashingPasswordService(PasswordService service) { if (service instanceof HashingPasswordService) { return (HashingPasswordService) service; } String msg = "AuthenticationInfo's stored credentials are a Hash instance, but the " + "configured passwordService is not a " + HashingPasswordService.class.getName() + " instance. This is required to perform Hash " + "object password comparisons."; throw new IllegalStateException(msg); } private PasswordService ensurePasswordService() { PasswordService service = getPasswordService(); if (service == null) { String msg = "Required PasswordService has not been configured."; throw new IllegalStateException(msg); } return service; } protected Object getSubmittedPassword(AuthenticationToken token) { return token != null ? token.getCredentials() : null; } private void assertStoredCredentialsType(Object credentials) { if (credentials instanceof String || credentials instanceof Hash) { return; } String msg = "Stored account credentials are expected to be either a " + Hash.class.getName() + " instance or a formatted hash String."; throw new IllegalArgumentException(msg); } protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) { Object stored = storedAccountInfo != null ? storedAccountInfo.getCredentials() : null; if (stored instanceof char[]) { stored = new String((char[])stored); } return stored; } public PasswordService getPasswordService() { return passwordService; } public void setPasswordService(PasswordService passwordService) { this.passwordService = passwordService; } }