diff options
Diffstat (limited to 'eaaf_core/src/main/java')
36 files changed, 1250 insertions, 866 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IJsonMapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IJsonMapper.java index b3e0c88f..08c48435 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IJsonMapper.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/api/utils/IJsonMapper.java @@ -3,8 +3,6 @@ package at.gv.egiz.eaaf.core.api.utils; import java.io.IOException; import java.io.InputStream; -import com.google.gson.JsonParseException; - import at.gv.egiz.eaaf.core.exceptions.EaafJsonMapperException; public interface IJsonMapper { diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGuiFormBuilderConfiguration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGuiFormBuilderConfiguration.java index b0718f85..f8e64c1a 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGuiFormBuilderConfiguration.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/gui/AbstractGuiFormBuilderConfiguration.java @@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory; import at.gv.egiz.eaaf.core.api.gui.GroupDefinition; import at.gv.egiz.eaaf.core.api.gui.GroupDefinition.Type; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; +import lombok.Setter; /** * Abstract Configuration implementation for GUI Builders. @@ -63,6 +64,9 @@ public abstract class AbstractGuiFormBuilderConfiguration implements IGuiBuilder private String authUrl = null; private String viewName = null; private String formSubmitEndpoint = null; + + @Setter + private boolean writeAsynch = true; private final Map<String, Object> params = new HashMap<>(); @@ -137,6 +141,13 @@ public abstract class AbstractGuiFormBuilderConfiguration implements IGuiBuilder } + + @Override + public final boolean isWriteAsynch() { + return this.writeAsynch; + + } + /** * Define the parameters, which should be evaluated in the template. <br> * <b>IMPORTANT:</b> external HTML escapetion is required, because it is NOT diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java index 677e3c46..4fe22feb 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/AuthenticationData.java @@ -26,16 +26,18 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.TimeZone; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; import org.apache.commons.collections4.map.HashedMap; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; -import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BpkBuilder; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; +import lombok.extern.slf4j.Slf4j; /** * Service-Provider specific authentication data. @@ -43,12 +45,12 @@ import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BpkBuilder; * @author tlenz * */ +@Slf4j public class AuthenticationData implements IAuthData, Serializable { - private static final Logger log = LoggerFactory.getLogger(AuthenticationData.class); - private static final long serialVersionUID = -1042697056735596866L; public static final String IDENTITY_LINK_DATE_FORMAT = "yyyy-MM-dd"; + public static final String IDENTITY_LINK_DATE_REGEX = "([0-9]{4})-([0-9]{2})-([0-9]{2})"; public static final String ISSUE_INSTANT_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; private boolean isBaseIdTransferRestrication = true; @@ -66,7 +68,7 @@ public class AuthenticationData implements IAuthData, Serializable { private String familyName; private String givenName; - private Date dateOfBirth; + private String dateOfBirth; private String encSourceId; private String encSourceIdType; @@ -135,7 +137,6 @@ public class AuthenticationData implements IAuthData, Serializable { } @Override - @Deprecated public String getBpk() { return bpk; } @@ -145,28 +146,41 @@ public class AuthenticationData implements IAuthData, Serializable { * * @param bpk The bPK to set */ - @Deprecated public void setBpk(final String bpk) { this.bpk = bpk; } @Override - public Date getDateOfBirth() { - return getDateCopyOrNull(this.dateOfBirth); + public String getDateOfBirth() { + return this.dateOfBirth; } @Override - public String getFormatedDateOfBirth() { - final DateFormat pvpDateFormat = new SimpleDateFormat(IDENTITY_LINK_DATE_FORMAT); - if (getDateOfBirth() != null) { - return pvpDateFormat.format(getDateOfBirth()); - } else { - return "2999-12-31"; - } - + public String getDateOfBirthFormated(String pattern) { + if (StringUtils.isNotEmpty(getDateOfBirth())) { + try { + final DateFormat dateFormat = new SimpleDateFormat(IDENTITY_LINK_DATE_FORMAT); + Date parsedDate = dateFormat.parse(getDateOfBirth()); + final String dateString = dateFormat.format(parsedDate); + if (getDateOfBirth().equals(dateString)) { + final DateFormat destDateFormat = new SimpleDateFormat(pattern); + return destDateFormat.format(parsedDate); + + } else { + log.info("DateOfBirth has an unusal format. Can not be converted to: {}", pattern); + + } + + } catch (ParseException | IllegalArgumentException e) { + log.error("Can not parse DateOfBirth.", e); + + } + } + return null; + } - + @Override public String getFamilyName() { return this.familyName; @@ -220,26 +234,16 @@ public class AuthenticationData implements IAuthData, Serializable { * * @param dateOfBirth The dateOfBirth to set */ - public void setDateOfBirth(final Date dateOfBirth) { - this.dateOfBirth = getDateCopyOrNull(dateOfBirth); - } - - /** - * Set the date of birth. - * - * @param dateOfBirth date of birth String as "yyyy-MM-dd" - */ - public void setDateOfBirth(final String dateOfBirth) { - try { - if (StringUtils.isNotEmpty(dateOfBirth)) { - final DateFormat identityLinkFormat = new SimpleDateFormat(IDENTITY_LINK_DATE_FORMAT); - this.dateOfBirth = identityLinkFormat.parse(dateOfBirth); - + public void setDateOfBirth(@Nullable final String dateOfBirth) { + if (dateOfBirth != null) { + if (Pattern.matches(IDENTITY_LINK_DATE_REGEX, dateOfBirth)) { + this.dateOfBirth = dateOfBirth; + + } else { + log.error("DateOfBirth: {} does NOT match to pattern: {}", + dateOfBirth, IDENTITY_LINK_DATE_REGEX); + } - - } catch (final ParseException e) { - log.warn("Parse dateOfBirht from IdentityLink FAILED", e); - } } @@ -282,7 +286,6 @@ public class AuthenticationData implements IAuthData, Serializable { } @Override - @Deprecated public String getBpkType() { return bpkType; } @@ -292,10 +295,9 @@ public class AuthenticationData implements IAuthData, Serializable { * * @param bpkType bPK type */ - @Deprecated public void setBpkType(final String bpkType) { this.bpkType = BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(bpkType); - + } @Override diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java index d2365e4a..89977308 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/AbstractAuthenticationManager.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import javax.annotation.PostConstruct; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -34,6 +35,7 @@ import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.IRequestStorage; @@ -66,6 +68,9 @@ public abstract class AbstractAuthenticationManager implements IAuthenticationMa public static final int SLOTIMEOUT = 30 * 1000; // 30 sec + @Autowired + private ApplicationContext ctx; + @Autowired(required = true) protected IConfiguration authConfig; @Autowired(required = true) @@ -76,31 +81,35 @@ public abstract class AbstractAuthenticationManager implements IAuthenticationMa protected IRevisionLogger revisionsLogger; @Autowired(required = false) protected ISsoManager ssoManager; - @Autowired + ModuleRegistration moduleRegistration; - /* - * (non-Javadoc) + @PostConstruct + private void initializer() { + moduleRegistration = ctx.getBean(ModuleRegistration.class); + + } + + /** + * Add a request parameter to whitelist. All parameters that are part of the + * white list are added into {@link ExecutionContext} * - * @see at.gv.egiz.eaaf.core.impl.idp.auth.IAuthenticationManager# - * addParameterNameToWhiteList(java.lang .String) + * @param httpReqParam http parameter name, but never null */ - @Override - public final void addParameterNameToWhiteList(final String httpReqParam) { + public static final void addParameterNameToWhiteList(final String httpReqParam) { if (StringUtils.isNotEmpty(httpReqParam)) { reqParameterWhiteListeForModules.add(httpReqParam); } } - /* - * (non-Javadoc) + /** + * Add a request header to whitelist. All parameters that are part of the white + * list are added into {@link ExecutionContext} * - * @see at.gv.egiz.eaaf.core.impl.idp.auth.IAuthenticationManager# - * addHeaderNameToWhiteList(java.lang. String) + * @param httpReqParam http header name, but never null */ - @Override - public final void addHeaderNameToWhiteList(final String httpReqParam) { + public static final void addHeaderNameToWhiteList(final String httpReqParam) { if (StringUtils.isNotEmpty(httpReqParam)) { reqHeaderWhiteListeForModules.add(httpReqParam.toLowerCase()); } @@ -348,7 +357,7 @@ public abstract class AbstractAuthenticationManager implements IAuthenticationMa if (processDefinitionId == null) { log.warn("No suitable process found for PendingReqId " + pendingReq.getPendingRequestId()); - throw new EaafException("process.02", new Object[] { pendingReq.getPendingRequestId() }); + throw new EaafException("process.02", null); } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java index 0834aa7c..db13bf71 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/RequestStorage.java @@ -69,10 +69,21 @@ public class RequestStorage implements IRequestStorage { // search invalid pending-request for errorHandling IRequest invalidPendingRequest = null; - try { + try { if (StringUtils.isNotEmpty(e.getInvalidInternalPendingReqId())) { + log.debug("Searching for expired pendingRequest with Id: {} ... ", e.getInvalidInternalPendingReqId()); invalidPendingRequest = transactionStorage.get(e.getInvalidInternalPendingReqId(), IRequest.class); + + // If pendingReq. was found, set transactionID and sessionID to Logger + TransactionIdUtils.setAllLoggingVariables(invalidPendingRequest); + + log.debug("{} expired pendingReq. Set it into Exception ...", + invalidPendingRequest != null ? "Find" : "Find NO "); + + } else { + log.debug("Get no internal pendingRequestId. Expired pendingRequest can not be set"); + } } catch (final EaafException e1) { @@ -213,7 +224,7 @@ public class RequestStorage implements IRequestStorage { throws EaafException { final IRequest pendingRequest = transactionStorage.get(internalPendingReqId, IRequest.class); if (pendingRequest == null) { - log.info("No PendingRequst found with pendingRequestID " + internalPendingReqId); + log.debug("No PendingRequst found with pendingRequestID " + internalPendingReqId); return null; } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java index c2f85fef..142dcf28 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/AbstractAuthenticationDataBuilder.java @@ -22,9 +22,9 @@ package at.gv.egiz.eaaf.core.impl.idp.auth.builder; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Collection; -import java.util.Map.Entry; +import java.util.HashSet; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -54,6 +54,7 @@ import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafParserException; import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; import at.gv.egiz.eaaf.core.exceptions.XPathException; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; @@ -72,9 +73,13 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati public static final String CONFIG_PROP_ENABLE_IDL_ATTRIBUTE_ESCAPEING = "configuration.bugfix.enable.idl.escaping"; - protected Collection<String> includedToGenericAuthData = null; + private static final String GENERIC_ATTR_CONTAINER = "processAuthParam;"; + @Autowired protected IConfigurationWithSP basicConfig; + + //protected ThreadLocal<Set<String>> includedToGenericAuthData = null; + @Override public IAuthData buildAuthenticationData(final IRequest pendingReq) @@ -137,7 +142,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati */ protected abstract void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) throws EaafException; - + /** * Add generic E-ID information into already existing AuthData. * @@ -169,7 +174,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati // includedToGenericAuthData = // authProcessData.getGenericSessionDataStorage().keySet(); // else - includedToGenericAuthData = new ArrayList<>(); + initializeThreadLocalVariable(authProcessData, new HashSet<>()); // #################################################### // set general authData info's @@ -204,24 +209,51 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati setCitizenCountryCode(internalAuthData, authProcessData); // set generic authProcessData to authdata - for (final Entry<String, Object> el : authProcessData.getGenericSessionDataStorage() - .entrySet()) { - if (el.getKey().startsWith(GENERIC_AUTHDATA_IDENTIFIER)) { - log.trace("Find generic authProcessData {}. Map it directly to authData", el.getKey()); - try { - internalAuthData.setGenericData(el.getKey(), el.getValue()); - - } catch (final EaafStorageException e) { - log.warn("Can NOT set authData with key: {}", el.getKey(), null, e); + authProcessData.getGenericSessionDataStream() + .filter(el -> el.getKey().startsWith(GENERIC_AUTHDATA_IDENTIFIER)) + .forEach(el -> { + log.trace("Find generic authProcessData {}. Map it directly to authData", el.getKey()); + try { + internalAuthData.setGenericData(el.getKey(), el.getValue()); - } + } catch (final EaafStorageException e) { + log.warn("Can NOT set authData with key: {}", el.getKey(), null, e); - } + } + }); + } + /** + * Initialize Thread-Local holder for generic attributes set in authenticated session. + * + * @param authProcessData Current authentication data holder + * @param data {@link Collection} of generic attribute-names + * @throws EaafAuthenticationException In case of an error + */ + protected void initializeThreadLocalVariable(@NonNull final IAuthProcessDataContainer authProcessData, + Set<String> data) + throws EaafAuthenticationException { + try { + authProcessData.setGenericDataToSession(GENERIC_ATTR_CONTAINER, data); + + } catch (EaafStorageException e) { + throw new EaafAuthenticationException("builder.11", new Object[] { e.getMessage() }, e); + } - + } - + + /** + * Initialize Thread-Local holder for generic attributes set in authenticated session. + * + * @param set {@link Collection} of generic attribute-names + */ + @SuppressWarnings("unchecked") + protected Set<String> getThreadLocalVariable(@NonNull final IAuthProcessDataContainer authProcessData) { + return authProcessData.getGenericDataFromSession(GENERIC_ATTR_CONTAINER, Set.class); + + } + /** * Parse citzen country-code into AuthData. * @@ -232,7 +264,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati */ private void setCitizenCountryCode(final AuthenticationData authData, final IAuthProcessDataContainer authProcessData) throws EaafAuthenticationException { - includedToGenericAuthData.remove(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME); final String pvpCccAttr = authProcessData .getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class); if (StringUtils.isNotEmpty(pvpCccAttr)) { @@ -265,7 +297,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati */ private void setQaaLevel(@NonNull final AuthenticationData authData, @NonNull final IAuthProcessDataContainer authProcessData) { - includedToGenericAuthData.remove(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME); String currentLoA = null; if (StringUtils.isNotEmpty(authProcessData.getQaaLevel())) { currentLoA = authProcessData.getQaaLevel(); @@ -331,9 +363,10 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati if (authProcessData.getGenericSessionDataStorage() != null && !authProcessData.getGenericSessionDataStorage().isEmpty()) { - includedToGenericAuthData = authProcessData.getGenericSessionDataStorage().keySet(); + initializeThreadLocalVariable(authProcessData, + authProcessData.getGenericSessionDataStorage().keySet()); } else { - includedToGenericAuthData = new ArrayList<>(); + initializeThreadLocalVariable(authProcessData, new HashSet<>()); } // #################################################### @@ -348,7 +381,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati IIdentityLink idlFromPvpAttr = null; final IIdentityLink identityLink = authProcessData.getIdentityLink(); if (identityLink != null) { - parseBasicUserInfosFromIdl(authData, identityLink, includedToGenericAuthData); + parseBasicUserInfosFromIdl(authData, identityLink, getThreadLocalVariable(authProcessData)); } else { // identityLink is not direct in MOASession @@ -362,7 +395,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati try { idlStream = new ByteArrayInputStream(Base64Utils.decodeFromString(pvpAttrIdl)); idlFromPvpAttr = new SimpleIdentityLinkAssertionParser(idlStream).parseIdentityLink(); - parseBasicUserInfosFromIdl(authData, idlFromPvpAttr, includedToGenericAuthData); + parseBasicUserInfosFromIdl(authData, idlFromPvpAttr, getThreadLocalVariable(authProcessData)); // set identitylink into AuthProcessData authProcessData.setIdentityLink(idlFromPvpAttr); @@ -375,7 +408,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati } finally { try { - includedToGenericAuthData.remove(PvpAttributeDefinitions.EID_IDENTITY_LINK_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.EID_IDENTITY_LINK_NAME); if (idlStream != null) { idlStream.close(); } @@ -403,11 +436,11 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati PvpAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME, String.class)); // remove corresponding keys from genericSessionData if exists - includedToGenericAuthData.remove(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME); - includedToGenericAuthData.remove(PvpAttributeDefinitions.GIVEN_NAME_NAME); - includedToGenericAuthData.remove(PvpAttributeDefinitions.BIRTHDATE_NAME); - includedToGenericAuthData.remove(PvpAttributeDefinitions.EID_SOURCE_PIN_NAME); - includedToGenericAuthData.remove(PvpAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.GIVEN_NAME_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.BIRTHDATE_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.EID_SOURCE_PIN_NAME); + getThreadLocalVariable(authProcessData).remove(PvpAttributeDefinitions.EID_SOURCE_PIN_TYPE_NAME); } } @@ -625,7 +658,7 @@ public abstract class AbstractAuthenticationDataBuilder implements IAuthenticati */ @Deprecated private void parseBasicUserInfosFromIdl(final AuthenticationData authData, - final IIdentityLink identityLink, final Collection<String> includedGenericSessionData) { + final IIdentityLink identityLink, final Set<String> includedGenericSessionData) { authData.setIdentificationValue(identityLink.getIdentificationValue()); authData.setIdentificationType(identityLink.getIdentificationType()); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BpkBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BpkBuilder.java deleted file mode 100644 index fed4af32..00000000 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/builder/BpkBuilder.java +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2014 Federal Chancellery Austria MOA-ID has been developed in a cooperation between - * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 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: http://www.osor.eu/eupl/ - * - * 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.core.impl.idp.auth.builder; - -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map.Entry; - -import javax.annotation.Nullable; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.util.Base64Utils; - -import at.gv.egiz.eaaf.core.api.data.EaafConstants; -import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; -import at.gv.egiz.eaaf.core.impl.data.Pair; -import lombok.extern.slf4j.Slf4j; - - -/** - * Builder for the bPK, as defined in - * <code>"Ableitung f¨r die bereichsspezifische Personenkennzeichnung"</code> - * version <code>1.0.1</code> from - * <code>"reference.e-government.gv.at"</code>. - * - */ -@Slf4j -public class BpkBuilder { - - private static final String ERROR_MSG_WRONG_TARGET_FORMAT = "bPK-target format must be full URI"; - - /** - * Calculates an area specific unique person-identifier from a baseID. - * - * @param baseID baseId from user but never null - * @param targetIdentifier target identifier for area specific identifier - * calculation but never null - * @return Pair consists of (unique person identifier for this target, - * targetArea) but never null - * @throws EaafBuilderException if some input data are not valid - */ - public static Pair<String, String> generateAreaSpecificPersonIdentifier(final String baseID, - final String targetIdentifier) throws EaafBuilderException { - return generateAreaSpecificPersonIdentifier(baseID, EaafConstants.URN_PREFIX_BASEID, - targetIdentifier); - - } - - /** - * Calculates an area specific unique person-identifier from an unique - * identifier with a specific type. - * - * @param baseID baseId from user but never null - * @param baseIdType Type of the baseID but never null - * @param targetIdentifier target identifier for area specific identifier - * calculation but never null - * @return Pair consists of (unique person identifier for this target, - * targetArea) but never null - * @throws EaafBuilderException if some input data are not valid - */ - public static Pair<String, String> generateAreaSpecificPersonIdentifier(final String baseID, - final String baseIdType, final String targetIdentifier) throws EaafBuilderException { - if (StringUtils.isEmpty(baseID)) { - throw new EaafBuilderException("builder.00", new Object[] { "baseID is empty or null" }, - "BaseId is empty or null"); - } - - if (StringUtils.isEmpty(baseIdType)) { - throw new EaafBuilderException("builder.00", - new Object[] { "the type of baseID is empty or null" }, "Type of baseId is empty or null"); - } - - if (StringUtils.isEmpty(targetIdentifier)) { - throw new EaafBuilderException("builder.00", - new Object[] { "SP specific target identifier is empty or null" }, - "SP specific target identifier is empty or null"); - } - - if (baseIdType.equals(EaafConstants.URN_PREFIX_BASEID)) { - log.trace("Find baseID. Starting unique identifier caluclation for this target"); - - if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_CDID)) { - log.trace("Calculate bPK identifier for target: " + targetIdentifier); - return Pair.newInstance(calculatebPKwbPK(baseID + "+" + targetIdentifier), - targetIdentifier); - - } else if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK)) { - log.trace("Calculate wbPK identifier for target: " + targetIdentifier); - return Pair.newInstance(calculatebPKwbPK( - baseID + "+" + normalizeBpkTargetIdentifierToCalculationFormat(targetIdentifier)), - normalizeBpkTargetIdentifierToCommonFormat(targetIdentifier)); - - } else if (targetIdentifier.startsWith(EaafConstants.URN_PREFIX_EIDAS)) { - log.trace("Calculate eIDAS identifier for target: " + targetIdentifier); - final String[] splittedTarget = targetIdentifier.split("\\+"); - final String cititzenCountryCode = splittedTarget[1]; - final String eidasOutboundCountry = splittedTarget[2]; - - if (cititzenCountryCode.equalsIgnoreCase(eidasOutboundCountry)) { - log.warn("Suspect configuration FOUND!!! CitizenCountry equals DestinationCountry"); - - } - return buildEidasIdentifer(baseID, baseIdType, cititzenCountryCode, eidasOutboundCountry); - - } else { - throw new EaafBuilderException("builder.00", - new Object[] { "Target identifier: " + targetIdentifier + " is NOT allowed or unknown" }, - "Target identifier: " + targetIdentifier + " is NOT allowed or unknown"); - } - - } else { - log.trace("BaseID is not of type " + EaafConstants.URN_PREFIX_BASEID - + ". Check type against requested target ..."); - if (baseIdType.equals(targetIdentifier)) { - log.debug("Unique identifier is already area specific. Is nothing todo"); - return Pair.newInstance(baseID, targetIdentifier); - - } else { - log.warn("Get unique identifier for target: " + baseIdType + " but target: " - + targetIdentifier + " is required!"); - throw new EaafBuilderException("builder.00", - new Object[] { "Get unique identifier for target: " + baseIdType + " but target: " - + targetIdentifier + " is required" }, - "Get unique identifier for target: " + baseIdType + " but target: " + targetIdentifier - + " is required"); - - } - } - } - - - - /** - * Create an encrypted bPK. - * - * @param bpk unencrypted bPK - * @param target bPK target in full form - * @param publicKey Public-Key used for encryption - * @return encrypted bPK - * @throws EaafBuilderException In case of an error - */ - public static String encryptBpk(final String bpk, String target, final PublicKey publicKey) - throws EaafBuilderException { - final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - - if (!target.startsWith(EaafConstants.URN_PREFIX_WITH_COLON)) { - throw new EaafBuilderException("builder.32", - null, ERROR_MSG_WRONG_TARGET_FORMAT); - - } - - target = normalizeBpkTargetIdentifierToCalculationFormat(target); - - final String input = - "V1::" + target + "::" + bpk + "::" + sdf.format(new Date()); - // System.out.println(input); - byte[] result; - try { - final byte[] inputBytes = input.getBytes("ISO-8859-1"); - result = encrypt(inputBytes, publicKey); - return new String(Base64Utils.encode(result), "ISO-8859-1").replaceAll("\r\n", ""); - // return new String(Base64Utils.encode(result, - // "ISO-8859-1")).replaceAll("\r\n", ""); - - } catch (final Exception e) { - throw new EaafBuilderException("bPK encryption FAILED", null, e.getMessage(), e); - - } - } - - /** - * Decrypt an encrypted bPK. - * - * @param encryptedBpk encrypted bPK - * @param target bPK target in full form - * @param privateKey private-key for decryption - * @return bPK Pair consists of (unique person identifier for this target, - * targetArea) but never null - * @throws EaafBuilderException In case of an error - */ - public static Pair<String, String> decryptBpk(final String encryptedBpk, String target, - final PrivateKey privateKey) throws EaafBuilderException { - String decryptedString; - - if (!target.startsWith(EaafConstants.URN_PREFIX_WITH_COLON)) { - throw new EaafBuilderException("builder.32", - null, ERROR_MSG_WRONG_TARGET_FORMAT); - - } - - try { - final byte[] encryptedBytes = Base64Utils.decode(encryptedBpk.getBytes("ISO-8859-1")); - final byte[] decryptedBytes = decrypt(encryptedBytes, privateKey); - decryptedString = new String(decryptedBytes, "ISO-8859-1"); - - } catch (final Exception e) { - throw new EaafBuilderException("bPK decryption FAILED", null, e.getMessage(), e); - - } - - String[] parts = decryptedString.split("::"); - if (parts.length != 4) { - log.trace("Encrypted bPK has value: {}", decryptedString); - throw new EaafBuilderException("builder.31", new Object[] {parts.length}, - "encBpk has a suspect format"); - - } - - final String sector = parts[1]; - final String bPK = parts[2]; - - if (target.equals(normalizeBpkTargetIdentifierToCommonFormat(sector))) { - return Pair.newInstance(bPK, target); - - } else { - throw new EaafBuilderException("builder.30", new Object[] {sector, target}, - "Decrypted bPK-target does not match"); - - } - } - - /** - * Normalize wbPK target identifier for FN, ZVR, and ERSB to XFN, XZVR, and XERSB. - * - * <p>If the target is not of this types the target will be returned as it is</p> - * @param targetIdentifier bPK input target - * @return XFN, XZVR, XERSB, or targetIdentfier if no normalization is required - */ - @Nullable - public static String normalizeBpkTargetIdentifierToCommonFormat(@Nullable String targetIdentifier) { - if (targetIdentifier != null - && !targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X)) { - for (Entry<String, String> mapper : EaafConstants.URN_WBPK_TARGET_X_TO_NONE_MAPPER.entrySet()) { - if (targetIdentifier.startsWith(mapper.getValue())) { - String wbpkTarget = mapper.getKey() + targetIdentifier.substring(mapper.getValue().length()); - log.trace("Normalize wbPK target: {} to {}", targetIdentifier, wbpkTarget); - return wbpkTarget; - - } - } - } - - return targetIdentifier; - } - - /** - * Normalize wbPK target identifier for XFN, XZVR, and XERSB to bPK calculation format like, FN, ZVR, and ERSB. - * - * <p>If the target is not of this types the target will be returned as it is</p> - * - * @param targetIdentifier bPK input target - * @return FN, ZVR, ERSB, or targetIdentfier if no normalization is required - */ - @Nullable - public static String normalizeBpkTargetIdentifierToCalculationFormat(@Nullable String targetIdentifier) { - if (targetIdentifier != null && targetIdentifier.startsWith(EaafConstants.URN_PREFIX_WBPK)) { - for (Entry<String, String> mapper : EaafConstants.URN_WBPK_TARGET_X_TO_NONE_MAPPER.entrySet()) { - if (targetIdentifier.startsWith(mapper.getKey())) { - String wbpkTarget = mapper.getValue() + targetIdentifier.substring(mapper.getKey().length()); - log.trace("Find new wbPK target: {}. Replace it by: {}", targetIdentifier, wbpkTarget); - return wbpkTarget; - - } - } - } - - return targetIdentifier; - } - - /** - * Builds the eIDAS from the given parameters. - * - * @param baseId baseID of the citizen - * @param baseIdType Type of the baseID - * @param sourceCountry CountryCode of that country, which build the eIDAs - * ID - * @param destinationCountry CountryCode of that country, which receives the - * eIDAs ID - * - * @return Pair eIDAs/bPKType in a BASE64 encoding - * @throws EaafBuilderException if some input data are not valid - */ - private static Pair<String, String> buildEidasIdentifer(final String baseId, - final String baseIdType, final String sourceCountry, final String destinationCountry) - throws EaafBuilderException { - String bpk = null; - String bpkType = null; - - // check if we have been called by public sector application - if (baseIdType.startsWith(EaafConstants.URN_PREFIX_BASEID)) { - bpkType = EaafConstants.URN_PREFIX_EIDAS + sourceCountry + "+" + destinationCountry; - log.debug("Building eIDAS identification from: [identValue]+" + bpkType); - bpk = calculatebPKwbPK(baseId + "+" + bpkType); - - } else { // if not, sector identification value is already calculated by BKU - log.debug("eIDAS eIdentifier already provided by BKU"); - bpk = baseId; - } - - if (StringUtils.isEmpty(bpk) || StringUtils.isEmpty(sourceCountry) - || StringUtils.isEmpty(destinationCountry)) { - throw new EaafBuilderException("builder.00", - new Object[] { "eIDAS-ID", - "Unvollständige Parameterangaben: identificationValue=" + bpk + ", Zielland=" - + destinationCountry + ", Ursprungsland=" + sourceCountry }, - "eIDAS-ID: Unvollständige Parameterangaben: identificationValue=" + bpk + ", Zielland=" - + destinationCountry + ", Ursprungsland=" + sourceCountry); - } - - log.trace("eIDAS pseudonym generation finished. "); - final String eIdentifier = sourceCountry + "/" + destinationCountry + "/" + bpk; - - return Pair.newInstance(eIdentifier, bpkType); - } - - private static String calculatebPKwbPK(final String basisbegriff) throws EaafBuilderException { - try { - final MessageDigest md = MessageDigest.getInstance("SHA-1"); - final byte[] hash = md.digest(basisbegriff.getBytes("ISO-8859-1")); - final String hashBase64 = - new String(Base64Utils.encode(hash), "ISO-8859-1").replaceAll("\r\n", ""); // Base64Utils.encode(hash); - return hashBase64; - - } catch (final Exception ex) { - throw new EaafBuilderException("builder.00", new Object[] { "bPK/wbPK", ex.toString() }, - ex.getMessage(), ex); - - } - - } - - private static byte[] encrypt(final byte[] inputBytes, final PublicKey publicKey) - throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException { - byte[] result; - Cipher cipher = null; - try { - cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle - - } catch (final NoSuchAlgorithmException e) { - cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider - } - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - result = cipher.doFinal(inputBytes); - - return result; - } - - private static byte[] decrypt(final byte[] encryptedBytes, final PrivateKey privateKey) - throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException { - byte[] result; - Cipher cipher = null; - try { - cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // try with bouncycastle - - } catch (final NoSuchAlgorithmException e) { - cipher = Cipher.getInstance("RSA/ECB/OAEP"); // try with iaik provider - - } - cipher.init(Cipher.DECRYPT_MODE, privateKey); - result = cipher.doFinal(encryptedBytes); - return result; - - } -} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java index 8eef4a8e..368652be 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/AuthProcessDataWrapper.java @@ -22,9 +22,11 @@ package at.gv.egiz.eaaf.core.impl.idp.auth.data; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.TimeZone; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Nullable; @@ -264,16 +266,20 @@ public class AuthProcessDataWrapper * getGenericSessionDataStorage() */ @Override - public Map<String, Object> getGenericSessionDataStorage() { - final Map<String, Object> result = new HashMap<>(); - for (final Map.Entry<String, Object> el : authProcessData.entrySet()) { - if (el.getKey().startsWith(GENERIC_PREFIX)) { - result.put(el.getKey().substring(GENERIC_PREFIX.length()), el.getValue()); - } - - } - - return result; + public Map<String, Object> getGenericSessionDataStorage() { + return authProcessData.entrySet().stream() + .filter(el -> el.getKey().startsWith(GENERIC_PREFIX)) + .collect( + Collectors.toMap( + el -> el.getKey().substring(GENERIC_PREFIX.length()), + value -> value.getValue())); + + } + + @Override + public Stream<Entry<String, Object>> getGenericSessionDataStream() { + return getGenericSessionDataStorage().entrySet().stream(); + } /* diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/EidAuthProcessDataWrapper.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/EidAuthProcessDataWrapper.java new file mode 100644 index 00000000..48a2206b --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/EidAuthProcessDataWrapper.java @@ -0,0 +1,34 @@ +package at.gv.egiz.eaaf.core.impl.idp.auth.data; + +import java.util.Map; + +import at.gv.egiz.eaaf.core.api.idp.auth.data.IEidAuthProcessData; + +/** + * Authentication session-data that adds ID Austria specific information. + * + * @author tlenz + * + */ +public class EidAuthProcessDataWrapper extends AuthProcessDataWrapper implements IEidAuthProcessData { + + private static final String VALUE_INTERNAL_TEST_IDENTITY_PROCESS = "direct_is_testidentity"; + + public EidAuthProcessDataWrapper(Map<String, Object> authProcessData) { + super(authProcessData); + + } + + @Override + public boolean isTestIdentity() { + return wrapStoredObject(VALUE_INTERNAL_TEST_IDENTITY_PROCESS, false, Boolean.class); + + } + + @Override + public void setTestIdentity(boolean flag) { + authProcessData.put(VALUE_INTERNAL_TEST_IDENTITY_PROCESS, flag); + + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java index ee1037a1..8327b544 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/data/IdentityLink.java @@ -23,15 +23,20 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Serializable; import java.security.PublicKey; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import javax.xml.transform.TransformerException; -import org.w3c.dom.Element; - import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.impl.utils.DomUtils; import at.gv.egiz.eaaf.core.impl.utils.XPathUtils; +import org.w3c.dom.Element; + +import lombok.extern.slf4j.Slf4j; + /** * Data contained in an identity link issued by BMI, relevant to the MOA ID * component. <br> @@ -41,10 +46,13 @@ import at.gv.egiz.eaaf.core.impl.utils.XPathUtils; * @author Paul Ivancsics * @version $Id$ */ +@Slf4j public class IdentityLink implements Serializable, IIdentityLink { private static final long serialVersionUID = 1L; + public static final String PATTERN_ISSUE_INSTANT = "yyyy-MM-dd'T'HH:mm:ssXXX"; + /** * <code>"identificationValue"</code> is the translation of * <code>"Stammzahl"</code>. @@ -372,6 +380,23 @@ public class IdentityLink implements Serializable, IIdentityLink { return issueInstant; } + @Override + public Date getIssueInstantDate() { + final SimpleDateFormat f = new SimpleDateFormat(PATTERN_ISSUE_INSTANT); + try { + if (issueInstant != null) { + return f.parse(issueInstant); + + } + + } catch (final ParseException e) { + log.error("Can NOT parse Date from String: {}", issueInstant, null, e); + + } + + return null; + } + /* * (non-Javadoc) * diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java index 3d093a9f..5b5d0aa8 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/AbstractAuthServletTask.java @@ -45,6 +45,7 @@ import org.springframework.core.io.ResourceLoader; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.IRequestStorage; import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.EaafEventCodes; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.services.IProtocolAuthenticationService; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; @@ -155,6 +156,36 @@ public abstract class AbstractAuthServletTask extends AbstractTask { } /** + * Stopping the current authentication process by User decision. + * + * @param executionContext Current execution context + * @param request Http request + * @param response Http response + * @throws TaskExecutionException In case of an error during process-stopping + */ + protected void stopProcessFromUserDecision(final ExecutionContext executionContext, + final HttpServletRequest request, final HttpServletResponse response) + throws TaskExecutionException { + try { + revisionsLogger.logEvent(pendingReq, EaafEventCodes.PROCESS_STOPPED_BY_USER); + pendingReq.setAbortedByUser(true); + pendingReq.setAuthenticated(false); + performRedirectToProtocolFinialization(executionContext, pendingReq, request, response); + + log.trace("Set process-cancelation flag"); + executionContext.setCanceleProcessFlag(); + + } catch (final EaafException e) { + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } catch (final Exception e) { + log.warn("Stopping auth.process FAILED", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + } + + /** * Parses the request input stream for parameters, assuming parameters are * encoded UTF-8 (no standard exists how browsers should encode them). * @@ -268,4 +299,21 @@ public abstract class AbstractAuthServletTask extends AbstractTask { return url + "&" + param; } } + + /** + * Get a {@link Boolean} parameter from http request. + * + * @param httpReq http Request object + * @param paramName http Parameter name + * @return <code>true</code> if the parameter exists and the <code>Boolean.parseBoolean(value)</code> + * evaluates to <code>true</code>, otherwise <code>false</code> + */ + protected boolean evaluteBooleanReqParam(final HttpServletRequest httpReq, final String paramName) { + final String value = httpReq.getParameter(paramName); + if (value != null) { + return Boolean.parseBoolean(value); + } else { + return false; + } + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java index c4f1b505..c1593cb1 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/modules/ModuleRegistration.java @@ -100,7 +100,7 @@ public class ModuleRegistration { */ private void initSpringModules() { log.debug("Discovering Spring modules."); - final Map<String, AuthModule> modules = ctx.getBeansOfType(AuthModule.class); + final Map<String, AuthModule> modules = ctx.getBeansOfType(AuthModule.class); for (final AuthModule module : modules.values()) { registerModuleProcessDefinitions(module); priorizedModules.add(module); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/DefaultErrorService.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/DefaultErrorService.java new file mode 100644 index 00000000..e41905a6 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/DefaultErrorService.java @@ -0,0 +1,111 @@ +package at.gv.egiz.eaaf.core.impl.idp.auth.services; + +import java.text.MessageFormat; +import java.util.HashSet; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; + +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import lombok.Builder; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DefaultErrorService implements IErrorService { + private static final String TECH_LOG_MSG = "errorCode={0} Message={1}"; + private static final String CONFIG_PROP_LOGGER_ON_INFO_LEVEL = "core.logging.level.info.errorcodes"; + + @Autowired IConfiguration basicConfig; + @Autowired IStatusMessenger statusMessager; + + private final HashSet<String> logOnInfoLevel = new HashSet<>(); + + @Override + public String getExternalCodeFromInternal(String internalCode) { + return statusMessager.mapInternalErrorToExternalError(internalCode); + + } + + @Override + public IHandleData createHandleData(Throwable throwable, boolean supportRedirctToSp) throws EaafException { + String internalErrorId = extractInternalErrorCode(throwable); + + return HandleData.builder() + .throwable(throwable) + .internalErrorCode(internalErrorId) + .actionType(ActionType.NO_TICKET) + .logLevel(logOnInfoLevel.contains(internalErrorId) ? LogLevel.INFO : LogLevel.WARN) + .build(); + + } + + @Override + public void displayErrorData(ModifyableGuiBuilderConfiguration c, IHandleData errorData, + HttpServletRequest httpReq) throws EaafException { + log.trace("Do nothing because Tickets are not supported by: {}", DefaultErrorService.class.getName()); + + } + + private String extractInternalErrorCode(Throwable throwable) { + Throwable originalException; + if (throwable instanceof TaskExecutionException + && ((TaskExecutionException) throwable).getOriginalException() != null) { + originalException = ((TaskExecutionException) throwable).getOriginalException(); + + } else { + originalException = throwable; + + } + + if (!(originalException instanceof EaafException)) { + return IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC; + + } else { + return ((EaafException) originalException).getErrorId(); + + } + } + + @PostConstruct + private void initialize() throws EaafException { + log.info("initErrorTicketService"); + + logOnInfoLevel.addAll(KeyValueUtils.getListOfCsvValues( + basicConfig.getBasicConfiguration(CONFIG_PROP_LOGGER_ON_INFO_LEVEL))); + log.info("Set errorCodes={} to LogLevel:INFO", String.join(",", logOnInfoLevel)); + + } + + @Builder + static class HandleData implements IHandleData { + + @Getter + private String errorIdTokenForRedirect; + + @Getter + private final Throwable throwable; + + @Getter + private String internalErrorCode; + + @Getter + private ActionType actionType; + + @Getter + private LogLevel logLevel; + + public String getPreFormatedErrorMessage() { + return MessageFormat.format(TECH_LOG_MSG, internalErrorCode, throwable.getMessage()); + + } + + } +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/IErrorService.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/IErrorService.java new file mode 100644 index 00000000..b6bc1056 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/IErrorService.java @@ -0,0 +1,164 @@ +package at.gv.egiz.eaaf.core.impl.idp.auth.services; + +import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; + +import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +public interface IErrorService { + + /** + * Describes the kind of action that should be taken. + */ + enum ActionType { + TICKET("ticket"), NO_TICKET("no_ticket"), ERRORPAGE("errorpage"); + + private final String name; + + ActionType(final String text) { + this.name = text; + } + + + /** + * Get flow type for error-handling from String representation. + * + * @param s Config parameter + * @return Error-handling flow + */ + public static ActionType fromString(final String s) { + try { + return ActionType.valueOf(s.toUpperCase()); + + } catch (IllegalArgumentException | NullPointerException e) { + return null; + + } + } + + @Override + public String toString() { + return name; + } + } + + /** + * Defines the LogLevel for this types of errors. + */ + enum LogLevel { + ERROR("error"), WARN("warn"), INFO("info"), DEBUG("debug"); + + private final String level; + + LogLevel(final String logLevel) { + this.level = logLevel; + + } + + + /** + * Get the log-level from String representation. + * + * @param s Config parameter + * @return Log-Level from configuration or ERROR as backup + */ + public static LogLevel fromString(final String s) { + try { + return LogLevel.valueOf(s.toUpperCase()); + + } catch (IllegalArgumentException | NullPointerException e) { + return LogLevel.ERROR; + + } + } + + @Override + public String toString() { + return level; + } + + } + + String PARAM_GUI_TICKET = "supportTicket"; + String PARAM_GUI_REDIRECT = "redirectLink"; + + /** + * Maps internal error codes to external ones. + * @param internalCode internal error code + * @return external error code + */ + @Nonnull + String getExternalCodeFromInternal(@Nonnull String internalCode); + + /** + * Creates error handling data. + * + * @param throwable Error that should be handled + * @param supportRedirctToSp <code>true</code> if the current process-state supports redirect + * to Service-Provider, otherwise <code>false</code> + * @return Information how the error should be handled + * @throws EaafException In case of an internal error + */ + @Nonnull + IHandleData createHandleData(@Nonnull Throwable throwable, boolean supportRedirctToSp) throws EaafException; + + /** + * Displays the error using suitable errordata. + * + * @param c guibuilder + * @param errorData Data to handle + * @param httpReq Current HTTP request + * @throws EaafException In case of an internal error + */ + void displayErrorData(@Nonnull ModifyableGuiBuilderConfiguration c, @Nonnull IErrorService.IHandleData errorData, + @Nonnull HttpServletRequest httpReq) throws EaafException; + + /** + * Contains all the Model data for Error Handling. + */ + interface IHandleData { + + /** + * Get a new pendingReqId that can be used to store the error for SP forwarding. + * + * @return errorToken as pendingRequest + */ + String getErrorIdTokenForRedirect(); + + /** + * Describes the kind of action that should be taken. + * + * @return The appropriate action + */ + ActionType getActionType(); + + /** + * Get internal errorCode describing the problem. + * + * @return internal error Code. + */ + String getInternalErrorCode(); + + /** + * Get the original throwable of the error. + * + * @return causing throwable + */ + Throwable getThrowable(); + + /** + * Get the log-level for this internal errorId. + * + * @return Level to Log the error + */ + LogLevel getLogLevel(); + + /** + * Get pre-formated text for log message. + * + * @return log message + */ + String getPreFormatedErrorMessage(); + } +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java index 5f84d118..ca2c92b1 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/auth/services/ProtocolAuthenticationService.java @@ -15,16 +15,13 @@ * 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.core.impl.idp.auth.services; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Arrays; -import java.util.List; +import javax.annotation.PostConstruct; import javax.naming.ConfigurationException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -32,6 +29,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringEscapeUtils; +import org.owasp.encoder.Encode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -39,12 +37,14 @@ import org.springframework.context.ApplicationContext; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; +import org.springframework.util.SerializationUtils; import at.gv.egiz.components.eventlog.api.EventConstants; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.IRequestStorage; import at.gv.egiz.eaaf.core.api.IStatusMessenger; import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; import at.gv.egiz.eaaf.core.api.gui.IGuiFormBuilder; @@ -60,6 +60,7 @@ import at.gv.egiz.eaaf.core.api.idp.auth.services.IProtocolAuthenticationService import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; @@ -72,6 +73,9 @@ import at.gv.egiz.eaaf.core.exceptions.ProtocolNotActiveException; import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.gui.AbstractGuiFormBuilderConfiguration; import at.gv.egiz.eaaf.core.impl.http.HttpUtils; +import at.gv.egiz.eaaf.core.impl.idp.auth.services.IErrorService.ActionType; +import at.gv.egiz.eaaf.core.impl.idp.auth.services.IErrorService.IHandleData; +import at.gv.egiz.eaaf.core.impl.idp.auth.services.IErrorService.LogLevel; import at.gv.egiz.eaaf.core.impl.idp.controller.ProtocolFinalizationController; import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; import at.gv.egiz.eaaf.core.impl.utils.ServletUtils; @@ -80,9 +84,6 @@ import at.gv.egiz.eaaf.core.impl.utils.ServletUtils; public class ProtocolAuthenticationService implements IProtocolAuthenticationService { private static final Logger log = LoggerFactory.getLogger(ProtocolAuthenticationService.class); - private static final List<String> ERROR_LOGGER_ON_INFO_LEVEL = - Arrays.asList(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP); - @Autowired(required = true) private ApplicationContext applicationContext; @Autowired(required = true) @@ -98,13 +99,21 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer @Autowired(required = true) IPendingRequestIdGenerationStrategy pendingReqIdGenerationStrategy; + @Autowired(required = true) + private IErrorService errorTicketService; + @Autowired(required = false) private ISsoManager ssoManager; + @Autowired private IStatisticLogger statisticLogger; + @Autowired private IRevisionLogger revisionsLogger; + @Autowired(required = true) + protected ITransactionStorage transactionStorage; + private IGuiFormBuilder guiBuilder; /* @@ -130,8 +139,7 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer final ISpConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); if (oaParam == null) { - throw new EaafAuthenticationException( - IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG, + throw new EaafAuthenticationException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOSPCONFIG, new Object[] { pendingReq.getSpEntityId() }); } @@ -142,8 +150,8 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer finalizeAuthentication(req, resp, pendingReq); // transaction is finished, log transaction finished event - revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, - pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq + .getUniqueTransactionIdentifier()); } @@ -170,7 +178,7 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer @Override public void finalizeAuthentication(final HttpServletRequest req, final HttpServletResponse resp, final IRequest pendingReq) throws EaafException, IOException { - log.debug("Finalize PendingRequest with ID " + pendingReq.getPendingRequestId()); + log.debug("Finalize PendingRequest with ID={} ", pendingReq.getPendingRequestId()); try { // check if pending-request has 'abortedByUser' flag set @@ -178,15 +186,8 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer // send authentication aborted error to Service Provider buildProtocolSpecificErrorResponse( new EaafAuthenticationException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_USERSTOP, - new Object[] {}), - req, resp, pendingReq); - - // do not remove the full active SSO-Session - // in case of only one Service-Provider authentication request is aborted - if (!pendingReq.needSingleSignOnFunctionality()) { - requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); - - } + new Object[] {}), req, + resp, pendingReq); // check if pending-request are authenticated } else if (pendingReq.isAuthenticated() && !pendingReq.isNeedUserConsent()) { @@ -194,11 +195,12 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer } else { // suspect state: pending-request is not aborted but also are not authenticated - log.warn("PendingRequest flag for 'authenticated':{} and 'needConsent':{}", - pendingReq.isAuthenticated(), pendingReq.isNeedUserConsent()); + log.warn("PendingRequest flag for 'authenticated':{} and 'needConsent':{}", pendingReq + .isAuthenticated(), + pendingReq.isNeedUserConsent()); if (pendingReq.isNeedUserConsent()) { - log.error( - "PendingRequest NEEDS user-consent. Can NOT fininalize authentication --> Abort authentication process!"); + log.error("PendingRequest NEEDS user-consent. " + + "Can NOT fininalize authentication --> Abort authentication process!"); } else { log.error("PendingRequest is NOT authenticated --> Abort authentication process!"); @@ -210,66 +212,106 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer } } catch (final Exception e) { - log.error("Finalize authentication protocol FAILED.", e); + log.info("Finalize authentication protocol FAILED. Reason: {}", e.getMessage()); buildProtocolSpecificErrorResponse(e, req, resp, pendingReq); + } finally { + // remove pending-request + requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq + .getUniqueTransactionIdentifier()); } - // remove pending-request - requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); - revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, - pendingReq.getUniqueTransactionIdentifier()); - } @Override - public void buildProtocolSpecificErrorResponse(final Throwable throwable, - final HttpServletRequest req, final HttpServletResponse resp, final IRequest protocolRequest) - throws EaafException, IOException { + public void buildProtocolSpecificErrorResponse(final Throwable throwable, final HttpServletRequest req, + final HttpServletResponse resp, final IRequest protocolRequest) throws EaafException, IOException { try { + + final IErrorService.IHandleData errorData = errorTicketService.createHandleData(throwable, true); - final Class<?> clazz = Class.forName(protocolRequest.requestedModule()); - - if (clazz == null || !IModulInfo.class.isAssignableFrom(clazz)) { - log.error( - "Requested protocol module Class is NULL or does not implement the IModulInfo interface."); - throw new Exception( - "Requested protocol module Class is NULL or does not implement the IModulInfo interface."); + // log Error to technical log + logExceptionToTechnicalLog(errorData); - } - - final IModulInfo handlingModule = (IModulInfo) applicationContext.getBean(clazz); + // log Error Message + statisticLogger.logErrorOperation(throwable, protocolRequest); + + // write revision log entries + revisionsLogger.logEvent(protocolRequest, EventConstants.TRANSACTION_ERROR, + protocolRequest.getUniqueTransactionIdentifier()); + + if (ActionType.TICKET.equals(errorData.getActionType()) + || ActionType.ERRORPAGE.equals(errorData.getActionType())) { + + if (errorData.getErrorIdTokenForRedirect() != null) { + // Put pending request + final ExceptionContainer exceptionContainer = new ExceptionContainer(protocolRequest, throwable); + final byte[] serialized = SerializationUtils.serialize(exceptionContainer); + log.debug("Put error into cache to support SP forwarding ... "); + String internalErrorToken = pendingReqIdGenerationStrategy.getPendingRequestIdWithOutChecks( + errorData.getErrorIdTokenForRedirect()); + log.trace("errorIdToken: {}", internalErrorToken); + transactionStorage.put(internalErrorToken, serialized, -1); + + } else { + log.debug("No errorTokenId. Forwarding to SP will not be available"); + + } - if (handlingModule.generateErrorMessage(throwable, req, resp, protocolRequest)) { + // render GUI + displayException(req, resp, errorData); - // log Error to technical log - logExceptionToTechnicalLog(throwable); + } else { + final IModulInfo handlingModule = extractShibbolethHandling(protocolRequest, applicationContext); + if (handlingModule.generateErrorMessage(throwable, req, resp, protocolRequest)) { + log.debug("Error-response to SP successfully written"); - // log Error Message - statisticLogger.logErrorOperation(throwable, protocolRequest); + } else { + log.info("Error-response to SP FAILED. Writing error message into GUI ... "); + displayException(req, resp, errorData); - // write revision log entries - revisionsLogger.logEvent(protocolRequest, EventConstants.TRANSACTION_ERROR, - protocolRequest.getUniqueTransactionIdentifier()); + } + } - return; + } catch (final Throwable e) { + // if building error response results in error, we try with with + // handleErrorNoRedirect + log.error("ErrorHandling has an internel error. Show process-error in GUI ... ", e); + handleErrorNoRedirect(throwable, req, resp, false); - } else { - handleErrorNoRedirect(throwable, req, resp, true); + } + } - } + /** + * Retrieves shibboleth module info. + * + * @param protocolRequest current request + * @param applicationContext spring context + * @return IModulInfo + * @throws ClassNotFoundException If no shibboleth handling implementation found + */ + public static IModulInfo extractShibbolethHandling(IRequest protocolRequest, + ApplicationContext applicationContext) + throws ClassNotFoundException { + final Class<?> clazz = Class.forName(protocolRequest.requestedModule()); - } catch (final Throwable e) { - handleErrorNoRedirect(throwable, req, resp, true); + if (clazz == null || !IModulInfo.class.isAssignableFrom(clazz)) { + log.error("Requested protocol module Class is NULL or does not implement the IModulInfo interface."); + throw new ClassCastException( + "Requested protocol module Class is NULL or does not implement the IModulInfo interface."); } + return (IModulInfo) applicationContext.getBean(clazz); } @Override public void handleErrorNoRedirect(final Throwable throwable, final HttpServletRequest req, - final HttpServletResponse resp, final boolean writeExceptionToStatisticLog) - throws IOException, EaafException { + final HttpServletResponse resp, final boolean writeExceptionToStatisticLog) throws EaafException, + IOException { + + final IErrorService.IHandleData errorData = errorTicketService.createHandleData(throwable, false); // log Exception into statistic database if (writeExceptionToStatisticLog) { @@ -277,61 +319,61 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer } // write errror to console - logExceptionToTechnicalLog(throwable); + logExceptionToTechnicalLog(errorData); + + // render GUI + displayException(req, resp, errorData); + + } + + private void logExceptionToTechnicalLog(IHandleData errorData) { + // In case of a TaskExecutionException, which is only a container for + // process-errors, + // extract internal exception + + // Log exception + if (!(errorData.getThrowable() instanceof EaafException) + || LogLevel.ERROR.equals(errorData.getLogLevel())) { + log.error(errorData.getPreFormatedErrorMessage(), errorData.getThrowable()); + + } else if (LogLevel.WARN.equals(errorData.getLogLevel())) { + log.warn(errorData.getPreFormatedErrorMessage(), errorData.getThrowable()); + + } else if (LogLevel.INFO.equals(errorData.getLogLevel())) { + log.info(errorData.getPreFormatedErrorMessage(), errorData.getThrowable()); + + } else if (LogLevel.DEBUG.equals(errorData.getLogLevel())) { + log.debug(errorData.getPreFormatedErrorMessage(), errorData.getThrowable()); - // return error to Web browser - if (throwable instanceof EaafException || throwable instanceof ProcessExecutionException) { - internalMoaidExceptionHandler(req, resp, (Exception) throwable, false); } else { - // write generic message for general exceptions - final String msg = - statusMessager.getMessage(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC, null); - writeHtmlErrorResponse(req, resp, msg, "9199", null, (Exception) throwable); + log.warn("Get unsupported LogLevelType: {}. Use {} as default", + errorData.getLogLevel(), LogLevel.ERROR); + log.error(errorData.getPreFormatedErrorMessage(), errorData.getThrowable()); } - } @Override public void forwardToErrorHandler(Pair<IRequest, Throwable> errorToHandle, String errorKey, final HttpServletRequest req, final HttpServletResponse resp) throws GuiBuildException { - IGuiBuilderConfiguration parentHopGuiConfig = - evaluateRequiredErrorHandlingMethod(errorToHandle.getFirst(), errorKey); + final IGuiBuilderConfiguration parentHopGuiConfig = evaluateRequiredErrorHandlingMethod(errorToHandle + .getFirst(), + errorKey); if (parentHopGuiConfig != null) { log.trace("iFrame to parent hop requested. Building GUI step for error handling ... "); guiBuilder.build(req, resp, parentHopGuiConfig, "iFrame-to-parent"); - - } else { + + } else { // build up redirect URL final String redirectUrl = generateErrorRedirectUrl(req, errorKey); resp.setContentType("text/html"); resp.setStatus(302); resp.addHeader("Location", redirectUrl); - log.debug("REDIRECT TO: " + redirectUrl); - + log.debug("REDIRECT TO: {}", redirectUrl); + } } - - private IGuiBuilderConfiguration evaluateRequiredErrorHandlingMethod(IRequest first, String errorId) { - if (first != null && first.isProcessInIframe()) { - return guiConfigFactory.getDefaultIFrameParentHopGui(first, - "/" + ProtocolFinalizationController.ENDPOINT_ERRORHANDLING, - errorId); - - } - return null; - } - - private String generateErrorRedirectUrl(final HttpServletRequest req, String errorKey) { - String redirectUrl = null; - redirectUrl = ServletUtils.getBaseUrl(req); - redirectUrl += "/" + ProtocolFinalizationController.ENDPOINT_ERRORHANDLING + "?" - + EaafConstants.PARAM_HTTP_ERROR_CODE + "=" + errorKey; - return redirectUrl; - - } - public void setGuiBuilder(final IGuiFormBuilder guiBuilder) { this.guiBuilder = guiBuilder; } @@ -339,15 +381,14 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer /** * Finalize the requested protocol operation. * - * @param httpReq HttpServletRequest - * @param httpResp HttpServletResponse - * @param protocolRequest Authentication request which is actually in process - * @param moaSession MOASession object, which is used to generate the - * protocol specific authentication information + * @param req HttpServletRequest + * @param resp HttpServletResponse + * @param pendingReq Authentication request which is actually in process * @throws Exception In case of an error */ protected void internalFinalizeAuthenticationProcess(final HttpServletRequest req, - final HttpServletResponse resp, final IRequest pendingReq) throws Exception { + final HttpServletResponse resp, + final IRequest pendingReq) throws Exception { String newSsoSessionId = null; @@ -369,8 +410,8 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer final IAuthData authData = authDataBuilder.buildAuthenticationData(pendingReq); // execute the protocol-specific action - final SloInformationInterface sloInformation = - executeProtocolSpecificAction(req, resp, pendingReq, authData); + final SloInformationInterface sloInformation = executeProtocolSpecificAction(req, resp, pendingReq, + authData); // Store OA specific SSO session information if an SSO cookie is set if (StringUtils.isNotEmpty(newSsoSessionId)) { @@ -390,21 +431,24 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer } // Advanced statistic logging - statisticLogger.logSuccessOperation(pendingReq, authData, - StringUtils.isNotEmpty(newSsoSessionId)); + statisticLogger.logSuccessOperation(pendingReq, authData, StringUtils.isNotEmpty(newSsoSessionId)); + + } + + @PostConstruct + private void initializer() { + log.trace("Initializing {} ...", ProtocolAuthenticationService.class.getName()); } /** * Executes the requested protocol action. * - * @param httpReq HttpServletRequest - * @param httpResp HttpServletResponse - * @param protocolRequest Authentication request which is actually in process - * @param authData Service-provider specific authentication data - * + * @param httpReq HttpServletRequest + * @param httpResp HttpServletResponse + * @param pendingReq Authentication request which is actually in process + * @param authData Service-provider specific authentication data * @return Return Single LogOut information or null if protocol supports no SSO - * * @throws Exception in case of an error */ private SloInformationInterface executeProtocolSpecificAction(final HttpServletRequest httpReq, @@ -416,7 +460,7 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer if (clazz == null || !IAction.class.isAssignableFrom(clazz)) { log.error( "Requested protocol-action processing Class is NULL or does not implement the IAction interface."); - throw new Exception( + throw new ClassCastException( "Requested protocol-action processing Class is NULL or does not implement the IAction interface."); } @@ -427,153 +471,130 @@ public class ProtocolAuthenticationService implements IProtocolAuthenticationSer } catch (final ClassNotFoundException e) { log.error( "Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); - throw new Exception( - "Requested Auth. protocol processing Class is NULL or does not implement the IAction interface."); + throw new ClassNotFoundException( + "Requested Auth. protocol processing Class is NULL or does not implement the IAction interface.", + e); } } - /** - * Write a Exception to the MOA-ID-Auth internal technical log. - * - * @param loggedException Exception to log - */ - protected void logExceptionToTechnicalLog(final Throwable loggedException) { - if (!(loggedException instanceof EaafException - || loggedException instanceof ProcessExecutionException)) { - log.error("Receive an internal error: Message=" + loggedException.getMessage(), - loggedException); - - } else { - if (loggedException instanceof EaafAuthenticationException && ERROR_LOGGER_ON_INFO_LEVEL - .contains(((EaafAuthenticationException) loggedException).getErrorId())) { - if (log.isDebugEnabled() || log.isTraceEnabled()) { - log.info(loggedException.getMessage(), loggedException); - - } else { - log.info(loggedException.getMessage()); - - } - - } else { - if (log.isDebugEnabled() || log.isTraceEnabled()) { - log.warn(loggedException.getMessage(), loggedException); - - } else { - log.warn(loggedException.getMessage()); - - } - } - } - } + // private void writeHtmlErrorResponse(@NonNull final HttpServletRequest + // httpReq, + // @NonNull final HttpServletResponse httpResp, @NonNull final String msg, + // @NonNull final String errorCode, + // @Nullable final Object[] params, String externalErrorCode) throws + // EaafException { + // this.writeHtmlErrorResponse(httpReq, httpResp, msg, errorCode, params, + // externalErrorCode, null, null); + // } private void writeHtmlErrorResponse(@NonNull final HttpServletRequest httpReq, - @NonNull final HttpServletResponse httpResp, @NonNull final String msg, - @NonNull final String errorCode, @Nullable final Object[] params, - @NonNull final Exception error) throws IOException, EaafException { + @NonNull final HttpServletResponse httpResp, @NonNull final String msg, @NonNull final String errorCode, + @Nullable final Object[] params, String externalErrorCode, IErrorService.IHandleData errorData) + throws EaafException { try { - final IGuiBuilderConfiguration config = - guiConfigFactory.getDefaultErrorGui(HttpUtils.extractAuthUrlFromRequest(httpReq)); + final IGuiBuilderConfiguration config = guiConfigFactory + .getDefaultErrorGui(HttpUtils.extractAuthUrlFromRequest(httpReq)); + String[] errorCodeParams = null; if (params == null) { errorCodeParams = new String[] {}; + } else { errorCodeParams = new String[params.length]; for (int i = 0; i < params.length; i++) { if (params[i] != null) { - errorCodeParams[i] = params[i].toString(); + /* replace all single-quotes by two single-quotes for escaping purposes to mitigate + * Thymeleaf error in: + * th:text="${#messages.msgWithParams('__${msg.errorCode}__', '__${msg.errorParams}__')}" + */ + errorCodeParams[i] = params[i].toString().replaceAll("'", "''"); + } else { errorCodeParams[i] = "null"; + } - } } // add errorcode and errormessage if (config instanceof ModifyableGuiBuilderConfiguration) { - ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( - AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERROMSG, msg); - ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( - AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORCODE, errorCode); - ((ModifyableGuiBuilderConfiguration) config).putCustomParameterWithOutEscaption( - AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORCODEPARAMS, - ArrayUtils.toString(errorCodeParams)); - - // add stacktrace if debug is enabled - if (log.isTraceEnabled()) { - ((ModifyableGuiBuilderConfiguration) config).putCustomParameter( - AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORSTACKTRACE, - getStacktraceFromException(error)); - - } + final ModifyableGuiBuilderConfiguration c = (ModifyableGuiBuilderConfiguration) config; + c.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERROMSG, msg); + c.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, PARAM_GUI_ERRORCODE, + errorCode); + // TODO: should we keep the internal errorcode secret? + c.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, + PARAM_GUI_EXTERNAL_ERRORCODE, + externalErrorCode); + c.putCustomParameterWithOutEscaption(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_MSG, + PARAM_GUI_ERRORCODEPARAMS, ArrayUtils.toString(errorCodeParams)); + errorTicketService.displayErrorData(c, errorData, httpReq); } else { - log.info( - "Can not ADD error message, because 'GUIBuilderConfiguration' is not modifieable "); + log.info("Can not ADD error message, because 'GUIBuilderConfiguration' is not modifieable "); } guiBuilder.build(httpReq, httpResp, config, "Error-Message"); } catch (final GuiBuildException e) { log.warn("Can not build error-message GUI.", e); - throw new EaafException("9199", null, e); + throw new EaafException("internal.99", new Object[] {e.getMessage()}, e); } } - private String getStacktraceFromException(final Exception ex) { - final StringWriter errors = new StringWriter(); - ex.printStackTrace(new PrintWriter(errors)); - return errors.toString(); + private void displayException(final HttpServletRequest req, final HttpServletResponse resp, + final IErrorService.IHandleData errorData) throws IOException, EaafException { + final Throwable e = errorData.getThrowable(); + final String internalErrorCode = errorData.getInternalErrorCode(); - } - - private void internalMoaidExceptionHandler(final HttpServletRequest req, - final HttpServletResponse resp, final Exception e, final boolean writeExceptionToStatisicLog) - throws IOException, EaafException { + // send error response if (e instanceof ProtocolNotActiveException) { - resp.getWriter().write(e.getMessage()); + resp.getWriter().write(Encode.forHtml(e.getMessage())); resp.setContentType(EaafConstants.CONTENTTYPE_HTML_UTF8); resp.sendError(HttpServletResponse.SC_FORBIDDEN, StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(e.getMessage()))); - } else if (e instanceof AuthnRequestValidatorException) { - final AuthnRequestValidatorException ex = (AuthnRequestValidatorException) e; - // log Error Message - if (writeExceptionToStatisicLog) { - statisticLogger.logErrorOperation(ex, ex.getErrorRequest()); - } - + } else if (e instanceof AuthnRequestValidatorException || e instanceof InvalidProtocolRequestException + || e instanceof ProcessExecutionException || e instanceof ConfigurationException) { // write error message - // writeBadRequestErrorResponse(req, resp, (EAAFException) e); - writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), - null, e); - - } else if (e instanceof InvalidProtocolRequestException) { - // send error response - // writeBadRequestErrorResponse(req, resp, (EAAFException) e); - writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), - null, e); - - } else if (e instanceof ConfigurationException) { - // send HTML formated error message - writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), - null, e); + writeHtmlErrorResponse(req, resp, e.getMessage(), internalErrorCode, null, + statusMessager.mapInternalErrorToExternalError(internalErrorCode), errorData); } else if (e instanceof EaafException) { // send HTML formated error message - writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), - ((EaafException) e).getParams(), e); + writeHtmlErrorResponse(req, resp, e.getMessage(), internalErrorCode, ((EaafException) e).getParams(), + statusMessager.mapInternalErrorToExternalError(internalErrorCode), errorData); - } else if (e instanceof ProcessExecutionException) { - // send HTML formated error message - writeHtmlErrorResponse(req, resp, e.getMessage(), statusMessager.getResponseErrorCode(e), - null, e); + } else { + // write generic message for general exceptions + final String msg = statusMessager.getMessage(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC, null); + writeHtmlErrorResponse(req, resp, msg, internalErrorCode, null, + statusMessager.mapInternalErrorToExternalError(internalErrorCode), errorData); } + } + + private IGuiBuilderConfiguration evaluateRequiredErrorHandlingMethod(IRequest first, String errorId) { + if (first != null && first.isProcessInIframe()) { + return guiConfigFactory + .getDefaultIFrameParentHopGui(first, ProtocolFinalizationController.ENDPOINT_ERRORHANDLING, + errorId); + + } + return null; + } + + private String generateErrorRedirectUrl(final HttpServletRequest req, String errorKey) { + String redirectUrl = null; + redirectUrl = ServletUtils.getBaseUrl(req); + redirectUrl += ProtocolFinalizationController.ENDPOINT_ERRORHANDLING + "?" + + EaafConstants.PARAM_HTTP_ERROR_CODE + "=" + errorKey; + return redirectUrl; } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/AttributeBuilderRegistration.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/AttributeBuilderRegistration.java new file mode 100644 index 00000000..b554ad05 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/AttributeBuilderRegistration.java @@ -0,0 +1,88 @@ +package at.gv.egiz.eaaf.core.impl.idp.builder; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.ServiceLoader; + +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AttributeBuilderRegistration { + + private static HashMap<String, IAttributeBuilder> builders; + + private static ServiceLoader<IAttributeBuilder> attributBuilderLoader = + ServiceLoader.load(IAttributeBuilder.class); + + private static void addBuilder(final IAttributeBuilder builder) { + builders.put(builder.getName(), builder); + } + + static { + builders = new HashMap<>(); + + log.info("Loading protocol attribut-builder modules:"); + if (attributBuilderLoader != null) { + final Iterator<IAttributeBuilder> moduleLoaderInterator = attributBuilderLoader.iterator(); + while (moduleLoaderInterator.hasNext()) { + try { + final IAttributeBuilder modul = moduleLoaderInterator.next(); + log.info("Loading attribut-builder Modul Information: " + modul.getName()); + addBuilder(modul); + + } catch (final Throwable e) { + log.error("Check configuration! " + "Some attribute-builder modul" + + " is not a valid IAttributeBuilder", e); + } + } + } + + log.info("Loading attribute-builder modules done"); + + } + + /** + * Get a specific attribute builder. + * + * @param name Attribute-builder friendly name + * + * @return Attribute-builder with this name or null if builder does not exists + */ + public static IAttributeBuilder getAttributeBuilder(final String name) { + return builders.get(name); + + } + + /** + * Check if a specific attribute-builder is available. + * + * @param name Attribute-builder friendly name + * @return <code>true</code> if the builder is registered, otherwise <code>false</code> + */ + public static boolean containsBuilder(final String name) { + return builders.containsKey(name); + + } + + /** + * Get all registered attribute-builder. + * + * @return {@link Iterator} of all available builders + */ + public static Iterator<IAttributeBuilder> getAllRegistratedBuilder() { + return builders.values().iterator(); + + } + + /** + * Get the number of currently register attribute builders. + * + * @return number of attribute builders + */ + public static int getNumberOfRegisteredBuilders() { + return builders.size(); + + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java index 19500cb3..a82a1a55 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BirthdateAttributeBuilder.java @@ -19,8 +19,7 @@ package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import org.apache.commons.lang3.StringUtils; import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -41,11 +40,8 @@ public class BirthdateAttributeBuilder implements IPvpAttributeBuilder { public <ATT> ATT build(final ISpConfiguration oaParam, final IAuthData authData, final IAttributeGenerator<ATT> g) throws AttributeBuilderException { - if (authData.getDateOfBirth() != null) { - final DateFormat pvpDateFormat = new SimpleDateFormat(BIRTHDATE_FORMAT_PATTERN); - final String dateString = pvpDateFormat.format(authData.getDateOfBirth()); - - return g.buildStringAttribute(BIRTHDATE_FRIENDLY_NAME, BIRTHDATE_NAME, dateString); + if (StringUtils.isNotEmpty(authData.getDateOfBirth())) { + return g.buildStringAttribute(BIRTHDATE_FRIENDLY_NAME, BIRTHDATE_NAME, authData.getDateOfBirth()); } else { throw new UnavailableAttributeException(BIRTHDATE_NAME); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BpkAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BpkAttributeBuilder.java index e18cc1a8..5cbfec01 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BpkAttributeBuilder.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/BpkAttributeBuilder.java @@ -19,27 +19,23 @@ package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; -import javax.annotation.Nonnull; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.Assert; -import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.IPvpAttributeBuilder; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; @PvpMetadata public class BpkAttributeBuilder implements IPvpAttributeBuilder { private static final Logger log = LoggerFactory.getLogger(BpkAttributeBuilder.class); - public static final String DELIMITER_BPKTYPE_BPK = ":"; - + @Override public String getName() { return BPK_NAME; @@ -60,12 +56,13 @@ public class BpkAttributeBuilder implements IPvpAttributeBuilder { } protected String getBpkForSP(final IAuthData authData) throws UnavailableAttributeException { - final String bpk = attrMaxSize(authData.getBpk()); - final String type = removeBpkTypePrefix(authData.getBpkType()); - - if (StringUtils.isEmpty(bpk)) { + if (StringUtils.isEmpty(authData.getBpk()) || StringUtils.isEmpty(authData.getBpkType())) { throw new UnavailableAttributeException(BPK_NAME); + } + + final String bpk = attrMaxSize(authData.getBpk()); + final String type = BpkBuilder.removeBpkTypePrefix(authData.getBpkType()); return type + DELIMITER_BPKTYPE_BPK + bpk; @@ -78,23 +75,5 @@ public class BpkAttributeBuilder implements IPvpAttributeBuilder { return attr; } - - @Nonnull - protected String removeBpkTypePrefix(@Nonnull final String type) { - Assert.isTrue(type != null, "bPKType is 'NULL'"); - if (type.startsWith(EaafConstants.URN_PREFIX_WBPK)) { - return type.substring(EaafConstants.URN_PREFIX_WBPK.length()); - - } else if (type.startsWith(EaafConstants.URN_PREFIX_CDID)) { - return type.substring(EaafConstants.URN_PREFIX_CDID.length()); - - } else if (type.startsWith(EaafConstants.URN_PREFIX_EIDAS)) { - return type.substring(EaafConstants.URN_PREFIX_EIDAS.length()); - - } else { - return type; - - } - - } + } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidCcsUrl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidCcsUrl.java index 27b78059..03c16aef 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidCcsUrl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidCcsUrl.java @@ -31,7 +31,8 @@ public class EidCcsUrl implements IPvpAttributeBuilder { } } else { - log.info(EID_CCS_URL_FRIENDLY_NAME + " is only available in MOA-ID context"); + log.info(EID_CCS_URL_FRIENDLY_NAME + " is only available in E-ID context"); + } throw new UnavailableAttributeException(EID_CCS_URL_NAME); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIdentityStatusLevelAttributeBuiler.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIdentityStatusLevelAttributeBuiler.java index ee51564e..8345dcf8 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIdentityStatusLevelAttributeBuiler.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIdentityStatusLevelAttributeBuiler.java @@ -1,8 +1,5 @@ package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; @@ -10,11 +7,11 @@ import at.gv.egiz.eaaf.core.api.idp.IPvpAttributeBuilder; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; +import lombok.extern.slf4j.Slf4j; +@Slf4j @PvpMetadata public class EidIdentityStatusLevelAttributeBuiler implements IPvpAttributeBuilder { - private static final Logger log = - LoggerFactory.getLogger(EidIdentityStatusLevelAttributeBuiler.class); @Override public String getName() { @@ -28,12 +25,15 @@ public class EidIdentityStatusLevelAttributeBuiler implements IPvpAttributeBuild if (authData instanceof IEidAuthData) { if (((IEidAuthData) authData).getEidStatus() == null) { throw new UnavailableAttributeException(getName()); + } return g.buildStringAttribute(getFriendlyName(), getName(), ((IEidAuthData) authData).getEidStatus().getUri()); + } else { log.info(getFriendlyName() + " is only available in EAAF context"); + } throw new UnavailableAttributeException(getName()); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIssuingNationAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIssuingNationAttributeBuilder.java index fd85871c..90e8c285 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIssuingNationAttributeBuilder.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidIssuingNationAttributeBuilder.java @@ -41,7 +41,7 @@ public class EidIssuingNationAttributeBuilder implements IPvpAttributeBuilder { final String countryCode = authData.getCiticenCountryCode(); if (StringUtils.isNotEmpty(countryCode)) { return g.buildStringAttribute(EID_ISSUING_NATION_FRIENDLY_NAME, EID_ISSUING_NATION_NAME, - countryCode); + countryCode.toUpperCase()); } else { return null; } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSectorForIdAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSectorForIdAttributeBuilder.java index 48d7a3a3..ba993b0c 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSectorForIdAttributeBuilder.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSectorForIdAttributeBuilder.java @@ -27,7 +27,7 @@ import at.gv.egiz.eaaf.core.api.idp.IPvpAttributeBuilder; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; -import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BpkBuilder; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; @PvpMetadata public class EidSectorForIdAttributeBuilder implements IPvpAttributeBuilder { @@ -48,7 +48,7 @@ public class EidSectorForIdAttributeBuilder implements IPvpAttributeBuilder { return g.buildStringAttribute(EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME, EID_SECTOR_FOR_IDENTIFIER_NAME, - BpkBuilder.normalizeBpkTargetIdentifierToCalculationFormat(bpktype)); + BpkBuilder.normalizeBpkTargetIdentifierToNonXFormat(bpktype)); } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSignerCertificate.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSignerCertificate.java index 6f857779..daed8455 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSignerCertificate.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/EidSignerCertificate.java @@ -53,16 +53,17 @@ public class EidSignerCertificate implements IPvpAttributeBuilder { EID_SIGNER_CERTIFICATE_NAME, Base64Utils.encodeToString(signerCertificate)); } else { - log.info(EID_SIGNER_CERTIFICATE_FRIENDLY_NAME + " is only available in MOA-ID context"); + log.debug("{} is not available", EID_SIGNER_CERTIFICATE_FRIENDLY_NAME); + } } catch (final Exception e) { - log.info("Signer certificate BASE64 encoding error"); + log.info("{} BASE64 encoding error", EID_SIGNER_CERTIFICATE_FRIENDLY_NAME); } } else { - log.info(EID_SIGNER_CERTIFICATE_FRIENDLY_NAME + " is only available in AuthHandler context"); + log.info("{} is only available in AuthHandler context", EID_SIGNER_CERTIFICATE_FRIENDLY_NAME); } throw new UnavailableAttributeException(EID_SIGNER_CERTIFICATE_NAME); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PiiTransactionIdAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PiiTransactionIdAttributeBuilder.java new file mode 100644 index 00000000..08911ac7 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/PiiTransactionIdAttributeBuilder.java @@ -0,0 +1,37 @@ +package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; + +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PiiTransactionIdAttributeBuilder implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return EID_PII_TRANSACTION_ID_NAME; + + } + + @Override + public <ATT> ATT build(ISpConfiguration oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeBuilderException { + String piiTransactionId = authData.getGenericData(EID_PII_TRANSACTION_ID_NAME, String.class); + log.trace("{} piiTransactionId: {} as attribute", + piiTransactionId != null ? "Set" : "Notset", log.isTraceEnabled() ? piiTransactionId : "********"); + return g.buildStringAttribute(EID_PII_TRANSACTION_ID_FRIENDLY_NAME, EID_PII_TRANSACTION_ID_NAME, + piiTransactionId); + + } + + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return g.buildEmptyAttribute(EID_PII_TRANSACTION_ID_FRIENDLY_NAME, EID_PII_TRANSACTION_ID_NAME); + + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpUsesMandates.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpMandateModeAttributeBuilder.java index 44ff4e50..3240cfca 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpUsesMandates.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpMandateModeAttributeBuilder.java @@ -26,11 +26,11 @@ import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; -public class SpUsesMandates implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { +public class SpMandateModeAttributeBuilder implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { @Override public String getName() { - return SP_USESMANDATES_NAME; + return SP_USED_MANDATE_TYPE_NAME; } @Override @@ -44,7 +44,7 @@ public class SpUsesMandates implements IAttributeBuilder, ExtendedPvpAttributeDe @Override public <ATT> ATT buildEmpty(final IAttributeGenerator<ATT> g) { - return g.buildEmptyAttribute(SP_USESMANDATES_FRIENDLY_NAME, SP_USESMANDATES_NAME); + return g.buildEmptyAttribute(SP_USED_MANDATE_TYPE_FRIENDLY_NAME, SP_USED_MANDATE_TYPE_NAME); } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpMandateProfilesAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpMandateProfilesAttributeBuilder.java new file mode 100644 index 00000000..e0d00f7d --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/SpMandateProfilesAttributeBuilder.java @@ -0,0 +1,51 @@ +/* + * 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.core.impl.idp.builder.attributes; + +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; + +public class SpMandateProfilesAttributeBuilder implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return SP_USED_MANDATE_PROFILES_NAME; + } + + @Override + public <ATT> ATT build(final ISpConfiguration oaParam, final IAuthData authData, + final IAttributeGenerator<ATT> g) + throws AttributeBuilderException { + // this attribute can not generated yet + return null; + + } + + @Override + public <ATT> ATT buildEmpty(final IAttributeGenerator<ATT> g) { + return g.buildEmptyAttribute(SP_USED_MANDATE_PROFILES_FRIENDLY_NAME, SP_USED_MANDATE_PROFILES_NAME); + + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java new file mode 100644 index 00000000..17b830dc --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/builder/attributes/TransactionIdAttributeBuilder.java @@ -0,0 +1,33 @@ +package at.gv.egiz.eaaf.core.impl.idp.builder.attributes; + +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; + +public class TransactionIdAttributeBuilder implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return EID_TRANSACTION_ID_NAME; + + } + + @Override + public <ATT> ATT build(ISpConfiguration oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeBuilderException { + return g.buildStringAttribute(EID_TRANSACTION_ID_FRIENDLY_NAME, EID_TRANSACTION_ID_NAME, + TransactionIdUtils.getTransactionId()); + + } + + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return g.buildEmptyAttribute(EID_TRANSACTION_ID_FRIENDLY_NAME, EID_TRANSACTION_ID_NAME); + + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java index fc62af45..b05d8df0 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractController.java @@ -26,11 +26,11 @@ import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.text.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.util.SerializationUtils; import org.springframework.web.bind.annotation.ExceptionHandler; import at.gv.egiz.components.eventlog.api.EventConstants; @@ -42,12 +42,12 @@ import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; import at.gv.egiz.eaaf.core.api.idp.auth.services.IProtocolAuthenticationService; import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.data.Pair; -import at.gv.egiz.eaaf.core.impl.utils.Random; /** * Basic application controller that implements core error-handling. @@ -69,10 +69,13 @@ public abstract class AbstractController { protected ITransactionStorage transactionStorage; @Autowired(required = true) protected IStatusMessenger statusMessager; - + @Autowired protected IRevisionLogger revisionsLogger; + @Autowired + protected IPendingRequestIdGenerationStrategy reqIdGenerationStrategy; + /** * EAAF framework exception handler. * @@ -92,11 +95,11 @@ public abstract class AbstractController { protAuthService.handleErrorNoRedirect(e, req, resp, true); } catch (final EaafException e1) { + log.warn("ErrorHandling failed with error: ", e.getMessage(), e); log.warn("Can NOT handle an 'EAAFException'. Forwarding to generic error ... ", e); ioExceptionHandler(resp, e); } - } /** @@ -106,20 +109,23 @@ public abstract class AbstractController { * This handler wrote an internal server error into http response * </p> * - * @param resp http response - * @param exception exception + * @param req http request + * @param resp http response + * @param e Catched exception * @throws IOException In case of an internal error. */ @ExceptionHandler({ Exception.class }) - public void genericExceptionHandler(final HttpServletResponse resp, final Exception exception) - throws IOException { - log.error("Internel Server Error.", exception); - resp.setContentType(EaafConstants.CONTENTTYPE_HTML_UTF8); - resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error!" - + "(Errorcode=9199" + " | Description=" - + StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(exception.getMessage())) - + ")"); + public void genericExceptionHandler(final HttpServletRequest req, final HttpServletResponse resp, + final Exception e) throws IOException { + try { + protAuthService.handleErrorNoRedirect(e, req, resp, true); + + } catch (final EaafException e1) { + log.warn("ErrorHandling failed with error: ", e.getMessage(), e); + log.error("Can NOT handle a generic 'Exception'. Forwarding to generic error ... ", e); + ioExceptionHandler(resp, e); + } } /** @@ -150,8 +156,6 @@ public abstract class AbstractController { try { final String errorKey = storeErrorAndGetErrorToken(errorToHandle); protAuthService.forwardToErrorHandler(errorToHandle, errorKey, req, resp); - - return; } catch (final Exception e) { log.warn("Default error-handling FAILED. Exception can not be stored ....", e); @@ -169,18 +173,30 @@ public abstract class AbstractController { } // put exception into transaction store for redirect - final String errorKey = Random.nextLongRandom(); + final String errorToken = reqIdGenerationStrategy.generateExternalPendingRequestId(); + final String errorKey = reqIdGenerationStrategy.getPendingRequestIdWithOutChecks(errorToken); + if (errorToHandle.getFirst() != null) { revisionsLogger.logEvent(errorToHandle.getFirst(), EventConstants.TRANSACTION_ERROR); - transactionStorage.put(errorKey, new ExceptionContainer(errorToHandle.getFirst(), errorToHandle - .getSecond()), -1); + + log.trace("Serializing {} ... ", ExceptionContainer.class.getName()); + final byte[] serializedError = SerializationUtils.serialize( + new ExceptionContainer(errorToHandle.getFirst(), errorToHandle.getSecond())); + + log.debug("Put 'ExceptionContainer' into cache with id: {}... ", errorKey); + transactionStorage.put(errorKey, serializedError, -1); } else { - transactionStorage.put(errorKey, new ExceptionContainer(null, errorToHandle.getSecond()), -1); + log.trace("Serializing {} ... ", ExceptionContainer.class.getName()); + final byte[] serializedError = SerializationUtils.serialize( + new ExceptionContainer(null, errorToHandle.getSecond())); + + log.trace("Put 'ExceptionContainer' into cache with id: {}... ",errorKey); + transactionStorage.put(errorKey, serializedError, -1); } - return errorKey; + return errorToken; } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java index 098bca4c..ea481bdb 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/AbstractProcessEngineSignalController.java @@ -36,6 +36,7 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; /** @@ -78,13 +79,16 @@ public abstract class AbstractProcessEngineSignalController extends AbstractCont // process instance is mandatory if (pendingReq.getProcessInstanceId() == null) { throw new EaafIllegalStateException( - new Object[] { "MOA session does not provide process instance id." }); + new Object[] { "PendingRequest does not provide process-instance id." }); } // wake up next task processEngine.signal(pendingReq); + } catch (PendingReqIdValidationException e) { + handleError(null, e, req, resp, e.getInvalidPendingReq()); + } catch (final Exception ex) { handleError(null, ex, req, resp, pendingReq); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java index 17da63f5..a22cbe9d 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/ProtocolFinalizationController.java @@ -15,7 +15,7 @@ * 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.core.impl.idp.controller; @@ -29,6 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.util.SerializationUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -38,22 +39,107 @@ import at.gv.egiz.eaaf.core.api.IRequestStorage; import at.gv.egiz.eaaf.core.api.IStatusMessenger; import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; +import at.gv.egiz.eaaf.core.api.idp.IModulInfo; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.auth.services.ProtocolAuthenticationService; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; /** * Protocol finialization end-point. * * @author tlenz - * */ @Controller public class ProtocolFinalizationController extends AbstractController { private static final Logger log = LoggerFactory.getLogger(ProtocolFinalizationController.class); - public static final String ENDPOINT_FINALIZEPROTOCOL = "finalizeAuthProtocol"; - public static final String ENDPOINT_ERRORHANDLING = "errorHandling"; + public static final String ENDPOINT_FINALIZEPROTOCOL = + EaafConstants.ENDPOINT_PREFIX_SECURED + "/finalizeAuthProtocol"; + public static final String ENDPOINT_ERRORHANDLING = + EaafConstants.ENDPOINT_PREFIX_SECURED + "/errorHandling"; + public static final String ENDPOINT_ERROR_REDIRECT = + EaafConstants.ENDPOINT_PREFIX_SECURED + "/errorRedirect"; @Autowired(required = true) IRequestStorage requestStorage; + @Autowired + IPendingRequestIdGenerationStrategy requestIdValidationStragegy; + + + /** + * Handles incoming requests for redirects to IDP. + * @param req http request + * @param resp http response + * @throws EaafException In case of an internal error + * @throws IOException In case of a servlet error + */ + @RequestMapping(value = ENDPOINT_ERROR_REDIRECT, method = {RequestMethod.GET, RequestMethod.POST}) + public void errorRedirect(final HttpServletRequest req, final HttpServletResponse resp) + throws EaafException, IOException { + + final String errorToken = StringEscapeUtils.escapeHtml4(req.getParameter(EaafConstants.PARAM_HTTP_ERROR_CODE)); + if (errorToken != null) { + IRequest pendingReq = null; + try { + String errorId = requestIdValidationStragegy.validateAndGetPendingRequestId(errorToken); + log.debug("Searching exception with internal error-token: {}", errorId); + + // load stored exception from database + final byte[] containerSerialized = transactionStorage.get(errorId, byte[].class); + if (containerSerialized != null) { + // remove exception if it was found + transactionStorage.remove(errorId); + log.trace("Find exception with internal error-token: {}", errorId); + + //final Object containerObj = EaafSerializationUtils.deserialize(containerSerialized, + // Arrays.asList( + // ExceptionContainer.class.getName() + // )); + final Object containerObj = SerializationUtils.deserialize(containerSerialized); + + if (containerObj instanceof ExceptionContainer) { + final ExceptionContainer container = (ExceptionContainer) containerObj; + final Throwable throwable = container.getExceptionThrown(); + pendingReq = container.getPendingRequest(); + + if (pendingReq != null) { + IModulInfo handlingModule = ProtocolAuthenticationService + .extractShibbolethHandling(pendingReq, applicationContext); + if (!handlingModule.generateErrorMessage(throwable, req, resp, pendingReq)) { + protAuthService.handleErrorNoRedirect(new EaafException("process.90", null), req, resp, false); + + } + } + } + } else { + log.info("Find no exception with internal error-token: {}", errorId); + protAuthService + .handleErrorNoRedirect(new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_TIMEOUT, null), + req, resp, false); + + } + + } catch (Throwable e) { + log.error(e.getMessage(), e); + protAuthService.handleErrorNoRedirect(e, req, resp, false); + + } finally { + // remove pending-request + if (pendingReq != null) { + requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier()); + + } + } + + } else { + log.debug("Request contains NO ErrorId"); + protAuthService + .handleErrorNoRedirect(new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), req, + resp, false); + + } + } /** * End-Point to handle errors. @@ -63,42 +149,62 @@ public class ProtocolFinalizationController extends AbstractController { * @throws EaafException In case of an internal error * @throws IOException In case of a servlet error */ - @RequestMapping(value = ENDPOINT_ERRORHANDLING, method = { RequestMethod.GET, RequestMethod.POST }) + @RequestMapping(value = ENDPOINT_ERRORHANDLING, method = {RequestMethod.GET, RequestMethod.POST}) public void errorHandling(final HttpServletRequest req, final HttpServletResponse resp) throws EaafException, IOException { // receive an authentication error - final String errorid = - StringEscapeUtils.escapeHtml4(req.getParameter(EaafConstants.PARAM_HTTP_ERROR_CODE)); - if (errorid != null) { + final String errorToken = StringEscapeUtils.escapeHtml4(req.getParameter(EaafConstants.PARAM_HTTP_ERROR_CODE)); + if (errorToken != null) { IRequest pendingReq = null; try { + String errorId = requestIdValidationStragegy.validateAndGetPendingRequestId(errorToken); + log.debug("Searching exception with internal error-token: {}", errorId); + // load stored exception from database - final ExceptionContainer container = - transactionStorage.get(errorid, ExceptionContainer.class); - if (container != null) { + final byte[] containerSerialized = transactionStorage.get(errorId, byte[].class); + if (containerSerialized != null) { // remove exception if it was found - transactionStorage.remove(errorid); + transactionStorage.remove(errorId); + log.trace("Find exception with internal error-token: {}", errorId); + + //final Object containerObj = EaafSerializationUtils.deserialize(containerSerialized, + // Arrays.asList( + // ExceptionContainer.class.getName() + // )); + final Object containerObj = SerializationUtils.deserialize(containerSerialized); + + if (containerObj instanceof ExceptionContainer) { + final ExceptionContainer container = (ExceptionContainer) containerObj; + final Throwable throwable = container.getExceptionThrown(); + pendingReq = container.getPendingRequest(); - final Throwable throwable = container.getExceptionThrown(); - pendingReq = container.getPendingRequest(); + if (pendingReq != null) { + //set MDC variables + TransactionIdUtils.setAllLoggingVariables(pendingReq); - if (pendingReq != null) { - // build protocol-specific error message if possible - protAuthService.buildProtocolSpecificErrorResponse(throwable, req, resp, pendingReq); + // build protocol-specific error message if possible + protAuthService.buildProtocolSpecificErrorResponse(throwable, req, resp, pendingReq); - // remove active user-session - transactionStorage.remove(pendingReq.getPendingRequestId()); + // remove active user-session + transactionStorage.remove(pendingReq.getPendingRequestId()); - return; + } else { + protAuthService.handleErrorNoRedirect(throwable, req, resp, true); + + } } else { - protAuthService.handleErrorNoRedirect(throwable, req, resp, true); + protAuthService + .handleErrorNoRedirect(new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_GENERIC, null), req, + resp, false); } + } else { - protAuthService.handleErrorNoRedirect( - new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), - req, resp, false); + log.info("Find no exception with internal error-token: {}", errorId); + protAuthService + .handleErrorNoRedirect(new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), + req, resp, false); } @@ -110,18 +216,20 @@ public class ProtocolFinalizationController extends AbstractController { // remove pending-request if (pendingReq != null) { requestStorage.removePendingRequest(pendingReq.getPendingRequestId()); - revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, - pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(EventConstants.TRANSACTION_DESTROYED, pendingReq.getUniqueTransactionIdentifier()); } + //remove all Logger variables + TransactionIdUtils.removeAllLoggingVariables(); + } } else { log.debug("Request contains NO ErrorId"); - protAuthService.handleErrorNoRedirect( - new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), req, - resp, false); + protAuthService + .handleErrorNoRedirect(new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_NOPENDIGREQID, null), req, + resp, false); } @@ -135,7 +243,7 @@ public class ProtocolFinalizationController extends AbstractController { * @throws EaafException In case of an internal error * @throws IOException In case of a servlet error */ - @RequestMapping(value = ENDPOINT_FINALIZEPROTOCOL, method = { RequestMethod.GET }) + @RequestMapping(value = ENDPOINT_FINALIZEPROTOCOL, method = {RequestMethod.GET}) public void finalizeAuthProtocol(final HttpServletRequest req, final HttpServletResponse resp) throws EaafException, IOException { @@ -145,14 +253,19 @@ public class ProtocolFinalizationController extends AbstractController { final IRequest pendingReq = requestStorage.getPendingRequest(pendingRequestID); if (pendingReq == null) { - log.error("No PendingRequest with ID " + pendingRequestID + " found.!"); + log.info("PendingReqId was valid but no PendingRequest with ID: {}. Looks already used", + pendingRequestID); protAuthService.handleErrorNoRedirect( - new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_TIMEOUT, - new Object[] { pendingRequestID, }), - req, resp, false); + new EaafException(IStatusMessenger.CODES_INTERNAL_ERROR_AUTH_TIMEOUT, new Object[]{pendingRequestID,}), req, + resp, false); } else { + //set MDC variables + TransactionIdUtils.setAllLoggingVariables(pendingReq); + + //perform protocol finalization steps protAuthService.finalizeAuthentication(req, resp, pendingReq); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/AbstractLocaleAuthServletTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/AbstractLocaleAuthServletTask.java index dcd5a1d1..007c3e1d 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/AbstractLocaleAuthServletTask.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/AbstractLocaleAuthServletTask.java @@ -11,9 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.eaaf.core.api.data.EaafConstants; -import at.gv.egiz.eaaf.core.api.data.EaafEventCodes; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; @@ -53,29 +51,6 @@ public abstract class AbstractLocaleAuthServletTask extends AbstractAuthServletT } - protected void stopProcessFromUserDecision(final ExecutionContext executionContext, - final HttpServletRequest request, final HttpServletResponse response) - throws TaskExecutionException { - try { - revisionsLogger.logEvent(pendingReq, EaafEventCodes.PROCESS_STOPPED_BY_USER); - pendingReq.setAbortedByUser(true); - pendingReq.setAuthenticated(false); - performRedirectToProtocolFinialization(executionContext, pendingReq, request, response); - - log.trace("Set process-cancelation flag"); - executionContext.setCanceleProcessFlag(); - - } catch (final EaafException e) { - throw new TaskExecutionException(pendingReq, e.getMessage(), e); - - } catch (final Exception e) { - log.warn("Stopping auth.process FAILED", e); - throw new TaskExecutionException(pendingReq, e.getMessage(), e); - - } - - } - protected boolean parseFlagFromHttpRequest(final HttpServletRequest httpReq, final String httpParamName, final boolean defaultValue) { final String flag = httpReq.getParameter(httpParamName); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java index 328a25c5..7a664915 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/controller/tasks/RestartAuthProzessManagement.java @@ -19,8 +19,6 @@ package at.gv.egiz.eaaf.core.impl.idp.controller.tasks; -import java.util.Set; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -32,6 +30,7 @@ import org.springframework.stereotype.Component; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.ModuleRegistration; @@ -73,12 +72,9 @@ public class RestartAuthProzessManagement extends AbstractAuthServletTask { } else { // create a new execution context and copy all elements to new context final ExecutionContext newec = new ExecutionContextImpl(); - final Set<String> entries = executionContext.keySet(); - for (final String key : entries) { - newec.put(key, executionContext.get(key)); - - } - + executionContext.keySet().stream().forEach( + key -> newec.put(key, executionContext.get(key))); + log.debug("Select new auth.-process and restart restart process-engine ... "); // select and create new process instance @@ -87,7 +83,7 @@ public class RestartAuthProzessManagement extends AbstractAuthServletTask { if (processDefinitionId == null) { log.warn("No suitable authentication process found for SessionID " + pendingReq.getPendingRequestId()); - throw new EaafException("process.02", new Object[] { pendingReq.getPendingRequestId() }); + throw new EaafException("process.02", null); } final String processInstanceId = @@ -112,10 +108,18 @@ public class RestartAuthProzessManagement extends AbstractAuthServletTask { processEngine.start(pendingReq); } - - } catch (final EaafException e) { - throw new TaskExecutionException(pendingReq, e.getMessage(), e); - + + } catch (final ProcessExecutionException e) { + //check if Task in already selected process failed or if process selection failed + if (e.getCause() != null && e.getCause() instanceof TaskExecutionException) { + log.info("New process was started, but one Task in process failed. Reason: {}", e.getMessage()); + throw (TaskExecutionException)e.getCause(); + + } else { + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + } catch (final Exception e) { log.warn("RestartAuthProzessManagement has an internal error", e); throw new TaskExecutionException(pendingReq, e.getMessage(), e); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java index 14537d44..edca0fba 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java @@ -101,6 +101,7 @@ public class ProcessDefinitionParser { // Standard implementation of XMLInputFactory seems not to be thread-safe final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); reader = inputFactory.createXMLEventReader(processDefinitionInputStream); final List<StartElement> transitionElements = new ArrayList<>(); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java index 9274ea81..6e83a201 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java @@ -21,15 +21,13 @@ package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.InputStream; import java.io.Serializable; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.collections4.IterableUtils; import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -51,14 +49,17 @@ import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessNode; import at.gv.egiz.eaaf.core.impl.idp.process.model.StartEvent; import at.gv.egiz.eaaf.core.impl.idp.process.model.TaskInfo; import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; +import lombok.extern.slf4j.Slf4j; /** * Process engine implementation allowing starting and continuing processes as * well as providing means for cleanup actions. */ +@Slf4j public class ProcessEngineImpl implements ProcessEngine { - private final Logger log = LoggerFactory.getLogger(getClass()); + private static final String ERROR_PROCESS_OBJECT_NOT_EXIST = + "Process instance: {0} does not exist for pendingReq: {0}"; @Autowired ProcessInstanceStoreDao piStoreDao; @@ -156,15 +157,16 @@ public class ProcessEngineImpl implements ProcessEngine { if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) { log.error("Pending-request with id:" + pendingReq.getPendingRequestId() + " includes NO 'ProcessInstanceId'"); - throw new ProcessExecutionException("Pending-request with id:" - + pendingReq.getPendingRequestId() + " includes NO 'ProcessInstanceId'"); + throw new ProcessExecutionException(MessageFormat.format(ERROR_PROCESS_OBJECT_NOT_EXIST, + pendingReq.getProcessInstanceId(), pendingReq.getPendingRequestId())); + } final ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId()); if (pi == null) { - throw new ProcessExecutionException( - "Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist."); + throw new ProcessExecutionException(MessageFormat.format(ERROR_PROCESS_OBJECT_NOT_EXIST, + pendingReq.getProcessInstanceId(), pendingReq.getPendingRequestId())); } @@ -449,11 +451,9 @@ public class ProcessEngineImpl implements ProcessEngine { final ExecutionContext executionContext = new ExecutionContextImpl(piStore.getProcessInstanceId()); - - final Map<String, Serializable> executionContextData = piStore.getExecutionContextData(); - for (final Entry<String, Serializable> el : executionContextData.entrySet()) { - executionContext.put(el.getKey(), el.getValue()); - } + + piStore.getExecutionContextData().entrySet().stream().forEach( + el -> executionContext.put(el.getKey(), el.getValue())); final ProcessInstance pi = new ProcessInstance( processDefinitions.get(piStore.getProcessDefinitionId()), executionContext); diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java index cca8872f..611572c0 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java @@ -72,7 +72,7 @@ public class ProcessInstanceStoreDaoImpl implements ProcessInstanceStoreDao { log.debug("Found process instance store for instance '{}'.", processInstanceId); } else { - log.debug("Unable to find process instance store for instance '{}'.", processInstanceId); + log.info("Unable to find process instance store for instance '{}'.", processInstanceId); } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DomUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DomUtils.java index 01b063aa..4b8a7a04 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DomUtils.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DomUtils.java @@ -33,6 +33,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.Vector; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -111,10 +112,10 @@ public class DomUtils { private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY = "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; - private static final String EXTERNAL_GENERAL_ENTITIES_FEATURE = + public static final String EXTERNAL_GENERAL_ENTITIES_FEATURE = "http://xml.org/sax/features/external-general-entities"; - private static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = + public static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = "http://xml.org/sax/features/external-parameter-entities"; public static final String DISALLOW_DOCTYPE_FEATURE = @@ -785,6 +786,7 @@ public class DomUtils { throws TransformerException, IOException { final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); final Transformer transformer = transformerFactory.newTransformer(); final ByteArrayOutputStream bos = new ByteArrayOutputStream(16384); @@ -1211,6 +1213,7 @@ public class DomUtils { // StringWriter stringWriter = new StringWriter(); final Result result = new StreamResult(out); final TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); final Transformer transformer = factory.newTransformer(); transformer.transform(source, result); return out.toByteArray(); |