I am wondering what is the best design for a class-wide prerrequisite be enforced at construction time.
Let me put a simplified example.
I have a class representing a secure string, for example a Password. Passwords are only stored as their hash representation. Passwords cannot be inspected, but only checked against an attempted value.
class Password {
private String passwordHash;
private Password(){};
public Password(String aPassword) {
setPassword(aPassword);
}
public void setPassword(String aPassword) {
passwordHash = hash(aPassword);
}
public boolean checkPassword(String attempt) {
return verify(attempt, passwordHash);
}
}
The question is how to design the selection of the hashing algorithm. The client code must be able to choose from different hash algorithms. And, in a given application all passwords must use the same hash algorithm.
So, I define class wide static
hasher object.
I declare a Hasher interface,
interface Hasher {
String hash(String password);
boolean verify(String attempt, String hash);
}
There might be different XxxxHasher implementations.
class SimpleHasher implements Hasher {
public String hash(String password) { // native java String.hashCode()
return Integer.toString(password.hashCode(),16);
}
public boolean verify(String attempt, String hash) {
return attempt.hashCode()==Integer.valueOf(hash, 16);
}
}
class SecureHasher implements Hasher {
public String hash(String password) { // Secure SCrypt hash
return com.lambdaworks.crypto.SCryptUtil.scrypt(password,16384,8,1);
}
public boolean verify(String attempt, String hash) {
return com.lambdaworks.crypto.SCryptUtil.check(attempt,hash);
}
}
The client code must choose an implementation and set the hasher. Until then, no one can instantiate a Password. And once set, the hasher cannot be changed.
Here is the design decision.
Currently, I declare a static private
variable, so the hasher is the same for all Password instances; and a setter that enforces that it cannot be changed once is set.
class Password {
static private Hasher hasher = null;;
static public void setHasher(Hasher ahasher) throws Exception {
if (hasher!=null) throw new Exception("hasher cannot be changed");
hasher = ahasher
}
....
and the constructor ensures that hasher is set
class Password {
...
public Password(String aPassword) throws Exception {
if (hasher==null) throw new Exception("no hasher set yet");
setPassword(aPassword);
}
...
so far, so good. But, in my opinion, it doesn't look quite nice. I wonder if there is some common pattern to solve this problem. So my question is if such a pattern exists and how it can be implemented in my case.
Aucun commentaire:
Enregistrer un commentaire