/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.identity.federation.bindings.servlets;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.cert.Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBElement;
import org.apache.log4j.Logger;
import org.jboss.identity.federation.api.saml.v2.metadata.KeyDescriptorMetaDataBuilder;
import org.jboss.identity.federation.api.saml.v2.metadata.MetaDataBuilder;
import org.jboss.identity.federation.api.util.KeyUtil;
import org.jboss.identity.federation.bindings.providers.IMetadataProvider;
import org.jboss.identity.federation.core.config.KeyProviderType;
import org.jboss.identity.federation.core.config.KeyValueType;
import org.jboss.identity.federation.core.config.MetadataProviderType;
import org.jboss.identity.federation.core.config.ProviderType;
import org.jboss.identity.federation.core.interfaces.TrustKeyManager;
import org.jboss.identity.federation.core.saml.v2.constants.JBossSAMLConstants;
import org.jboss.identity.federation.core.util.XMLEncryptionUtil;
import org.jboss.identity.federation.saml.v2.metadata.EntityDescriptorType;
import org.jboss.identity.federation.saml.v2.metadata.KeyDescriptorType;
import org.jboss.identity.federation.saml.v2.metadata.RoleDescriptorType;
import org.jboss.identity.federation.web.util.ConfigurationUtil;
import org.jboss.identity.xmlsec.w3.xmldsig.KeyInfoType;
/**
* Metadata servlet for the IDP/SP
* @author Anil.Saldhana@redhat.com
* @since Apr 22, 2009
*/
public class MetadataServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static Logger log = Logger.getLogger(MetadataServlet.class);
private boolean trace = log.isTraceEnabled();
private String configFileLocation = "/WEB-INF/jboss-idfed.xml";
private transient MetadataProviderType metadataProviderType = null;
private transient IMetadataProvider<?> metadataProvider = null;
private transient EntityDescriptorType metadata;
private String signingAlias = null;
private String encryptingAlias = null;
private TrustKeyManager keyManager;
@SuppressWarnings("unchecked")
@Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
try
{
ServletContext context = config.getServletContext();
String configL = config.getInitParameter("configFile");
if(configL != null && configL.length() > 0)
configFileLocation = configL;
if(trace)
log.trace("Config File Location="+ configFileLocation);
InputStream is = context.getResourceAsStream(configFileLocation);
if(is == null)
throw new RuntimeException(configFileLocation + " missing");
//Look for signing alias
signingAlias = config.getInitParameter("signingAlias");
encryptingAlias = config.getInitParameter("encryptingAlias");
ProviderType providerType = ConfigurationUtil.getIDPConfiguration(is);
metadataProviderType = providerType.getMetaDataProvider();
String fqn = metadataProviderType.getClassName();
ClassLoader tcl = SecurityActions.getContextClassLoader();
Class<?> clazz = tcl.loadClass(fqn);
metadataProvider = (IMetadataProvider) clazz.newInstance();
List<KeyValueType> keyValues = metadataProviderType.getOption();
Map<String,String> options = new HashMap<String,String>();
if(keyValues != null)
{
for(KeyValueType kvt: keyValues)
options.put(kvt.getKey(), kvt.getValue());
}
metadataProvider.init(options);
if(metadataProvider.isMultiple())
throw new RuntimeException("Multiple Entities not currently supported");
/**
* Since a metadata provider does not have access to the servlet context.
* It may be difficult to get to the resource from the TCL.
*/
String fileInjectionStr = metadataProvider.requireFileInjection();
if(fileInjectionStr != null && fileInjectionStr.length() > 0)
{
metadataProvider.injectFileStream(context.getResourceAsStream(fileInjectionStr));
}
metadata = (EntityDescriptorType) metadataProvider.getMetaData();
//Get the trust manager information
KeyProviderType keyProvider = providerType.getKeyProvider();
signingAlias = keyProvider.getSigningAlias();
String keyManagerClassName = keyProvider.getClassName();
if(keyManagerClassName == null)
throw new RuntimeException("KeyManager class name is null");
clazz = tcl.loadClass(keyManagerClassName);
this.keyManager = (TrustKeyManager) clazz.newInstance();
keyManager.setAuthProperties(keyProvider.getAuth());
Certificate cert = keyManager.getCertificate(signingAlias);
KeyInfoType keyInfo = KeyUtil.getKeyInfo(cert);
//TODO: Assume just signing key for now
KeyDescriptorType keyDescriptor = KeyDescriptorMetaDataBuilder.createKeyDescriptor(keyInfo,
null, 0, true, false);
updateKeyDescriptor(metadata, keyDescriptor);
//encryption
if(this.encryptingAlias != null)
{
cert = keyManager.getCertificate(encryptingAlias);
keyInfo = KeyUtil.getKeyInfo(cert);
String certAlgo = cert.getPublicKey().getAlgorithm();
keyDescriptor = KeyDescriptorMetaDataBuilder.createKeyDescriptor(keyInfo,
XMLEncryptionUtil.getEncryptionURL(certAlgo),
XMLEncryptionUtil.getEncryptionKeySize(certAlgo), false, true);
updateKeyDescriptor(metadata, keyDescriptor);
}
} catch(Exception e)
{
log.error("Exception in starting servlet:",e);
throw new ServletException("Unable to start servlet");
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType(JBossSAMLConstants.METADATA_MIME.get());
OutputStream os = resp.getOutputStream();
JAXBElement<?> jaxbEl = MetaDataBuilder.getObjectFactory().createEntityDescriptor(metadata);
try
{
MetaDataBuilder.getMarshaller().marshal(jaxbEl , os);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
private void updateKeyDescriptor(EntityDescriptorType entityD, KeyDescriptorType keyD)
{
List<RoleDescriptorType> objs = entityD.getRoleDescriptorOrIDPSSODescriptorOrSPSSODescriptor();
if(objs != null)
{
for(RoleDescriptorType roleD: objs)
{
roleD.getKeyDescriptor().add(keyD);
}
}
}
}