/* * 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.idp.impl.builder; import java.util.ArrayList; import java.util.List; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; 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.common.xml.SAMLConstants; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.encryption.Encrypter; import org.opensaml.saml2.encryption.Encrypter.KeyPlacement; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.security.MetadataCredentialResolver; import org.opensaml.security.MetadataCriteria; import org.opensaml.xml.encryption.EncryptionException; import org.opensaml.xml.encryption.EncryptionParameters; import org.opensaml.xml.encryption.KeyEncryptionParameters; 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.keyinfo.KeyInfoGeneratorFactory; import org.opensaml.xml.security.x509.X509Credential; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Authentication response builder. * * @author tlenz * */ public class AuthResponseBuilder { private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); /** * 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 * @return PVP2 S-Profile authentication response * @throws InvalidAssertionEncryptionException In case of an error */ public static Response buildResponse(final MetadataProvider metadataProvider, final String issuerEntityID, final RequestAbstractType req, final DateTime date, final Assertion assertion, final boolean enableEncryption) throws InvalidAssertionEncryptionException { final Response authResponse = Saml2Utils.createSamlObject(Response.class); final Issuer nissuer = Saml2Utils.createSamlObject(Issuer.class); nissuer.setValue(issuerEntityID); nissuer.setFormat(NameIDType.ENTITY); authResponse.setIssuer(nissuer); authResponse.setInResponseTo(req.getID()); // set responseID 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 EntityIDCriteria(req.getIssuer().getValue())); criteriaSet .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); criteriaSet.add(new UsageCriteria(UsageType.ENCRYPTION)); X509Credential encryptionCredentials = null; try { encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); } catch (final SecurityException e2) { log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); throw new InvalidAssertionEncryptionException(); } if (encryptionCredentials != null && enableEncryption) { // encrypt SAML2 assertion try { 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(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.INLINE); samlEncrypter.setKeyPlacement(KeyPlacement.PEER); EncryptedAssertion encryptAssertion = null; encryptAssertion = samlEncrypter.encrypt(assertion); authResponse.getEncryptedAssertions().add(encryptAssertion); } catch (final EncryptionException e1) { log.warn("Can not encrypt the PVP2 assertion", e1); throw new InvalidAssertionEncryptionException(); } } else { authResponse.getAssertions().add(assertion); } return authResponse; } }