1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.pdfbox.pdmodel.encryption; 19 20 import java.lang.reflect.Constructor; 21 import java.security.Security; 22 import java.util.Hashtable; 23 24 import org.bouncycastle.jce.provider.BouncyCastleProvider; 25 26 /** 27 * This class manages security handlers for the application. It follows the singleton pattern. 28 * To be usable, security managers must be registered in it. Security managers are retrieved by 29 * the application when necessary. 30 * 31 * @author Benoit Guillon (benoit.guillon@snv.jussieu.fr) 32 * 33 * @version $Revision: 1.3 $ 34 * 35 */ 36 public class SecurityHandlersManager 37 { 38 39 /** 40 * The unique instance of this manager. 41 */ 42 private static SecurityHandlersManager instance; 43 44 /** 45 * hashtable used to index handlers regarding their name. 46 * Basically this will be used when opening an encrypted 47 * document to find the appropriate security handler to handle 48 * security features of the document. 49 */ 50 private Hashtable handlerNames = null; 51 52 /** 53 * Hashtable used to index handlers regarding the class of 54 * protection policy they use. Basically this will be used when 55 * encrypting a document. 56 */ 57 private Hashtable handlerPolicyClasses = null; 58 59 /** 60 * private constructor. 61 */ 62 private SecurityHandlersManager() 63 { 64 handlerNames = new Hashtable(); 65 handlerPolicyClasses = new Hashtable(); 66 try 67 { 68 this.registerHandler( 69 StandardSecurityHandler.FILTER, 70 StandardSecurityHandler.class, 71 StandardProtectionPolicy.class); 72 this.registerHandler( 73 PublicKeySecurityHandler.FILTER, 74 PublicKeySecurityHandler.class, 75 PublicKeyProtectionPolicy.class); 76 } 77 catch(Exception e) 78 { 79 System.err.println("SecurityHandlersManager strange error with builtin handlers: " + e.getMessage()); 80 System.exit(1); 81 } 82 } 83 84 /** 85 * register a security handler. 86 * 87 * If the security handler was already registered an exception is thrown. 88 * If another handler was previously registered for the same filter name or 89 * for the same policy name, an exception is thrown 90 * 91 * @param filterName The name of the filter. 92 * @param securityHandlerClass Security Handler class to register. 93 * @param protectionPolicyClass Protection Policy class to register. 94 * 95 * @throws BadSecurityHandlerException If there is an error registering the security handler. 96 */ 97 public void registerHandler(String filterName, Class securityHandlerClass, Class protectionPolicyClass) 98 throws BadSecurityHandlerException 99 { 100 if(handlerNames.contains(securityHandlerClass) || handlerPolicyClasses.contains(securityHandlerClass)) 101 { 102 throw new BadSecurityHandlerException("the following security handler was already registered: " + 103 securityHandlerClass.getName()); 104 } 105 106 if(SecurityHandler.class.isAssignableFrom(securityHandlerClass)) 107 { 108 try 109 { 110 if(handlerNames.containsKey(filterName)) 111 { 112 throw new BadSecurityHandlerException("a security handler was already registered " + 113 "for the filter name " + filterName); 114 } 115 if(handlerPolicyClasses.containsKey(protectionPolicyClass)) 116 { 117 throw new BadSecurityHandlerException("a security handler was already registered " + 118 "for the policy class " + protectionPolicyClass.getName()); 119 } 120 121 handlerNames.put(filterName, securityHandlerClass); 122 handlerPolicyClasses.put(protectionPolicyClass, securityHandlerClass); 123 } 124 catch(Exception e) 125 { 126 throw new BadSecurityHandlerException(e); 127 } 128 } 129 else 130 { 131 throw new BadSecurityHandlerException("The class is not a super class of SecurityHandler"); 132 } 133 } 134 135 136 /** 137 * Get the singleton instance. 138 * 139 * @return The SecurityHandlersManager. 140 */ 141 public static SecurityHandlersManager getInstance() 142 { 143 if(instance == null) 144 { 145 instance = new SecurityHandlersManager(); 146 } 147 Security.addProvider(new BouncyCastleProvider()); 148 149 return instance; 150 } 151 152 /** 153 * Get the security handler for the protection policy. 154 * 155 * @param policy The policy to get the security handler for. 156 * 157 * @return The appropriate security handler. 158 * 159 * @throws BadSecurityHandlerException If it is unable to create a SecurityHandler. 160 */ 161 public SecurityHandler getSecurityHandler(ProtectionPolicy policy) throws BadSecurityHandlerException 162 { 163 164 Object found = handlerPolicyClasses.get(policy.getClass()); 165 if(found == null) 166 { 167 throw new BadSecurityHandlerException( 168 "Cannot find an appropriate security handler for " + policy.getClass().getName()); 169 } 170 Class handlerclass = (Class) found; 171 Class[] argsClasses = {policy.getClass()}; 172 Object[] args = {policy}; 173 try 174 { 175 Constructor c = handlerclass.getDeclaredConstructor(argsClasses); 176 SecurityHandler handler = (SecurityHandler)c.newInstance(args); 177 return handler; 178 } 179 catch(Exception e) 180 { 181 e.printStackTrace(); 182 throw new BadSecurityHandlerException( 183 "problem while trying to instanciate the security handler "+ 184 handlerclass.getName() + ": " + e.getMessage()); 185 } 186 } 187 188 189 190 /** 191 * Retrieve the appropriate SecurityHandler for a the given filter name. 192 * The filter name is an entry of the encryption dictionary of an encrypted document. 193 * 194 * @param filterName The filter name. 195 * 196 * @return The appropriate SecurityHandler if it exists. 197 * 198 * @throws BadSecurityHandlerException If the security handler does not exist. 199 */ 200 public SecurityHandler getSecurityHandler(String filterName) throws BadSecurityHandlerException 201 { 202 Object found = handlerNames.get(filterName); 203 if(found == null) 204 { 205 throw new BadSecurityHandlerException("Cannot find an appropriate security handler for " + filterName); 206 } 207 Class handlerclass = (Class) found; 208 Class[] argsClasses = {}; 209 Object[] args = {}; 210 try 211 { 212 Constructor c = handlerclass.getDeclaredConstructor(argsClasses); 213 SecurityHandler handler = (SecurityHandler)c.newInstance(args); 214 return handler; 215 } 216 catch(Exception e) 217 { 218 e.printStackTrace(); 219 throw new BadSecurityHandlerException( 220 "problem while trying to instanciate the security handler "+ 221 handlerclass.getName() + ": " + e.getMessage()); 222 } 223 } 224 }