/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ package at.gv.egovernment.moa.id.protocols.pvp2x; import java.io.StringWriter; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.joda.time.DateTime; import org.opensaml.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml2.metadata.AttributeConsumingService; import org.opensaml.saml2.metadata.ContactPerson; import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.IDPSSODescriptor; import org.opensaml.saml2.metadata.KeyDescriptor; import org.opensaml.saml2.metadata.LocalizedString; import org.opensaml.saml2.metadata.NameIDFormat; import org.opensaml.saml2.metadata.RoleDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.ServiceName; import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.xml.io.Marshaller; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.SecurityHelper; import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.Signer; import org.w3c.dom.Document; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationInterface; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IRequest; import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; public class MetadataAction implements IAction { private static final int VALIDUNTIL_IN_HOURS = 24; public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { try { MOAReversionLogger.getInstance().logEvent(req, MOAIDEventConstants.AUTHPROTOCOL_PVP_METADATA); EntitiesDescriptor idpEntitiesDescriptor = SAML2Utils.createSAMLObject(EntitiesDescriptor.class); idpEntitiesDescriptor.setName(PVPConfiguration.getInstance().getIDPIssuerName()); idpEntitiesDescriptor.setID(SAML2Utils.getSecureIdentifier()); DateTime date = new DateTime(); idpEntitiesDescriptor.setValidUntil(date.plusHours(VALIDUNTIL_IN_HOURS)); EntityDescriptor idpEntityDescriptor = SAML2Utils .createSAMLObject(EntityDescriptor.class); idpEntitiesDescriptor.getEntityDescriptors().add(idpEntityDescriptor); //TODO: maybe change EntityID to Metadata URL //idpEntityDescriptor // .setEntityID(PVPConfiguration.getInstance().getIDPSSOMetadataService()); idpEntityDescriptor .setEntityID(req.getAuthURLWithOutSlash()); idpEntityDescriptor.setValidUntil(date.plusDays(VALIDUNTIL_IN_HOURS)); List persons = PVPConfiguration.getInstance() .getIDPContacts(); idpEntityDescriptor.getContactPersons().addAll(persons); idpEntityDescriptor.setOrganization(PVPConfiguration.getInstance() .getIDPOrganisation()); X509KeyInfoGeneratorFactory keyInfoFactory = new X509KeyInfoGeneratorFactory(); //keyInfoFactory.setEmitPublicKeyValue(true); keyInfoFactory.setEmitEntityIDAsKeyName(true); keyInfoFactory.setEmitEntityCertificate(true); KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); Credential metadataSigningCredential = CredentialProvider.getIDPMetaDataSigningCredential(); Signature signature = CredentialProvider .getIDPSignature(metadataSigningCredential); //set KeyInfo Element SecurityHelper.prepareSignatureParams(signature, metadataSigningCredential, null, null); idpEntitiesDescriptor.setSignature(signature); //set IDP metadata idpEntityDescriptor.getRoleDescriptors().add(generateIDPMetadata(req, keyInfoGenerator)); //set SP metadata for interfederation idpEntityDescriptor.getRoleDescriptors().add(generateSPMetadata(req, keyInfoGenerator)); DocumentBuilder builder; DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); Marshaller out = Configuration.getMarshallerFactory() .getMarshaller(idpEntitiesDescriptor); out.marshall(idpEntitiesDescriptor, document); Signer.signObject(signature); Transformer transformer = TransformerFactory.newInstance() .newTransformer(); StringWriter sw = new StringWriter(); StreamResult sr = new StreamResult(sw); DOMSource source = new DOMSource(document); transformer.transform(source, sr); sw.close(); String metadataXML = sw.toString(); Logger.debug("METADATA: " + metadataXML); httpResp.setContentType("text/xml"); httpResp.getOutputStream().write(metadataXML.getBytes("UTF-8")); httpResp.getOutputStream().close(); return null; } catch (Exception e) { Logger.error("Failed to generate metadata", e); throw new MOAIDException("pvp2.13", null); } } public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { return false; } public String getDefaultActionName() { return (PVP2XProtocol.METADATA); } private RoleDescriptor generateSPMetadata(IRequest req, KeyInfoGenerator keyInfoGenerator) throws CredentialsNotAvailableException, SecurityException, ConfigurationException { Logger.debug("Set SP Metadata key information"); SPSSODescriptor spSSODescriptor = SAML2Utils .createSAMLObject(SPSSODescriptor.class); spSSODescriptor.setAuthnRequestsSigned(true); spSSODescriptor.setWantAssertionsSigned(false); //Set AuthRequest Signing certificate X509Credential authcredential = CredentialProvider.getIDPAssertionSigningCredential(); KeyDescriptor signKeyDescriptor = SAML2Utils .createSAMLObject(KeyDescriptor.class); signKeyDescriptor.setUse(UsageType.SIGNING); signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authcredential)); spSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); //set AuthRequest encryption certificate X509Credential authEncCredential = CredentialProvider.getIDPAssertionEncryptionCredential(); if (authEncCredential != null) { KeyDescriptor encryKeyDescriptor = SAML2Utils .createSAMLObject(KeyDescriptor.class); encryKeyDescriptor.setUse(UsageType.ENCRYPTION); encryKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(authEncCredential)); spSSODescriptor.getKeyDescriptors().add(encryKeyDescriptor); } else { Logger.warn("No Assertion Encryption-Key defined. This setting is not recommended!"); } NameIDFormat persistentnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); persistentnameIDFormat.setFormat(NameIDType.PERSISTENT); spSSODescriptor.getNameIDFormats().add(persistentnameIDFormat); NameIDFormat transientnameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); transientnameIDFormat.setFormat(NameIDType.TRANSIENT); spSSODescriptor.getNameIDFormats().add(transientnameIDFormat); NameIDFormat unspecifiednameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); unspecifiednameIDFormat.setFormat(NameIDType.UNSPECIFIED); spSSODescriptor.getNameIDFormats().add(unspecifiednameIDFormat); //add assertion consumer services AssertionConsumerService postassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); postassertionConsumerService.setIndex(0); postassertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); postassertionConsumerService.setLocation(PVPConfiguration .getInstance().getSPSSOPostService(req.getAuthURL())); postassertionConsumerService.setIsDefault(true); spSSODescriptor.getAssertionConsumerServices().add(postassertionConsumerService); AssertionConsumerService redirectassertionConsumerService = SAML2Utils.createSAMLObject(AssertionConsumerService.class); redirectassertionConsumerService.setIndex(1); redirectassertionConsumerService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); redirectassertionConsumerService.setLocation(PVPConfiguration .getInstance().getSPSSORedirectService(req.getAuthURL())); spSSODescriptor.getAssertionConsumerServices().add(redirectassertionConsumerService); //add SLO descriptor // SingleLogoutService postSLOService = // SAML2Utils.createSAMLObject(SingleLogoutService.class); // postSLOService.setLocation(PVPConfiguration // .getInstance().getIDPSSOPostService()); // postSLOService // .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); // spSSODescriptor.getSingleLogoutServices().add(postSLOService); SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); redirectSLOService.setLocation(PVPConfiguration .getInstance().getSPSSORedirectService(req.getAuthURL())); redirectSLOService .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); spSSODescriptor.getSingleLogoutServices().add(redirectSLOService); spSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); AttributeConsumingService attributeService = SAML2Utils.createSAMLObject(AttributeConsumingService.class); attributeService.setIndex(0); attributeService.setIsDefault(true); ServiceName serviceName = SAML2Utils.createSAMLObject(ServiceName.class); serviceName.setName(new LocalizedString("Default Service", "de")); attributeService.getNames().add(serviceName); return spSSODescriptor; } private IDPSSODescriptor generateIDPMetadata(IRequest req, KeyInfoGenerator keyInfoGenerator) throws ConfigurationException, CredentialsNotAvailableException, SecurityException { // //set SignatureMethode // signature.setSignatureAlgorithm(PVPConstants.DEFAULT_SIGNING_METHODE); // // //set DigestMethode // List contentList = signature.getContentReferences(); // for (ContentReference content : contentList) { // // if (content instanceof SAMLObjectContentReference) { // // SAMLObjectContentReference el = (SAMLObjectContentReference) content; // el.setDigestAlgorithm(PVPConstants.DEFAULT_DIGESTMETHODE); // // } // } // KeyInfoBuilder metadataKeyInfoBuilder = new KeyInfoBuilder(); // KeyInfo metadataKeyInfo = metadataKeyInfoBuilder.buildObject(); // //KeyInfoHelper.addCertificate(metadataKeyInfo, metadataSigningCredential.); // signature.setKeyInfo(metadataKeyInfo ); IDPSSODescriptor idpSSODescriptor = SAML2Utils .createSAMLObject(IDPSSODescriptor.class); idpSSODescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); idpSSODescriptor.setWantAuthnRequestsSigned(true); if (PVPConfiguration.getInstance().getIDPSSOPostService(req.getAuthURL()) != null) { //add SSO descriptor SingleSignOnService postSingleSignOnService = SAML2Utils .createSAMLObject(SingleSignOnService.class); postSingleSignOnService.setLocation(PVPConfiguration .getInstance().getIDPSSOPostService(req.getAuthURL())); postSingleSignOnService .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); idpSSODescriptor.getSingleSignOnServices().add( postSingleSignOnService); //add SLO descriptor // SingleLogoutService postSLOService = // SAML2Utils.createSAMLObject(SingleLogoutService.class); // postSLOService.setLocation(PVPConfiguration // .getInstance().getIDPSSOPostService()); // postSLOService // .setBinding(SAMLConstants.SAML2_POST_BINDING_URI); // idpSSODescriptor.getSingleLogoutServices().add(postSLOService); } if (PVPConfiguration.getInstance().getIDPSSORedirectService(req.getAuthURL()) != null) { //add SSO descriptor SingleSignOnService redirectSingleSignOnService = SAML2Utils .createSAMLObject(SingleSignOnService.class); redirectSingleSignOnService.setLocation(PVPConfiguration .getInstance().getIDPSSORedirectService(req.getAuthURL())); redirectSingleSignOnService .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); idpSSODescriptor.getSingleSignOnServices().add( redirectSingleSignOnService); //add SLO descriptor SingleLogoutService redirectSLOService = SAML2Utils.createSAMLObject(SingleLogoutService.class); redirectSLOService.setLocation(PVPConfiguration .getInstance().getIDPSSORedirectService(req.getAuthURL())); redirectSLOService .setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); idpSSODescriptor.getSingleLogoutServices().add(redirectSLOService); } /*if (PVPConfiguration.getInstance().getIDPResolveSOAPService() != null) { ArtifactResolutionService artifactResolutionService = SAML2Utils .createSAMLObject(ArtifactResolutionService.class); artifactResolutionService .setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); artifactResolutionService.setLocation(PVPConfiguration .getInstance().getIDPResolveSOAPService()); artifactResolutionService.setIndex(0); idpSSODescriptor.getArtifactResolutionServices().add( artifactResolutionService); }*/ //set assertion signing key Credential assertionSigingCredential = CredentialProvider .getIDPAssertionSigningCredential(); KeyDescriptor signKeyDescriptor = SAML2Utils .createSAMLObject(KeyDescriptor.class); signKeyDescriptor.setUse(UsageType.SIGNING); signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(assertionSigingCredential)); idpSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); idpSSODescriptor.getAttributes().addAll(PVPAttributeBuilder.buildSupportedEmptyAttributes()); NameIDFormat persistenNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); persistenNameIDFormat.setFormat(NameIDType.PERSISTENT); idpSSODescriptor.getNameIDFormats().add(persistenNameIDFormat); NameIDFormat transientNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); transientNameIDFormat.setFormat(NameIDType.TRANSIENT); idpSSODescriptor.getNameIDFormats().add(transientNameIDFormat); NameIDFormat unspecifiedNameIDFormat = SAML2Utils.createSAMLObject(NameIDFormat.class); unspecifiedNameIDFormat.setFormat(NameIDType.UNSPECIFIED); idpSSODescriptor.getNameIDFormats().add(unspecifiedNameIDFormat); return idpSSODescriptor; } }