/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/
package org.restlet.ext.crypto;
import java.util.logging.Level;
import org.restlet.Context;
import org.restlet.data.Digest;
import org.restlet.security.LocalVerifier;
import org.restlet.security.SecretVerifier;
/**
* Wrapper verifier that can verify digested secrets. If the provided secret is
* a digest, then the local secret must either be a digest of the same algorithm
* or the wrapped verifier must be a {@link LocalVerifier} returning secrets in
* clear.<br>
* <br>
* If the provided secret is a regular secret, then the local secret can be in
* any digest algorithm or a regular secret.
*
* @see Digest
* @see DigestAuthenticator
* @author Jerome Louvel
*/
public class DigestVerifier<T extends SecretVerifier> extends SecretVerifier {
/** The digest algorithm of provided secrets. */
private String algorithm;
/** The digest algorithm of secrets returned by the wrapped verifier. */
private String wrappedAlgorithm;
/** The wrapped secret verifier. */
private T wrappedVerifier;
/**
* Constructor.
*
* @param algorithm
* The digest algorithm of provided secrets.
* @param wrappedVerifier
* The wrapped secret verifier.
* @param wrappedAlgorithm
* The digest algorithm of secrets provided by the wrapped
* verifier.
* @see Digest
*/
public DigestVerifier(String algorithm, T wrappedVerifier,
String wrappedAlgorithm) {
this.algorithm = algorithm;
this.wrappedAlgorithm = wrappedAlgorithm;
this.wrappedVerifier = wrappedVerifier;
}
/**
* Computes the digest of a secret according to a specified algorithm. By
* default, MD5 hashes (represented as a sequence of 32 hexadecimal digits)
* and SHA-1 hashes are supported. For additional algorithm, override this
* method.
*
* @param identifier
* The user identifier.
* @param secret
* The regular secret to digest.
* @param algorithm
* The digest algorithm to use.
* @return The digested secret.
* @see Digest
*/
protected char[] digest(String identifier, char[] secret, String algorithm) {
return DigestUtils.digest(secret, algorithm);
}
/**
* Returns the digest algorithm of provided secrets. Provided secrets are
* the ones sent by clients when attempting to authenticate.
*
* @return The digest algorithm of input secrets.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* Returns the digest algorithm of secrets returned by the wrapped verifier.
* The secrets from the wrapped verifier are the ones used by the verifier
* to compare those sent by clients when attempting to authenticate.
*
* @return The digest algorithm of secrets returned by the wrapped verifier.
*/
public String getWrappedAlgorithm() {
return wrappedAlgorithm;
}
/**
* Returns the wrapped secret associated to a given identifier. This method
* can only be called if the wrapped verifier is a {@link LocalVerifier}.
*
* @param identifier
* The identifier to lookup.
* @return The secret associated to the identifier or null.
*/
public char[] getWrappedSecret(String identifier) {
char[] result = null;
if (getWrappedVerifier() instanceof LocalVerifier) {
LocalVerifier localVerifier = (LocalVerifier) getWrappedVerifier();
result = localVerifier.getLocalSecret(identifier);
} else {
Context
.getCurrentLogger()
.log(
Level.WARNING,
"The wrapped verifier must be a LocalVerifier to allow digesting of wrapped secrets.");
}
return result;
}
/**
* Returns the digest of the wrapped secret associated to a given
* identifier. If the wrapped algorithm is null it returns the digest of the
* wrapped secret, otherwise the algorithms must be identical. This method
* can only be called if the wrapped verifier is a {@link LocalVerifier}.
*
* @param identifier
* The identifier to lookup.
* @return The secret associated to the identifier or null.
*/
public char[] getWrappedSecretDigest(String identifier) {
char[] result = null;
if (getWrappedAlgorithm() == null) {
result = digest(identifier, getWrappedSecret(identifier),
getAlgorithm());
} else if (getAlgorithm().equals(getWrappedAlgorithm())) {
result = getWrappedSecret(identifier);
} else {
Context.getCurrentLogger().log(Level.WARNING,
"The digest algorithms can't be different.");
}
return result;
}
/**
* Returns the wrapped secret verifier.
*
* @return The wrapped secret verifier.
*/
public T getWrappedVerifier() {
return wrappedVerifier;
}
/**
* Sets the digest algorithm of provided secrets. Provided secrets are the
* ones sent by clients when attempting to authenticate.
*
* @param algorithm
* The digest algorithm of secrets provided by the user.
* @see Digest
*/
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
/**
* Sets the digest algorithm of secrets returned by the wrapped verifier.
* The secrets from the wrapped verifier are the ones used by the verifier
* to compare those sent by clients when attempting to authenticate.
*
* @param wrappedAlgorithm
* The digest algorithm of secrets returned by the wrapped
* verifier.
* @see Digest
*/
public void setWrappedAlgorithm(String wrappedAlgorithm) {
this.wrappedAlgorithm = wrappedAlgorithm;
}
/**
* Sets the wrapped secret verifier.
*
* @param wrappedVerifier
* The wrapped secret verifier.
*/
public void setWrappedVerifier(T wrappedVerifier) {
this.wrappedVerifier = wrappedVerifier;
}
@Override
public boolean verify(String identifier, char[] secret) {
boolean result = false;
char[] secretDigest = secret;
if (getAlgorithm() == null) {
if (getWrappedAlgorithm() != null) {
secretDigest = digest(identifier, secret, getWrappedAlgorithm());
} else {
// Both secrets should be in clear
}
result = getWrappedVerifier().verify(identifier, secretDigest);
} else {
if (getWrappedAlgorithm() == null) {
result = compare(secretDigest,
getWrappedSecretDigest(identifier));
} else if (getAlgorithm().equals(getWrappedAlgorithm())) {
result = getWrappedVerifier().verify(identifier, secretDigest);
} else {
Context.getCurrentLogger().log(Level.WARNING,
"The input and output algorithms can't be different.");
}
}
return result;
}
}