1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  package org.apache.wss4j.common.saml;
21  
22  import javax.xml.namespace.QName;
23  
24  import net.shibboleth.shared.xml.impl.BasicParserPool;
25  import net.shibboleth.shared.xml.ParserPool;
26  
27  import org.apache.wss4j.common.crypto.WSProviderConfig;
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.opensaml.core.config.Configuration;
30  import org.opensaml.core.config.ConfigurationService;
31  import org.opensaml.core.config.provider.MapBasedConfiguration;
32  import org.opensaml.core.xml.XMLObject;
33  import org.opensaml.core.xml.XMLObjectBuilder;
34  import org.opensaml.core.xml.XMLObjectBuilderFactory;
35  import org.opensaml.core.xml.config.XMLConfigurationException;
36  import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
37  import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
38  import org.opensaml.core.xml.io.Marshaller;
39  import org.opensaml.core.xml.io.MarshallerFactory;
40  import org.opensaml.core.xml.io.MarshallingException;
41  import org.opensaml.core.xml.io.Unmarshaller;
42  import org.opensaml.core.xml.io.UnmarshallerFactory;
43  import org.opensaml.core.xml.io.UnmarshallingException;
44  import org.opensaml.saml.common.SignableSAMLObject;
45  import org.opensaml.saml.config.SAMLConfiguration;
46  import org.opensaml.xmlsec.config.DecryptionParserPool;
47  import org.opensaml.xmlsec.signature.Signature;
48  import org.opensaml.xmlsec.signature.support.SignatureException;
49  import org.opensaml.xmlsec.signature.support.Signer;
50  import org.opensaml.xmlsec.signature.support.SignerProvider;
51  import org.w3c.dom.Document;
52  import org.w3c.dom.DocumentFragment;
53  import org.w3c.dom.Element;
54  
55  
56  
57  
58  public final class OpenSAMLUtil {
59      private static final org.slf4j.Logger LOG =
60          org.slf4j.LoggerFactory.getLogger(OpenSAMLUtil.class);
61  
62      private static XMLObjectProviderRegistry providerRegistry;
63      private static XMLObjectBuilderFactory builderFactory;
64      private static MarshallerFactory marshallerFactory;
65      private static UnmarshallerFactory unmarshallerFactory;
66      private static boolean samlEngineInitialized = false;
67  
68      private OpenSAMLUtil() {
69          
70      }
71  
72      
73  
74  
75      public static synchronized void initSamlEngine() {
76          initSamlEngine(true);
77      }
78  
79      public static synchronized void initSamlEngine(boolean includeXacml) {
80          if (!samlEngineInitialized) {
81              LOG.debug("Initializing the opensaml2 library...");
82              WSProviderConfig.init();
83  
84              Configuration configuration = new MapBasedConfiguration();
85              ConfigurationService.setConfiguration(configuration);
86  
87              providerRegistry = new XMLObjectProviderRegistry();
88              configuration.register(XMLObjectProviderRegistry.class, providerRegistry,
89                                     ConfigurationService.DEFAULT_PARTITION_NAME);
90  
91              try {
92                  OpenSAMLBootstrap.bootstrap(includeXacml);
93  
94                  SAMLConfiguration samlConfiguration = new SAMLConfiguration();
95  
96                  configuration.register(SAMLConfiguration.class, samlConfiguration,
97                                         ConfigurationService.DEFAULT_PARTITION_NAME);
98  
99                  builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory();
100                 marshallerFactory = XMLObjectProviderRegistrySupport.getMarshallerFactory();
101                 unmarshallerFactory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory();
102 
103                 try {
104                     configureParserPool();
105 
106                     
107                     configuration.register(DecryptionParserPool.class, new DecryptionParserPool(getParserPool()),
108                         ConfigurationService.DEFAULT_PARTITION_NAME);
109                 } catch (Throwable t) {
110                     LOG.warn("Unable to bootstrap the parser pool part of the opensaml library "
111                              + "- some SAML operations may fail", t);
112                 }
113 
114                 samlEngineInitialized = true;
115                 LOG.debug("opensaml3 library bootstrap complete");
116             } catch (XMLConfigurationException ex) {
117                 LOG.error("Unable to bootstrap the opensaml3 library - all SAML operations will fail", ex);
118             }
119         }
120     }
121 
122     private static void configureParserPool() throws Throwable {
123         BasicParserPool pp = new BasicParserPool();
124         pp.setMaxPoolSize(50);
125         pp.initialize();
126         providerRegistry.setParserPool(pp);
127     }
128 
129     
130 
131 
132 
133 
134     public static ParserPool getParserPool() {
135         return providerRegistry.getParserPool();
136     }
137 
138     
139 
140 
141 
142 
143 
144 
145     public static XMLObject fromDom(Element root) throws WSSecurityException {
146         if (root == null) {
147             LOG.debug("Attempting to unmarshal a null element!");
148             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
149                                           new Object[] {"Error unmarshalling a SAML assertion"});
150         }
151         Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(root);
152         if (unmarshaller == null) {
153             LOG.debug("Unable to find an unmarshaller for element: " + root.getLocalName());
154             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
155                                           new Object[] {"Error unmarshalling a SAML assertion"});
156         }
157         try {
158             return unmarshaller.unmarshall(root);
159         } catch (UnmarshallingException ex) {
160             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
161                                           new Object[] {"Error unmarshalling a SAML assertion"});
162         }
163     }
164 
165     
166 
167 
168 
169 
170 
171 
172 
173     public static Element toDom(
174         XMLObject xmlObject,
175         Document doc
176     ) throws WSSecurityException {
177         return toDom(xmlObject, doc, true);
178     }
179 
180     
181 
182 
183 
184 
185 
186 
187 
188 
189     public static Element toDom(
190         XMLObject xmlObject,
191         Document doc,
192         boolean signObject
193     ) throws WSSecurityException {
194         Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
195         Element element = null;
196         DocumentFragment frag = doc == null ? null : doc.createDocumentFragment();
197         try {
198             if (frag != null) {
199                 while (doc.getFirstChild() != null) {
200                     frag.appendChild(doc.removeChild(doc.getFirstChild()));
201                 }
202             }
203             try {
204                 if (doc == null) {
205                     element = marshaller.marshall(xmlObject);
206                 } else {
207                     element = marshaller.marshall(xmlObject, doc);
208                 }
209             } catch (MarshallingException ex) {
210                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
211                                               new Object[] {"Error marshalling a SAML assertion"});
212             }
213 
214             if (signObject) {
215                 signXMLObject(xmlObject);
216             }
217         } finally {
218             if (frag != null) {
219                 while (doc.getFirstChild() != null) {
220                     doc.removeChild(doc.getFirstChild());
221                 }
222                 doc.appendChild(frag);
223             }
224         }
225         return element;
226     }
227 
228     private static void signXMLObject(XMLObject xmlObject) throws WSSecurityException {
229         if (xmlObject instanceof org.opensaml.saml.saml1.core.Response) {
230             org.opensaml.saml.saml1.core.Response response =
231                     (org.opensaml.saml.saml1.core.Response)xmlObject;
232 
233             
234             if (response.getAssertions() != null) {
235                 for (org.opensaml.saml.saml1.core.Assertion assertion : response.getAssertions()) {
236                     signObject(assertion.getSignature());
237                 }
238             }
239 
240             signObject(response.getSignature());
241         } else if (xmlObject instanceof org.opensaml.saml.saml2.core.Response) {
242             org.opensaml.saml.saml2.core.Response response =
243                     (org.opensaml.saml.saml2.core.Response)xmlObject;
244 
245             
246             if (response.getAssertions() != null) {
247                 for (org.opensaml.saml.saml2.core.Assertion assertion : response.getAssertions()) {
248                     signObject(assertion.getSignature());
249                 }
250             }
251 
252             signObject(response.getSignature());
253         } else if (xmlObject instanceof SignableSAMLObject) {
254             signObject(((SignableSAMLObject)xmlObject).getSignature());
255         }
256     }
257 
258     private static void signObject(Signature signature) throws WSSecurityException {
259         if (signature != null) {
260             ClassLoader loader = Thread.currentThread().getContextClassLoader();
261             try {
262                 Thread.currentThread().setContextClassLoader(SignerProvider.class.getClassLoader());
263                 Signer.signObject(signature);
264             } catch (SignatureException ex) {
265                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
266                                               new Object[] {"Error signing a SAML assertion"});
267             } finally {
268                 Thread.currentThread().setContextClassLoader(loader);
269             }
270         }
271     }
272 
273     
274 
275 
276 
277 
278     @SuppressWarnings("unchecked")
279     public static Signature buildSignature() {
280         QName qName = Signature.DEFAULT_ELEMENT_NAME;
281         XMLObjectBuilder<Signature> builder =
282             (XMLObjectBuilder<Signature>)builderFactory.getBuilder(qName);
283         if (builder == null) {
284             LOG.error(
285                 "Unable to retrieve builder for object QName "
286                 + qName
287             );
288             return null;
289         }
290         return
291             builder.buildObject(
292                  qName.getNamespaceURI(), qName.getLocalPart(), qName.getPrefix()
293              );
294     }
295 
296     
297 
298 
299 
300 
301 
302     public static boolean isMethodSenderVouches(String confirmMethod) {
303         return
304             confirmMethod != null && confirmMethod.startsWith("urn:oasis:names:tc:SAML:")
305                 && confirmMethod.endsWith(":cm:sender-vouches");
306     }
307 
308     
309 
310 
311 
312 
313 
314     public static boolean isMethodHolderOfKey(String confirmMethod) {
315         return
316             confirmMethod != null && confirmMethod.startsWith("urn:oasis:names:tc:SAML:")
317                 && confirmMethod.endsWith(":cm:holder-of-key");
318     }
319 
320 }