diff options
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java')
-rw-r--r-- | eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java new file mode 100644 index 00000000..1c7a9652 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java @@ -0,0 +1,247 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 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: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * 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.egiz.eaaf.modules.pvp2.impl.utils; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.validation.Schema; +import javax.xml.validation.Validator; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.Status; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.ws.soap.soap11.Body; +import org.opensaml.ws.soap.soap11.Envelope; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.schema.impl.XSStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +public class Saml2Utils { + private static final Logger log = LoggerFactory.getLogger(Saml2Utils.class); + + private static SecureRandomIdentifierGenerator idGenerator; + + private static DocumentBuilder builder; + + static { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + + try { + builder = factory.newDocumentBuilder(); + + } catch (final ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + idGenerator = new SecureRandomIdentifierGenerator(); + + } catch (final NoSuchAlgorithmException e) { + e.printStackTrace(); + + } + } + + /** + * Create a SAML2 object. + * + * @param <T> SAML2 object class + * @param clazz object class + * @return SAML2 object + */ + public static <T> T createSamlObject(final Class<T> clazz) { + try { + final XMLObjectBuilderFactory builderFactory = + org.opensaml.xml.Configuration.getBuilderFactory(); + + final QName defaultElementName = + (QName) clazz.getDeclaredField("DEFAULT_ELEMENT_NAME").get(null); + @SuppressWarnings("unchecked") + final T object = + (T) builderFactory.getBuilder(defaultElementName).buildObject(defaultElementName); + return object; + } catch (final Throwable e) { + e.printStackTrace(); + return null; + } + } + + /** + * Get a new SAML2 conform random value. + * + * @return + */ + public static String getSecureIdentifier() { + return "_".concat(Random.nextHexRandom16()); + + } + + + /** + * Transform SAML2 Object to Element. + * + * @param object SAML2 object + * @return Element + * @throws IOException In case of an transformation error + * @throws MarshallingException In case of an transformation error + * @throws TransformerException In case of an transformation error + */ + public static Document asDomDocument(final XMLObject object) + throws IOException, MarshallingException, TransformerException { + final Document document = builder.newDocument(); + final Marshaller out = + org.opensaml.xml.Configuration.getMarshallerFactory().getMarshaller(object); + out.marshall(object, document); + return document; + } + + /** + * Build success status element. + * + * @return + */ + public static Status getSuccessStatus() { + final Status status = Saml2Utils.createSamlObject(Status.class); + final StatusCode statusCode = Saml2Utils.createSamlObject(StatusCode.class); + statusCode.setValue(StatusCode.SUCCESS_URI); + status.setStatusCode(statusCode); + return status; + } + + /** + * Get AssertionConsumerService Index from metadata element. + * + * @param spSsoDescriptor metadata element + * @return + */ + public static int getDefaultAssertionConsumerServiceIndex(final SPSSODescriptor spSsoDescriptor) { + + final List<AssertionConsumerService> assertionConsumerList = + spSsoDescriptor.getAssertionConsumerServices(); + + for (final AssertionConsumerService el : assertionConsumerList) { + if (el.isDefault()) { + return el.getIndex(); + } + + } + + return 0; + } + + /** + * Build SOAP11 body from SAML2 object. + * + * @param payload SAML2 object + * @return + */ + public static Envelope buildSoap11Envelope(final XMLObject payload) { + final XMLObjectBuilderFactory bf = org.opensaml.xml.Configuration.getBuilderFactory(); + final Envelope envelope = (Envelope) bf.getBuilder(Envelope.DEFAULT_ELEMENT_NAME) + .buildObject(Envelope.DEFAULT_ELEMENT_NAME); + final Body body = + (Body) bf.getBuilder(Body.DEFAULT_ELEMENT_NAME).buildObject(Body.DEFAULT_ELEMENT_NAME); + + body.getUnknownXMLObjects().add(payload); + envelope.setBody(body); + + return envelope; + } + + /** + * Generate EAAF specific requested attribute. + * + * @param attr SAML2 attribute definition + * @param isRequired is-mandatory flag + * @param value Attribute value + * @return + */ + public static EaafRequestedAttribute generateReqAuthnAttributeSimple(final Attribute attr, + final boolean isRequired, final String value) { + final EaafRequestedAttribute requested = + Saml2Utils.createSamlObject(EaafRequestedAttribute.class); + requested.setName(attr.getName()); + requested.setNameFormat(attr.getNameFormat()); + requested.setFriendlyName(attr.getFriendlyName()); + requested.setIsRequired(String.valueOf(isRequired)); + final List<XMLObject> attributeValues = requested.getAttributeValues(); + if (StringUtils.isNotEmpty(value)) { + final XMLObject attributeValueForRequest = + createAttributeValue(PvpConstants.EIDAS_REQUESTED_ATTRIBUTE_VALUE_TYPE, value); + attributeValues.add(attributeValueForRequest); + } + return requested; + + } + + /** + * Perform XML schema-validation on SAML2 object. + * + * @param xmlObject SAML2 object + * @throws Exception In case of a validation error + */ + public static void schemeValidation(final XMLObject xmlObject) throws Exception { + try { + final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Validator val = test.newValidator(); + final DOMSource source = new DOMSource(xmlObject.getDOM()); + val.validate(source); + log.debug("SAML2 Scheme validation successful"); + return; + + } catch (final Exception e) { + log.warn("SAML2 scheme validation FAILED.", e); + throw e; + + } + } + + private static XMLObject createAttributeValue(final QName attributeValueType, + final String value) { + final XSStringBuilder stringBuilder = (XSStringBuilder) org.opensaml.xml.Configuration + .getBuilderFactory().getBuilder(XSString.TYPE_NAME); + final XSString stringValue = stringBuilder.buildObject(attributeValueType, XSString.TYPE_NAME); + stringValue.setValue(value); + return stringValue; + + } +} |