/**
* Copyright (c) Members of the EGEE Collaboration. 2006-2009.
* See http://www.eu-egee.org/partners/ for details on the copyright holders.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glite.authz.pap.repository;
import java.util.LinkedList;
import java.util.List;
import org.glite.authz.pap.common.xacml.impl.TypeStringUtils;
import org.glite.authz.pap.common.xacml.utils.PolicySetHelper;
import org.glite.authz.pap.common.xacml.wizard.PolicySetWizard;
import org.glite.authz.pap.papmanagement.PapContainer;
import org.glite.authz.pap.papmanagement.PapManager;
import org.glite.authz.pap.repository.exceptions.RepositoryException;
import org.opensaml.xacml.policy.PolicySetType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class contains utility functions for the repository.
*/
public class RepositoryUtils {
private static final Logger log = LoggerFactory.getLogger(RepositoryUtils.class);
/**
* Checks the repository (all the local paps) for loops (i.e. policy sets containing circular
* references.
*
* @param repair if <code>true</code> loops are fixed by deleting lower level references, if
* <code>false</code> no action is performed and an error is logged.
* @return <code>true</code> if the check is successful (i.e. no loops are found or some loop
* were found but they were successfully deleleted), <code>false</code> otherwise.
*/
public static boolean checkForLoops(boolean repair) {
boolean result = true;
for (PapContainer papContainer : PapContainer.getContainers(PapManager.getInstance().getAllPaps())) {
if (checkForLoops(papContainer,
papContainer.getRootPolicySet(),
new LinkedList<String>(),
repair) == false) {
result = false;
}
}
return result;
}
/**
* Validates the XML of the policies in the repository (for the local paps). No log messages is
* printed in case of problems.
*
* @return <code>true</code> if the validation is successfully, <code>false</code> otherwise.
*/
public static boolean checkXMLValidation() {
List<PapContainer> containerList = PapContainer.getContainers(PapManager.getInstance().getLocalPaps());
for (PapContainer papContainer : containerList) {
try {
papContainer.getAllPolicySets();
papContainer.getAllPolicies();
} catch (RepositoryException e) {
log.error("Repository checkXMLValidation() failed: " + e.getMessage());
return false;
}
}
return true;
}
/**
* Validates the XML of the policies in the repository (for the local paps). In case of problems
* detailed log messages are printed reporting which file is corrupted and the suggested action
* to fix the problem.
*
* @param repair if <code>true</code> in case of problems tries to fix the repository by
* applying the suggested action (i.e. by removing the corrupted policy and all its
* references)..
* @return @return <code>true</code> if the validation is successfully or if the repository were
* successfully fixed, <code>false</code> otherwise.
*/
public static boolean checkXMLValidationInDetail(boolean repair) {
boolean result = true;
for (PapContainer papContainer : PapContainer.getContainers(PapManager.getInstance().getLocalPaps())) {
PolicySetType rootPS;
try {
rootPS = papContainer.getRootPolicySet();
} catch (RepositoryException e) {
String rootAlias = papContainer.getPap().getAlias();
String action = String.format("remove all policies and and policy sets for root policy set %s",
rootAlias);
log.error(String.format("The root policy set %s (id=%s) is corrupted. Suggested action: %s",
rootAlias,
action));
if (repair) {
log.info("Automatic repair is set. Action: " + action);
papContainer.deleteAllPolicies();
papContainer.deleteAllPolicySets();
papContainer.createRootPolicySet();
log.info("Automatic repair successfully completed (deleted root policy set " + rootAlias
+ ")");
} else {
result = false;
}
continue;
}
// check referenced policy sets (the root policy set doesn't have references to
// policies)
for (String policySetId : PolicySetHelper.getPolicySetIdReferencesValues(rootPS)) {
PolicySetType policySet;
try {
policySet = papContainer.getPolicySet(policySetId);
} catch (RepositoryException e) {
String action = String.format("remove policy set %s", policySetId);
log.error(String.format("The policy set \"%s\" is corrupted. Suggested action: %s",
policySetId,
action));
if (repair) {
log.info("Automatic repair is set. Action: " + action);
PolicySetHelper.deletePolicySetReference(rootPS, policySetId);
String version = rootPS.getVersion();
PolicySetWizard.increaseVersion(rootPS);
papContainer.updatePolicySet(version, rootPS);
papContainer.deletePolicySet(policySetId);
log.info("Automatic repair successfully completed (deleted policy set " + policySetId
+ ")");
} else {
result = false;
}
continue;
}
// check referenced policies (non-root policy sets don't have references to policy
// sets)
for (String policyId : PolicySetHelper.getPolicyIdReferencesValues(policySet)) {
try {
papContainer.getPolicy(policyId);
} catch (RepositoryException e) {
String action = String.format("remove policy %s", policyId);
log.error(String.format("The policy \"%s\" is corrupted. Suggested action: %s",
policyId,
action));
if (repair) {
log.info("Automatic repair is set. Action: " + action);
PolicySetHelper.deletePolicyReference(policySet, policyId);
String version = policySet.getVersion();
PolicySetWizard.increaseVersion(policySet);
papContainer.updatePolicySet(version, policySet);
papContainer.deletePolicy(policyId);
log.info("Automatic repair successfully completed (deleted policy " + policyId
+ ")");
} else {
result = false;
}
}
}
}
}
return result;
}
/**
* Perform all the consistency checks of the repository (for the local paps), in order:
* <code>checkXMLValidation</code> (if the result is <code>false</code> then a
* <code>checkXMLValidationInDetail</code>), <code>checkForLoops</code>,
* <code>purgeUnreferencedPolicySets</code> and <code>purgeUnreferencedPolicies</code>.
*
* @param repair if <code>true</code> problems are automatically fixed.
* @return <code>true</code> on success (both no problems found or repository successfully
* fixed), <code>false</code> otherwise.
*/
public static boolean performAllChecks(boolean repair) {
boolean success = true;
if (checkXMLValidation() == false) {
log.info("Starting detailed check for XML validation");
success = checkXMLValidationInDetail(repair);
}
if (success == true) {
log.info("Starting check for loops");
success = checkForLoops(repair);
}
if (success == true) {
log.info("Starting purge of unreferenced objects");
purgeUnreferencedPolicySets();
purgeUnreferencedPolicies();
}
return success;
}
/**
* Delete policies without rules for all local paps.
*/
public static void purgeUnreferencedPolicies() {
for (PapContainer papContainer : PapContainer.getContainers(PapManager.getInstance().getLocalPaps())) {
papContainer.purgeUnreferencesPolicies();
}
}
/**
* Delete policy sets without policies for all local paps.
*/
public static void purgeUnreferencedPolicySets() {
for (PapContainer papContainer : PapContainer.getContainers(PapManager.getInstance().getLocalPaps())) {
papContainer.purgeUnreferencedPolicySets();
}
}
/**
* Checks if there are loops in the policy set of a specific pap.
*
* @param papContainer check the policies of this pap.
* @param policySet policy set belonging to the policies of <code>papContainer</code> to check
* loops for.
* @param forbiddenIdList list of policy set ids that cannot appear inside this policy set and
* inside its children.
* @param repair if <code>true</code> references to ids contained in the
* <code>forbiddenList</code> are deleted.
* @return <code>true</code> if the check is successful (i.e. no loops are found or some loop
* were found but they were successfully deleleted), <code>false</code> otherwise.
*/
private static boolean checkForLoops(PapContainer papContainer, PolicySetType policySet,
List<String> forbiddenIdList, boolean repair) {
boolean result = true;
String policySetId = policySet.getPolicySetId();
forbiddenIdList.add(policySetId);
for (String id : forbiddenIdList) {
if (PolicySetHelper.hasPolicySetReferenceId(policySet, id)) {
String action = String.format("remove reference to policy set %s inside policy set %s",
id,
policySetId);
log.error(String.format("The policy set \"%s\" contains a loop. Suggested action: %s",
policySetId,
action));
if (repair) {
log.info("Automatic repair is set. Action: " + action);
PolicySetHelper.deletePolicySetReference(policySet, id);
String version = policySet.getVersion();
PolicySetWizard.increaseVersion(policySet);
papContainer.updatePolicySet(version, policySet);
log.info("Automatic repair successfully completed for policy set " + policySetId);
} else {
result = false;
}
}
}
List<String> policySetIdList = PolicySetHelper.getPolicySetIdReferencesValues(policySet);
TypeStringUtils.releaseUnneededMemory(policySet);
for (String id : policySetIdList) {
List<String> newForbiddenList = new LinkedList<String>();
for (String s : forbiddenIdList) {
newForbiddenList.add(s);
}
result = result
&& checkForLoops(papContainer, papContainer.getPolicySet(id), newForbiddenList, repair);
}
return result;
}
}