This is an automated email from the ASF dual-hosted git repository. angela pushed a commit to branch SLING-9976 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git
commit c33c6ab72bf476f851764842b8b84d7f2585a403 Author: angela <[email protected]> AuthorDate: Thu Dec 10 10:40:28 2020 +0100 SLING-9976 : Refactor RepPolicyEntryHandler to allow for other types of access control lists --- .../handlers/AbstractPolicyEntryHandler.java | 89 ++++++++++++ .../cpconverter/handlers/AbstractPolicyParser.java | 103 ++++++++++++++ .../handlers/RepPolicyEntryHandler.java | 156 ++------------------- 3 files changed, 206 insertions(+), 142 deletions(-) diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java new file mode 100644 index 0000000..8b27527 --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyEntryHandler.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.feature.cpconverter.handlers; + +import org.apache.commons.io.IOUtils; +import org.apache.jackrabbit.vault.fs.io.Archive; +import org.apache.jackrabbit.vault.util.PlatformNameFormat; +import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter; +import org.apache.sling.feature.cpconverter.accesscontrol.AclManager; +import org.apache.sling.feature.cpconverter.shared.RepoPath; +import org.jetbrains.annotations.NotNull; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.regex.Matcher; + +abstract class AbstractPolicyEntryHandler extends AbstractRegexEntryHandler { + + private final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance(); + + AbstractPolicyEntryHandler(@NotNull String regex) { + super(regex); + } + + @Override + public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Archive.Entry entry, @NotNull ContentPackage2FeatureModelConverter converter) + throws Exception { + String resourcePath; + Matcher matcher = getPattern().matcher(path); + // we are pretty sure it matches, here + if (matcher.matches()) { + resourcePath = matcher.group(1); + } else { + throw new IllegalStateException("Something went terribly wrong: pattern '" + + getPattern().pattern() + + "' should have matched already with path '" + + path + + "' but it does not, currently"); + } + + TransformerHandler handler = saxTransformerFactory.newTransformerHandler(); + handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); + handler.getTransformer().setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); + handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + StringWriter stringWriter = new StringWriter(); + handler.setResult(new StreamResult(stringWriter)); + + AbstractPolicyParser systemUserParser = createPolicyParser(new RepoPath(PlatformNameFormat.getRepositoryPath(resourcePath)), + converter.getAclManager(), + handler); + boolean hasRejectedAcls; + + try (InputStream input = archive.openInputStream(entry)) { + hasRejectedAcls = systemUserParser.parse(input); + } + + if (hasRejectedAcls) { + try (Reader reader = new StringReader(stringWriter.toString()); + OutputStreamWriter writer = new OutputStreamWriter(converter.getMainPackageAssembler().createEntry(path))) { + IOUtils.copy(reader, writer); + } + } + } + + @NotNull + abstract AbstractPolicyParser createPolicyParser(@NotNull RepoPath repositoryPath, @NotNull AclManager aclManager, @NotNull TransformerHandler handler); +} \ No newline at end of file diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java new file mode 100644 index 0000000..c36479a --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.feature.cpconverter.handlers; + +import org.apache.sling.feature.cpconverter.accesscontrol.AccessControlEntry; +import org.apache.sling.feature.cpconverter.accesscontrol.AclManager; +import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser; +import org.apache.sling.feature.cpconverter.shared.RepoPath; +import org.jetbrains.annotations.NotNull; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +import javax.xml.transform.sax.TransformerHandler; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +abstract class AbstractPolicyParser extends AbstractJcrNodeParser<Boolean> { + + static final String REP_RESTRICTIONS = "rep:Restrictions"; + static final String REP_PRINCIPAL_NAME = "rep:principalName"; + + private static final String REP_PRIVILEGES = "rep:privileges"; + private static final String[] RESTRICTIONS = new String[] { "rep:glob", "rep:ntNames", "rep:prefixes", "rep:itemNames" }; + + private static final Pattern typeIndicatorPattern = Pattern.compile("\\{[^\\}]+\\}\\[(.+)\\]"); + + private final RepoPath repositoryPath; + + final TransformerHandler handler; + final AclManager aclManager; + + boolean onRepAclNode = false; + // ACL processing result + boolean hasRejectedNodes = false; + + public AbstractPolicyParser(@NotNull String primaryType, @NotNull RepoPath repositoryPath, @NotNull AclManager aclManager, @NotNull TransformerHandler handler) { + super(primaryType); + this.handler = handler; + this.repositoryPath = repositoryPath; + this.aclManager = aclManager; + } + + private static String extractValue(String expression) { + if (expression == null || expression.isEmpty()) { + return expression; + } + + Matcher matcher = typeIndicatorPattern.matcher(expression); + if (matcher.matches()) { + return matcher.group(1); + } + + return expression; + } + + static void addRestrictions(@NotNull AccessControlEntry ace, @NotNull Attributes attributes) { + for (String restriction : RESTRICTIONS) { + String v = extractValue(attributes.getValue(restriction)); + + if (v != null && !v.isEmpty()) { + ace.addRestriction(restriction + ',' + v); + } + } + } + + AccessControlEntry createEntry(boolean isAllow, @NotNull Attributes attributes) { + return new AccessControlEntry(isAllow, extractValue(attributes.getValue(REP_PRIVILEGES)), repositoryPath); + } + + @Override + public void startDocument() throws SAXException { + handler.startDocument(); + } + + @Override + public void endDocument() throws SAXException { + handler.endDocument(); + } + + @Override + protected void onJcrRootElement(String uri, String localName, String qName, Attributes attributes) { + onRepAclNode = true; + } + + @Override + protected Boolean getParsingResult() { + return hasRejectedNodes; + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandler.java index 38b9204..1ac8e97 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandler.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPolicyEntryHandler.java @@ -16,137 +16,49 @@ */ package org.apache.sling.feature.cpconverter.handlers; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; - -import org.apache.commons.io.IOUtils; -import org.apache.jackrabbit.vault.fs.io.Archive; -import org.apache.jackrabbit.vault.fs.io.Archive.Entry; -import org.apache.jackrabbit.vault.util.PlatformNameFormat; -import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter; import org.apache.sling.feature.cpconverter.accesscontrol.AccessControlEntry; import org.apache.sling.feature.cpconverter.accesscontrol.AclManager; -import org.apache.sling.feature.cpconverter.shared.AbstractJcrNodeParser; import org.apache.sling.feature.cpconverter.shared.RepoPath; +import org.jetbrains.annotations.NotNull; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; +import javax.xml.transform.sax.TransformerHandler; import java.util.HashMap; import java.util.Map; import java.util.Stack; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.transform.OutputKeys; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.sax.TransformerHandler; -import javax.xml.transform.stream.StreamResult; import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; -public final class RepPolicyEntryHandler extends AbstractRegexEntryHandler { - - private final SAXTransformerFactory saxTransformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance(); +public final class RepPolicyEntryHandler extends AbstractPolicyEntryHandler { public RepPolicyEntryHandler() { super("/jcr_root(.*/)_rep_policy.xml"); } - @Override - public void handle(String path, Archive archive, Entry entry, ContentPackage2FeatureModelConverter converter) - throws Exception { - String resourcePath; - Matcher matcher = getPattern().matcher(path); - // we are pretty sure it matches, here - if (matcher.matches()) { - resourcePath = matcher.group(1); - } else { - throw new IllegalStateException("Something went terribly wrong: pattern '" - + getPattern().pattern() - + "' should have matched already with path '" - + path - + "' but it does not, currently"); - } - - TransformerHandler handler = saxTransformerFactory.newTransformerHandler(); - handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); - handler.getTransformer().setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); - handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - StringWriter stringWriter = new StringWriter(); - handler.setResult(new StreamResult(stringWriter)); - - RepPolicyParser systemUserParser = new RepPolicyParser(new RepoPath(PlatformNameFormat.getRepositoryPath(resourcePath)), - converter.getAclManager(), - handler); - boolean hasRejectedAcls; - - try (InputStream input = archive.openInputStream(entry)) { - hasRejectedAcls = systemUserParser.parse(input); - } - - if (hasRejectedAcls) { - try (Reader reader = new StringReader(stringWriter.toString()); - OutputStreamWriter writer = new OutputStreamWriter(converter.getMainPackageAssembler().createEntry(path))) { - IOUtils.copy(reader, writer); - } - } + @NotNull + AbstractPolicyParser createPolicyParser(@NotNull RepoPath repositoryPath, @NotNull AclManager aclManager, @NotNull TransformerHandler handler) { + return new RepPolicyParser(repositoryPath, aclManager, handler); } - private static final class RepPolicyParser extends AbstractJcrNodeParser<Boolean> { + private static final class RepPolicyParser extends AbstractPolicyParser { private static final String REP_ACL = "rep:ACL"; - private static final String REP_GRANT_ACE = "rep:GrantACE"; - private static final String REP_DENY_ACE = "rep:DenyACE"; - - private static final String REP_RESTRICTIONS = "rep:Restrictions"; - - private static final String REP_PRINCIPAL_NAME = "rep:principalName"; - - private static final String REP_PRIVILEGES = "rep:privileges"; - private static final Map<String, Boolean> operations = new HashMap<>(); - static { operations.put(REP_GRANT_ACE, true); operations.put(REP_DENY_ACE, false); } - private static final String[] RESTRICTIONS = new String[] { "rep:glob", "rep:ntNames", "rep:prefixes", "rep:itemNames" }; - - private static final Pattern typeIndicatorPattern = Pattern.compile("\\{[^\\}]+\\}\\[(.+)\\]"); - private final Stack<AccessControlEntry> acls = new Stack<>(); - private final RepoPath repositoryPath; - - private final AclManager aclManager; - - private final TransformerHandler handler; - - private boolean onRepAclNode = false; - - // ACL processing result - private boolean hasRejectedNodes = false; - // just internal pointer for every iteration private boolean processCurrentAcl = false; public RepPolicyParser(RepoPath repositoryPath, AclManager aclManager, TransformerHandler handler) { - super(REP_ACL); - this.repositoryPath = repositoryPath; - this.aclManager = aclManager; - this.handler = handler; - } - - @Override - public void startDocument() throws SAXException { - handler.startDocument(); + super(REP_ACL, repositoryPath, aclManager, handler); } @Override @@ -156,12 +68,7 @@ public final class RepPolicyEntryHandler extends AbstractRegexEntryHandler { String primaryType = attributes.getValue(JCR_PRIMARYTYPE); if (REP_GRANT_ACE.equals(primaryType) || REP_DENY_ACE.equals(primaryType)) { String principalName = attributes.getValue(REP_PRINCIPAL_NAME); - - Boolean isAllow = operations.get(primaryType); - - String privileges = extractValue(attributes.getValue(REP_PRIVILEGES)); - - AccessControlEntry acl = new AccessControlEntry(isAllow, privileges, repositoryPath); + AccessControlEntry acl = createEntry(operations.get(primaryType), attributes); processCurrentAcl = aclManager.addAcl(principalName, acl); if (processCurrentAcl) { @@ -171,14 +78,9 @@ public final class RepPolicyEntryHandler extends AbstractRegexEntryHandler { } } else if (REP_RESTRICTIONS.equals(primaryType) && !acls.isEmpty()) { if (processCurrentAcl) { - acls.add(acls.peek()); - for (String restriction : RESTRICTIONS) { - String path = extractValue(attributes.getValue(restriction)); - - if (path != null && !path.isEmpty()) { - acls.peek().addRestriction(restriction + ',' + path); - } - } + AccessControlEntry ace = acls.peek(); + acls.add(ace); + addRestrictions(ace, attributes); } } } else { @@ -199,35 +101,5 @@ public final class RepPolicyEntryHandler extends AbstractRegexEntryHandler { handler.endElement(uri, localName, qName); } } - - @Override - public void endDocument() throws SAXException { - handler.endDocument(); - } - - @Override - protected void onJcrRootElement(String uri, String localName, String qName, Attributes attributes) { - onRepAclNode = true; - } - - @Override - protected Boolean getParsingResult() { - return hasRejectedNodes; - } - - private static String extractValue(String expression) { - if (expression == null || expression.isEmpty()) { - return expression; - } - - Matcher matcher = typeIndicatorPattern.matcher(expression); - if (matcher.matches()) { - return matcher.group(1); - } - - return expression; - } - } - }
