From e7610325ee2f1d1f4e97e1e7a9b212e692836b5a Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 4 Feb 2020 17:37:34 +0100 Subject: first stable version that uses OpenSAML 3.x --- .../pvp2/idp/impl/builder/AuthResponseBuilder.java | 169 ++++++++++++++------- 1 file changed, 116 insertions(+), 53 deletions(-) (limited to 'eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java') diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index 8cafebb9..55e3e8b4 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -19,37 +19,55 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.List; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.joda.time.DateTime; import org.opensaml.core.criterion.EntityIdCriterion; import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.criterion.EntityRoleCriterion; +import org.opensaml.saml.criterion.ProtocolCriterion; +import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.Issuer; import org.opensaml.saml.saml2.core.NameIDType; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.encryption.Encrypter; import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml.security.impl.MetadataCredentialResolver; -import org.opensaml.security.MetadataCriteria; import org.opensaml.security.credential.UsageType; import org.opensaml.security.criteria.UsageCriterion; import org.opensaml.security.x509.X509Credential; -import org.opensaml.xmlsec.EncryptionParameters; +import org.opensaml.xmlsec.SecurityConfigurationSupport; +import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters; import org.opensaml.xmlsec.encryption.support.EncryptionException; import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; +import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver; import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; /** * Authentication response builder. @@ -65,17 +83,17 @@ public class AuthResponseBuilder { * Build PVP2 S-Profile authentication response. * * @param metadataProvider Service-Provider metadata - * @param issuerEntityID IDP entityId - * @param req current pending request - * @param date Timestamp - * @param assertion PVP2 S-Profil Assertion - * @param enableEncryption encrypt Assertion flag + * @param issuerEntityID IDP entityId + * @param req current pending request + * @param date Timestamp + * @param assertion PVP2 S-Profil Assertion + * @param authConfig {@link IConfiguration} * @return PVP2 S-Profile authentication response * @throws InvalidAssertionEncryptionException In case of an error */ public static Response buildResponse(final IPvp2MetadataProvider metadataProvider, final String issuerEntityID, final RequestAbstractType req, final DateTime date, - final Assertion assertion, final boolean enableEncryption) + final Assertion assertion, IConfiguration authConfig) throws InvalidAssertionEncryptionException { final Response authResponse = Saml2Utils.createSamlObject(Response.class); @@ -90,72 +108,117 @@ public class AuthResponseBuilder { final String remoteSessionID = Saml2Utils.getSecureIdentifier(); authResponse.setID(remoteSessionID); - // SAML2 response required IssueInstant authResponse.setIssueInstant(date); authResponse.setStatus(Saml2Utils.getSuccessStatus()); // check, if metadata includes an encryption key - final MetadataCredentialResolver mdCredResolver = - new MetadataCredentialResolver(metadataProvider); - - final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); - criteriaSet - .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + final X509Credential encryptionCredentials = resolveEncryptionCredential(req, metadataProvider); - X509Credential encryptionCredentials = null; - try { - encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + if (encryptionCredentials != null + && authConfig.getBasicConfigurationBoolean( + PvpConstants.CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)) { + authResponse.getEncryptedAssertions().add( + doEncryption(assertion, encryptionCredentials, authConfig)); - } catch (final SecurityException e2) { - log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); - throw new InvalidAssertionEncryptionException(); + } else { + authResponse.getAssertions().add(assertion); } - if (encryptionCredentials != null && enableEncryption) { - // encrypt SAML2 assertion + return authResponse; + } + + private static EncryptedAssertion doEncryption(Assertion assertion, + X509Credential encryptionCredentials, IConfiguration authConfig) + throws InvalidAssertionEncryptionException { + try { + final String keyEncAlg = selectKeyEncryptionAlgorithm(encryptionCredentials, authConfig); - try { + final DataEncryptionParameters dataEncParams = new DataEncryptionParameters(); + dataEncParams.setAlgorithm(authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_DATA, PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE)); - final EncryptionParameters dataEncParams = new EncryptionParameters(); - dataEncParams.setAlgorithm(PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE); + final List keyEncParamList = new ArrayList<>(); + final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + keyEncParam.setEncryptionCredential(encryptionCredentials); + keyEncParam.setAlgorithm(keyEncAlg); - final List keyEncParamList = new ArrayList<>(); - final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + final KeyInfoGeneratorFactory kigf = + SecurityConfigurationSupport.getGlobalEncryptionConfiguration() + .getKeyTransportKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); + keyEncParam.setKeyInfoGenerator(kigf.newInstance()); + keyEncParamList.add(keyEncParam); - keyEncParam.setEncryptionCredential(encryptionCredentials); - keyEncParam.setAlgorithm(PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); - final KeyInfoGeneratorFactory kigf = - org.opensaml.xml.Configuration.getGlobalSecurityConfiguration() - .getKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); - keyEncParam.setKeyInfoGenerator(kigf.newInstance()); - keyEncParamList.add(keyEncParam); + final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); + samlEncrypter.setKeyPlacement(KeyPlacement.PEER); - final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); - // samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); - samlEncrypter.setKeyPlacement(KeyPlacement.PEER); + return samlEncrypter.encrypt(assertion); - EncryptedAssertion encryptAssertion = null; + } catch (final EncryptionException | SamlSigningException e1) { + log.warn("Can not encrypt the PVP2 assertion", e1); + throw new InvalidAssertionEncryptionException(); - encryptAssertion = samlEncrypter.encrypt(assertion); + } - authResponse.getEncryptedAssertions().add(encryptAssertion); + } - } catch (final EncryptionException e1) { - log.warn("Can not encrypt the PVP2 assertion", e1); - throw new InvalidAssertionEncryptionException(); + private static String selectKeyEncryptionAlgorithm(X509Credential encryptionCredentials, + IConfiguration authConfig) throws SamlSigningException { + final PublicKey privatekey = encryptionCredentials.getPublicKey(); + if (privatekey instanceof RSAPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_RSA); - } + } else if (privatekey instanceof ECPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_EC); } else { - authResponse.getAssertions().add(assertion); + log.warn("Could NOT evaluate the Private-Key type from " + encryptionCredentials.getEntityId() + + " credential."); + throw new SamlSigningException("internal.pvp.97", + new Object[] { encryptionCredentials.getEntityId(), privatekey.getClass().getName() }); } - return authResponse; + } + + private static X509Credential resolveEncryptionCredential(RequestAbstractType req, + IPvp2MetadataProvider metadataProvider) throws InvalidAssertionEncryptionException { + try { + final List keyInfoProvider = new ArrayList<>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver( + metadataProvider); + roleDescriptorResolver.setRequireValidMetadata(true); + roleDescriptorResolver.initialize(); + + final MetadataCredentialResolver mdCredResolver = new MetadataCredentialResolver(); + mdCredResolver.setRoleDescriptorResolver(roleDescriptorResolver); + mdCredResolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver); + mdCredResolver.initialize(); + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); + criteriaSet.add(new ProtocolCriterion(SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + + return (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + + } catch (final SecurityException | ComponentInitializationException | ResolverException e2) { + log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); + throw new InvalidAssertionEncryptionException(); + + } } } -- cgit v1.2.3