se.idsec.signservice.integration.signmessage.impl.DefaultSignMessageProcessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2019-2023 IDsec Solutions AB
*
* 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 se.idsec.signservice.integration.signmessage.impl;
import jakarta.annotation.Nonnull;
import jakarta.annotation.PostConstruct;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.resolver.CriteriaSet;
import net.shibboleth.shared.resolver.ResolverException;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.saml.criterion.RoleDescriptorCriterion;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml.saml2.metadata.SSODescriptor;
import org.opensaml.saml.security.impl.MetadataCredentialResolver;
import org.opensaml.saml.security.impl.SAMLMetadataEncryptionParametersResolver;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.criteria.UsageCriterion;
import org.opensaml.xmlsec.EncryptionConfiguration;
import org.opensaml.xmlsec.config.impl.DefaultSecurityConfigurationBootstrap;
import org.opensaml.xmlsec.criterion.EncryptionConfigurationCriterion;
import org.opensaml.xmlsec.criterion.EncryptionOptionalCriterion;
import org.opensaml.xmlsec.encryption.EncryptedData;
import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters;
import org.opensaml.xmlsec.encryption.support.Encrypter;
import org.opensaml.xmlsec.encryption.support.EncryptionException;
import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;
import org.w3c.dom.Element;
import se.idsec.signservice.integration.config.IntegrationServiceConfiguration;
import se.idsec.signservice.integration.core.error.ErrorCode;
import se.idsec.signservice.integration.core.error.SignServiceIntegrationException;
import se.idsec.signservice.integration.core.error.impl.SignServiceProtocolException;
import se.idsec.signservice.integration.core.impl.CorrelationID;
import se.idsec.signservice.integration.security.IdpMetadataResolver;
import se.idsec.signservice.integration.security.MetadataException;
import se.idsec.signservice.integration.security.SignServiceEncryptException;
import se.idsec.signservice.integration.security.impl.EncryptionConfigurationWrapper;
import se.idsec.signservice.integration.security.impl.OpenSAMLEncryptionParameters;
import se.idsec.signservice.integration.signmessage.SignMessageParameters;
import se.idsec.signservice.integration.signmessage.SignMessageProcessor;
import se.idsec.signservice.utils.AssertThat;
import se.swedenconnect.opensaml.saml2.metadata.EntityDescriptorUtils;
import se.swedenconnect.opensaml.sweid.saml2.signservice.build.SignMessageBuilder;
import se.swedenconnect.opensaml.sweid.saml2.signservice.dss.EncryptedMessage;
import se.swedenconnect.opensaml.sweid.saml2.signservice.dss.SignMessageMimeTypeEnum;
import se.swedenconnect.schemas.csig.dssext_1_1.SignMessage;
import se.swedenconnect.xml.jaxb.JAXBContextUtils;
/**
* SignMessageProcessor default implementation.
*
* @author Martin Lindström ([email protected])
* @author Stefan Santesson ([email protected])
*/
@Slf4j
public class DefaultSignMessageProcessor implements SignMessageProcessor {
/** The metadata resolver. */
protected IdpMetadataResolver idpMetadataResolver;
/** The resolver for encryption parameters. */
protected SAMLMetadataEncryptionParametersResolver encryptionParametersResolver;
/** The encrypter to use. */
protected Encrypter encrypter = new Encrypter();
/**
* Constructor.
*/
public DefaultSignMessageProcessor() {
final MetadataCredentialResolver credentialResolver = new MetadataCredentialResolver();
credentialResolver.setKeyInfoCredentialResolver(
DefaultSecurityConfigurationBootstrap.buildBasicInlineKeyInfoCredentialResolver());
try {
credentialResolver.initialize();
}
catch (final ComponentInitializationException e) {
// Can not happen
}
this.encryptionParametersResolver = new SAMLMetadataEncryptionParametersResolver(credentialResolver);
this.encryptionParametersResolver.setMergeMetadataRSAOAEPParametersWithConfig(true);
this.encryptionParametersResolver.setAutoGenerateDataEncryptionCredential(true);
}
/** {@inheritDoc} */
@Override
public SignMessage create(@Nonnull final SignMessageParameters input,
@Nonnull final IntegrationServiceConfiguration config) throws SignServiceIntegrationException {
final se.swedenconnect.opensaml.sweid.saml2.signservice.dss.SignMessage signMessage = SignMessageBuilder.builder()
.message(input.getSignMessage())
.mimeType(SignMessageMimeTypeEnum.parse(input.getMimeType()))
.mustShow(input.getMustShow())
.displayEntity(input.getDisplayEntity())
.build();
if (input.isPerformEncryption()) {
log.debug("{}: Encrypting SignMessage for IdP '{}' ...", CorrelationID.id(), input.getDisplayEntity());
// Find IdP metadata ...
//
final EntityDescriptor metadata = this.idpMetadataResolver.resolveMetadata(input.getDisplayEntity(), config);
final SSODescriptor descriptor = EntityDescriptorUtils.getSSODescriptor(metadata);
if (descriptor == null) {
final String msg =
String.format("Metadata for '%s' does not contain an SSO descriptor", input.getDisplayEntity());
log.error("{}: {}", CorrelationID.id(), msg);
throw new MetadataException(msg);
}
final EncryptionConfiguration econfig;
if (config.getDefaultEncryptionParameters() instanceof OpenSAMLEncryptionParameters
&& ((OpenSAMLEncryptionParameters) config.getDefaultEncryptionParameters()).getSystemConfiguration() instanceof EncryptionConfiguration) {
econfig = ((OpenSAMLEncryptionParameters) config.getDefaultEncryptionParameters())
.getSystemConfiguration();
}
else {
econfig = new EncryptionConfigurationWrapper(config.getDefaultEncryptionParameters());
}
final CriteriaSet criteriaSet = new CriteriaSet();
criteriaSet.add(new RoleDescriptorCriterion(descriptor));
criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION));
criteriaSet.add(new EncryptionConfigurationCriterion(econfig));
criteriaSet.add(new EncryptionOptionalCriterion(false));
try {
final org.opensaml.xmlsec.EncryptionParameters openSAMLEncryptionParameters =
this.encryptionParametersResolver.resolveSingle(criteriaSet);
// Let's encrypt!
//
final DataEncryptionParameters dataEncryptionParameters =
new DataEncryptionParameters(openSAMLEncryptionParameters);
final KeyEncryptionParameters kekParams =
new KeyEncryptionParameters(openSAMLEncryptionParameters, input.getDisplayEntity());
final EncryptedData encryptedData =
this.encrypter.encryptElement(signMessage.getMessage(), dataEncryptionParameters, kekParams);
final EncryptedMessage encryptedMessage =
(EncryptedMessage) XMLObjectSupport.buildXMLObject(EncryptedMessage.DEFAULT_ELEMENT_NAME);
encryptedMessage.setEncryptedData(encryptedData);
signMessage.setMessage(null);
signMessage.setEncryptedMessage(encryptedMessage);
}
catch (final ResolverException e) {
log.error("{}: Error during resolve of encryption parameters", CorrelationID.id(), e);
throw new SignServiceEncryptException(new ErrorCode.Code("resolve"), "Failed to resolve encryption parameters",
e);
}
catch (final EncryptionException e) {
final String msg = String.format("Encryption failure - %s", e.getMessage());
log.error("{}: {}", CorrelationID.id(), msg);
throw new SignServiceEncryptException(new ErrorCode.Code("crypt"), msg, e);
}
log.debug("{}: SignMessage successfully encrypted for IdP '{}'", CorrelationID.id(), input.getDisplayEntity());
}
try {
final Element element = XMLObjectSupport.marshall(signMessage);
final JAXBContext context = JAXBContextUtils.createJAXBContext(SignMessage.class);
final Object jaxb = context.createUnmarshaller().unmarshal(element);
return (SignMessage) jaxb;
}
catch (final MarshallingException | JAXBException e) {
throw new SignServiceProtocolException("Failed to marshall DSS protocol object", e);
}
}
/**
* Assigns the metadata resolver for IdP metadata
*
* @param idpMetadataResolver metadata resolver
*/
public void setIdpMetadataResolver(final IdpMetadataResolver idpMetadataResolver) {
this.idpMetadataResolver = idpMetadataResolver;
}
/**
* The encrypter to use.
*
* If not assigned, an instance of {@link org.opensaml.xmlsec.encryption.support.Encrypter} is used.
*
*
* @param encrypter the encrypter
*/
public void setEncrypter(final Encrypter encrypter) {
if (encrypter != null) {
this.encrypter = encrypter;
}
}
/**
* Ensures that all required properties have been assigned.
*
*
* Note: If executing in a Spring Framework environment this method is automatically invoked after all properties have
* been assigned. Otherwise it should be explicitly invoked.
*
*
* @throws Exception if not all settings are correct
*/
@PostConstruct
public void afterPropertiesSet() throws Exception {
AssertThat.isNotNull(this.idpMetadataResolver, "'idpMetadataResolver' must be assigned");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy