package mujina.idp; import mujina.api.IdpConfiguration; import org.joda.time.DateTime; import org.opensaml.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.IDPSSODescriptor; import org.opensaml.saml2.metadata.KeyDescriptor; import org.opensaml.saml2.metadata.NameIDFormat; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.xml.io.Marshaller; import org.opensaml.xml.io.MarshallingException; import org.opensaml.xml.security.CriteriaSet; import org.opensaml.xml.security.SecurityException; import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.security.credential.UsageType; import org.opensaml.xml.security.criteria.EntityIDCriteria; import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.SignatureConstants; import org.opensaml.xml.signature.SignatureException; import org.opensaml.xml.signature.Signer; import org.opensaml.xml.util.XMLHelper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.security.saml.key.KeyManager; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.w3c.dom.Element; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.util.UUID; import static mujina.saml.SAMLBuilder.buildSAMLObject; @RestController public class MetadataController { @Autowired private KeyManager keyManager; @Autowired private IdpConfiguration idpConfiguration; @Autowired Environment environment; @RequestMapping(method = RequestMethod.GET, value = "/metadata", produces = "application/xml") public String metadata() throws SecurityException, ParserConfigurationException, SignatureException, MarshallingException, TransformerException { EntityDescriptor entityDescriptor = buildSAMLObject(EntityDescriptor.class, EntityDescriptor.DEFAULT_ELEMENT_NAME); entityDescriptor.setEntityID(idpConfiguration.getEntityId()); entityDescriptor.setID(UUID.randomUUID().toString()); entityDescriptor.setValidUntil(new DateTime().plusMillis(86400000)); Signature signature = buildSAMLObject(Signature.class, Signature.DEFAULT_ELEMENT_NAME); Credential credential = keyManager.resolveSingle(new CriteriaSet(new EntityIDCriteria(idpConfiguration.getEntityId()))); signature.setSigningCredential(credential); signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); entityDescriptor.setSignature(signature); Configuration.getMarshallerFactory().getMarshaller(entityDescriptor).marshall(entityDescriptor); Signer.signObject(signature); IDPSSODescriptor idpssoDescriptor = buildSAMLObject(IDPSSODescriptor.class, IDPSSODescriptor.DEFAULT_ELEMENT_NAME); NameIDFormat nameIDFormat = buildSAMLObject(NameIDFormat.class, NameIDFormat.DEFAULT_ELEMENT_NAME); nameIDFormat.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"); idpssoDescriptor.getNameIDFormats().add(nameIDFormat); idpssoDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); String localPort = environment.getProperty("local.server.port"); SingleSignOnService singleSignOnService = buildSAMLObject(SingleSignOnService.class, SingleSignOnService.DEFAULT_ELEMENT_NAME); singleSignOnService.setLocation("http://localhost:" + localPort + "/SingleSignOnService"); singleSignOnService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); idpssoDescriptor.getSingleSignOnServices().add(singleSignOnService); X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); keyInfoGeneratorFactory.setEmitEntityCertificate(true); KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); KeyDescriptor encKeyDescriptor = buildSAMLObject(KeyDescriptor.class, KeyDescriptor.DEFAULT_ELEMENT_NAME); encKeyDescriptor.setUse(UsageType.SIGNING); encKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(credential)); idpssoDescriptor.getKeyDescriptors().add(encKeyDescriptor); entityDescriptor.getRoleDescriptors().add(idpssoDescriptor); return writeEntityDescriptor(entityDescriptor); } private String writeEntityDescriptor(EntityDescriptor entityDescriptor) throws ParserConfigurationException, MarshallingException, TransformerException { Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(entityDescriptor); Element element = marshaller.marshall(entityDescriptor); return XMLHelper.nodeToString(element); } }