package org.jboss.seam.security.external.saml; import java.io.Reader; import java.io.Writer; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.servlet.ServletContext; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import org.jboss.seam.security.external.EntityBean; import org.jboss.seam.security.external.JaxbContext; import org.jboss.seam.security.external.jaxb.samlv2.metadata.EntitiesDescriptorType; import org.jboss.seam.security.external.jaxb.samlv2.metadata.EntityDescriptorType; import org.jboss.seam.security.external.jaxb.samlv2.metadata.IndexedEndpointType; import org.jboss.seam.security.external.jaxb.samlv2.metadata.KeyDescriptorType; import org.jboss.seam.security.external.jaxb.samlv2.metadata.KeyTypes; import org.jboss.seam.security.external.jaxb.samlv2.metadata.ObjectFactory; import org.jboss.seam.security.external.jaxb.samlv2.metadata.RoleDescriptorType; import org.jboss.seam.security.external.jaxb.samlv2.metadata.SSODescriptorType; import org.jboss.seam.security.external.jaxb.xmldsig.KeyInfoType; import org.jboss.seam.security.external.jaxb.xmldsig.X509DataType; import org.jboss.seam.security.external.saml.api.SamlBinding; import org.jboss.seam.security.external.saml.api.SamlEntityConfigurationApi; /** * @author Marcel Kolsteren */ public abstract class SamlEntityBean extends EntityBean implements SamlEntityConfigurationApi { private Map<String, SSODescriptorType> metaInfo = new HashMap<String, SSODescriptorType>(); private String entityId; private SamlSigningKey samlSigningKey; private SamlBinding preferredBinding = SamlBinding.HTTP_Post; @Inject private ServletContext servletContext; @Inject @JaxbContext(ObjectFactory.class) protected JAXBContext metaDataJaxbContext; private boolean singleLogoutMessagesSigned = true; private boolean wantSingleLogoutMessagesSigned = true; public String getServiceURL(SamlServiceType service) { return createURL(servletContext.getContextPath() + "/saml/" + getIdpOrSp() + "/" + service.getName()); } public String getMetaDataURL() { return getServiceURL(SamlServiceType.SAML_META_DATA_SERVICE); } public void setEntityId(String entityId) { this.entityId = entityId; } public String getEntityId() { return entityId; } protected SamlSigningKey getSigningKey() { return samlSigningKey; } public void setSigningKey(String keyStoreUrl, String keyStorePass, String signingKeyAlias, String signingKeyPass) { if (signingKeyPass == null) { signingKeyPass = keyStorePass; } samlSigningKey = new SamlSigningKey(keyStoreUrl, keyStorePass, signingKeyAlias, signingKeyPass); } public boolean isSingleLogoutMessagesSigned() { return singleLogoutMessagesSigned; } public void setSingleLogoutMessagesSigned(boolean singleLogoutMessagesSigned) { this.singleLogoutMessagesSigned = singleLogoutMessagesSigned; } public boolean isWantSingleLogoutMessagesSigned() { return wantSingleLogoutMessagesSigned; } public void setWantSingleLogoutMessagesSigned(boolean wantSingleLogoutMessagesSigned) { this.wantSingleLogoutMessagesSigned = wantSingleLogoutMessagesSigned; } public abstract SamlIdpOrSp getIdpOrSp(); public abstract SamlExternalEntity getExternalSamlEntityByEntityId(String entityId); public abstract SamlExternalEntity addExternalSamlEntity(Reader reader); public abstract List<SamlExternalEntity> getExternalSamlEntities(); protected void readEntitiesDescriptor(Reader reader) { try { Unmarshaller unmarshaller = metaDataJaxbContext.createUnmarshaller(); JAXBElement<?> o = (JAXBElement<?>) unmarshaller.unmarshal(reader); EntitiesDescriptorType entitiesDescriptor = (EntitiesDescriptorType) o.getValue(); readEntitiesDescriptor(entitiesDescriptor); } catch (JAXBException e) { throw new RuntimeException(e); } } private void readEntitiesDescriptor(EntitiesDescriptorType entitiesDescriptor) { for (Object object : entitiesDescriptor.getEntityDescriptorOrEntitiesDescriptor()) { if (object instanceof EntityDescriptorType) { EntityDescriptorType entityDescriptor = (EntityDescriptorType) object; readEntityDescriptor(entityDescriptor); } else { EntitiesDescriptorType descriptor = (EntitiesDescriptorType) object; readEntitiesDescriptor(descriptor); } } } private void readEntityDescriptor(EntityDescriptorType entityDescriptor) { String entityId = entityDescriptor.getEntityID(); for (RoleDescriptorType roleDescriptor : entityDescriptor.getRoleDescriptorOrIDPSSODescriptorOrSPSSODescriptor()) { metaInfo.put(entityId, (SSODescriptorType) roleDescriptor); } } public Map<String, SSODescriptorType> getMetaInfo() { return metaInfo; } protected EntityDescriptorType readEntityDescriptor(Reader metaInfoReader) { try { Unmarshaller unmarshaller = metaDataJaxbContext.createUnmarshaller(); JAXBElement<?> o = (JAXBElement<?>) unmarshaller.unmarshal(metaInfoReader); EntityDescriptorType entityDescriptor = (EntityDescriptorType) o.getValue(); return entityDescriptor; } catch (JAXBException e) { throw new RuntimeException(e); } } public abstract void writeMetaData(Writer writer); protected void addKeyDescriptorToMetaData(SSODescriptorType ssoDescriptor) { ObjectFactory metaDataFactory = new ObjectFactory(); org.jboss.seam.security.external.jaxb.xmldsig.ObjectFactory signatureFactory = new org.jboss.seam.security.external.jaxb.xmldsig.ObjectFactory(); X509Certificate certificate = getSigningKey().getCertificate(); if (certificate == null) throw new RuntimeException("Certificate obtained from configuration is null"); JAXBElement<byte[]> X509Certificate; try { X509Certificate = signatureFactory.createX509DataTypeX509Certificate(certificate.getEncoded()); } catch (CertificateEncodingException e) { throw new RuntimeException(e); } X509DataType X509Data = signatureFactory.createX509DataType(); X509Data.getX509IssuerSerialOrX509SKIOrX509SubjectName().add(X509Certificate); KeyInfoType keyInfo = signatureFactory.createKeyInfoType(); keyInfo.getContent().add(signatureFactory.createX509Data(X509Data)); KeyDescriptorType keyDescriptor = metaDataFactory.createKeyDescriptorType(); keyDescriptor.setUse(KeyTypes.SIGNING); keyDescriptor.setKeyInfo(keyInfo); ssoDescriptor.getKeyDescriptor().add(keyDescriptor); } protected void addSloEndpointsToMetaData(SSODescriptorType ssoDescriptor) { ObjectFactory metaDataFactory = new ObjectFactory(); IndexedEndpointType sloRedirectEndpoint = metaDataFactory.createIndexedEndpointType(); sloRedirectEndpoint.setBinding(SamlConstants.HTTP_REDIRECT_BINDING); sloRedirectEndpoint.setLocation(getServiceURL(SamlServiceType.SAML_SINGLE_LOGOUT_SERVICE)); IndexedEndpointType sloPostEndpoint = metaDataFactory.createIndexedEndpointType(); sloPostEndpoint.setBinding(SamlConstants.HTTP_POST_BINDING); sloPostEndpoint.setLocation(getServiceURL(SamlServiceType.SAML_SINGLE_LOGOUT_SERVICE)); ssoDescriptor.getSingleLogoutService().add(sloRedirectEndpoint); ssoDescriptor.getSingleLogoutService().add(sloPostEndpoint); } protected void addNameIDFormatsToMetaData(SSODescriptorType idpSsoDescriptor) { idpSsoDescriptor.getNameIDFormat().add("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"); idpSsoDescriptor.getNameIDFormat().add("urn:oasis:names:tc:SAML:2.0:nameid-format:transient"); idpSsoDescriptor.getNameIDFormat().add("urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified"); idpSsoDescriptor.getNameIDFormat().add("urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress"); } public SamlBinding getPreferredBinding() { return preferredBinding; } public void setPreferredBinding(SamlBinding preferredBinding) { this.preferredBinding = preferredBinding; } }