*** empty log message ***
[java-idp.git] / src / org / apache / xml / security / Init.java
1 /*
2  * Copyright  1999-2004 The Apache Software Foundation.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  */
17 package org.apache.xml.security;
18
19
20
21 import java.io.*;
22 import java.lang.reflect.Method;
23 import java.util.*;
24 import javax.xml.parsers.*;
25 import org.apache.xml.security.algorithms.JCEMapper;
26 import org.apache.xml.security.algorithms.SignatureAlgorithm;
27 import org.apache.xml.security.c14n.Canonicalizer;
28 import org.apache.xml.security.exceptions.XMLSecurityException;
29 import org.apache.xml.security.keys.ContentHandlerAlreadyRegisteredException;
30 import org.apache.xml.security.keys.KeyInfo;
31 import org.apache.xml.security.keys.keyresolver.KeyResolver;
32 import org.apache.xml.security.transforms.Transform;
33 import org.apache.xml.security.transforms.implementations.FuncHere;
34 import org.apache.xml.security.utils.*;
35 import org.apache.xml.security.utils.resolver.ResourceResolver;
36 import org.apache.xpath.XPathAPI;
37 import org.apache.xpath.compiler.FuncLoader;
38 import org.apache.xpath.compiler.FunctionTable;
39 import org.apache.xpath.functions.Function;
40 import org.w3c.dom.*;
41
42
43 /**
44  * This class does the configuration of the library. This includes creating
45  * the mapping of Canonicalization and Transform algorithms. Initialization is
46  * done by calling {@link Init#init} which should be done in any static block
47  * of the files of this library. We ensure that this call is only executed once.
48  *
49  * @author $Author$
50  */
51 public class Init {
52
53   /** {@link org.apache.commons.logging} logging facility */
54   static org.apache.commons.logging.Log log = 
55         org.apache.commons.logging.LogFactory.getLog(Init.class.getName());
56
57    /** Field _initialized */
58    private static boolean _alreadyInitialized = false;
59
60    /**
61     * Method isInitialized
62     *
63     *
64     */
65    public static final boolean isInitialized() {
66       return Init._alreadyInitialized;
67    }
68
69    /**
70     * Method init
71     *
72     */
73    public synchronized static void init() {
74
75       if (!_alreadyInitialized) {
76          _alreadyInitialized = true;
77
78          try {
79             long XX_init_start = System.currentTimeMillis();
80             long XX_prng_start = System.currentTimeMillis();
81
82             PRNG.init(new java.security.SecureRandom());
83
84             long XX_prng_end = System.currentTimeMillis();
85
86             /* read library configuration file */
87             long XX_parsing_start = System.currentTimeMillis();
88             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
89
90             dbf.setNamespaceAware(true);
91             dbf.setValidating(false);
92
93             DocumentBuilder db = dbf.newDocumentBuilder();
94             // InputStream is = Class.forName("org.apache.xml.security.Init").getResourceAsStream("resource/config.xml");
95             String cfile = System.getProperty("org.apache.xml.security.resource.config");
96             InputStream is =
97                Class.forName("org.apache.xml.security.Init")
98                   .getResourceAsStream(cfile != null ? cfile : "resource/config.xml");
99
100             Document doc = db.parse(is);
101             long XX_parsing_end = System.currentTimeMillis();
102             Element context = doc.createElementNS(null, "nscontext");
103
104             context.setAttributeNS(
105                Constants.NamespaceSpecNS, "xmlns:x",
106                     "http://www.xmlsecurity.org/NS/#configuration");
107             long XX_configure_i18n_start = System.currentTimeMillis();
108
109             {
110
111                /* configure internationalization */
112                Attr langAttr = (Attr) XPathAPI.selectSingleNode(
113                   doc,
114                   "/x:Configuration/x:ResourceBundles/@defaultLanguageCode",
115                   context);
116                Attr countryAttr = (Attr) XPathAPI.selectSingleNode(
117                   doc,
118                   "/x:Configuration/x:ResourceBundles/@defaultCountryCode",
119                   context);
120                String languageCode = (langAttr == null)
121                                      ? null
122                                      : langAttr.getNodeValue();
123                String countryCode = (countryAttr == null)
124                                     ? null
125                                     : countryAttr.getNodeValue();
126
127                I18n.init(languageCode, countryCode);
128             }
129
130             long XX_configure_i18n_end = System.currentTimeMillis();
131
132             /**
133              * Try to register our here() implementation as internal function.
134              */
135             long XX_configure_reg_here_start = System.currentTimeMillis();
136
137             {
138                 FunctionTable.installFunction("here", new FuncHere());
139                 log.debug("Registered class " + FuncHere.class.getName()
140                         + " for XPath function 'here()' function in internal table");
141
142                 /* The following tweak by "Eric Olson" <ego@alum.mit.edu>
143                  * is to enable xml-security to play with JDK 1.4 which
144                  * unfortunately bundles an old version of Xalan
145                  */
146                 FuncLoader funcHereLoader = new FuncHereLoader();
147
148                 try {
149                     java.lang.reflect.Field mFunctions = FunctionTable.class.getField("m_functions");
150                     FuncLoader[] m_functions = (FuncLoader[]) mFunctions.get(null);
151
152                     for (int i = 0; i < m_functions.length; i++) {
153                         FuncLoader loader = m_functions[i];
154
155                         if (loader != null) {
156                             log.debug("Func " + i + " " + loader.getName());
157
158                             if (loader.getName().equals(funcHereLoader.getName())) {
159                                 m_functions[i] = funcHereLoader;
160                             }
161                         }
162                     }
163                 } catch (Exception e) {
164                     log.info("Unable to patch xalan function table.", e);
165                 }
166             }
167              
168             long XX_configure_reg_here_end = System.currentTimeMillis();
169             long XX_configure_reg_c14n_start = System.currentTimeMillis();
170
171             {
172                Canonicalizer.init();
173
174                NodeList c14nElem = XPathAPI.selectNodeList(
175                   doc,
176                   "/x:Configuration/x:CanonicalizationMethods/x:CanonicalizationMethod",
177                   context);
178
179                for (int i = 0; i < c14nElem.getLength(); i++) {
180                   String URI = ((Element) c14nElem.item(i)).getAttributeNS(null,
181                                   "URI");
182                   String JAVACLASS =
183                      ((Element) c14nElem.item(i)).getAttributeNS(null,
184                         "JAVACLASS");
185                   boolean registerClass = true;
186
187                   try {
188                      Class c = Class.forName(JAVACLASS);
189                      Method methods[] = c.getMethods();
190
191                      for (int j = 0; j < methods.length; j++) {
192                         Method currMeth = methods[j];
193
194                         if (currMeth.getDeclaringClass().getName()
195                                 .equals(JAVACLASS)) {
196                            log.debug(currMeth.getDeclaringClass());
197                         }
198                      }
199                   } catch (ClassNotFoundException e) {
200                      Object exArgs[] = { URI, JAVACLASS };
201
202                      log.fatal(I18n.translate("algorithm.classDoesNotExist",
203                                               exArgs));
204
205                      registerClass = false;
206                   }
207
208                   if (registerClass) {
209                      log.debug("Canonicalizer.register(" + URI + ", "
210                                + JAVACLASS + ")");
211                      Canonicalizer.register(URI, JAVACLASS);
212                   }
213                }
214             }
215
216             long XX_configure_reg_c14n_end = System.currentTimeMillis();
217             long XX_configure_reg_transforms_start = System.currentTimeMillis();
218
219             {
220                Transform.init();
221
222                NodeList tranElem = XPathAPI.selectNodeList(
223                   doc,
224                   "/x:Configuration/x:TransformAlgorithms/x:TransformAlgorithm",
225                   context);
226
227                for (int i = 0; i < tranElem.getLength(); i++) {
228                   String URI = ((Element) tranElem.item(i)).getAttributeNS(null,
229                                   "URI");
230                   String JAVACLASS =
231                      ((Element) tranElem.item(i)).getAttributeNS(null,
232                         "JAVACLASS");
233                   boolean registerClass = true;
234
235                   try {
236                      Class.forName(JAVACLASS);
237                   } catch (ClassNotFoundException e) {
238                      Object exArgs[] = { URI, JAVACLASS };
239
240                      log.fatal(I18n.translate("algorithm.classDoesNotExist",
241                                               exArgs));
242
243                      registerClass = false;
244                   }
245
246                   if (registerClass) {
247                      log.debug("Transform.register(" + URI + ", " + JAVACLASS
248                                + ")");
249                      Transform.register(URI, JAVACLASS);
250                   }
251                }
252             }
253
254             long XX_configure_reg_transforms_end = System.currentTimeMillis();
255             long XX_configure_reg_jcemapper_start = System.currentTimeMillis();
256
257             {
258                Element jcemapperElem = (Element) XPathAPI.selectSingleNode(
259                   doc, "/x:Configuration/x:JCEAlgorithmMappings", context);
260
261                JCEMapper.init(jcemapperElem);
262             }
263
264             long XX_configure_reg_jcemapper_end = System.currentTimeMillis();
265             long XX_configure_reg_sigalgos_start = System.currentTimeMillis();
266
267             {
268                SignatureAlgorithm.providerInit();
269
270                NodeList sigElems = XPathAPI.selectNodeList(
271                   doc,
272                   "/x:Configuration/x:SignatureAlgorithms/x:SignatureAlgorithm",
273                   context);
274
275                for (int i = 0; i < sigElems.getLength(); i++) {
276                   String URI = ((Element) sigElems.item(i)).getAttributeNS(null,
277                                   "URI");
278                   String JAVACLASS =
279                      ((Element) sigElems.item(i)).getAttributeNS(null,
280                         "JAVACLASS");
281
282                   /** $todo$ handle registering */
283                   boolean registerClass = true;
284
285                   try {
286                      Class c = Class.forName(JAVACLASS);
287                      Method methods[] = c.getMethods();
288
289                      for (int j = 0; j < methods.length; j++) {
290                         Method currMeth = methods[j];
291
292                         if (currMeth.getDeclaringClass().getName()
293                                 .equals(JAVACLASS)) {
294                            log.debug(currMeth.getDeclaringClass());
295                         }
296                      }
297                   } catch (ClassNotFoundException e) {
298                      Object exArgs[] = { URI, JAVACLASS };
299
300                      log.fatal(I18n.translate("algorithm.classDoesNotExist",
301                                               exArgs));
302
303                      registerClass = false;
304                   }
305
306                   if (registerClass) {
307                      log.debug("SignatureAlgorithm.register(" + URI + ", "
308                                + JAVACLASS + ")");
309                      SignatureAlgorithm.register(URI, JAVACLASS);
310                   }
311                }
312             }
313
314             long XX_configure_reg_sigalgos_end = System.currentTimeMillis();
315             long XX_configure_reg_resourceresolver_start =
316                System.currentTimeMillis();
317
318             {
319                ResourceResolver.init();
320
321                NodeList resolverElem = XPathAPI.selectNodeList(
322                   doc, "/x:Configuration/x:ResourceResolvers/x:Resolver",
323                   context);
324
325                for (int i = 0; i < resolverElem.getLength(); i++) {
326                   String JAVACLASS =
327                      ((Element) resolverElem.item(i)).getAttributeNS(null,
328                         "JAVACLASS");
329                   String Description =
330                      ((Element) resolverElem.item(i)).getAttributeNS(null,
331                         "DESCRIPTION");
332
333                   if ((Description != null) && (Description.length() > 0)) {
334                      log.debug("Register Resolver: " + JAVACLASS + ": "
335                                + Description);
336                   } else {
337                      log.debug("Register Resolver: " + JAVACLASS
338                                + ": For unknown purposes");
339                   }
340
341                   ResourceResolver.register(JAVACLASS);
342                }
343             }
344
345             long XX_configure_reg_resourceresolver_end =
346                System.currentTimeMillis();
347             long XX_configure_reg_keyInfo_start = System.currentTimeMillis();
348
349             {
350                try {
351                   KeyInfo.init();
352
353                   Init._contentHandlerHash = new HashMap(10);
354
355                   {
356                      NodeList keyElem = XPathAPI.selectNodeList(
357                         doc, "/x:Configuration/x:KeyInfo/x:ContentHandler",
358                         context);
359
360                      for (int i = 0; i < keyElem.getLength(); i++) {
361                         String namespace =
362                            ((Element) keyElem.item(i)).getAttributeNS(null,
363                               "NAMESPACE");
364                         String localname =
365                            ((Element) keyElem.item(i)).getAttributeNS(null,
366                               "LOCALNAME");
367                         String JAVACLASS =
368                            ((Element) keyElem.item(i)).getAttributeNS(null,
369                               "JAVACLASS");
370
371                         log.debug("KeyInfoContent: " + namespace + " "
372                                   + localname + " " + JAVACLASS);
373                         Init.registerKeyInfoContentHandler(namespace,
374                                                            localname,
375                                                            JAVACLASS);
376                      }
377                   }
378                } catch (Exception e) {
379                   e.printStackTrace();
380
381                   throw e;
382                }
383             }
384
385             long XX_configure_reg_keyInfo_end = System.currentTimeMillis();
386             long XX_configure_reg_keyResolver_start =
387                System.currentTimeMillis();
388
389             {
390                KeyResolver.init();
391
392                NodeList resolverElem = XPathAPI.selectNodeList(
393                   doc, "/x:Configuration/x:KeyResolver/x:Resolver", context);
394
395                for (int i = 0; i < resolverElem.getLength(); i++) {
396                   String JAVACLASS =
397                      ((Element) resolverElem.item(i)).getAttributeNS(null,
398                         "JAVACLASS");
399                   String Description =
400                      ((Element) resolverElem.item(i)).getAttributeNS(null,
401                         "DESCRIPTION");
402
403                   if ((Description != null) && (Description.length() > 0)) {
404                      log.debug("Register Resolver: " + JAVACLASS + ": "
405                                + Description);
406                   } else {
407                      log.debug("Register Resolver: " + JAVACLASS
408                                + ": For unknown purposes");
409                   }
410
411                   KeyResolver.register(JAVACLASS);
412                }
413             }
414
415             long XX_configure_reg_keyResolver_end = System.currentTimeMillis();
416             long XX_configure_reg_prefixes_start = System.currentTimeMillis();
417
418             {
419                log.debug("Now I try to bind prefixes:");
420
421                NodeList nl = XPathAPI.selectNodeList(
422                   doc, "/x:Configuration/x:PrefixMappings/x:PrefixMapping",
423                   context);
424
425                for (int i = 0; i < nl.getLength(); i++) {
426                   String namespace = ((Element) nl.item(i)).getAttributeNS(null,
427                                         "namespace");
428                   String prefix = ((Element) nl.item(i)).getAttributeNS(null,
429                                      "prefix");
430
431                   log.debug("Now I try to bind " + prefix + " to " + namespace);
432                   org.apache.xml.security.utils.ElementProxy
433                      .setDefaultPrefix(namespace, prefix);
434                }
435             }
436
437             long XX_configure_reg_prefixes_end = System.currentTimeMillis();
438             long XX_init_end = System.currentTimeMillis();
439
440             //J-
441             log.debug("XX_init                             " + ((int)(XX_init_end - XX_init_start)) + " ms");
442             log.debug("  XX_prng                           " + ((int)(XX_prng_end - XX_prng_start)) + " ms");
443             log.debug("  XX_parsing                        " + ((int)(XX_parsing_end - XX_parsing_start)) + " ms");
444             log.debug("  XX_configure_i18n                 " + ((int)(XX_configure_i18n_end- XX_configure_i18n_start)) + " ms");
445             log.debug("  XX_configure_reg_c14n             " + ((int)(XX_configure_reg_c14n_end- XX_configure_reg_c14n_start)) + " ms");
446             log.debug("  XX_configure_reg_here             " + ((int)(XX_configure_reg_here_end- XX_configure_reg_here_start)) + " ms");
447             log.debug("  XX_configure_reg_jcemapper        " + ((int)(XX_configure_reg_jcemapper_end- XX_configure_reg_jcemapper_start)) + " ms");
448             log.debug("  XX_configure_reg_keyInfo          " + ((int)(XX_configure_reg_keyInfo_end- XX_configure_reg_keyInfo_start)) + " ms");
449             log.debug("  XX_configure_reg_keyResolver      " + ((int)(XX_configure_reg_keyResolver_end- XX_configure_reg_keyResolver_start)) + " ms");
450             log.debug("  XX_configure_reg_prefixes         " + ((int)(XX_configure_reg_prefixes_end- XX_configure_reg_prefixes_start)) + " ms");
451             log.debug("  XX_configure_reg_resourceresolver " + ((int)(XX_configure_reg_resourceresolver_end- XX_configure_reg_resourceresolver_start)) + " ms");
452             log.debug("  XX_configure_reg_sigalgos         " + ((int)(XX_configure_reg_sigalgos_end- XX_configure_reg_sigalgos_start)) + " ms");
453             log.debug("  XX_configure_reg_transforms       " + ((int)(XX_configure_reg_transforms_end- XX_configure_reg_transforms_start)) + " ms");
454             //J+
455          } catch (Exception e) {
456             log.fatal("Bad: ", e);
457             e.printStackTrace();
458          }
459       }
460    }
461
462    /**
463     * This method customizes the library with user supplied configuration.
464     * This includes access to keystores etc.
465     * By default, this method tries to find the configurationfile in
466     * the System.getProperty("user.home") directory.
467     *
468     * @throws XMLSecurityException
469     */
470    public static void readUserConfiguration() throws XMLSecurityException {
471
472       try {
473          String filename = System.getProperty("user.home") + "/"
474                            + Constants.configurationFileNew;
475          InputStream is = new FileInputStream(filename);
476
477          Init.readUserConfiguration(is);
478       } catch (IOException ex) {
479          throw new XMLSecurityException("generic.EmptyMessage", ex);
480       }
481    }
482
483    /**
484     * This method customizes the library with user supplied configuration.
485     * This includes access to keystores etc.
486     *
487     * @param fileURI
488     * @throws XMLSecurityException
489     */
490    public static void readUserConfiguration(String fileURI)
491            throws XMLSecurityException {
492
493       try {
494          InputStream is = null;
495
496          // first try to interpret fileURI as filename in the local file system
497          File f = new File(fileURI);
498
499          if (f.exists()) {
500             is = new FileInputStream(f);
501          } else {
502
503             // then treat it as USI
504             is = new java.net.URL(fileURI).openStream();
505          }
506
507          Init.readUserConfiguration(is);
508       } catch (IOException ex) {
509          throw new XMLSecurityException("generic.EmptyMessage", ex);
510       }
511    }
512
513    /**
514     * Method readUserConfiguration
515     *
516     * @param is
517     * @throws XMLSecurityException
518     */
519    public static void readUserConfiguration(InputStream is)
520            throws XMLSecurityException {
521
522       try {
523
524          /* read library configuration file */
525          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
526
527          dbf.setNamespaceAware(true);
528          dbf.setValidating(false);
529
530          DocumentBuilder db = dbf.newDocumentBuilder();
531          Document doc = db.parse(is);
532          Element context = XMLUtils.createDSctx(
533             doc, "x", "http://www.xmlsecurity.org/NS/#configuration");
534
535          {
536             NodeList nl =
537                XPathAPI.selectNodeList(doc, "/x:AppConfiguration/x:KeyStore",
538                                        context);
539
540             for (int i = 0; i < nl.getLength(); i++) {
541                //EK: the registerStore method was already commented out.
542                //unsure what needs to happen with it now.
543                /*
544                Element e = (Element) nl.item(i);
545                String URI = e.getAttributeNS(null, "URI");
546                String keyStoreType = e.getAttributeNS(null, "Type");
547                String defaultKeyAlias = e.getAttributeNS(null,
548                                                          "DefaultKeyAlias");
549                String storePass = e.getAttributeNS(null, "StorePass");
550                String KeyPass = e.getAttributeNS(null, "KeyPass");
551                */
552
553                // org.apache.xml.security.keys.keyStorage.KeyStorage.registerStore(URI, JAVACLASS, LOCATION, DEFAULTKEYOBJECT, CONTEXT);
554             }
555          }
556       } catch (Exception ex) {
557          throw new XMLSecurityException("generic.EmptyMessage", ex);
558       }
559    }
560
561    /** Field _contentHandlerHash */
562    public static HashMap _contentHandlerHash;
563
564    /**
565     * Method registerKeyinfoContentHandler
566     *
567     * @param namespace
568     * @param localname
569     * @param implementingClass
570     * @throws ContentHandlerAlreadyRegisteredException
571     */
572    public static void registerKeyInfoContentHandler(
573            String namespace, String localname, String implementingClass)
574               throws ContentHandlerAlreadyRegisteredException {
575
576       String namespacequali = Init.qualifyNamespace(namespace, localname);
577
578       // are we already registered?
579       if (Init._contentHandlerHash.containsKey(namespacequali)) {
580          log.error("Already registered");
581
582          Object exArgs[] = { namespacequali,
583                              ((String) Init._contentHandlerHash
584                                 .get(namespacequali)) };
585
586          throw new ContentHandlerAlreadyRegisteredException(
587             "algorithm.alreadyRegistered", exArgs);
588       }
589
590       synchronized (Init._contentHandlerHash) {
591          Init._contentHandlerHash.put(namespacequali, implementingClass);
592          log.debug("Init._contentHandlerHash.put(\"" + namespacequali
593                    + "\", \"" + implementingClass + "\")");
594          log.debug("Init._contentHandlerHash.size()="
595                    + Init._contentHandlerHash.size());
596       }
597    }
598
599    /**
600     * Method qualifyNamespace
601     *
602     * @param namespace
603     * @param localname
604     *
605     */
606    private static String qualifyNamespace(String namespace, String localname) {
607       return "{" + namespace + "}" + localname;
608    }
609
610    /**
611     * Method getContentHandlerClass
612     *
613     * @param namespace
614     * @param localname
615     *
616     */
617    public static String getKeyInfoContentHandler(String namespace,
618            String localname) {
619
620       /*
621       Iterator i = KeyInfo._contentHandlerHash.keySet().iterator();
622       while (i.hasNext()) {
623          String key = (String) i.next();
624          if (key.equals(URI)) {
625             return (String) KeyInfo._contentHandlerHash.get(key);
626          }
627       }
628       return null;
629       */
630       String namespacequali = Init.qualifyNamespace(namespace, localname);
631
632       log.debug("Asked for handler for " + namespacequali);
633
634       if (Init._contentHandlerHash == null) {
635          log.debug("But I can't help (hash==null) ");
636
637          return null;
638       }
639
640       if (Init._contentHandlerHash.size() == 0) {
641          log.debug("But I can't help (size()==0)");
642
643          return null;
644       }
645
646       Set keyset = Init._contentHandlerHash.keySet();
647       Iterator i = keyset.iterator();
648
649       while (i.hasNext()) {
650          String key = (String) i.next();
651
652          if (key.equals(namespacequali)) {
653             return (String) Init._contentHandlerHash.get(key);
654          }
655       }
656
657       return null;
658    }
659
660    /**
661     * Class FuncHereLoader
662     *
663     * @author $Author$
664     * @version $Revision$
665     */
666    public static class FuncHereLoader extends FuncLoader {
667
668       /**
669        * Constructor FuncHereLoader
670        *
671        */
672       public FuncHereLoader() {
673          super(FuncHere.class.getName(), 0);
674       }
675
676       /**
677        * Method getFunction
678        *
679        *
680        * @throws javax.xml.transform.TransformerException
681        */
682       public Function getFunction()
683               throws javax.xml.transform.TransformerException {
684          return new FuncHere();
685       }
686
687       /**
688        * Method getName
689        *
690        *
691        */
692       public String getName() {
693          return FuncHere.class.getName();
694       }
695    }
696 }
697