/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.rendering.macro; import java.io.IOException; import java.security.GeneralSecurityException; import javax.inject.Inject; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.component.manager.ComponentManager; import org.xwiki.component.util.DefaultParameterizedType; import org.xwiki.crypto.pkix.CertificateProvider; import org.xwiki.crypto.signer.param.CMSSignedDataGeneratorParameters; import org.xwiki.crypto.signer.param.CMSSignedDataVerified; import org.xwiki.crypto.store.SignatureStore; import org.xwiki.crypto.store.SignatureStoreException; import org.xwiki.model.reference.BlockReferenceResolver; import org.xwiki.model.reference.EntityReference; import org.xwiki.rendering.block.Block; import org.xwiki.rendering.macro.descriptor.ContentDescriptor; import org.xwiki.rendering.signature.BlockSignatureGenerator; import org.xwiki.rendering.signature.BlockSignatureVerifier; /** * Helper to implement signable Macro, supplementing the default implementation provided * by {@link org.xwiki.rendering.macro.AbstractMacro} to ease the support of signatures. * * @param <P> the type of the macro parameters bean * @version $Id: 11774a40e438014158da212b347f7ea167023733 $ * @since 6.1M2 */ public abstract class AbstractSignableMacro<P> extends AbstractMacro<P> implements SignableMacro { private static final String HINT = "macro"; /** * Used to lazily load of other components, avoiding normal macro that never get signed to need these components. */ @Inject private ComponentManager componentManager; // Lazily loaded components. private SignatureStore signatureStore; private BlockSignatureGenerator signer; private BlockSignatureVerifier verifier; private BlockReferenceResolver<Block> blockResolver; /** * Creates a new {@link Macro} instance. *5005 * @param name the name of the macro (eg "Table Of Contents" for the TOC macro) */ public AbstractSignableMacro(String name) { super(name); } /** * Creates a new {@link Macro} instance. * * @param name the name of the macro (eg "Table Of Contents" for the TOC macro) * @param description a string describing this macro. */ public AbstractSignableMacro(String name, String description) { super(name, description); } /** * Creates a new {@link Macro} instance. * * @param name the name of the macro (eg "Table Of Contents" for the TOC macro) * @param description a string describing this macro. * @param contentDescriptor {@link ContentDescriptor} for this macro. */ public AbstractSignableMacro(String name, String description, ContentDescriptor contentDescriptor) { super(name, description, contentDescriptor); } /** * Creates a new {@link Macro} instance. * * @param name the name of the macro (eg "Table Of Contents" for the TOC macro) * @param description a string describing this macro. * @param parametersBeanClass class of the parameters bean of this macro. */ public AbstractSignableMacro(String name, String description, Class<?> parametersBeanClass) { super(name, description, parametersBeanClass); } /** * Creates a new {@link Macro} instance. * * @param name the name of the macro (eg "Table Of Contents" for the TOC macro) * @param description string describing this macro. * @param contentDescriptor the {@link ContentDescriptor} describing the content of this macro. * @param parametersBeanClass class of the parameters bean. */ public AbstractSignableMacro(String name, String description, ContentDescriptor contentDescriptor, Class<?> parametersBeanClass) { super(name, description, contentDescriptor, parametersBeanClass); } /** * @return the component manager * @since 2.0M1 (moved from AbstractScriptMacro) */ protected ComponentManager getComponentManager() { return this.componentManager; } /** * @return the default signature store. Lazy get to avoid strong dependency. * @throws ComponentLookupException if no instance has been found. */ private SignatureStore getSignatureStore() throws ComponentLookupException { if (signatureStore == null) { signatureStore = getComponentManager().getInstance(SignatureStore.class); } return signatureStore; } /** * @return the macro block signer. Lazy get to avoid strong dependency. * @throws ComponentLookupException if no instance has been found. */ private BlockSignatureGenerator getSigner() throws ComponentLookupException { if (signer == null) { signer = getComponentManager().getInstance(BlockSignatureGenerator.class, HINT); } return signer; } /** * @return the macro block verifier. Lazy get to avoid strong dependency. * @throws ComponentLookupException if no instance has been found. */ private BlockSignatureVerifier getVerifier() throws ComponentLookupException { if (verifier == null) { verifier = getComponentManager().getInstance(BlockSignatureVerifier.class, HINT); } return verifier; } /** * @return the current signed macro block reference resolver. Lazy get to avoid strong dependency. * @throws ComponentLookupException if no instance has been found. */ private BlockReferenceResolver<Block> getBlockResolver() throws ComponentLookupException { if (blockResolver == null) { blockResolver = getComponentManager().getInstance( new DefaultParameterizedType(null, BlockReferenceResolver.class, Block.class), "currentsignedmacro"); } return blockResolver; } @Override public void sign(Block block, CMSSignedDataGeneratorParameters parameters) throws MacroSignatureException { EntityReference blockRef = getBlockReference(block); try { getSignatureStore().store(blockRef, getSigner().generate(block, parameters)); } catch (SignatureStoreException e) { throw new MacroSignatureException( String.format("Unable to store the signature of macro block [%s].", blockRef), e); } catch (GeneralSecurityException e) { throw new MacroSignatureException( String.format("Unable to compute signature of macro block [%s].", blockRef), e); } catch (IOException e) { throw new MacroSignatureException( String.format("Unable to encode signature of macro block [%s].", blockRef), e); } catch (ComponentLookupException e) { throw new MacroSignatureException( String.format("Missing components to sign macro block [%s].", blockRef), e); } } @Override public CMSSignedDataVerified verify(Block block, CertificateProvider certificateProvider) throws MacroSignatureException { EntityReference blockRef = getBlockReference(block); try { return getVerifier().verify(getSignatureStore().retrieve(blockRef), block, certificateProvider); } catch (SignatureStoreException e) { throw new MacroSignatureException( String.format("Unable to retrieve the signature of macro block [%s].", blockRef), e); } catch (GeneralSecurityException e) { throw new MacroSignatureException( String.format("Unable to verify signature of macro block [%s].", blockRef), e); } catch (IOException e) { throw new MacroSignatureException( String.format("Unable to decode signature of macro block [%s].", blockRef), e); } catch (ComponentLookupException e) { throw new MacroSignatureException( String.format("Missing components to verify macro block [%s].", blockRef), e); } } private EntityReference getBlockReference(Block block) throws MacroSignatureException { EntityReference blockRef; try { blockRef = getBlockResolver().resolve(block); } catch (ComponentLookupException e) { throw new MacroSignatureException("Missing component to resolve macro block reference.", e); } if (blockRef == null) { throw new MacroSignatureException("Unable to determine the block reference of the macro block."); } return blockRef; } }