fr.mby.saml2.sp.impl.config.BasicSpConfig.java Source code

Java tutorial

Introduction

Here is the source code for fr.mby.saml2.sp.impl.config.BasicSpConfig.java

Source

/**
 * Copyright (C) 2012 RECIA http://www.recia.fr
 * @Author (C) 2012 Maxime Bossard <mxbossard@gmail.com>
 *
 * Licensed 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 fr.mby.saml2.sp.impl.config;

import java.security.PrivateKey;
import java.security.spec.EncodedKeySpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.metadata.AssertionConsumerService;
import org.opensaml.saml2.metadata.AttributeConsumingService;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.KeyDescriptor;
import org.opensaml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.opensaml.security.MetadataCredentialResolver;
import org.opensaml.security.MetadataCriteria;
import org.opensaml.xml.parse.XMLParserException;
import org.opensaml.xml.security.Criteria;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.criteria.EntityIDCriteria;
import org.opensaml.xml.security.criteria.UsageCriteria;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import fr.mby.saml2.sp.api.config.ISpConfig;
import fr.mby.saml2.sp.api.core.SamlBindingEnum;
import fr.mby.saml2.sp.impl.helper.SecurityHelper;
import fr.mby.saml2.sp.opensaml.helper.OpenSamlHelper;

/**
 * Basic SP Configuration.
 * 
 * @author GIP RECIA 2012 - Maxime BOSSARD.
 * 
 */
public class BasicSpConfig implements ISpConfig, InitializingBean {

    /** SVUID. */
    private static final long serialVersionUID = 7578815619985801219L;

    /** Logger. */
    private static final Log LOGGER = LogFactory.getLog(BasicSpConfig.class);

    private String id;

    private String entityId;

    private String description;

    private String pictureUrl;

    private Resource decryptionKeyResource;

    private Class<EncodedKeySpec> decryptionKeySpec;

    private String decryptionKeyType;

    private PrivateKey decryptionKey;

    private Resource signingKeyResource;

    private Class<EncodedKeySpec> signingKeySpec;

    private String signingKeyType;

    private PrivateKey signingKey;

    /** Used to configure the SP. */
    private Resource spMetadata;

    /** SP metadata provider. */
    private MetadataProvider spMetadataProvider;

    private final Map<SamlBindingEnum, AssertionConsumerService> spAssertionConsumerServices = new HashMap<SamlBindingEnum, AssertionConsumerService>();

    private final Map<SamlBindingEnum, SingleLogoutService> spSingleLogoutServices = new HashMap<SamlBindingEnum, SingleLogoutService>();

    private final Map<Integer, AttributeConsumingService> attributeConsumingServices = new HashMap<Integer, AttributeConsumingService>();

    private final Map<UsageType, BasicX509Credential> spCredentials = new HashMap<UsageType, BasicX509Credential>();

    @Override
    public PrivateKey getDecryptionKey() {
        return this.decryptionKey;
    }

    @Override
    public PrivateKey getSigningKey() {
        return this.signingKey;
    }

    @Override
    public BasicX509Credential getSigningCredential() {
        return this.spCredentials.get(UsageType.SIGNING);
    }

    @Override
    public BasicX509Credential getDecryptionCredential() {
        return this.spCredentials.get(UsageType.ENCRYPTION);
    }

    @Override
    public String getEndpointUrl(final SamlBindingEnum binding) {
        final AssertionConsumerService acService = this.spAssertionConsumerServices.get(binding);
        return acService.getLocation();
    }

