blob: 11b1f4bbc47be7b0a4ea78f5f63d7ae9a827f326 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../.resources/report.css" type="text/css"/><link rel="shortcut icon" href="../.resources/report.gif" type="image/gif"/><title>CommonUtil.java</title><link rel="stylesheet" href="../.resources/prettify.css" type="text/css"/><script type="text/javascript" src="../.resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../.sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Coverage Report</a> &gt; <a href="index.source.html" class="el_package">org.apache.rahas.impl.util</a> &gt; <span class="el_source">CommonUtil.java</span></div><h1>CommonUtil.java</h1><pre class="source lang-java linenums">/*
* Copyright 2004,2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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.rahas.impl.util;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.dom.DOMMetaFactory;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.Parameter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.rahas.RahasData;
import org.apache.rahas.TrustException;
import org.apache.rahas.impl.SAMLTokenIssuerConfig;
import org.apache.rahas.impl.TokenIssuerUtil;
import org.apache.ws.security.*;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.components.crypto.CryptoFactory;
import org.apache.ws.security.components.crypto.CryptoType;
import org.apache.ws.security.handler.RequestData;
import org.apache.ws.security.message.WSSecEncryptedKey;
import org.apache.ws.security.processor.EncryptedKeyProcessor;
import org.apache.ws.security.util.Base64;
import org.apache.ws.security.util.Loader;
import org.apache.xml.security.utils.EncryptionConstants;
import org.opensaml.Configuration;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.XMLObjectBuilder;
import org.opensaml.xml.encryption.EncryptedKey;
import org.opensaml.xml.signature.KeyInfo;
import org.opensaml.xml.signature.X509Data;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.security.auth.callback.CallbackHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Properties;
import static org.apache.axiom.om.OMAbstractFactory.FEATURE_DOM;
/**
* This class implements some utility methods common to SAML1 and SAML2.
*/
<span class="nc" id="L65">public class CommonUtil {</span>
<span class="fc" id="L67"> private static Log log = LogFactory.getLog(CommonUtil.class);</span>
/**
* This method creates a DOM compatible Axiom document.
* @return DOM compatible Axiom document
* @throws TrustException If an error occurred while creating the Document.
*/
public static Document getOMDOMDocument() throws TrustException {
<span class="fc" id="L75"> DOMMetaFactory metaFactory = (DOMMetaFactory) OMAbstractFactory.getMetaFactory(FEATURE_DOM);</span>
<span class="fc" id="L76"> DocumentBuilderFactory dbf = metaFactory.newDocumentBuilderFactory();</span>
try {
<span class="fc" id="L78"> return dbf.newDocumentBuilder().newDocument();</span>
<span class="nc" id="L79"> } catch (ParserConfigurationException e) {</span>
<span class="nc" id="L80"> throw new TrustException(&quot;Error creating Axiom compatible DOM Document&quot;, e);</span>
}
}
/**
* Gets the certificates chain by alias. Always returns the first certificate if a certificate chain is found.
* @param crypto Crypto to lookup certificate.
* @param alias Alias name.
* @return X509 certificate object.
* @throws org.apache.rahas.TrustException If an error occurred
* while retrieving the certificate or if no certificates are found for given alias.
*/
public static X509Certificate getCertificateByAlias(Crypto crypto, String alias) throws TrustException {
<span class="fc" id="L94"> X509Certificate[] certificates = getCertificatesByAlias(crypto, alias);</span>
<span class="pc bpc" id="L96" title="1 of 2 branches missed."> if (certificates == null) {</span>
<span class="nc" id="L97"> log.error(&quot;Unable to retrieve certificate for alias &quot; + alias);</span>
<span class="nc" id="L98"> throw new TrustException(&quot;issuerCertificateNotFound&quot;);</span>
}
<span class="fc" id="L101"> return certificates[0];</span>
}
/**
* Gets the certificates chain by alias. If no certificates are found return an empty array.
* @param crypto Crypto to lookup certificate.
* @param alias Alias name.
* @return X509 certificates array.
* @throws org.apache.rahas.TrustException If an error occurred
* while retrieving the certificate.
*/
public static X509Certificate[] getCertificatesByAlias(Crypto crypto, String alias) throws TrustException {
// TODO are we always looking up by alias ? Dont we need to lookup by any other attribute ?
<span class="fc" id="L115"> CryptoType type = new CryptoType(CryptoType.TYPE.ALIAS);</span>
<span class="fc" id="L116"> type.setAlias(alias);</span>
try {
<span class="fc" id="L119"> X509Certificate[] certificates = crypto.getX509Certificates(type);</span>
<span class="pc bpc" id="L121" title="1 of 2 branches missed."> if (certificates == null) {</span>
<span class="nc" id="L122"> log.debug(&quot;Unable to retrieve certificate for alias &quot; + alias);</span>
<span class="nc" id="L123"> return new X509Certificate[0];</span>
}
<span class="fc" id="L125"> return certificates;</span>
<span class="nc" id="L126"> } catch (WSSecurityException e) {</span>
<span class="nc" id="L127"> log.error(&quot;Unable to retrieve certificate for alias &quot; + alias, e);</span>
<span class="nc" id="L128"> throw new TrustException(&quot;issuerCertificateNotFound&quot;, e);</span>
}
}
/**
* Decrypts the EncryptedKey element and returns the secret that was used.
* @param callbackHandler Callback handler to pass to WSS4J framework.
* @param crypto To get private key information.
* @param encryptedKeyElement The encrypted Key element.
* @return The secret as a byte stream.
* @throws WSSecurityException If an error is occurred while decrypting the element.
*/
public static byte[] getDecryptedBytes(CallbackHandler callbackHandler, Crypto crypto, Node encryptedKeyElement)
throws WSSecurityException {
<span class="fc" id="L143"> EncryptedKeyProcessor encryptedKeyProcessor = new EncryptedKeyProcessor();</span>
<span class="fc" id="L145"> RequestData requestData = new RequestData();</span>
<span class="fc" id="L146"> requestData.setCallbackHandler(callbackHandler);</span>
<span class="fc" id="L147"> requestData.setDecCrypto(crypto);</span>
<span class="fc" id="L149"> final WSSConfig cfg = WSSConfig.getNewInstance();</span>
<span class="fc" id="L150"> requestData.setWssConfig(cfg);</span>
<span class="fc" id="L152"> WSDocInfo docInfo = new WSDocInfo(encryptedKeyElement.getOwnerDocument());</span>
List&lt;WSSecurityEngineResult&gt; resultList;
<span class="fc" id="L156"> resultList = encryptedKeyProcessor.handleToken((Element) encryptedKeyElement, requestData, docInfo);</span>
<span class="fc" id="L159"> WSSecurityEngineResult wsSecurityEngineResult = resultList.get(0);</span>
<span class="fc" id="L161"> return (byte[]) wsSecurityEngineResult.get(WSSecurityEngineResult.TAG_SECRET);</span>
}
/**
* Constructs crypto configuration based on the given properties. Provider is instantiated using
* given class loader.
* @param properties Crypto configuration properties.
* @param classLoader Class loader used to create provider.
* @return A crypto object.
* @throws TrustException If an error occurred while creating the Crypto object.
*/
public static Crypto getCrypto(Properties properties, ClassLoader classLoader) throws TrustException {
try {
<span class="nc" id="L174"> return CryptoFactory.getInstance(properties, classLoader);</span>
<span class="nc" id="L175"> } catch (WSSecurityException e) {</span>
<span class="nc" id="L176"> log.error(&quot;An error occurred while loading crypto properties&quot;, e);</span>
<span class="nc" id="L177"> throw new TrustException(&quot;errorLoadingCryptoProperties&quot;, e);</span>
}
}
/**
* Constructs crypto configuration based on the given properties. Provider is instantiated using
* given class loader.
* @param propertiesFile Crypto configuration properties file name.
* @param classLoader Class loader used to create provider.
* @return A crypto object.
* @throws TrustException If an error occurred while creating the Crypto object.
*/
public static Crypto getCrypto(String propertiesFile, ClassLoader classLoader) throws TrustException {
try {
<span class="nc" id="L192"> return CryptoFactory.getInstance(propertiesFile, classLoader);</span>
<span class="nc" id="L193"> } catch (WSSecurityException e) {</span>
<span class="nc" id="L194"> log.error(&quot;An error occurred while loading crypto properties with property file &quot; + propertiesFile, e);</span>
<span class="nc" id="L195"> throw new TrustException(&quot;errorLoadingCryptoProperties&quot;, new Object[]{propertiesFile}, e);</span>
}
}
/**
* Creates the token issuer configuration. The configuration is created in following order,
* 1. Try create token configuration using configuration OMElement
* 2. Try create token configuration using a configuration file name
* 3. Try create token configuration using a parameter name in message context.
* The issuer configuration would look like as follows,
*
* &lt;pre&gt; &amp;lt;saml-issuer-config&amp;gt;
* &amp;lt;issuerName&amp;gt;Test_STS&amp;lt;/issuerName&amp;gt;
* &amp;lt;issuerKeyAlias&amp;gt;ip&amp;lt;/issuerKeyAlias&amp;gt;
* &amp;lt;issuerKeyPassword&amp;gt;password&amp;lt;/issuerKeyPassword&amp;gt;
* &amp;lt;cryptoProperties&amp;gt;
* &amp;lt;crypto provider=&quot;org.apache.ws.security.components.crypto.Merlin&quot;&amp;gt;
* &amp;lt;property name=&quot;org.apache.ws.security.crypto.merlin.keystore.type&quot;&amp;gt;JKS&amp;lt;/property&amp;gt;
* &amp;lt;property name=&quot;org.apache.ws.security.crypto.merlin.file&quot;&amp;gt;META-INF/rahas-sts.jks&amp;lt;/property&amp;gt;
* &amp;lt;property name=&quot;org.apache.ws.security.crypto.merlin.keystore.password&quot;&amp;gt;password&amp;lt;/property&amp;gt;
* &amp;lt;/crypto&amp;gt;
* &amp;lt;/cryptoProperties&amp;gt;
* &amp;lt;timeToLive&amp;gt;300000&amp;lt;/timeToLive&amp;gt;
* &amp;lt;keySize&amp;gt;256&amp;lt;/keySize&amp;gt;
* &amp;lt;addRequestedAttachedRef /&amp;gt;
* &amp;lt;addRequestedUnattachedRef /&amp;gt;
* &amp;lt;keyComputation&amp;gt;2&amp;lt;/keyComputation&amp;gt;
* &amp;lt;proofKeyType&amp;gt;BinarySecret&amp;lt;/proofKeyType&amp;gt;
* &amp;lt;trusted-services&amp;gt;
* &amp;lt;service alias=&quot;bob&quot;&amp;gt;http://localhost:8080/axis2/services/STS&amp;lt;/service&amp;gt;
* &amp;lt;/trusted-services&amp;gt;
* &amp;lt;/saml-issuer-config&amp;gt;&lt;/pre&gt;
*
* @param configElement Configuration as an OMElement.
* @param configFile Configuration as a file.
* @param messageContextParameter Configuration as a message context parameter.
* @return Token issuer configuration as a SAMLTokenIssuerConfig object.
* @throws TrustException If an error occurred while creating SAMLTokenIssuerConfig object.
*/
public static SAMLTokenIssuerConfig getTokenIssuerConfiguration(OMElement configElement, String configFile,
Parameter messageContextParameter) throws TrustException {
// First try using configuration element
<span class="fc" id="L239"> SAMLTokenIssuerConfig tokenIssuerConfiguration = createTokenIssuerConfiguration(configElement);</span>
<span class="fc bfc" id="L241" title="All 2 branches covered."> if (tokenIssuerConfiguration == null) {</span>
// Now try file
<span class="fc" id="L244"> tokenIssuerConfiguration = createTokenIssuerConfiguration(configFile);</span>
<span class="pc bpc" id="L246" title="1 of 2 branches missed."> if (tokenIssuerConfiguration == null) {</span>
// Finally try using the parameter
<span class="pc bpc" id="L249" title="1 of 2 branches missed."> if (messageContextParameter != null) {</span>
<span class="fc" id="L250"> tokenIssuerConfiguration = createTokenIssuerConfiguration(messageContextParameter);</span>
}
<span class="fc" id="L253"> return tokenIssuerConfiguration;</span>
} else {
<span class="nc" id="L255"> return tokenIssuerConfiguration;</span>
}
} else {
<span class="fc" id="L259"> return tokenIssuerConfiguration;</span>
}
}
protected static SAMLTokenIssuerConfig createTokenIssuerConfiguration(OMElement configElement)
throws TrustException {
<span class="fc bfc" id="L266" title="All 2 branches covered."> if (configElement != null) {</span>
<span class="fc" id="L268"> log.debug(&quot;Creating token issuer configuration using OMElement&quot;);</span>
<span class="fc" id="L270"> return new SAMLTokenIssuerConfig(configElement</span>
.getFirstChildWithName(SAMLTokenIssuerConfig.SAML_ISSUER_CONFIG));
}
<span class="fc" id="L274"> return null;</span>
}
protected static SAMLTokenIssuerConfig createTokenIssuerConfiguration(String configFile) throws TrustException {
<span class="fc bfc" id="L279" title="All 2 branches covered."> if (configFile != null) {</span>
<span class="pc bpc" id="L281" title="1 of 2 branches missed."> if (log.isDebugEnabled()) {</span>
<span class="nc" id="L282"> log.debug(&quot;Creating token issuer configuration using file &quot; + configFile);</span>
}
<span class="fc" id="L285"> return new SAMLTokenIssuerConfig(configFile);</span>
}
<span class="fc" id="L288"> return null;</span>
}
protected static SAMLTokenIssuerConfig createTokenIssuerConfiguration(Parameter messageContextParameter)
throws TrustException {
<span class="pc bpc" id="L294" title="2 of 4 branches missed."> if (messageContextParameter != null &amp;&amp; messageContextParameter.getParameterElement() != null) {</span>
<span class="fc" id="L296"> log.debug(&quot;Creating token issuer configuration using the config parameter&quot;);</span>
<span class="fc" id="L298"> return new SAMLTokenIssuerConfig(messageContextParameter</span>
.getParameterElement().getFirstChildWithName(
SAMLTokenIssuerConfig.SAML_ISSUER_CONFIG));
}
<span class="nc" id="L303"> return null;</span>
}
/**
* Builds the requested XMLObject.
*
* @param objectQName name of the XMLObject
* @return the build XMLObject
* @throws org.apache.rahas.TrustException If unable to find the appropriate builder.
*/
public static XMLObject buildXMLObject(QName objectQName) throws TrustException {
<span class="fc" id="L314"> XMLObjectBuilder builder = Configuration.getBuilderFactory().getBuilder(objectQName);</span>
<span class="fc bfc" id="L315" title="All 2 branches covered."> if (builder == null) {</span>
<span class="fc" id="L316"> log.debug(&quot;Unable to find OpenSAML builder for object &quot; + objectQName);</span>
<span class="fc" id="L317"> throw new TrustException(&quot;builderNotFound&quot;,new Object[]{objectQName});</span>
}
<span class="fc" id="L319"> return builder.buildObject(objectQName.getNamespaceURI(), objectQName.getLocalPart(), objectQName.getPrefix());</span>
}
/**
* This method creates KeyInfo element of an assertion. This is a facade, in which it calls
* to other helper methods to create KeyInfo. The TokenIssuer will call this method to
* create the KeyInfo.
* @param doc An Axiom based DOM Document.
* @param data The ephemeral key which we use here need in encrypting the message also. Therefore
* we need to save the ephemeral key in RahasData passed here.
* @param serviceCert Public key used to encrypt the assertion is extracted from this certificate.
* @param keySize Size of the key to be used
* @param crypto The relevant private key
* @param keyComputation Key computation mechanism.
* @return OpenSAML KeyInfo representation.
* @throws WSSecurityException We use WSS4J to generate encrypted key. This exception will trigger if an
* error occurs while generating the encrypted key.
* @throws TrustException If an error occurred while creating KeyInfo object.
*/
public static KeyInfo getSymmetricKeyBasedKeyInfo(Document doc,
RahasData data,
X509Certificate serviceCert,
int keySize,
Crypto crypto,
int keyComputation) throws WSSecurityException, TrustException {
<span class="fc" id="L345"> byte[] ephemeralKey = TokenIssuerUtil.getSharedSecret(</span>
data, keyComputation, keySize);
<span class="fc" id="L348"> WSSecEncryptedKey encryptedKey = getSymmetricKeyBasedKeyInfoContent(doc, ephemeralKey, serviceCert, crypto);</span>
// Extract the base64 encoded secret value
<span class="fc" id="L351"> byte[] tempKey = new byte[keySize / 8];</span>
<span class="fc" id="L352"> System.arraycopy(encryptedKey.getEphemeralKey(), 0, tempKey,</span>
0, keySize / 8);
<span class="fc" id="L356"> data.setEphmeralKey(tempKey);</span>
<span class="fc" id="L358"> EncryptedKey samlEncryptedKey = SAMLUtils.createEncryptedKey(serviceCert, encryptedKey);</span>
<span class="fc" id="L359"> return SAMLUtils.createKeyInfo(samlEncryptedKey);</span>
}
static WSSecEncryptedKey getSymmetricKeyBasedKeyInfoContent(Document doc,
byte[] ephemeralKey,
X509Certificate serviceCert,
Crypto crypto) throws WSSecurityException,
TrustException {
// Create the encrypted key
<span class="fc" id="L368"> WSSecEncryptedKey encryptedKeyBuilder = new WSSecEncryptedKey();</span>
// Use thumbprint id
<span class="fc" id="L371"> encryptedKeyBuilder</span>
.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
// SEt the encryption cert
<span class="fc" id="L375"> encryptedKeyBuilder.setUseThisCert(serviceCert);</span>
<span class="fc" id="L377"> encryptedKeyBuilder.setEphemeralKey(ephemeralKey);</span>
// Set key encryption algo
<span class="fc" id="L380"> encryptedKeyBuilder</span>
.setKeyEncAlgo(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSA15);
// Build
<span class="fc" id="L384"> encryptedKeyBuilder.prepare(doc, crypto);</span>
<span class="fc" id="L386"> return encryptedKeyBuilder;</span>
}
/**
* Creates the certificate based KeyInfo object.
* @param certificate The public key certificate used to create the KeyInfo object.
* @return OpenSAML representation of KeyInfo object.
* @throws TrustException If an error occurred while creating the KeyInfo
*/
public static KeyInfo getCertificateBasedKeyInfo(X509Certificate certificate) throws TrustException {
<span class="fc" id="L396"> X509Data x509Data = CommonUtil.createX509Data(certificate);</span>
<span class="fc" id="L397"> return SAMLUtils.createKeyInfo(x509Data);</span>
}
/**
* Creates the X509 data element in a SAML issuer token. Should create an element similar to following,
* &lt;X509Data xmlns:xenc=&quot;http://www.w3.org/2001/04/xmlenc#&quot;
* xmlns:ds=&quot;http://www.w3.org/2000/09/xmldsig#&quot;&gt;
* &lt;X509Certificate&gt;
* MIICNTCCAZ6gAwIB...
* &lt;/X509Certificate&gt;
* &lt;/X509Data&gt;
* @param clientCert Client certificate to be used when generating X509 data
* @return SAML X509Data representation.
* @throws TrustException If an error occurred while creating X509Data and X509Certificate.
*/
static X509Data createX509Data(X509Certificate clientCert) throws TrustException {
byte[] clientCertBytes;
try {
<span class="fc" id="L416"> clientCertBytes = clientCert.getEncoded();</span>
<span class="nc" id="L417"> } catch (CertificateEncodingException e) {</span>
<span class="nc" id="L418"> log.error(&quot;An error occurred while encoding certificate.&quot;, e);</span>
<span class="nc" id="L419"> throw new TrustException(&quot;An error occurred while encoding certificate.&quot;, e);</span>
<span class="fc" id="L420"> }</span>
<span class="fc" id="L421"> String base64Cert = Base64.encode(clientCertBytes);</span>
<span class="fc" id="L423"> org.opensaml.xml.signature.X509Certificate x509Certificate</span>
= (org.opensaml.xml.signature.X509Certificate)CommonUtil.buildXMLObject
(org.opensaml.xml.signature.X509Certificate.DEFAULT_ELEMENT_NAME);
<span class="fc" id="L427"> x509Certificate.setValue(base64Cert);</span>
<span class="fc" id="L429"> X509Data x509Data = (X509Data)CommonUtil.buildXMLObject(X509Data.DEFAULT_ELEMENT_NAME);</span>
<span class="fc" id="L430"> x509Data.getX509Certificates().add(x509Certificate);</span>
<span class="fc" id="L432"> return x509Data;</span>
}
/**
* Gets the SAML callback handler. First checks whether there is a registered callback handler in token
* issuer configuration. If not this will check whether there is a callback class configured in token issuer
* configuration. If class name is specified this method will create an object of the class and will return.
* If class name is also not specified this method will return null.
* @param tokenIssuerConfiguration The SAML token issuer configuration.
* @param data The RahasData.
* @return The SAMLCallbackHandler if configured in token issuer configuration, else null.
* @throws TrustException If an error occurred while loading class from class loader
*/
public static SAMLCallbackHandler getSAMLCallbackHandler(SAMLTokenIssuerConfig tokenIssuerConfiguration,
RahasData data) throws TrustException {
<span class="fc bfc" id="L447" title="All 2 branches covered."> if (tokenIssuerConfiguration.getCallbackHandler() != null) {</span>
<span class="fc" id="L449"> return tokenIssuerConfiguration.getCallbackHandler();</span>
<span class="pc bpc" id="L451" title="1 of 4 branches missed."> } else if (tokenIssuerConfiguration.getCallbackHandlerName() != null</span>
&amp;&amp; tokenIssuerConfiguration.getCallbackHandlerName().trim().length() &gt; 0) {
SAMLCallbackHandler handler;
<span class="fc" id="L455"> MessageContext msgContext = data.getInMessageContext();</span>
<span class="fc" id="L456"> ClassLoader classLoader = msgContext.getAxisService().getClassLoader();</span>
Class cbClass;
try {
<span class="fc" id="L459"> cbClass = Loader.loadClass(classLoader, tokenIssuerConfiguration.getCallbackHandlerName());</span>
<span class="nc" id="L460"> } catch (ClassNotFoundException e) {</span>
<span class="nc" id="L461"> throw new TrustException(&quot;cannotLoadPWCBClass&quot;, new String[]{tokenIssuerConfiguration</span>
.getCallbackHandlerName()}, e);
<span class="fc" id="L463"> }</span>
try {
<span class="fc" id="L465"> handler = (SAMLCallbackHandler) cbClass.newInstance();</span>
<span class="nc" id="L466"> } catch (java.lang.Exception e) {</span>
<span class="nc" id="L467"> throw new TrustException(&quot;cannotCreatePWCBInstance&quot;, new String[]{tokenIssuerConfiguration</span>
.getCallbackHandlerName()}, e);
<span class="fc" id="L469"> }</span>
<span class="fc" id="L471"> return handler;</span>
}
<span class="fc" id="L474"> return null;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.eclemma.org/jacoco">JaCoCo</a> 0.7.5.201505241946</span></div></body></html>