Task #3289
closedValidator Refactoring
100%
Description
We have several features and issues about Validator, which is more or less coupled.
We can take this opportunity to refactor Validator to make it simple and modular.
An ideal Validator should consists of three parts:
- a policy checker which determine if a packet complies with the trust model;
- key/cert retrieval from cache, trust anchor and network.
- a list of active validation instances of which each tracks the validation of an original packet.
The top-level class Validator defines the inter-operations between these modules, and virtual interface for others to implement detailed features.
class Validator {
public:
/** @brief Construct a Validator using @p face
*
* The policy checking module is implemented as checkPolicy method
* The instance management is internally managed by InstancePool
* @param enableLoopDetection Enable loop detection if true
*/
Validator(Face* face, bool enableLoopDetection = false);
/// @brief Validate data, invoke @p succeed if validated, otherwise invoke @p fail
void
validate(const Data& data, const SuccessCallback& succeed, const FailureCallback& fail)
{
auto instance = m_instancePool.allocate(data, succeed, fail);
reqs = validate(data, instance.succeed, instance.fail, instance.id);
}
/// @brief Validate interest, invoke @p succeed if validated, otherwise invoke @p fail
void
validate(const Interest& interest, const SuccessCallback& succeed, const FailureCallback& fail)
{
auto instance = m_instancePool.allocate(interest, succeed, fail);
reqs = validate(interest, instance.succeed, instance.fail, instance.id);
}
protected:
/** @brief Validate data, invoke @p succeed if validated, otherwise invoke @p fail,
* @param id The id of validation instance.
*/
template<typename Packet> void
validate(const Packet& packet, const SuccessCallback& succeed, const FailureCallback& fail, uint32_t id)
{
list<KeyRequest> reqs = checkPolicy(packet, succeed, fail, id);
// retrieve keys
for (const auto& req : reqs)
if (m_enableLoopDetection && m_instancePool.isLoopDetected(id, req))
req.FailureCallback();
else {
// retrieve keys...
auto cert = RetrieveTrustedKey(req);
if (cert != nullptr)
RetrievalSuccessCallback(cert);
else
RetrieveCertificate(req);
}
}
private:
virtual list<KeyRequest>
checkPolicy(const Data& data, const SuccessCallback& succeed, const FailureCallback& fail) = 0;
virtual list<KeyRequest>
checkPolicy(const Data& data, const SuccessCallback& succeed, const FailureCallback& fail) = 0;
protected:
// key management;
TrustAnchorContainer m_anchorCache;
CertificateCache m_verifiedKeyCache;
Cache m_unVerifiedKeyCache;
private:
Face* m_face;
// loop detection mode
bool m_enableLoopDetection;
// instance management;
InstancePool m_instancePool;
};
Updated by Junxiao Shi about 9 years ago
What is loop detection?
What's the benefit of having a pool for validation instances?
If it's just "memory allocation", a benchmark is needed.
Updated by Qiuhan Ding about 9 years ago
- Description updated (diff)
- Status changed from New to Code review
- Assignee changed from Yingdi Yu to Qiuhan Ding
Updated by Alex Afanasyev almost 8 years ago
- Assignee changed from Qiuhan Ding to Alex Afanasyev
- Target version changed from v0.5 to v0.6
In my latest implementation, the design has been adjusted: Validator is split from the ValidationPolicy. ValidationPolicy determines whether data/interest can be signed by the key name specified in the KeyLocator field, Validator performs actual signature verification, key retrieval, etc.
Here is the high-level interface:
/**
* @brief Abstraction that implements validation policy for Data and Interest packets
*/
class ValidationPolicy
{
public:
using ValidationContinuation = std::function<void(const shared_ptr<ValidationState>& state,
const shared_ptr<KeyRequest>& keyRequest)>;
/**
* @brief Check @p data against the policy
*
* Semantics of checkPolicy has changed from v1::Validator
* - If packet violates policy, the policy should call `state.fail` with appropriate error
* code and error description.
* - If packet conforms to the policy and no further key retrievals are necessary,
* the policy should call continueValidation(state, nullptr)
* - If packet conforms to the policy and key needs to be fetched, the policy should call
* continueValidation(state, <appropriate-key-request-instance>)
*/
virtual void
checkPolicy(const Data& data, const shared_ptr<ValidationState>& state,
const ValidationContinuation& continueValidation) = 0;
/**
* @brief Check @p interest against the policy
*
* Semantics of checkPolicy has changed from v1::Validator
* - If packet violates policy, the policy should call `state.fail` with appropriate error
* code and error description.
* - If packet conforms to the policy and no further key retrievals are necessary,
* the policy should call continueValidation(state, nullptr)
* - If packet conforms to the policy and key needs to be fetched, the policy should call
* continueValidation(state, <appropriate-key-request-instance>)
*/
virtual void
checkPolicy(const Interest& interest, const shared_ptr<ValidationState>& state,
const ValidationContinuation& continueValidation) = 0;
};
/**
* @brief Interface for validating data and interest packets.
*
* A validator can either operate in online mode or offline mode:
* - In online mode (a pointer to a valid Face instance passed to the constructor): certificates
* missing in the local cache will be retrieved from the network
* - In offline mode (nullptr passed to the constructor): only local cache will be used, failing
* validation if some certificates are missing.
*
* Every time a validation process initiated, it creates a ValidationState that exist until
* validation finishes either with success of failure. This instance ensures that each key is
* requested no more than once.
*
* A validator has a trust anchor cache to save static and dynamic trust anchors, a verified
* key cache for saving keys that is already verified and an unverified key cache for saving
* prefetched but not yet verified keys.
*/
class Validator : noncopyable
{
public:
/**
* @brief Validator constructor.
*
* @param policy Validation policy to be associated with the validator
* @param face Pointer to face for fetching keys from network. If provided, the Validator
* operates in online mode; otherwise, the Validator operates in offline mode.
*/
explicit
Validator(unique_ptr<ValidationPolicy> policy, Face* face = nullptr);
/**
* @brief Validate Data and trigger either success callback or failure callback.
*
* @param data Data to check.
* @param successCb Callback when @p data is validated.
* @param failureCb Callback when @p data is not validated.
*/
void
validate(const Data& data,
const DataValidationSuccessCallback& successCb,
const DataValidationFailureCallback& failureCb);
/**
* @brief Validate Interest and trigger either success callback or failure callback.
*
* @param interest Interest to check.
* @param successCb Callback when @p interest is validated.
* @param failureCb Callback when @p interest is not validated.
*/
void
validate(const Interest& interest,
const InterestValidationSuccessCallback& successCb,
const InterestValidationFailureCallback& failureCb);
};
Updated by Zhiyi Zhang almost 8 years ago
- Blocks Feature #2237: Remote prefix registration: fetch certificates from requester added
Updated by Zhiyi Zhang over 7 years ago
- Related to Task #3920: Convert existing validator implementations to v2::Validator added
Updated by Junxiao Shi over 7 years ago
- Status changed from Code review to Closed
There is no open Change on Gerrit for this issue. Further ValidationPolicy
work is being performed in #3920.