    /**
     * Process SP metadatas.
     * 
     * @throws MetadataProviderException
     * @throws XMLParserException
     */
    protected void processSpMetadata() throws MetadataProviderException, XMLParserException {
        Assert.notNull(this.spMetadata, "No SP metadata provided !");
        Assert.isTrue(this.spMetadata.exists(),
                String.format("SP metadata [%s] cannot be found !", this.spMetadata.getFilename()));

        this.spMetadataProvider = OpenSamlHelper.buildMetadataProvider(this.spMetadata);
        Assert.notNull(this.spMetadataProvider, "SP metadata provider wasn't build !");

        final String spEntityId = this.getEntityId();
        final EntityDescriptor spEntityDescriptor = this.spMetadataProvider.getEntityDescriptor(spEntityId);
        Assert.notNull(spEntityDescriptor,
                String.format("No entity descriptor found in SP metadata for SP entityId [%s]", spEntityId));

        final SPSSODescriptor ssoDescriptors = spEntityDescriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
        if (ssoDescriptors != null) {
            // Retrieve Assertion Consumer endpoints URL.
            final List<AssertionConsumerService> acServices = ssoDescriptors.getAssertionConsumerServices();
            if (!CollectionUtils.isEmpty(acServices)) {
                for (final AssertionConsumerService acService : acServices) {
                    if (acService != null) {
                        final SamlBindingEnum binding = SamlBindingEnum.fromSamlUri(acService.getBinding());
                        if (binding != null) {
                            this.spAssertionConsumerServices.put(binding, acService);
                        }
                    }
                }
            }

            // Retrieve Single Logout endpoints URL.
            final List<SingleLogoutService> slServices = ssoDescriptors.getSingleLogoutServices();
            if (!CollectionUtils.isEmpty(slServices)) {
                for (final SingleLogoutService slService : slServices) {
                    if (slService != null) {
                        final SamlBindingEnum binding = SamlBindingEnum.fromSamlUri(slService.getBinding());
                        if (binding != null) {
                            this.spSingleLogoutServices.put(binding, slService);
                        }
                    }
                }
            }

            // Retrieve AttributeConsumingInformations.
            final List<AttributeConsumingService> attrConsumingServices = ssoDescriptors
                    .getAttributeConsumingServices();
            if (!CollectionUtils.isEmpty(attrConsumingServices)) {
                for (final AttributeConsumingService attrConsumingService : attrConsumingServices) {
                    if (attrConsumingService != null) {
                        this.attributeConsumingServices.put(attrConsumingService.getIndex(), attrConsumingService);
                    }
                }
            }

            // Retrieve KeyDescriptors
            final List<KeyDescriptor> keyDescriptors = ssoDescriptors.getKeyDescriptors();
            if (!CollectionUtils.isEmpty(keyDescriptors)) {
                for (final KeyDescriptor keyDescriptor : keyDescriptors) {
                    if (keyDescriptor != null) {
                        final UsageType usageType = keyDescriptor.getUse();
                        final org.opensaml.xml.signature.KeyInfo keyInfo = keyDescriptor.getKeyInfo();
                        if (keyInfo != null) {
                            final MetadataCredentialResolver mcr = new MetadataCredentialResolver(
                                    this.spMetadataProvider);

                            final Criteria criteria1 = new UsageCriteria(keyDescriptor.getUse());
                            final Criteria criteria2 = new EntityIDCriteria(this.getEntityId());
                            final Criteria criteria3 = new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME,
                                    null);
                            final CriteriaSet criteriaSet = new CriteriaSet(criteria1);
                            criteriaSet.add(criteria2);
                            criteriaSet.add(criteria3);
                            try {
                                final BasicX509Credential credentials = (BasicX509Credential) mcr
                                        .resolveSingle(criteriaSet);
                                this.spCredentials.put(usageType, credentials);
                            } catch (final SecurityException e) {
                                BasicSpConfig.LOGGER.error("Error while loading SP metadata credentials !", e);
                            }
                        }
                    }
                }
            }
        }

        for (final SamlBindingEnum binding : SamlBindingEnum.values()) {
            final AssertionConsumerService service = this.spAssertionConsumerServices.get(binding);
            Assert.notNull(service, String.format(
                    "No AssertionConsumingService for binding [%s] found in the SP metadata with entityId [%s] !",
                    binding.getDescription(), spEntityId));
            Assert.isTrue(StringUtils.hasText(service.getLocation()), String.format(
                    "No AssertionConsumingService location provided in SP metadata for binding [%s]", binding));
        }

