/* * 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.pdfbox.pdmodel.encryption; import java.lang.reflect.Constructor; import java.security.Security; import java.util.Hashtable; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * This class manages security handlers for the application. It follows the singleton pattern. To be usable, security managers must be registered in it. Security managers are retrieved by the * application when necessary. * * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) * * @version $Revision: 1.3 $ * */ public class SecurityHandlersManager { /** * The unique instance of this manager. */ private static SecurityHandlersManager instance; /** * Get the singleton instance. * * @return The SecurityHandlersManager. */ public static SecurityHandlersManager getInstance() { if (instance == null) { instance = new SecurityHandlersManager(); } Security.addProvider(new BouncyCastleProvider()); return instance; } /** * hashtable used to index handlers regarding their name. Basically this will be used when opening an encrypted document to find the appropriate security handler to handle security features of the * document. */ private Hashtable handlerNames = null; /** * Hashtable used to index handlers regarding the class of protection policy they use. Basically this will be used when encrypting a document. */ private Hashtable handlerPolicyClasses = null; /** * private constructor. */ private SecurityHandlersManager() { handlerNames = new Hashtable(); handlerPolicyClasses = new Hashtable(); try { this.registerHandler(StandardSecurityHandler.FILTER, StandardSecurityHandler.class, StandardProtectionPolicy.class); this.registerHandler(PublicKeySecurityHandler.FILTER, PublicKeySecurityHandler.class, PublicKeyProtectionPolicy.class); } catch (final Exception e) { System.err.println("SecurityHandlersManager strange error with builtin handlers: " + e.getMessage()); System.exit(1); } } /** * Get the security handler for the protection policy. * * @param policy * The policy to get the security handler for. * * @return The appropriate security handler. * * @throws BadSecurityHandlerException * If it is unable to create a SecurityHandler. */ public SecurityHandler getSecurityHandler(final ProtectionPolicy policy) throws BadSecurityHandlerException { final Object found = handlerPolicyClasses.get(policy.getClass()); if (found == null) { throw new BadSecurityHandlerException("Cannot find an appropriate security handler for " + policy.getClass().getName()); } final Class handlerclass = (Class) found; final Class[] argsClasses = { policy.getClass() }; final Object[] args = { policy }; try { final Constructor c = handlerclass.getDeclaredConstructor(argsClasses); final SecurityHandler handler = (SecurityHandler) c.newInstance(args); return handler; } catch (final Exception e) { e.printStackTrace(); throw new BadSecurityHandlerException("problem while trying to instanciate the security handler " + handlerclass.getName() + ": " + e.getMessage()); } } /** * Retrieve the appropriate SecurityHandler for a the given filter name. The filter name is an entry of the encryption dictionary of an encrypted document. * * @param filterName * The filter name. * * @return The appropriate SecurityHandler if it exists. * * @throws BadSecurityHandlerException * If the security handler does not exist. */ public SecurityHandler getSecurityHandler(final String filterName) throws BadSecurityHandlerException { final Object found = handlerNames.get(filterName); if (found == null) { throw new BadSecurityHandlerException("Cannot find an appropriate security handler for " + filterName); } final Class handlerclass = (Class) found; final Class[] argsClasses = {}; final Object[] args = {}; try { final Constructor c = handlerclass.getDeclaredConstructor(argsClasses); final SecurityHandler handler = (SecurityHandler) c.newInstance(args); return handler; } catch (final Exception e) { e.printStackTrace(); throw new BadSecurityHandlerException("problem while trying to instanciate the security handler " + handlerclass.getName() + ": " + e.getMessage()); } } /** * register a security handler. * * If the security handler was already registered an exception is thrown. If another handler was previously registered for the same filter name or for the same policy name, an exception is thrown * * @param filterName * The name of the filter. * @param securityHandlerClass * Security Handler class to register. * @param protectionPolicyClass * Protection Policy class to register. * * @throws BadSecurityHandlerException * If there is an error registering the security handler. */ public void registerHandler(final String filterName, final Class securityHandlerClass, final Class protectionPolicyClass) throws BadSecurityHandlerException { if (handlerNames.contains(securityHandlerClass) || handlerPolicyClasses.contains(securityHandlerClass)) { throw new BadSecurityHandlerException("the following security handler was already registered: " + securityHandlerClass.getName()); } if (SecurityHandler.class.isAssignableFrom(securityHandlerClass)) { try { if (handlerNames.containsKey(filterName)) { throw new BadSecurityHandlerException("a security handler was already registered " + "for the filter name " + filterName); } if (handlerPolicyClasses.containsKey(protectionPolicyClass)) { throw new BadSecurityHandlerException("a security handler was already registered " + "for the policy class " + protectionPolicyClass.getName()); } handlerNames.put(filterName, securityHandlerClass); handlerPolicyClasses.put(protectionPolicyClass, securityHandlerClass); } catch (final Exception e) { throw new BadSecurityHandlerException(e); } } else { throw new BadSecurityHandlerException("The class is not a super class of SecurityHandler"); } } }