All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opensaml.saml.common.xml.SAMLSchemaBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the University Corporation for Advanced Internet Development,
 * Inc. (UCAID) under one or more contributor license agreements.  See the
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID licenses this file to You under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.opensaml.saml.common.xml;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.xml.validation.Schema;

import net.shibboleth.utilities.java.support.annotation.ParameterName;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.xml.ClasspathResolver;
import net.shibboleth.utilities.java.support.xml.SchemaBuilder;

import org.opensaml.core.xml.XMLRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import com.google.common.io.ByteStreams;

/**
 * A convenience builder for creating {@link Schema}s for validating SAML 1.0, 1.1, and 2.0.
 * 
 * 

Additional schemas may be included in the resulting object by supplying their locations * to an injected {@link SchemaBuilder} object.

*/ @ThreadSafe public class SAMLSchemaBuilder { /** Classpath relative location of basic XML schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] baseXMLSchemas = { SAMLConstants.XML_SCHEMA_LOCATION, SAMLConstants.XSD_SCHEMA_LOCATION, SAMLConstants.XMLSIG_SCHEMA_LOCATION, SAMLConstants.XMLENC_SCHEMA_LOCATION, SAMLConstants.XMLSIG11_SCHEMA_LOCATION, SAMLConstants.XMLENC11_SCHEMA_LOCATION, }; /** Classpath relative location of SOAP 1_1 schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] soapSchemas = { SAMLConstants.SOAP11ENV_SCHEMA_LOCATION, }; /** Classpath relative location of SAML 1_0 schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] saml10Schemas = { SAMLConstants.SAML10_SCHEMA_LOCATION, SAMLConstants.SAML10P_SCHEMA_LOCATION, }; /** Classpath relative location of SAML 1_1 schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] saml11Schemas = { SAMLConstants.SAML11_SCHEMA_LOCATION, SAMLConstants.SAML11P_SCHEMA_LOCATION, }; /** Classpath relative location of SAML 2_0 schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] saml20Schemas = { SAMLConstants.SAML20_SCHEMA_LOCATION, SAMLConstants.SAML20P_SCHEMA_LOCATION, SAMLConstants.SAML20MD_SCHEMA_LOCATION, SAMLConstants.SAML20AC_SCHEMA_LOCATION, "/schema/saml-schema-authn-context-auth-telephony-2.0.xsd", "/schema/saml-schema-authn-context-ip-2.0.xsd", "/schema/saml-schema-authn-context-ippword-2.0.xsd", "/schema/saml-schema-authn-context-kerberos-2.0.xsd", "/schema/saml-schema-authn-context-mobileonefactor-reg-2.0.xsd", "/schema/saml-schema-authn-context-mobileonefactor-unreg-2.0.xsd", "/schema/saml-schema-authn-context-mobiletwofactor-reg-2.0.xsd", "/schema/saml-schema-authn-context-mobiletwofactor-unreg-2.0.xsd", "/schema/saml-schema-authn-context-nomad-telephony-2.0.xsd", "/schema/saml-schema-authn-context-personal-telephony-2.0.xsd", "/schema/saml-schema-authn-context-pgp-2.0.xsd", "/schema/saml-schema-authn-context-ppt-2.0.xsd", "/schema/saml-schema-authn-context-pword-2.0.xsd", "/schema/saml-schema-authn-context-session-2.0.xsd", "/schema/saml-schema-authn-context-smartcard-2.0.xsd", "/schema/saml-schema-authn-context-smartcardpki-2.0.xsd", "/schema/saml-schema-authn-context-softwarepki-2.0.xsd", "/schema/saml-schema-authn-context-spki-2.0.xsd", "/schema/saml-schema-authn-context-srp-2.0.xsd", "/schema/saml-schema-authn-context-sslcert-2.0.xsd", "/schema/saml-schema-authn-context-telephony-2.0.xsd", "/schema/saml-schema-authn-context-timesync-2.0.xsd", "/schema/saml-schema-authn-context-x509-2.0.xsd", "/schema/saml-schema-authn-context-xmldsig-2.0.xsd", SAMLConstants.SAML20DCE_SCHEMA_LOCATION, SAMLConstants.SAML20ECP_SCHEMA_LOCATION, SAMLConstants.SAML20X500_SCHEMA_LOCATION, SAMLConstants.SAML20XACML_SCHEMA_LOCATION, }; /** Classpath relative location of SAML extension schemas. */ @Nonnull @NonnullElements @NotEmpty private static String[] baseExtSchemas = { SAMLConstants.SAML1MD_SCHEMA_LOCATION, SAMLConstants.SAML_IDP_DISCO_SCHEMA_LOCATION, SAMLConstants.SAML20PTHRPTY_SCHEMA_LOCATION, SAMLConstants.SAML20MDQUERY_SCHEMA_LOCATION, SAMLConstants.SAML20DEL_SCHEMA_LOCATION, SAMLConstants.SAML20MDUI_SCHEMA_LOCATION, SAMLConstants.SAML20MDATTR_SCHEMA_LOCATION, SAMLConstants.SAML20MDRPI_SCHEMA_LOCATION, SAMLConstants.SAML20ALG_SCHEMA_LOCATION, SAMLConstants.SAML20CB_SCHEMA_LOCATION, SAMLConstants.SAML20PASLO_SCHEMA_LOCATION, SAMLConstants.SAMLEC_GSS_SCHEMA_LOCATION, }; /** Logger. */ private Logger log = LoggerFactory.getLogger(SAMLSchemaBuilder.class); /** Flag indicating whether the failure to resolve a schema resource should be considered fatal. */ private boolean unresolvedSchemaFatal; /** Cached copy of the schema produced by the builder. */ @Nullable private Schema cachedSchema; /** Reference to SAML 1.x schemas to apply. */ @Nonnull @NonnullElements @NotEmpty private String[] saml1xSchemas; /** The builder to use. */ @Nonnull private SchemaBuilder schemaBuilder; /** Identifies which SAML 1.x version is in use. */ public enum SAML1Version { /** SAML 1.0. */ SAML_10, /** SAML 1.1. */ SAML_11, } /** * Constructor. * *

A default {@link SchemaBuilder} is constructed, and injected with a * {@link ClasspathResolver} for resolving supplementary schemas. * * @param ver the SAML 1.x version to use */ public SAMLSchemaBuilder(@Nonnull @ParameterName(name="ver") final SAML1Version ver) { unresolvedSchemaFatal = true; if (ver == SAML1Version.SAML_11) { saml1xSchemas = saml11Schemas; } else { saml1xSchemas = saml10Schemas; } } /** * Set the flag indicating whether the failure to resolve a schema resource should be considered fatal. * *

Default value: true.

* * @param flag true if should be fatal, false if not */ public void setUnresolvedSchemaFatal(final boolean flag) { unresolvedSchemaFatal = flag; } /** * Set a custom {@link SchemaBuilder} to use. * * @param builder SchemaBuilder to use */ public synchronized void setSchemaBuilder(@Nonnull final SchemaBuilder builder) { schemaBuilder = Constraint.isNotNull(builder, "SchemaBuilder cannot be null"); cachedSchema = null; configureBuilder(); } /** * Get a schema that can validate SAML 1.x, 2.0, and all registered extensions. * * @return schema * * @throws SAXException thrown if a schema object cannot be created */ @Nonnull public synchronized Schema getSAMLSchema() throws SAXException { if (cachedSchema == null) { if (schemaBuilder == null) { try { schemaBuilder = new SchemaBuilder(); schemaBuilder.setResourceResolver(new ClasspathResolver()); configureBuilder(); } catch (final RuntimeException e) { schemaBuilder = null; throw e; } } cachedSchema = schemaBuilder.buildSchema(); } return cachedSchema; } /** * Configure the appropriate {@link SchemaBuilder} with the right set of schemas. */ @Nonnull private void configureBuilder() { for (final String source : baseXMLSchemas) { addSchemaToBuilder(source); } for (final String source : soapSchemas) { addSchemaToBuilder(source); } for (final String source : saml1xSchemas) { addSchemaToBuilder(source); } for (final String source : saml20Schemas) { addSchemaToBuilder(source); } for (final String source : baseExtSchemas) { addSchemaToBuilder(source); } } /** * Load the schema from the specified source and add it to the internal {@link SchemaBuilder}. * * @param source the schema resource path */ private void addSchemaToBuilder(@Nonnull final String source) { final Class clazz = SAMLSchemaBuilder.class; // To be safe, rather than pass the resource InputStream directly to the consumer, // copy the bytes and ensure that the resource stream is closed. try (final InputStream stream = clazz.getResourceAsStream(source)) { if (stream != null) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteStreams.copy(stream, baos); schemaBuilder.addSchema(new ByteArrayInputStream(baos.toByteArray())); } else { log.error("Failed to locate schema resource: {}", source); if (unresolvedSchemaFatal) { throw new XMLRuntimeException("Failed to locate schema resource: " + source); } } } catch (final IOException e) { if (unresolvedSchemaFatal) { throw new XMLRuntimeException("Error loading schema resource: " + source); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy