From 545bda2ed80c3ca45e2be1723a514b21c780a05a Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Tue, 28 May 2013 16:37:44 +0200 Subject: Metadata generation for IDP --- .../moa/id/entrypoints/DispatcherServlet.java | 1 + .../moa/id/protocols/pvp2x/MetadataAction.java | 184 +++++++++++++++++++++ .../moa/id/protocols/pvp2x/PVP2XProtocol.java | 10 ++ .../protocols/pvp2x/config/PVPConfiguration.java | 183 +++++++++++++++++++- 4 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java index 585655e7c..c993290e9 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java @@ -256,6 +256,7 @@ public class DispatcherServlet extends AuthServlet { AuthenticationManager.logout(req, resp); } catch (Throwable e) { + e.printStackTrace(); // Try handle module specific, if not possible rethrow if (!info.generateErrorMessage(e, req, resp, protocolRequest)) { throw e; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java new file mode 100644 index 000000000..75fc6197f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/MetadataAction.java @@ -0,0 +1,184 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x; + +import java.io.IOException; +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.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.opensaml.Configuration; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.metadata.ArtifactResolutionService; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory.BasicKeyInfoGenerator; +import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory; +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.signature.Signature; +import org.opensaml.xml.signature.SignatureException; +import org.opensaml.xml.signature.Signer; +import org.w3c.dom.Document; + +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IRequest; +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; + +public class MetadataAction implements IAction { + + public void processRequest(IRequest req, HttpServletRequest httpReq, + HttpServletResponse httpResp) throws MOAIDException { + try { + + EntityDescriptor idpEntityDescriptor = SAML2Utils + .createSAMLObject(EntityDescriptor.class); + + idpEntityDescriptor.setEntityID("https://localhost:8443/moa-id-auth"); + + List persons = PVPConfiguration.getInstance().getIDPContacts(); + + idpEntityDescriptor.getContactPersons().addAll(persons); + + idpEntityDescriptor.setOrganization(PVPConfiguration.getInstance().getIDPOrganisation()); + + BasicKeyInfoGeneratorFactory keyInfoFactory = new BasicKeyInfoGeneratorFactory(); + keyInfoFactory.setEmitPublicKeyValue(true); + keyInfoFactory.setEmitEntityIDAsKeyName(true); + KeyInfoGenerator keyInfoGenerator = keyInfoFactory.newInstance(); + + Credential credential = CredentialProvider + .getIDPSigningCredential(); + + KeyDescriptor signKeyDescriptor = SAML2Utils + .createSAMLObject(KeyDescriptor.class); + signKeyDescriptor.setUse(UsageType.SIGNING); + signKeyDescriptor.setKeyInfo(keyInfoGenerator.generate(credential)); + + Signature signature = CredentialProvider + .getIDPSignature(credential); + + idpEntityDescriptor.setSignature(signature); + + IDPSSODescriptor idpSSODescriptor = SAML2Utils.createSAMLObject(IDPSSODescriptor.class); + + idpSSODescriptor.setWantAuthnRequestsSigned(true); + + SingleSignOnService postSingleSignOnService = + SAML2Utils.createSAMLObject(SingleSignOnService.class); + + postSingleSignOnService.setLocation("https://enter.post.url"); + postSingleSignOnService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + + idpSSODescriptor.getSingleSignOnServices().add(postSingleSignOnService); + + SingleSignOnService redirectSingleSignOnService = + SAML2Utils.createSAMLObject(SingleSignOnService.class); + + redirectSingleSignOnService.setLocation("https://enter.redirect.url"); + redirectSingleSignOnService.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + + ArtifactResolutionService artifactResolutionService = SAML2Utils.createSAMLObject( + ArtifactResolutionService.class); + + artifactResolutionService.setBinding(SAMLConstants.SAML2_SOAP11_BINDING_URI); + artifactResolutionService.setLocation("https://enter.soap.url"); + + idpSSODescriptor.getArtifactResolutionServices().add(artifactResolutionService); + + idpSSODescriptor.getSingleSignOnServices().add(redirectSingleSignOnService); + + idpSSODescriptor.getKeyDescriptors().add(signKeyDescriptor); + + idpEntityDescriptor.getRoleDescriptors().add(idpSSODescriptor); + + DocumentBuilder builder; + DocumentBuilderFactory factory = DocumentBuilderFactory + .newInstance(); + + builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + Marshaller out = Configuration.getMarshallerFactory() + .getMarshaller(idpEntityDescriptor); + out.marshall(idpEntityDescriptor, 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(); + + System.out.println("METADATA: " + metadataXML); + + httpResp.setContentType("text/xml"); + httpResp.getOutputStream().write(metadataXML.getBytes()); + + httpResp.getOutputStream().close(); + + } catch (CredentialsNotAvailableException e) { + e.printStackTrace(); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (MarshallingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (SignatureException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerFactoryConfigurationError e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, + HttpServletResponse httpResp) { + return false; + } + + public String getDefaultActionName() { + return (PVP2XProtocol.METADATA); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java index 673b65243..4633f22d2 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java @@ -48,6 +48,7 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { public static final String REDIRECT = "Redirect"; public static final String POST = "Post"; public static final String SOAP = "Soap"; + public static final String METADATA = "Metadata"; private static List servletList = new ArrayList(); @@ -70,6 +71,7 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { actions.put(REDIRECT, new AuthenticationAction()); actions.put(POST, new AuthenticationAction()); + actions.put(METADATA, new MetadataAction()); instance = new PVP2XProtocol(); } @@ -118,6 +120,10 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { public IRequest preProcess(HttpServletRequest request, HttpServletResponse response, String action) throws MOAIDException { + if(METADATA.equals(action)) { + return new PVPTargetConfiguration(); + } + IDecoder decoder = findDecoder(action); if (decoder == null) { return null; @@ -213,6 +219,10 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { if(request.getParameter("SAMLRequest") != null) { return getAction(REDIRECT); } + + if(METADATA.equals(request.getParameter("action"))) { + return getAction(METADATA); + } return null; } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java index 5ec852d46..79126416f 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/config/PVPConfiguration.java @@ -2,9 +2,40 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.config; import java.io.File; import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Properties; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.opensaml.saml2.common.Extensions; +import org.opensaml.saml2.metadata.Company; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; +import org.opensaml.saml2.metadata.EmailAddress; +import org.opensaml.saml2.metadata.GivenName; +import org.opensaml.saml2.metadata.LocalizedString; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.OrganizationDisplayName; +import org.opensaml.saml2.metadata.OrganizationName; +import org.opensaml.saml2.metadata.OrganizationURL; +import org.opensaml.saml2.metadata.SurName; +import org.opensaml.saml2.metadata.TelephoneNumber; +import org.opensaml.xml.Namespace; +import org.opensaml.xml.NamespaceManager; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.schema.XSBooleanValue; +import org.opensaml.xml.util.AttributeMap; +import org.opensaml.xml.util.IDIndex; +import org.opensaml.xml.validation.ValidationException; +import org.opensaml.xml.validation.Validator; +import org.w3c.dom.Element; import at.gv.egovernment.moa.id.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; public class PVPConfiguration { @@ -24,13 +55,29 @@ public class PVPConfiguration { public static final String IDP_KEY_PASS = "idp.ks.keypassword"; public static final String METADATA_FILE = "md.file"; + public static final String IDP_ENTITY = "idp.entityid"; + public static final String IDP_ORG_NAME = "idp.org.name"; + public static final String IDP_ORG_DISPNAME = "idp.org.dispname"; + public static final String IDP_ORG_URL = "idp.org.url"; + + public static final String IDP_CONTACT_PREFIX = "idp.contact"; + public static final String IDP_CONTACT_LIST = "idp.contact_list"; + + public static final String IDP_CONTACT_SURNAME = "surname"; + public static final String IDP_CONTACT_GIVENNAME = "givenname"; + public static final String IDP_CONTACT_MAIL = "mail"; + public static final String IDP_CONTACT_TYPE = "type"; + public static final String IDP_CONTACT_COMPANY = "company"; + public static final String IDP_CONTACT_PHONE = "phone"; + + Properties props = new Properties(); private PVPConfiguration() { try { String fileName = System.getProperty(ConfigurationProvider.CONFIG_PROPERTY_NAME); String pathName = (new File(fileName)).getParent(); - String configFile = pathName + File.pathSeparator + PVP_CONFIG_FILE; + String configFile = pathName + "/" + PVP_CONFIG_FILE; Logger.info("PVP Config file " + configFile); FileInputStream is = new FileInputStream(configFile); @@ -60,4 +107,138 @@ public class PVPConfiguration { public String getMetadataFile() { return props.getProperty(METADATA_FILE); } + + public List getIDPContacts() { + List list = new ArrayList(); + + String contactList = props.getProperty(IDP_CONTACT_LIST); + + if(contactList != null) { + + String[] contact_keys = contactList.split(","); + + for(int i = 0; i < contact_keys.length; i++) { + + String key = contact_keys[i]; + + ContactPerson person = SAML2Utils.createSAMLObject(ContactPerson.class); + + String type = props.getProperty(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_TYPE); + + if(type == null) { + Logger.error("IDP Contact with key " + key + " has no type defined!"); + break; + } + + ContactPersonTypeEnumeration enumType = null; + + if(type.equals(ContactPersonTypeEnumeration.ADMINISTRATIVE.toString())) { + enumType = ContactPersonTypeEnumeration.ADMINISTRATIVE; + } else if(type.equals(ContactPersonTypeEnumeration.BILLING.toString())){ + enumType = ContactPersonTypeEnumeration.BILLING; + } else if(type.equals(ContactPersonTypeEnumeration.OTHER.toString())){ + enumType = ContactPersonTypeEnumeration.OTHER; + }else if(type.equals(ContactPersonTypeEnumeration.SUPPORT.toString())){ + enumType = ContactPersonTypeEnumeration.SUPPORT; + }else if(type.equals(ContactPersonTypeEnumeration.TECHNICAL.toString())){ + enumType = ContactPersonTypeEnumeration.TECHNICAL; + } + + if(enumType == null) { + Logger.error("IDP Contact with key " + key + " has invalid type defined: " + + type); + break; + } + + person.setType(enumType); + + String givenName = props.getProperty(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_GIVENNAME); + + if(givenName != null) { + GivenName name = SAML2Utils.createSAMLObject(GivenName.class); + name.setName(givenName); + person.setGivenName(name); + } + + String company = props.getProperty(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_COMPANY); + + if(company != null) { + Company comp = SAML2Utils.createSAMLObject(Company.class); + comp.setName(company); + person.setCompany(comp); + } + + String surname = props.getProperty(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_SURNAME); + + if(surname != null) { + SurName name = SAML2Utils.createSAMLObject(SurName.class); + name.setName(surname); + person.setSurName(name); + } + + Set keySet = props.keySet(); + Iterator keyIt = keySet.iterator(); + + while(keyIt.hasNext()) { + + String currentKey = keyIt.next().toString(); + + if(currentKey.startsWith(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_PHONE)) { + String phone = props.getProperty(currentKey); + + if(phone != null) { + TelephoneNumber telePhone = SAML2Utils.createSAMLObject(TelephoneNumber.class); + telePhone.setNumber(phone); + person.getTelephoneNumbers().add(telePhone); + } + } else if(currentKey.startsWith(IDP_CONTACT_PREFIX + + "." + key + "." + IDP_CONTACT_MAIL)) { + String mail = props.getProperty(currentKey); + + if(mail != null) { + EmailAddress mailAddress = SAML2Utils.createSAMLObject(EmailAddress.class); + mailAddress.setAddress(mail); + person.getEmailAddresses().add(mailAddress); + } + } + } + list.add(person); + } + } + return list; + } + + public Organization getIDPOrganisation() { + Organization org = SAML2Utils.createSAMLObject(Organization.class); + + String org_name = props.getProperty(IDP_ORG_NAME); + String org_dispname = props.getProperty(IDP_ORG_DISPNAME); + String org_url = props.getProperty(IDP_ORG_URL); + + if(org_name == null || org_dispname == null || org_url == null) { + return null; + } + + OrganizationDisplayName dispName = SAML2Utils.createSAMLObject( + OrganizationDisplayName.class); + dispName.setName(new LocalizedString(org_dispname, "de")); + org.getDisplayNames().add(dispName); + + OrganizationName name = SAML2Utils.createSAMLObject( + OrganizationName.class); + name.setName(new LocalizedString(org_name, "de")); + org.getOrganizationNames().add(name); + + OrganizationURL url = SAML2Utils.createSAMLObject( + OrganizationURL.class); + url.setURL(new LocalizedString(org_url, "de")); + org.getURLs().add(url); + + return org; + } } -- cgit v1.2.3