/*
* Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE file for licensing information.
*/
package eu.emi.security.authn.x509;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import eu.emi.security.authn.x509.impl.X500NameUtils;
/**
* Holds information about a single validation problem with a reference to
* the certificate chain.
* Each error may refer to particular certificate in the chain, contains an unique
* code and a coarse grained category.
*
* @author K. Benedyczak
* @see ValidationResult
* @see ValidationErrorListener
* @see ValidationErrorCategory
*/
public class ValidationError
{
private static final String BUNDLE_NAME = ValidationError.class.getPackage().getName() +
"." + "valiadationErrors";
private int position;
private ValidationErrorCode errorCode;
private ValidationErrorCategory errorCategory;
private String message;
private Object[] parameters;
private X509Certificate[] chain;
public ValidationError(X509Certificate[] chain, int position, ValidationErrorCode errorCode, Object... params)
{
this.position = position;
this.chain = chain;
if (errorCode == null)
throw new IllegalArgumentException("errorCode can not be null");
this.errorCode = errorCode;
this.errorCategory = ValidationErrorCategory.getErrorCategory(errorCode);
this.parameters = params;
ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME);
String pattern;
try
{
pattern = bundle.getString(errorCode.name());
} catch (MissingResourceException e)
{
pattern = "Other validation error";
}
if (parameters.length > 0 && parameters[0] instanceof Throwable
&& !pattern.matches(".*\\{[0-9]\\}.*"))
{
message = pattern + makeReasonFromStack((Throwable) parameters[0]);
} else
message = MessageFormat.format(pattern, params);
}
public static String makeReasonFromStack(Throwable t)
{
StringBuilder sb = new StringBuilder();
do
{
sb.append(" Cause: ").append(makeReason(t));
t = t.getCause();
} while (t != null);
return sb.toString();
}
public static String makeReason(Throwable t)
{
return (t.getMessage() != null) ?
t.getMessage() : t.getClass().getSimpleName();
}
/**
* Returns position in chain of the certificate causing the error.
* If the error is related to chain inconsistency (so more then one certificate is
* involved) then the lowest number of the certificate
* involved must be returned.
* @return position of the erroneous certificate in chain or -1 if not defied.
*/
public int getPosition()
{
return position;
}
/**
* Returns human readable message describing this error. The message is
* formatted in accordance to the current locale settings.
* @return the error message
*/
public String getMessage()
{
return message;
}
/**
* Gets the unique error code. Error codes are defined in bundle with messages
* (in a properties file).
*
* @return the error code
*/
public ValidationErrorCode getErrorCode()
{
return errorCode;
}
/**
* Gets the error parameters.
*
* @return the error parameters
*/
public Object[] getParameters()
{
return parameters;
}
/**
* Returns a coarse grained error category.
* @return error category
*/
public ValidationErrorCategory getErrorCategory()
{
return errorCategory;
}
/**
*
* @return the certificate chain which caused the validation error
*/
public X509Certificate[] getChain()
{
return chain;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("error");
if (position != -1)
{
sb.append(" at position ").append(getPosition()).append(" in chain");
sb.append(", problematic certificate subject: ").append(
X500NameUtils.getReadableForm(chain[position].getSubjectX500Principal()));
} else
sb.append(" affecting the whole chain");
sb.append(" (category: ").append(errorCategory).append(")");
sb.append(": ").append(getMessage());
return sb.toString();
}
}