/** * Copyright (c) Codice Foundation * <p/> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p/> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.security.realm.sts; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.xml.stream.XMLStreamException; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.cxf.Bus; import org.apache.cxf.BusException; import org.apache.cxf.BusFactory; import org.apache.cxf.bus.CXFBusFactory; import org.apache.cxf.bus.spring.SpringBusFactory; import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.configuration.security.FiltersType; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.EndpointException; import org.apache.cxf.staxutils.W3CDOMStreamWriter; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.ws.security.SecurityConstants; import org.apache.cxf.ws.security.tokenstore.SecurityToken; import org.apache.cxf.ws.security.trust.STSClient; import org.apache.cxf.ws.security.trust.STSUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.realm.AuthenticatingRealm; import org.apache.shiro.subject.SimplePrincipalCollection; import org.codice.ddf.configuration.ConfigurationManager; import org.codice.ddf.configuration.ConfigurationWatcher; import org.codice.ddf.security.handler.api.BaseAuthenticationToken; import org.codice.ddf.security.handler.api.SAMLAuthenticationToken; import org.codice.ddf.security.policy.context.ContextPolicy; import org.codice.ddf.security.policy.context.ContextPolicyManager; import org.slf4j.LoggerFactory; import org.slf4j.ext.XLogger; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; import ddf.security.PropertiesLoader; import ddf.security.assertion.SecurityAssertion; import ddf.security.assertion.impl.SecurityAssertionImpl; import ddf.security.common.audit.SecurityLogger; import ddf.security.common.util.CommonSSLFactory; import ddf.security.encryption.EncryptionService; import ddf.security.sts.client.configuration.STSClientConfiguration; /** * The STS Realm is the main piece of the security framework responsible for exchanging a binary * security token for a SAML assertion. */ public class StsRealm extends AuthenticatingRealm implements ConfigurationWatcher { private static final XLogger LOGGER = new XLogger(LoggerFactory.getLogger(StsRealm.class)); private static final String NAME = StsRealm.class.getSimpleName(); private static final String HTTPS = "https"; private static final String ADDRESSING_NAMESPACE = "http://www.w3.org/2005/08/addressing"; // AES is the best encryption but isn't always supported, 3DES is widely // supported and is very difficult to crack private static final String[] SSL_ALLOWED_ALGORITHMS = {".*_EXPORT_.*", ".*_WITH_AES_.*", ".*_WITH_3DES_.*"}; private static final String[] SSL_DISALLOWED_ALGORITHMS = {".*_WITH_NULL_.*", ".*_DH_anon_.*"}; private STSClient stsClient; private Bus bus; private String trustStorePath; private String trustStorePassword; private String keyStorePath; private String keyStorePassword; private boolean settingsConfigured; private EncryptionService encryptionService; private STSClientConfiguration stsClientConfig; private ContextPolicyManager contextPolicyManager; public StsRealm() { this.bus = getBus(); setCredentialsMatcher(new STSCredentialsMatcher()); } public void setEncryptionService(EncryptionService encryptionService) { this.encryptionService = encryptionService; } public void setStsClientConfig(STSClientConfiguration stsClientConfig) { this.stsClientConfig = stsClientConfig; configureStsClient(); } public ContextPolicyManager getContextPolicyManager() { return contextPolicyManager; } public void setContextPolicyManager(ContextPolicyManager contextPolicyManager) { this.contextPolicyManager = contextPolicyManager; } /** * Watch for changes in System Settings and STS Client Settings from the configuration page in * the DDF console. */ @Override public void configurationUpdateCallback(Map<String, String> properties) { settingsConfigured = false; if (properties != null && !properties.isEmpty()) { if (LOGGER.isDebugEnabled()) { logIncomingProperties(properties); } if (isDdfConfigurationUpdate(properties)) { LOGGER.debug("Got system configuration update."); setDdfPropertiesFromConfigAdmin(properties); try { configureStsClient(); settingsConfigured = true; } catch (Exception e) { LOGGER.debug( "STS was not available during configuration update, will try again when realm is called. Full stack trace is available at the TRACE level."); LOGGER.trace("Could not create STS client", e); } } } else { LOGGER.debug("properties are NULL or empty"); } } /** * Determine if the supplied token is supported by this realm. */ @Override public boolean supports(AuthenticationToken token) { boolean supported = token != null && token.getCredentials() != null; if (supported) { LOGGER.debug("Token {} is supported by {}.", token.getClass(), StsRealm.class.getName()); } else if (token != null) { LOGGER.debug("Token {} is not supported by {}.", token.getClass(), StsRealm.class.getName()); } else { LOGGER.debug("The supplied authentication token is null. Sending back not supported."); } return supported; } /** * Perform authentication based on the supplied token. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) { String method = "doGetAuthenticationInfo( AuthenticationToken token )"; LOGGER.entry(method); Object credential; if (token instanceof SAMLAuthenticationToken) { credential = token.getCredentials(); } else if (token instanceof BaseAuthenticationToken) { credential = ((BaseAuthenticationToken) token).getCredentialsAsXMLString(); } else { credential = token.getCredentials().toString(); } if (credential == null) { String msg = "Unable to authenticate credential. A NULL credential was provided in the supplied authentication token. This may be due to an error with the SSO server that created the token."; LOGGER.error(msg); throw new AuthenticationException(msg); } else { //removed the credentials from the log message for now, I don't think we should be dumping user/pass into log LOGGER.debug("Received credentials."); } if (!settingsConfigured) { configureStsClient(); settingsConfigured = true; } else { setClaimsOnStsClient(createClaimsElement()); } SecurityToken securityToken; if (token instanceof SAMLAuthenticationToken && credential instanceof SecurityToken) { securityToken = renewSecurityToken((SecurityToken) credential); } else { securityToken = requestSecurityToken(credential); } LOGGER.debug("Creating token authentication information with SAML."); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(); SimplePrincipalCollection principals = new SimplePrincipalCollection(); SecurityAssertion assertion = new SecurityAssertionImpl(securityToken); principals.add(assertion.getPrincipal(), NAME); principals.add(assertion, NAME); simpleAuthenticationInfo.setPrincipals(principals); simpleAuthenticationInfo.setCredentials(credential); LOGGER.exit(method); return simpleAuthenticationInfo; } /** * Request a security token (SAML assertion) from the STS. * * @param authToken The subject the security token is being request for. * @return security token (SAML assertion) */ protected SecurityToken requestSecurityToken(Object authToken) { SecurityToken token = null; String stsAddress = stsClientConfig.getAddress(); try { LOGGER.debug("Requesting security token from STS at: " + stsAddress + "."); if (authToken != null) { LOGGER.debug( "Telling the STS to request a security token on behalf of the auth token"); SecurityLogger.logInfo( "Telling the STS to request a security token on behalf of the auth token"); stsClient.setWsdlLocation(stsAddress); stsClient.setOnBehalfOf(authToken); stsClient.setTokenType(stsClientConfig.getAssertionType()); stsClient.setKeyType(stsClientConfig.getKeyType()); stsClient.setKeySize(Integer.valueOf(stsClientConfig.getKeySize())); token = stsClient.requestSecurityToken(stsAddress); LOGGER.debug("Finished requesting security token."); SecurityLogger.logInfo("Finished requesting security token."); SecurityLogger.logSecurityAssertionInfo(token); } } catch (Exception e) { String msg = "Error requesting the security token from STS at: " + stsAddress + "."; LOGGER.error(msg, e); SecurityLogger.logError(msg); throw new AuthenticationException(msg, e); } return token; } /** * Renew a security token (SAML assertion) from the STS. * * @param securityToken The token being renewed. * @return security token (SAML assertion) */ protected SecurityToken renewSecurityToken(SecurityToken securityToken) { SecurityToken token = null; String stsAddress = stsClientConfig.getAddress(); try { LOGGER.debug("Renewing security token from STS at: " + stsAddress + "."); if (securityToken != null) { LOGGER.debug( "Telling the STS to renew a security token on behalf of the auth token"); SecurityLogger.logInfo( "Telling the STS to renew a security token on behalf of the auth token"); stsClient.setWsdlLocation(stsAddress); stsClient.setTokenType(stsClientConfig.getAssertionType()); stsClient.setKeyType(stsClientConfig.getKeyType()); stsClient.setKeySize(Integer.valueOf(stsClientConfig.getKeySize())); stsClient.setAllowRenewing(true); token = stsClient.renewSecurityToken(securityToken); LOGGER.debug("Finished renewing security token."); SecurityLogger.logInfo("Finished renewing security token."); SecurityLogger.logSecurityAssertionInfo(token); } } catch (Exception e) { String msg = "Error renewing the security token from STS at: " + stsAddress + "."; LOGGER.error(msg, e); SecurityLogger.logError(msg); throw new AuthenticationException(msg, e); } return token; } /** * Log properties from DDF configuration updates. */ private void logIncomingProperties(@SuppressWarnings("rawtypes") Map properties) { @SuppressWarnings("unchecked") Set<String> keys = properties.keySet(); StringBuilder builder = new StringBuilder(); builder.append("\nIncoming properties:\n"); for (String key : keys) { builder.append("key: " + key + "; value: " + properties.get(key) + "\n"); } LOGGER.debug(builder.toString()); } /** * Logs the current STS client configuration. */ private void logStsClientConfiguration() { StringBuilder builder = new StringBuilder(); builder.append("\nSTS Client configuration:\n"); builder.append("STS WSDL location: " + stsClient.getWsdlLocation() + "\n"); builder.append("STS service name: " + stsClient.getServiceQName() + "\n"); builder.append("STS endpoint name: " + stsClient.getEndpointQName() + "\n"); Map<String, Object> map = stsClient.getProperties(); Set<String> keys = map.keySet(); builder.append("\nSTS Client properties:\n"); for (String key : keys) { builder.append("key: " + key + "; value: " + map.get(key) + "\n"); } LOGGER.debug(builder.toString()); } /** * Determines if the received update is a DDF System Settings update. */ private boolean isDdfConfigurationUpdate(@SuppressWarnings("rawtypes") Map properties) { boolean updated = false; if (properties.containsKey(ConfigurationManager.TRUST_STORE) && properties .containsKey(ConfigurationManager.TRUST_STORE_PASSWORD) && properties .containsKey(ConfigurationManager.KEY_STORE) && properties .containsKey(ConfigurationManager.KEY_STORE_PASSWORD)) { updated = true; } else { updated = false; } return updated; } /** * Setup trust store for SSL client. */ private void setupTrustStore(TLSClientParameters tlsParams, String trustStorePath, String trustStorePassword) { File trustStoreFile = new File(trustStorePath); if (trustStoreFile.exists() && trustStorePassword != null) { KeyStore trustStore = null; FileInputStream fis = null; try { trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); fis = new FileInputStream(trustStoreFile); LOGGER.debug("Loading trustStore"); trustStore.load(fis, trustStorePassword.toCharArray()); TrustManagerFactory trustFactory = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustFactory.init(trustStore); LOGGER.debug("trust manager factory initialized"); TrustManager[] tm = trustFactory.getTrustManagers(); tlsParams.setTrustManagers(tm); } catch (FileNotFoundException e) { LOGGER.error("Unable to find SSL store: " + trustStorePath, e); } catch (IOException e) { LOGGER.error("Unable to load trust store. " + trustStore, e); } catch (CertificateException e) { LOGGER.error("Unable to load certificates from trust store. " + trustStore, e); } catch (KeyStoreException e) { LOGGER.error("Unable to read trust store: ", e); } catch (NoSuchAlgorithmException e) { LOGGER.error("Problems creating SSL socket. Usually this is " + "referring to the certificate sent by the server not being trusted by the client.", e); } finally { IOUtils.closeQuietly(fis); } } } /** * Setup key store for SSL client. */ private void setupKeyStore(TLSClientParameters tlsParams, String keyStorePath, String keyStorePassword) { File keyStoreFile = new File(keyStorePath); if (keyStoreFile.exists() && keyStorePassword != null) { FileInputStream fis = null; KeyStore keyStore = null; try { keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); fis = new FileInputStream(keyStoreFile); LOGGER.debug("Loading keyStore"); keyStore.load(fis, keyStorePassword.toCharArray()); KeyManagerFactory keyFactory = KeyManagerFactory .getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyFactory.init(keyStore, keyStorePassword.toCharArray()); LOGGER.debug("key manager factory initialized"); KeyManager[] km = keyFactory.getKeyManagers(); tlsParams.setKeyManagers(km); } catch (FileNotFoundException e) { LOGGER.error("Unable to find SSL store: " + keyStorePath, e); } catch (IOException e) { LOGGER.error("Unable to load key store. " + keyStoreFile, e); } catch (CertificateException e) { LOGGER.error("Unable to load certificates from key store. " + keyStoreFile, e); } catch (KeyStoreException e) { LOGGER.error("Unable to read key store: ", e); } catch (NoSuchAlgorithmException e) { LOGGER.error("Problems creating SSL socket. Usually this is " + "referring to the certificate sent by the server not being trusted by the client.", e); } catch (UnrecoverableKeyException e) { LOGGER.error("Unable to read key store: ", e); } finally { IOUtils.closeQuietly(fis); } } } /** * Setup cipher suites filter for SSL client. */ private void setupCipherSuiteFilters(TLSClientParameters tlsParams) { // this sets the algorithms that we accept for SSL FiltersType filter = new FiltersType(); filter.getInclude().addAll(Arrays.asList(SSL_ALLOWED_ALGORITHMS)); filter.getExclude().addAll(Arrays.asList(SSL_DISALLOWED_ALGORITHMS)); tlsParams.setCipherSuitesFilter(filter); } /** * Configure SSL on the client. */ private void configureSslOnClient(Client client) { HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); if (null != httpConduit) { TLSClientParameters tlsParams = new TLSClientParameters(); tlsParams.setDisableCNCheck(true); setupTrustStore(tlsParams, trustStorePath, trustStorePassword); setupKeyStore(tlsParams, keyStorePath, keyStorePassword); setupCipherSuiteFilters(tlsParams); httpConduit.setTlsClientParameters(tlsParams); } } /** * Set properties based on DDF System Setting updates. */ private void setDdfPropertiesFromConfigAdmin(Map<String, String> properties) { String setTrustStorePath = properties.get(ConfigurationManager.TRUST_STORE); if (StringUtils.isNotBlank(setTrustStorePath)) { LOGGER.debug("Setting trust store path: " + setTrustStorePath); this.trustStorePath = setTrustStorePath; } String setTrustStorePassword = properties.get(ConfigurationManager.TRUST_STORE_PASSWORD); if (StringUtils.isNotBlank(setTrustStorePassword)) { if (encryptionService == null) { LOGGER.error( "The StsRealm has a null Encryption Service. Unable to decrypt the encrypted " + "trustStore password. Setting decrypted password to null."); this.trustStorePassword = null; } else { setTrustStorePassword = encryptionService.decryptValue(setTrustStorePassword); LOGGER.debug("Setting trust store password."); this.trustStorePassword = setTrustStorePassword; } } String setKeyStorePath = properties.get(ConfigurationManager.KEY_STORE); if (StringUtils.isNotBlank(setKeyStorePath)) { LOGGER.debug("Setting key store path: " + setKeyStorePath); this.keyStorePath = setKeyStorePath; } String setKeyStorePassword = properties.get(ConfigurationManager.KEY_STORE_PASSWORD); if (StringUtils.isNotBlank(setKeyStorePassword)) { if (encryptionService == null) { LOGGER.error( "The StsRealm has a null Encryption Service. Unable to decrypt the encrypted " + "keyStore password. Setting decrypted password to null."); this.keyStorePassword = null; } else { setKeyStorePassword = encryptionService.decryptValue(setKeyStorePassword); LOGGER.debug("Setting key store password."); this.keyStorePassword = setKeyStorePassword; } } } /** * Helper method to setup STS Client. */ private Bus getBus() { BusFactory bf = new CXFBusFactory(); Bus setBus = bf.createBus(); SpringBusFactory.setDefaultBus(setBus); SpringBusFactory.setThreadDefaultBus(setBus); return setBus; } /** * Helper method to setup STS Client. */ private void addStsProperties() { Map<String, Object> map = new HashMap<String, Object>(); String signaturePropertiesPath = stsClientConfig.getSignatureProperties(); if (signaturePropertiesPath != null && !signaturePropertiesPath.isEmpty()) { LOGGER.debug("Setting signature properties on STSClient: " + signaturePropertiesPath); Properties signatureProperties = PropertiesLoader .loadProperties(signaturePropertiesPath); map.put(SecurityConstants.SIGNATURE_PROPERTIES, signatureProperties); } String encryptionPropertiesPath = stsClientConfig.getEncryptionProperties(); if (encryptionPropertiesPath != null && !encryptionPropertiesPath.isEmpty()) { LOGGER.debug("Setting encryption properties on STSClient: " + encryptionPropertiesPath); Properties encryptionProperties = PropertiesLoader .loadProperties(encryptionPropertiesPath); map.put(SecurityConstants.ENCRYPT_PROPERTIES, encryptionProperties); } String stsPropertiesPath = stsClientConfig.getTokenProperties(); if (stsPropertiesPath != null && !stsPropertiesPath.isEmpty()) { LOGGER.debug("Setting sts properties on STSClient: " + stsPropertiesPath); Properties stsProperties = PropertiesLoader.loadProperties(stsPropertiesPath); map.put(SecurityConstants.STS_TOKEN_PROPERTIES, stsProperties); } LOGGER.debug("Setting callback handler on STSClient"); //DDF-733 map.put(SecurityConstants.CALLBACK_HANDLER, new CommonCallbackHandler()); LOGGER.debug("Setting STS TOKEN USE CERT FOR KEY INFO to \"true\""); map.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, String.valueOf(stsClientConfig.getUseKey())); LOGGER.debug("Adding in realm information to the STSClient"); map.put("CLIENT_REALM", "DDF"); stsClient.setProperties(map); } /** * Helper method to setup STS Client. */ private void configureBaseStsClient() { stsClient = new STSClient(bus); String stsAddress = stsClientConfig.getAddress(); String stsServiceName = stsClientConfig.getServiceName(); String stsEndpointName = stsClientConfig.getEndpointName(); if (stsAddress != null) { LOGGER.debug("Setting WSDL location on STSClient: " + stsAddress); stsClient.setWsdlLocation(stsAddress); } if (stsServiceName != null) { LOGGER.debug("Setting service name on STSClient: " + stsServiceName); stsClient.setServiceName(stsServiceName); } if (stsEndpointName != null) { LOGGER.debug("Setting endpoint name on STSClient: " + stsEndpointName); stsClient.setEndpointName(stsEndpointName); } LOGGER.debug("Setting addressing namespace on STSClient: " + ADDRESSING_NAMESPACE); stsClient.setAddressingNamespace(ADDRESSING_NAMESPACE); } /** * Helper method to setup STS Client. */ protected void configureStsClient() { LOGGER.debug("Configuring the STS client."); try { if (trustStorePath != null && trustStorePassword != null && keyStorePath != null && keyStorePassword != null) { HttpsURLConnection.setDefaultSSLSocketFactory(CommonSSLFactory .createSocket(trustStorePath, trustStorePassword, keyStorePath, keyStorePassword)); } } catch (IOException ioe) { throw new RuntimeException( "Could not create SSL connection with given trust/key stores.", ioe); } configureBaseStsClient(); addStsProperties(); setClaimsOnStsClient(createClaimsElement()); if (stsClient.getWsdlLocation() != null && stsClient.getWsdlLocation().startsWith(HTTPS)) { if (trustStorePath != null && trustStorePassword != null && keyStorePath != null && keyStorePassword != null) { setupSslOnStsClientHttpConduit(); } } else { LOGGER.debug("STS address is null, unable to create STS Client"); } if (LOGGER.isDebugEnabled()) { logStsClientConfiguration(); } } /** * Helper method to setup STS Client. */ private void setupSslOnStsClientHttpConduit() { LOGGER.debug("Setting up SSL on the STSClient HTTP conduit"); try { Client client = stsClient.getClient(); if (client != null) { configureSslOnClient(client); } else { LOGGER.debug( "CXF STS endpoint client is null. Unable to setup SSL on the STSClient HTTP conduit."); } } catch (BusException e) { LOGGER.error("Unable to create STS client.", e); } catch (EndpointException e) { LOGGER.error("Unable to create STS client endpoint.", e); } } /** * Set the claims on the sts client. */ private void setClaimsOnStsClient(Element claimsElement) { if (claimsElement != null) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(" Setting STS claims to:\n" + this.getFormattedXml(claimsElement)); } stsClient.setClaims(claimsElement); } } /** * Create the claims element with the claims provided in the STS client configuration in the * admin console. */ protected Element createClaimsElement() { Element claimsElement = null; List<String> claims = new ArrayList<String>(); claims.addAll(stsClientConfig.getClaims()); if (contextPolicyManager != null) { Collection<ContextPolicy> contextPolicies = contextPolicyManager .getAllContextPolicies(); Set<String> attributes = new LinkedHashSet<String>(); if (contextPolicies != null && contextPolicies.size() > 0) { for (ContextPolicy contextPolicy : contextPolicies) { attributes.addAll(contextPolicy.getAllowedAttributeNames()); } } if (attributes.size() > 0) { claims.addAll(attributes); } } if (claims.size() != 0) { W3CDOMStreamWriter writer = null; try { writer = new W3CDOMStreamWriter(); writer.writeStartElement("wst", "Claims", STSUtils.WST_NS_05_12); writer.writeNamespace("wst", STSUtils.WST_NS_05_12); writer.writeNamespace("ic", "http://schemas.xmlsoap.org/ws/2005/05/identity"); writer.writeAttribute("Dialect", "http://schemas.xmlsoap.org/ws/2005/05/identity"); for (String claim : claims) { LOGGER.trace("Claim: " + claim); writer.writeStartElement("ic", "ClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity"); writer.writeAttribute("Uri", claim); writer.writeAttribute("Optional", "true"); writer.writeEndElement(); } writer.writeEndElement(); claimsElement = writer.getDocument().getDocumentElement(); } catch (XMLStreamException e) { String msg = "Unable to create claims."; LOGGER.error(msg, e); claimsElement = null; } finally { if (writer != null) { try { writer.close(); } catch (XMLStreamException ignore) { //ignore } } } if (LOGGER.isDebugEnabled()) { if (claimsElement != null) { LOGGER.debug("\nClaims:\n" + getFormattedXml(claimsElement)); } } } else { LOGGER.debug("There are no claims to process."); claimsElement = null; } return claimsElement; } /** * Transform into formatted XML. */ private String getFormattedXml(Node node) { Document document = node.getOwnerDocument().getImplementation() .createDocument("", "fake", null); Element copy = (Element) document.importNode(node, true); document.importNode(node, false); document.removeChild(document.getDocumentElement()); document.appendChild(copy); DOMImplementation domImpl = document.getImplementation(); DOMImplementationLS domImplLs = (DOMImplementationLS) domImpl.getFeature("LS", "3.0"); if (null != domImplLs) { LSSerializer serializer = domImplLs.createLSSerializer(); serializer.getDomConfig().setParameter("format-pretty-print", true); return serializer.writeToString(document); } else { return ""; } } /** * Credentials matcher class that ensures the AuthInfo received from the STS matches the * AuthToken */ private static class STSCredentialsMatcher implements CredentialsMatcher { @Override public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { if (token instanceof SAMLAuthenticationToken) { SecurityToken oldToken = (SecurityToken) token.getCredentials(); SecurityToken newToken = (SecurityToken) info.getCredentials(); return oldToken.getId().equals(newToken.getId()); } else if (token instanceof BaseAuthenticationToken) { String xmlCreds = ((BaseAuthenticationToken) token).getCredentialsAsXMLString(); if (xmlCreds != null && info.getCredentials() != null) { return xmlCreds.equals(info.getCredentials()); } } else { if (token.getCredentials() != null && info.getCredentials() != null) { return token.getCredentials().equals(info.getCredentials()); } } return false; } } }