Custom IExternalApplicationProcessor In Acumatica

In a relatively recent version of Acumatica, the “External Applications” screen was added, adding in an easy way to connect to OAuth 2.0 Applications.

There is a relatively short list of “Types” of applications that can be used with this screen. But how would one perhaps add their own custom type to this drop-down list? In this blog post, I will show you how.

IExternalApplicationProcessor, the interface that defines the class that handles the OAuth Processing, implements two important fields, TypeCode, which corresponds with the drop down value in the “Type” field, and TypeName which is the label that corresponds with the drop down value.

Acumatica automatically detects all classes that implement this interface and injects them inside of the ExternalApplicationProcessorFactory, and makes them available for choosing in the Type dropdown and also makes them available for use.
Now with your new external application using your custom type, you can leverage the functionality by using the methods on ApplicationMaint. Unfortunately it seems like the ApplicationMaint graph does not automatically take into account whether the token is expired or not, since there are two methods, SignInWithoutRefresh, and RefreshAccessToken. Here are the method signatures

    [PXInternalUseOnly]
    public OAuthToken SignInWithoutRefresh(
      OAuthApplication oAuthApplication,
      OAuthToken existingToken = null)
    {
    }

    [PXInternalUseOnly]
    public void RefreshAccessToken(OAuthToken token, OAuthApplication oAuthApplication)
    {
    }

Of course, with these methods marked with [PXInternalUseOnly], don’t expect to get any certification by using them in your solution! But it might be very helpful to leverage this screen’s functionality in a one-off customization rather than manually managing authorization tokens and catching the redirect manually.

Allowing SystemDefaultTlsVersions

Recently, I was integrating Acumatica with an ActiveMQ message queue. I was having a problem connecting and getting the following error:

The specified value is not valid in the 'SslProtocolType' enumeration.
Parameter name: sslProtocolType

   at System.Net.Security.SslState.ValidateCreateContext(Boolean isServer, String targetHost, SslProtocols enabledSslProtocols, X509Certificate serverCertificate, X509CertificateCollection clientCertificates, Boolean remoteCertRequired, Boolean checkCertRevocationStatus, Boolean checkCertName)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)
   at Apache.NMS.ActiveMQ.Transport.Tcp.SslTransport.CreateSocketStream()
   at Apache.NMS.ActiveMQ.Transport.Tcp.TcpTransport.Start()
   at Apache.NMS.ActiveMQ.Transport.WireFormatNegotiator.Start()
   at Apache.NMS.ActiveMQ.Transport.TransportFilter.StartAsync()
   at Apache.NMS.ActiveMQ.Connection.d__225.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Apache.NMS.ActiveMQ.Connection.d__206.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Apache.NMS.ActiveMQ.Connection.CreateSession()

After digging into the pull requests, I saw that the following internal property on the ServicePointManager was what was giving me grief, not allowing Windows to default to the latest TLS version, even though the ActiveMQ .Net client wanted to:

update getAllowedProtocol default return value by PatMealeyTR · Pull Request #21 · apache/activemq-nms-openwire (github.com)

_SslState.cs (microsoft.com)

This property can be enabled in the web.config file, or in the system registry. I chose to add it to the system registry. It is suggested that you also add the following registry keys here to make sure you don’t default to unsecure TLS/SSL protocols. (WARNING, CHANGING THE REGISTRY CAN BREAK YOUR COMPUTER, PLEASE VERIFY THIS WILL WORK IN YOUR SITUATION)

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -Name 'DisabledByDefault' -Value '1' -Type DWord

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -Name 'Enabled' -Value '1' -Type DWord

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Name 'DisabledByDefault' -Value '1' -Type DWord

Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Name 'Enabled' -Value '1' -Type DWord

The key you need to add to also allow the system to default to a TLS protocol (for .NET Framework 4.8) is here:

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319

Add a DWord (32 bit) called SystemDefaultTlsVersions and set its value to Hexidecimal 1, here is a powershell script to do it

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SystemDefaultTlsVersions' -Value '1' -Type DWord

Voila, error resolved!