/* * Part of the CCNx Java Library. * * Copyright (C) 2008-2012 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.impl.repo; import static org.ccnx.ccn.impl.repo.RepositoryStore.REPO_DATA; import static org.ccnx.ccn.impl.repo.RepositoryStore.REPO_POLICY; import java.io.InputStream; import java.util.ArrayList; import org.ccnx.ccn.impl.encoding.TextXMLCodec; import org.ccnx.ccn.impl.encoding.XMLCodecFactory; import org.ccnx.ccn.impl.encoding.XMLDecoder; import org.ccnx.ccn.impl.support.Log; import org.ccnx.ccn.io.content.ContentDecodingException; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.MalformedContentNameStringException; /** * A reference implementation of Policy using an XML based policy file * * TODO policy change requests via the network are currently totally insecure and could easily be * exploited to disrupt the proper functioning of a repository. * * The policy file is structured as follows: * * All elements must be nested within a <policy> element.<p> * * The file must contain a <version> element with an id attribute set to a string * corresponding to the current version of the repository which is "1.4".<p> * * The file must contain a <localname> element which specifies the local name.<p> * The file must contain a <globalname> element which specifies the global name.<p> * The file may contain any number of <namespace> elements specifying namespaces<p> * covered by the repository * * <pre> * For example: * <Policy> * <PolicyVersion> 1.5 </PolicyVersion> * <LocalName> TestRepository </LocalName> * <GlobalPrefix> parc.com/csl/ccn/repositories </GlobalPrefix> * <Namespace> /testNameSpace </Namespace> * <Namespace> /testNameSpace2 </Namespace> * </Policy> * </pre> * */ public class BasicPolicy implements Policy { public static final String POLICY = "POLICY"; public String POLICY_VERSION = "1.5"; protected String _repoVersion = null; // set from repo protected PolicyXML _pxml = null; /** * Constructor defaulting initial namespace to everything with no * localName */ public BasicPolicy() { this(null); } /** * Constructor defaulting the initial namespace to "everything" * @param name local name for this repository */ public BasicPolicy(String name) { _pxml = new PolicyXML(); try { if (null != name) _pxml.setLocalName(name); _pxml.setVersion(POLICY_VERSION); _pxml.addNamespace(ContentName.fromNative("/")); } catch (MalformedContentNameStringException e) {} } /** * Constructor allowing an initial namespace to be set * @param name local name for this repository * @param namespace the initial namespace */ public BasicPolicy(String name, ArrayList<ContentName> namespace) { this(name); if (null != namespace) { _pxml.setNamespace(namespace); } } public void updateFromInputStream(InputStream stream) throws RepositoryException { PolicyXML pxml; try { pxml = createPolicyXML(stream); } catch (ContentDecodingException e) { throw new RepositoryException(e.getMessage()); } update(pxml, false); _pxml = pxml; } /** * Applies policy changes * * @param pxml policy data * @return * @throws XMLStreamException */ public void update(PolicyXML pxml, boolean fromNet) throws RepositoryException { Log.info(Log.FAC_REPO, "Updating policy"); if (pxml._version == null) throw new RepositoryException("No version in policy file"); if (!pxml._version.equals(POLICY_VERSION)) { Log.warning(Log.FAC_REPO, "Bad version in policy file: {0}", pxml._version); throw new RepositoryException("Bad version in policy file"); } if (null == pxml._localName) throw new RepositoryException("No local name in policy file"); if (fromNet) { if (!pxml._localName.equals(_pxml.getLocalName())) { Log.warning(Log.FAC_REPO, "Repository local name doesn't match: request = {0}", pxml._localName); throw new RepositoryException("Repository local name doesn't match policy file"); } } else { try { setLocalName(pxml._localName); } catch (MalformedContentNameStringException e) { throw new RepositoryException(e.getMessage()); } } if (null == pxml._globalPrefix) throw new RepositoryException("No globalPrefix in policy file"); if (fromNet) { if (!pxml.getGlobalPrefix().equals(_pxml.getGlobalPrefix())) { Log.warning("Repository globalPrefix doesn't match: request = {0}", pxml._globalPrefix); throw new RepositoryException("Repository global prefix doesn't match policy file"); } } else { _pxml.setGlobalPrefixOnly(pxml._globalPrefix); } _pxml.setNamespace(pxml.getNamespace()); if (null != pxml.getNamespace()) { String message = ""; for (ContentName name : pxml.getNamespace()) { message += name.toString() + ':'; } Log.info(Log.FAC_REPO, "Policy has been updated. New namespace is: " + message); } } public ArrayList<ContentName> getNamespace() { return _pxml.getNamespace(); } public void setNamespace(ArrayList<ContentName> namespace) { _pxml.setNamespace(namespace); } /** * Creates the path for a policy file for a repository given it's global prefix and local name * * @param globalPrefix global prefix as a ContentName * @param localName local name as a / separated String * @return the name as a ContentName */ public static ContentName getPolicyName(ContentName globalPrefix) { return new ContentName(globalPrefix, REPO_DATA, REPO_POLICY); } public static PolicyXML createPolicyXML(InputStream stream) throws ContentDecodingException { Log.info(Log.FAC_REPO, "Creating policy file"); XMLDecoder decoder = XMLCodecFactory.getDecoder(TextXMLCodec.codecName()); decoder.beginDecoding(stream); PolicyXML pxml = new PolicyXML(); pxml.decode(decoder); Log.fine(Log.FAC_REPO, "Finished pxml decoding"); decoder.endDecoding(); return pxml; } /** * Gets the policy path for this repository * @return the policy path as a ContentName */ public ContentName getPolicyName() { return getPolicyName(_pxml.getGlobalPrefix()); } /** * Sets the repository version to be used by this policy interpreter. After this call any * policy file containing a different version will be rejected. * * @param version The version as a String */ public void setVersion(String version) { _repoVersion = version; } /** * Sets the global prefix for this policy interpreter. After this call any policy file * containing a different global prefix will be rejected * * @param globalPrefix the global prefix as a slash separated String */ public void setGlobalPrefix(String globalPrefix) throws MalformedContentNameStringException { _pxml.setGlobalPrefix(globalPrefix); } /** * Gets the global prefix currently in use for this repository * * @return the global prefix as a ContentName */ public ContentName getGlobalPrefix() { return _pxml.getGlobalPrefix(); } /** * Gets the local name currently used by this repository * * @return the local name as a slash separated String */ public String getLocalName() { return _pxml.getLocalName(); } public void setLocalName(String localName) throws MalformedContentNameStringException { if (null == _pxml.getLocalName()) { _pxml.setLocalName(localName); } } public synchronized PolicyXML getPolicyXML() { return _pxml; } public synchronized void setPolicyXML(PolicyXML pxml) { _pxml = pxml; } }