Skip to content

Commit

Permalink
Improved AS4 profile handling
Browse files Browse the repository at this point in the history
  • Loading branch information
phax committed Oct 24, 2024
1 parent dc056dc commit 096e03f
Show file tree
Hide file tree
Showing 32 changed files with 214 additions and 287 deletions.
20 changes: 15 additions & 5 deletions phase4-lib/src/main/java/com/helger/phase4/dump/AS4DumpReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
import com.helger.phase4.incoming.spi.AS4SignalMessageProcessorResult;
import com.helger.phase4.incoming.spi.IAS4IncomingMessageProcessorSPI;
import com.helger.phase4.model.pmode.IPMode;
import com.helger.phase4.model.pmode.resolve.DefaultPModeResolver;
import com.helger.phase4.model.pmode.resolve.AS4DefaultPModeResolver;
import com.helger.phase4.util.Phase4Exception;
import com.helger.servlet.mock.MockServletContext;
import com.helger.web.scope.mgr.WebScopeManager;
Expand Down Expand Up @@ -97,7 +97,7 @@ private AS4DumpReader ()
/**
* Utility method to just read and consume the leading HTTP headers from a
* dump. Usually this method is not called explicitly but invoked directly by
* {@link #decryptAS4In(byte[], IAS4CryptoFactory, IAS4CryptoFactory, Consumer, IDecryptedPayloadConsumer)}
* {@link #decryptAS4In(String, byte[], IAS4CryptoFactory, IAS4CryptoFactory, Consumer, IDecryptedPayloadConsumer)}
*
* @param aAS4InData
* The byte array with the dump. May not be <code>null</code>.
Expand Down Expand Up @@ -169,6 +169,9 @@ public static void readAndSkipInitialHttpHeaders (@Nonnull final byte [] aAS4InD
* Note: this method was mainly created for internal use and does not win the
* prize for the most sexy piece of software in the world ;-)
*
* @param sAS4ProfileID
* The AS4 profile ID to use. May neither be <code>null</code> nor
* empty.
* @param aAS4InData
* The byte array with the dumped data.
* @param aCryptoFactorySign
Expand All @@ -191,7 +194,8 @@ public static void readAndSkipInitialHttpHeaders (@Nonnull final byte [] aAS4InD
* @throws MessagingException
* In case of error
*/
public static void decryptAS4In (@Nonnull final byte [] aAS4InData,
public static void decryptAS4In (@Nonnull @Nonempty final String sAS4ProfileID,
@Nonnull final byte [] aAS4InData,
@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nullable final Consumer <HttpHeaderMap> aHttpHeaderConsumer,
Expand All @@ -200,6 +204,12 @@ public static void decryptAS4In (@Nonnull final byte [] aAS4InData,
IOException,
MessagingException
{
ValueEnforcer.notEmpty (sAS4ProfileID, "AS4ProfileID");
ValueEnforcer.notNull (aAS4InData, "AS4InData");
ValueEnforcer.notNull (aCryptoFactorySign, "CryptoFactorySign");
ValueEnforcer.notNull (aCryptoFactoryCrypt, "CryptoFactoryCrypt");
ValueEnforcer.notNull (aDecryptedConsumer, "DecryptedConsumer");

final HttpHeaderMap hm = new HttpHeaderMap ();
final MutableInt aHttpEndIndex = new MutableInt (-1);
readAndSkipInitialHttpHeaders (aAS4InData, hm::setAllHeaders, aHttpEndIndex::set);
Expand All @@ -219,12 +229,12 @@ public static void decryptAS4In (@Nonnull final byte [] aAS4InData,
}

try (final WebScoped w = new WebScoped ();
final AS4RequestHandler aHandler = new AS4RequestHandler (AS4IncomingMessageMetadata.createForRequest ()))
final AS4RequestHandler aHandler = new AS4RequestHandler (AS4IncomingMessageMetadata.createForRequest ()))
{
// Set default values in handler
aHandler.setCryptoFactorySign (aCryptoFactorySign);
aHandler.setCryptoFactoryCrypt (aCryptoFactoryCrypt);
aHandler.setPModeResolver (DefaultPModeResolver.DEFAULT_PMODE_RESOLVER);
aHandler.setPModeResolver (new AS4DefaultPModeResolver (sAS4ProfileID));
aHandler.setIncomingAttachmentFactory (IAS4IncomingAttachmentFactory.DEFAULT_INSTANCE);
aHandler.setIncomingSecurityConfiguration (AS4IncomingSecurityConfiguration.createDefaultInstance ());
aHandler.setIncomingReceiverConfiguration (new AS4IncomingReceiverConfiguration ());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
import com.helger.phase4.model.message.MessageHelperMethods;
import com.helger.phase4.model.pmode.IPMode;
import com.helger.phase4.model.pmode.leg.PModeLeg;
import com.helger.phase4.model.pmode.resolve.IPModeResolver;
import com.helger.phase4.model.pmode.resolve.IAS4PModeResolver;
import com.helger.phase4.profile.IAS4Profile;
import com.helger.phase4.profile.IAS4ProfileValidator;
import com.helger.phase4.profile.IAS4ProfileValidator.EAS4ProfileValidationMode;
Expand Down Expand Up @@ -824,7 +824,7 @@ public static IAS4IncomingMessageState processEbmsMessage (@Nonnull @WillNotClos
@Nullable
private static IAS4IncomingMessageState _parseMessage (@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nonnull final IPModeResolver aPModeResolver,
@Nonnull final IAS4PModeResolver aPModeResolver,
@Nonnull final IAS4IncomingAttachmentFactory aIAF,
@Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector,
@Nonnull @WillNotClose final AS4ResourceHelper aResHelper,
Expand Down Expand Up @@ -910,7 +910,7 @@ private static IAS4IncomingMessageState _parseMessage (@Nonnull final IAS4Crypto
@Nullable
public static Ebms3SignalMessage parseSignalMessage (@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nonnull final IPModeResolver aPModeResolver,
@Nonnull final IAS4PModeResolver aPModeResolver,
@Nonnull final IAS4IncomingAttachmentFactory aIAF,
@Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector,
@Nonnull @WillNotClose final AS4ResourceHelper aResHelper,
Expand Down Expand Up @@ -965,7 +965,7 @@ public static Ebms3SignalMessage parseSignalMessage (@Nonnull final IAS4CryptoFa
@Nullable
public static Ebms3UserMessage parseUserMessage (@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nonnull final IPModeResolver aPModeResolver,
@Nonnull final IAS4PModeResolver aPModeResolver,
@Nonnull final IAS4IncomingAttachmentFactory aIAF,
@Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector,
@Nonnull @WillNotClose final AS4ResourceHelper aResHelper,
Expand Down Expand Up @@ -1019,7 +1019,7 @@ public static Ebms3UserMessage parseUserMessage (@Nonnull final IAS4CryptoFactor
@Nonnull
public static ESuccess parseUserOrSignalMessage (@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nonnull final IPModeResolver aPModeResolver,
@Nonnull final IAS4PModeResolver aPModeResolver,
@Nonnull final IAS4IncomingAttachmentFactory aIAF,
@Nonnull final IAS4IncomingProfileSelector aAS4ProfileSelector,
@Nonnull @WillNotClose final AS4ResourceHelper aResHelper,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class AS4IncomingProfileSelectorFromGlobal implements IAS4IncomingProfile
@Nullable
public String getAS4ProfileID (@Nonnull final IAS4IncomingMessageState aIncomingState)
{
return AS4ProfileSelector.getAS4ProfileID ();
return AS4ProfileSelector.getDefaultAS4ProfileID ();
}

public boolean validateAgainstProfile ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
import com.helger.phase4.model.pmode.leg.EPModeSendReceiptReplyPattern;
import com.helger.phase4.model.pmode.leg.PModeLeg;
import com.helger.phase4.model.pmode.leg.PModeLegSecurity;
import com.helger.phase4.model.pmode.resolve.IPModeResolver;
import com.helger.phase4.model.pmode.resolve.IAS4PModeResolver;
import com.helger.phase4.profile.IAS4Profile;
import com.helger.phase4.util.AS4ResourceHelper;
import com.helger.phase4.util.AS4XMLHelper;
Expand Down Expand Up @@ -351,7 +351,7 @@ public boolean hasAsyncResponseURL ()
private final IAS4IncomingMessageMetadata m_aMessageMetadata;
private IAS4CryptoFactory m_aCryptoFactorySign;
private IAS4CryptoFactory m_aCryptoFactoryCrypt;
private IPModeResolver m_aPModeResolver;
private IAS4PModeResolver m_aPModeResolver;
private IAS4IncomingAttachmentFactory m_aIncomingAttachmentFactory;
private IAS4IncomingSecurityConfiguration m_aIncomingSecurityConfig;
private IAS4IncomingReceiverConfiguration m_aIncomingReceiverConfig;
Expand Down Expand Up @@ -469,12 +469,12 @@ public final AS4RequestHandler setCryptoFactory (@Nonnull final IAS4CryptoFactor
}

/**
* @return The {@link IPModeResolver} to be used. May be <code>null</code> if
* @return The {@link IAS4PModeResolver} to be used. May be <code>null</code> if
* not initialized.
* @since 3.0.0
*/
@Nullable
public final IPModeResolver getPModeResolver ()
public final IAS4PModeResolver getPModeResolver ()
{
return m_aPModeResolver;
}
Expand All @@ -486,7 +486,7 @@ public final IPModeResolver getPModeResolver ()
* @since 3.0.0
*/
@Nonnull
public final AS4RequestHandler setPModeResolver (@Nonnull final IPModeResolver aPModeResolver)
public final AS4RequestHandler setPModeResolver (@Nonnull final IAS4PModeResolver aPModeResolver)
{
ValueEnforcer.notNull (aPModeResolver, "PModeResolver");
m_aPModeResolver = aPModeResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.helger.phase4.v3.ChangePhase4V3;

/**
* Callback interface to determine the used AS4 profile of an incoming message.
*
* @author Philip Helger
* @since 0.13.0
*/
@ChangePhase4V3 ("As the AS4 profile ID is part of the sending process, reuse it for receiving")
public interface IAS4IncomingProfileSelector
{
/**
Expand All @@ -35,6 +38,7 @@ public interface IAS4IncomingProfileSelector
* The message state of processing. Never <code>null</code>.
* @return The AS4 profile ID or <code>null</code> if none was found.
*/
// TODO remove?
@Nullable
String getAS4ProfileID (@Nonnull IAS4IncomingMessageState aIncomingState);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@
import javax.annotation.concurrent.ThreadSafe;

import com.helger.commons.concurrent.SimpleReadWriteLock;
import com.helger.commons.string.StringHelper;
import com.helger.phase4.config.AS4Configuration;
import com.helger.phase4.mgr.MetaAS4Manager;
import com.helger.phase4.profile.IAS4Profile;
import com.helger.phase4.profile.IAS4ProfileManager;
import com.helger.phase4.v3.ChangePhase4V3;

/**
* Static helper class to make the AS4 profile selection more deterministic and
* flexible.
* Static helper class for the fallback AS4 profile selection.
*
* @author Philip Helger
* @since 0.9.13
*/
@ThreadSafe
@ChangePhase4V3 ("this class looks a bit superflowous and global. Think about a better solution")
public final class AS4ProfileSelector
{
private static final SimpleReadWriteLock RW_LOCK = new SimpleReadWriteLock ();
Expand All @@ -45,43 +40,48 @@ public final class AS4ProfileSelector
private AS4ProfileSelector ()
{}

/**
* @return The custom default AS4 profile ID. Defaults to <code>null</code>.
*/
@Nullable
public static String getCustomAS4ProfileID ()
public static String getCustomDefaultAS4ProfileID ()
{
return RW_LOCK.readLockedGet ( () -> s_sAS4ProfileID);
}

public static void setCustomAS4ProfileID (@Nullable final String sAS4ProfileID)
/**
* Set the custom default AS4 profile ID. This has precedence over the
* configured AS4 default profile ID, to allow for a runtime change.
*
* @param sAS4ProfileID
* The AS4 profile ID to set. May be <code>null</code>.
*/
public static void setCustomDefaultAS4ProfileID (@Nullable final String sAS4ProfileID)
{
RW_LOCK.writeLocked ( () -> s_sAS4ProfileID = sAS4ProfileID);
}

/**
* Get the AS4 profile ID to be used in the following order:
* Get the default AS4 profile ID to be used in the following order:
* <ol>
* <li>From {@link #getCustomAS4ProfileID()}</li>
* <li>from the configuration properties</li>
* <li>from the current {@link IAS4ProfileManager} (since v2.3.0)</li>
* <li>From {@link #getCustomDefaultAS4ProfileID()}</li>
* <li>from the configuration properties.</li>
* </ol>
*
* @return The AS4 profile ID to be used. May be <code>null</code>.
*/
@Nullable
public static String getAS4ProfileID ()
public static String getDefaultAS4ProfileID ()
{
String ret = getCustomAS4ProfileID ();
if (ret == null)
// Is a custom default provided?
String ret = getCustomDefaultAS4ProfileID ();
if (StringHelper.hasNoText (ret))
{
// Fall back to the configuration file
// The profile ID from the configuration file is optional
// This should be the only place, where this method is called for
// evaluation - all other occurrences should use this method instead.
ret = AS4Configuration.getDefaultAS4ProfileID ();
if (ret == null)
{
// Fall back to the default profile ID
final IAS4Profile aDefProfile = MetaAS4Manager.getProfileMgr ().getDefaultProfileOrNull ();
if (aDefProfile != null)
ret = aDefProfile.getID ();
}
}
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
import com.helger.phase4.model.mpc.IMPCManager;
import com.helger.phase4.model.pmode.IPMode;
import com.helger.phase4.model.pmode.leg.PModeLeg;
import com.helger.phase4.model.pmode.resolve.IPModeResolver;
import com.helger.phase4.model.pmode.resolve.IAS4PModeResolver;
import com.helger.xml.XMLHelper;

/**
Expand All @@ -85,7 +85,7 @@ public class SoapHeaderElementProcessorExtractEbms3Messaging implements ISoapHea

private static final Logger LOGGER = LoggerFactory.getLogger (SoapHeaderElementProcessorExtractEbms3Messaging.class);

private final IPModeResolver m_aPModeResolver;
private final IAS4PModeResolver m_aPModeResolver;
private final Consumer <? super IPMode> m_aPModeConsumer;
private final IAS4IncomingReceiverConfiguration m_aIncomingReceiverConfiguration;

Expand All @@ -101,7 +101,7 @@ public class SoapHeaderElementProcessorExtractEbms3Messaging implements ISoapHea
* The incoming receiver configuration. May not be <code>null</code>.
* Since v3.0.0.
*/
public SoapHeaderElementProcessorExtractEbms3Messaging (@Nonnull final IPModeResolver aPModeResolver,
public SoapHeaderElementProcessorExtractEbms3Messaging (@Nonnull final IAS4PModeResolver aPModeResolver,
@Nullable final Consumer <? super IPMode> aPModeConsumer,
@Nonnull final IAS4IncomingReceiverConfiguration aIRC)
{
Expand Down Expand Up @@ -345,6 +345,8 @@ public ESuccess processHeaderElement (@Nonnull final Document aSoapDoc,
{
// Find PMode
String sPModeID = null;
final String sService = aCollaborationInfo.getService ().getValue ();
final String sAction = aCollaborationInfo.getAction ();
String sAgreementRef = null;
if (aCollaborationInfo.getAgreementRef () != null)
{
Expand All @@ -356,8 +358,8 @@ public ESuccess processHeaderElement (@Nonnull final Document aSoapDoc,
final String sAddress = m_aIncomingReceiverConfiguration.getReceiverEndpointAddress ();

aPMode = m_aPModeResolver.findPMode (sPModeID,
aCollaborationInfo.getService ().getValue (),
aCollaborationInfo.getAction (),
sService,
sAction,
sInitiatorID,
sResponderID,
sAgreementRef,
Expand All @@ -366,7 +368,22 @@ public ESuccess processHeaderElement (@Nonnull final Document aSoapDoc,
// Should be screened by the XSD conversion already
if (aPMode == null)
{
final String sDetails = "Failed to resolve PMode '" + sPModeID + "' using resolver " + m_aPModeResolver;
final String sDetails = "Failed to resolve PMode '" +
sPModeID +
"' / '" +
sService +
"' / '" +
sAction +
"' / '" +
sInitiatorID +
"' / '" +
sResponderID +
"' / '" +
sAgreementRef +
"' / '" +
sAddress +
"' using resolver " +
m_aPModeResolver;
LOGGER.error (sDetails);
aProcessingErrorMessagesTarget.add (EEbmsError.EBMS_PROCESSING_MODE_MISMATCH.errorBuilder (aLocale)
.errorDetail (sDetails)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import com.helger.phase4.incoming.IAS4IncomingReceiverConfiguration;
import com.helger.phase4.incoming.crypto.IAS4IncomingSecurityConfiguration;
import com.helger.phase4.model.pmode.IPMode;
import com.helger.phase4.model.pmode.resolve.IPModeResolver;
import com.helger.phase4.model.pmode.resolve.IAS4PModeResolver;

/**
* This class manages the SOAP header element processors. This is used to
Expand Down Expand Up @@ -94,7 +94,7 @@ public ICommonsOrderedMap <QName, ISoapHeaderElementProcessor> getAllElementProc
}

@Nonnull
public static SoapHeaderElementProcessorRegistry createDefault (@Nonnull final IPModeResolver aPModeResolver,
public static SoapHeaderElementProcessorRegistry createDefault (@Nonnull final IAS4PModeResolver aPModeResolver,
@Nonnull final IAS4CryptoFactory aCryptoFactorySign,
@Nonnull final IAS4CryptoFactory aCryptoFactoryCrypt,
@Nullable final IPMode aFallbackPMode,
Expand Down
Loading

0 comments on commit 096e03f

Please sign in to comment.