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 }