        for (final SamlBindingEnum binding : SamlBindingEnum.values()) {
            final SingleLogoutService service = this.spSingleLogoutServices.get(binding);
            Assert.notNull(service,
                    String.format(
                            "No SingleLogoutService for binding [%s] found in the SP metadata with entityId [%s] !",
                            binding.getDescription(), spEntityId));
            Assert.isTrue(StringUtils.hasText(service.getLocation()), String
                    .format("No SingleLogoutService location provided in SP metadata for binding [%s]", binding));
        }

        final BasicX509Credential signingCredential = this.spCredentials.get(UsageType.SIGNING);
        Assert.notNull(signingCredential, "No signing credential provided in SP metadata !");

        final BasicX509Credential encryptionCredential = this.spCredentials.get(UsageType.ENCRYPTION);
        if (encryptionCredential == null) {
            this.spCredentials.put(UsageType.ENCRYPTION, signingCredential);
        }
    }

    /**
     * Build private Keys.
     * 
     * @throws Exception
     */
    protected void buildSpPrivateKeys() throws Exception {
        Assert.notNull(this.decryptionKeyResource, "No encryption key configured for CAS SP");
        Assert.notNull(this.decryptionKeySpec, "No java encryption key specification configured for CAS SP");
        Assert.notNull(this.decryptionKeyType, "No encryption key type configured for CAS SP");
        Assert.notNull(this.signingKeyResource, "No signing key configured for CAS SP");
        Assert.notNull(this.signingKeySpec, "No java signing key specification configured for CAS SP");
        Assert.notNull(this.signingKeyType, "No signing key type configured for CAS SP");

        this.decryptionKey = SecurityHelper.buildPrivateKey(this.decryptionKeyResource, this.decryptionKeySpec,
                this.decryptionKeyType);
        this.signingKey = SecurityHelper.buildPrivateKey(this.signingKeyResource, this.signingKeySpec,
                this.signingKeyType);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.id, "No id configured for Basic SP Config !");
        Assert.notNull(this.entityId, "No entity ID configured for Basic SP Config !");

        this.processSpMetadata();

        this.buildSpPrivateKeys();
    }

    @Override
    public String getId() {
        return this.id;
    }

    public void setId(final String id) {
        this.id = id;
    }

    @Override
    public String getEntityId() {
        return this.entityId;
    }

    public void setEntityId(final String entityId) {
        this.entityId = entityId;
    }

    @Override
    public String getDescription() {
        return this.description;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    @Override
    public String getPictureUrl() {
        return this.pictureUrl;
    }

    public void setPictureUrl(final String pictureUrl) {
        this.pictureUrl = pictureUrl;
    }

    public Resource getDecryptionKeyResource() {
        return this.decryptionKeyResource;
    }

    public void setDecryptionKeyResource(final Resource decryptionKeyResource) {
        this.decryptionKeyResource = decryptionKeyResource;
    }

    public Resource getSigningKeyResource() {
        return this.signingKeyResource;
    }

    public void setSigningKeyResource(final Resource signingKeyResource) {
        this.signingKeyResource = signingKeyResource;
    }

    public void setDecryptionKeyType(final String encryptionKeyType) {
        this.decryptionKeyType = encryptionKeyType;
    }

    public void setSigningKeyType(final String signingKeyType) {
        this.signingKeyType = signingKeyType;
    }

    public void setDecryptionKeySpec(final Class<EncodedKeySpec> encryptionKeySpec) {
        this.decryptionKeySpec = encryptionKeySpec;
    }

    public void setSigningKeySpec(final Class<EncodedKeySpec> signingKeySpec) {
        this.signingKeySpec = signingKeySpec;
    }

    public void setSpMetadata(final Resource spMetadata) {
        this.spMetadata = spMetadata;
    }

}