All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.security.fences.config.Fence Maven / Gradle / Ivy

Go to download

Augments Java's access control by checking that a Maven Project and all its dependencies conform to a policy that specifies which classes/packages can link to which others.

There is a newer version: 1.9-beta
Show newest version
package com.google.security.fences.config;

import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.security.fences.inheritance.InheritanceGraph;
import com.google.security.fences.namespace.Namespace;
import com.google.security.fences.policy.ApiElement;

/**
 * A bean object that can be populated from a POM file {@code }
 * element to specify a {@link com.google.security.fences.policy.Policy}.
 */
public abstract class Fence {
  private final List trusts = Lists.newArrayList();
  private final List distrusts = Lists.newArrayList();
  private final Rationale.Builder rationale = new Rationale.Builder();
  /**
   * We keep track of the round in which this is imported, so that when
   * combining configurations into policies, we can drop imported rationales
   * in fovor of project-level ones that override them for a particular
   * API element.
   */
  private int importOrder = -1;

  Fence() {
    // package private
  }

  /**
   * A key used to group children that refer to the same API element.
   * When used, the key will be prefixed with the class name, which has the
   * effect of segregating method/field/class namespaces.
   * 

* This must be independent of children, trusts, distrusts, and rationale -- * all of the state that can be merged with another node. */ abstract String getKey(); /** * A setter called by reflection during rule configuration. Actually adds * instead of blowing away prior value. */ public void setTrusts(String s) throws EnforcerRuleException { trusts.add(parsePrinciple(s)); } /** * A setter called by reflection during rule configuration. Actually adds * instead of blowing away prior value. */ public void setDistrusts(String s) throws EnforcerRuleException { distrusts.add(parsePrinciple(s)); } /** * A human readable string shown when a policy violation is detected that * explains how to work within the policy and where to find more help. *

* The documentation at src/site/markdown/configuration.md explains how * to write a good one. * * @param s Human-readable text that may contain maven property expressions. */ public void setRationale(@Nullable String s) throws EnforcerRuleException { if (s != null) { rationale.addBody(s); } } /** * A human readable string like a {@link #setRationale rationale} but which * is appended at the end regardless of whether there is a more specific * rationale. *

* The documentation at src/site/markdown/configuration.md explains how * to use addenda. * * @param s Human-readable text that may contain maven property expressions. */ public void setAddendum(@Nullable String s) throws EnforcerRuleException { if (s != null) { rationale.addAddendum(s); } } /** By default, just checks children. */ public void check() throws EnforcerRuleException { for (Fence childFence : getChildFences()) { childFence.check(); } } /** Fences contained herein. */ public abstract Iterable getChildFences(); /** Updates the list from {@link #getChildFences}. */ abstract void replaceChildFences(Iterable newChildren); /** * The API elements trusted or distrusted by the API element specified by * this fence. */ public final Frenemies getFrenemies() { Frenemies.Builder b = Frenemies.builder(); for (Namespace ns : trusts) { b.addFriend(ns); } for (Namespace ns : distrusts) { b.addEnemy(ns); } b.setRationale(rationale.build()); return b.build(); } /** * Called to specify the import order used when resolving duplicate * rationales for a particular API element. */ public final void assignImportOrder(int newImportOrder) { Preconditions.checkState(this.importOrder == -1); Preconditions.checkArgument(newImportOrder >= 0); this.importOrder = newImportOrder; for (Fence child : getChildFences()) { child.assignImportOrder(newImportOrder); } } /** * Modifies children in place so that no node in the fence tree has a dotted * name. * @return the split node so that parents may modify their child lists. */ public abstract Fence splitDottedNames(ApiElement parent, InheritanceGraph g) // TODO: better exception type throws EnforcerRuleException; /** * Does minimal wrapping to produce a top-level API fence. */ public ApiFence promoteToApi() { throw new IllegalStateException("Cannot promote " + getClass()); } final void mergeFrom(Fence that) { this.trusts.addAll(that.trusts); this.distrusts.addAll(that.distrusts); // Merge rationales, giving preference to bodies with a lower import order. if (this.importOrder > that.importOrder && !that.rationale.getBody().isEmpty()) { this.rationale.setBodyFrom(that.rationale.build()); } else if (this.importOrder == that.importOrder) { this.rationale.addBodyFrom(that.rationale.build()); } this.rationale.addAddendumFrom(that.rationale.build()); } /** * Merge the salient details of the given configuration into this one, * guaranteeing that there is only one child with a given name. */ public final void mergeDeep(Fence f) { mergeFrom(f); // Group children by key, merging recursively. Map childrenByKey = Maps.newLinkedHashMap(); ImmutableList childrenToMerge = ImmutableList.builder() .addAll(getChildFences()) .addAll(f.getChildFences()) .build(); for (Fence childToMerge : childrenToMerge) { String fullKey = childToMerge.getClass().getName() + " : " + childToMerge.getKey(); Fence previousChild = childrenByKey.get(fullKey); if (previousChild != null) { previousChild.mergeDeep(childToMerge); } else { childrenByKey.put(fullKey, childToMerge); } } replaceChildFences(childrenByKey.values()); } abstract void visit(FenceVisitor v, ApiElement el); /** Start recursively walking the fence tree. */ public final void visit(FenceVisitor v) { visit(v, ApiElement.DEFAULT_PACKAGE); } abstract String getConfigurationElementName(); void fleshOutEffectiveConfiguration(Element el) { Document doc = el.getOwnerDocument(); for (Namespace ns : trusts) { Element trustElement = doc.createElement("trusts"); trustElement.appendChild(doc.createTextNode(toTextNode(ns))); el.appendChild(trustElement); } for (Namespace ns : distrusts) { Element trustElement = doc.createElement("distrusts"); trustElement.appendChild(doc.createTextNode(toTextNode(ns))); el.appendChild(trustElement); } HumanReadableText rbody = rationale.getBody(); if (!rbody.isEmpty()) { Element rationaleElement = doc.createElement("rationale"); rationaleElement.appendChild(doc.createTextNode(rbody.text)); el.appendChild(rationaleElement); } HumanReadableText addendum = rationale.getAddendum(); if (!addendum.isEmpty()) { Element addendumElement = doc.createElement("addendum"); addendumElement.appendChild(doc.createTextNode(addendum.text)); el.appendChild(addendumElement); } for (Fence child : getChildFences()) { Element childEl = doc.createElement(child.getConfigurationElementName()); el.appendChild(childEl); child.fleshOutEffectiveConfiguration(childEl); } } private static String toTextNode(Namespace ns) { if (Namespace.DEFAULT_PACKAGE.equals(ns)) { return "*"; } return ns.toString(); } private static Namespace parsePrinciple(String s) throws EnforcerRuleException { String trimmed = s.trim(); if (!"*".equals(trimmed) && trimmed.contains("*")) { throw new EnforcerRuleException( "Globs not allowed in namespace names: " + trimmed); } return Namespace.fromDottedString(trimmed); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy