/* * Copyright 2018 A-SIT Plus GmbH * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, * A-SIT Plus GmbH, 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 "License"); * You may not use this work except in compliance with the License. * You may obtain a copy of the License at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * 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. * * 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.asitplus.eidas.specific.core.builder; import java.time.Instant; import java.util.Optional; import java.util.Set; import at.asitplus.eidas.specific.core.MsEidasNodeConstants; import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.data.IAuthProcessDataContainer; import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.data.Triple; import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.EidAuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; import lombok.extern.slf4j.Slf4j; @Slf4j public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder { private static final String ERROR_B11 = "builder.11"; @Override protected IAuthData buildDeprecatedAuthData(IRequest pendingReq) throws EaafException { final EidAuthProcessDataWrapper authProcessData = pendingReq.getSessionData(EidAuthProcessDataWrapper.class); final EidAuthenticationData authData = new EidAuthenticationData(); // set basis infos super.generateDeprecatedBasicAuthData(authData, pendingReq, authProcessData); // set specific informations authData.setSsoSessionValidTo( Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); authData.setEidStatus(authProcessData.isTestIdentity() ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); return authData; } @Override protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) throws EaafException { if (authData instanceof EidAuthenticationData) { ((EidAuthenticationData) authData).setGenericData( ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, pendingReq.getUniquePiiTransactionIdentifier()); log.trace("Inject piiTransactionId: {} into AuthData", pendingReq.getUniquePiiTransactionIdentifier()); // set specific informations ((EidAuthenticationData) authData).setSsoSessionValidTo( Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); // set E-ID status-level final EidAuthProcessDataWrapper authProcessData = pendingReq.getSessionData(EidAuthProcessDataWrapper.class); ((EidAuthenticationData) authData).setEidStatus(authProcessData.isTestIdentity() ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); // forward all requested IDA attributes into authData forwardAllRequestedIdaAttributes(authProcessData, (EidAuthenticationData) authData, pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class) .getRequestedAttributes()); // build specific bPK attribute buildNatPersonInfos((EidAuthenticationData) authData, authProcessData); // handle mandate informations buildMandateInformation((EidAuthenticationData) authData, pendingReq, authProcessData); } else { throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + authData.getClass().getName()); } } @Override protected IAuthData getAuthDataInstance(IRequest arg0) throws EaafException { return new EidAuthenticationData(); } @Override protected Pair buildOAspecificbPK(IRequest pendingReq, AuthenticationData authData) throws EaafBuilderException { return super.buildOAspecificbPK(pendingReq, authData); } @Override protected Pair getEncryptedBpkFromPvpAttribute(IAuthProcessDataContainer arg0, AuthenticationData arg1, ISpConfiguration arg2) throws EaafBuilderException { return null; } @Override protected Pair getbaseIdFromSzr(AuthenticationData arg0, String arg1, String arg2) { return null; } protected String customizeLegalPersonSourcePin(String sourcePin, String sourcePinType) { log.trace("Use legal-person sourcePin as it is"); return sourcePin; } protected String customizeBpkAttribute(String pvpBpkAttrValue) { log.trace("Use natural-person bPK as it is"); return pvpBpkAttrValue; } private void forwardAllRequestedIdaAttributes(EidAuthProcessDataWrapper authProcessData, EidAuthenticationData authData, Set requestedIdaAttributes) { if (requestedIdaAttributes != null && !requestedIdaAttributes.isEmpty()) { log.trace("Forwarding IDA requested attributes ... "); authProcessData.getGenericSessionDataStream() .filter(el -> requestedIdaAttributes.contains(el.getKey())) .forEach(el -> { try { authData.setGenericData(el.getKey(), el.getValue()); } catch (final EaafStorageException e) { log.error("Can not store attribute: {} into session.", el.getKey(), e); throw new RuntimeException(e); } }); } else { log.trace("No IDA requested attributes to forwarding. Nothing todo"); } } private void buildMandateInformation(EidAuthenticationData authData, IRequest pendingReq, EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, EaafStorageException { authData.setUseMandate(authProcessData.isMandateUsed()); if (authProcessData.isMandateUsed()) { log.debug("Build mandate-releated authentication data ... "); if (authProcessData.isForeigner()) { buildMandateInformationForEidasIncoming(); } else { buildMandateInformationForEidasOutgoing(authData, pendingReq, authProcessData); } } } private void buildMandateInformationForEidasIncoming() { log.debug("Find eIDAS incoming process. Generated mandate-information for ID-Austria system ... "); // TODO: implement IDA specific processing of foreign mandate } private void buildNatPersonInfos(EidAuthenticationData authData, EidAuthProcessDataWrapper authProcessData) throws EaafStorageException { // clean-up BPK attribute and forward it as new property authData.setGenericData(PvpAttributeDefinitions.BPK_NAME, customizeBpkAttribute(authProcessData.getGenericDataFromSession( PvpAttributeDefinitions.BPK_NAME, String.class))); } private void buildMandateInformationForEidasOutgoing(EidAuthenticationData authData, IRequest pendingReq, EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, EaafStorageException { log.debug("Find eIDAS outgoing process. Generated mandate-information for other country ... "); if (authProcessData.getGenericDataFromSession( PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME) != null) { final Optional> missingAttribute = MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES.stream() .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) .findFirst(); if (missingAttribute.isPresent()) { log.error("ID-Austria response contains not all attributes for nat. person mandator. Missing: {}", missingAttribute.get().getFirst()); throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Nat. person mandate" }); } else { log.trace("Find nat. person mandate. Mandate can be used as it is "); authData.setGenericData(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, customizeBpkAttribute(authProcessData.getGenericDataFromSession( PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class))); } } else { final Optional> missingAttribute = MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES.stream() .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) .findFirst(); if (missingAttribute.isPresent()) { log.error("ID-Austria response contains not all attributes for legal. person mandator. Missing: {}", missingAttribute.get().getFirst()); throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Legal. person mandate" }); } else { log.trace( "Find jur. person mandate. Generate eIDAS identifier from legal-person sourcePin and type ... "); final String sourcePin = authProcessData.getGenericDataFromSession( PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class); final String sourcePinType = authProcessData.getGenericDataFromSession( PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, String.class); // customize attribute-value for source-pin final String sourcePinToUse = customizeLegalPersonSourcePin(sourcePin, sourcePinType); log.debug("Use legal-person eIDAS identifer: {} from baseId: {} and baseIdType: {}", sourcePinToUse, sourcePin, sourcePinType); authData.setGenericData(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinToUse); } } } }