Infor Grid on CryptDB

I made a proof of concept of the Infor ION Grid running on CryptDB, a database that computes on encrypted data.

Fully homomorphic encryption

Let’s suppose Alice is a client that is computationally bounded, she has an input X, she wants to compute an arbitrary program P on her input X and get the result where P is computationally intensive, she wants to delegate her computation to a powerful server (e.g. cloud provider) while preserving the privacy of her input (untrusted cloud). The way to do this is to encrypt the input, do the computation on the cipher text, and output the encryption of the result. A fully homomorphic encryption (FHE) is an encryption scheme that achieves that. It is currently still impractical in its full form because the algorithms take exponential time, but it is generating a lot of research in both academia and the industry, and they are bringing variants that make it practical.

CryptDB

CryptDB is a practical database server that allows SQL queries on encrypted data using SQL-aware encryption schemes (e.g. deterministic encryption for joins, order-preserving encryption for comparison predicates, homomorphic encryption for sums). The threat model for CryptDB is to ensure the privacy of the data in the face of a compromise of the database server.

I learned about CryptDB during the MIT cyber security courseMicrosoft Always Encrypted with SQL Server is another implementation.

Proof of concept

I made a proof of concept of the Grid running on CryptDB. I have not followed the guidelines to optimize the encryption schemes for the Grid; I just used the default CryptDB with the goal to spark interest in homomorphic encryption. The ideal would be to apply homomorphic encryption to M3.

1. Preparation

Install Ubuntu 12.04 (as required by CryptDB), Ruby, Git, and JDK 7 (minimum requirement for the Grid):

sudo apt-get install ruby git openjdk-7-jdk

2. Install CryptDB

  1. Download and build CryptDB; it will take some time:
    git clone -b public git://g.csail.mit.edu/cryptdb
    cd cryptdb/cd cryptdb/
    sudo scripts/install.rb .

  2. It will install MySQL on default port 3306; for the root password, enter CryptDB’s default letmein
  3. Start the CryptDB proxy (e.g. on default port 3307; change the EDBDIR accordingly):
    export EDBDIR=/home/thibaud/cryptdb/
    cd $EDBDIR
    bins/proxy-bin/bin/mysql-proxy \
     --plugins=proxy --event-threads=4 \
     --max-open-files=1024 \
     --proxy-lua-script=$EDBDIR/mysqlproxy/wrapper.lua \
     --proxy-address=127.0.0.1:3307 \
     --proxy-backend-addresses=localhost:3306

3. Install the Grid

  1. Install the Grid on MySQL (see part 8), but via CryptDB (i.e. port 3307 instead of 3306):
    mysql -u root -pletmein -h 127.0.0.1 -P 3307
    create database InforIONGrid;
    use InforIONGrid;
    CREATE TABLE ...

  2. Change the Grid’s config/jdbc.properties to use CryptDB instead of MySQL (i.e. port 3307 instead of 3306):
  3. Fix the CryptDB proxy query parser (it fails on column aliases and on the USER() function):
    cryptdb/mysqlproxy/wrapper.lua
    if string.find(query, "auto_increment_increment AS auto_increment_increment") then
        return -- fix for MySQL JDBC driver ConnectionImpl.loadServerVariables
    end
    if query == "SELECT USER()" then
        query = "SELECT CURRENT_USER()" -- fix for Grid Agent
    end
    

4. Start the Grid

Start the Grid as usual (see part 8).

Result

The result is a Grid running transparently on CryptDB, unaware that the underlying data is encrypted, while CryptDB does the computation on the encrypted data on behalf of the Grid:

The CryptDB proxy intercepts the queries (QUERY), it parses them and encrypts them (NEW QUERY), it executes them on MySQL, it decrypts the result and returns the clear text to the Grid:

Benefits

The advantages are that the Grid data is encrypted which preserves its privacy in case the database server is compromised, and the Grid application did not have to be rewritten for it.

If someone were to compromise the database server, they would only see encrypted table names and columns and encrypted data that does not reveal information about the actual data:

Potential

I hope this proof of concept inspires Infor Product Development to consider this type of security for their applications that run on the multi-tenant cloud, such as M3. Secure multi-party computation and homomorphic encryption are the future direction for the security of multi-tenant clouds and a potential market not yet realized.

That’s it!

Please like, comment, share, subscribe, and come write the next idea.

Building an Infor Grid Lab – Part 3

I am building an Infor ION Grid laboratory manually without LifeCycle Manager (LCM) for my learning purposes. In part 2, I had made the installation using cryptographic keys taken from an existing Grid installation. Today, I will create new keys.

About

The Grid uses TLS to ensure privacy, authentication, and integrity of communication within the Grid. That involves asymmetric cryptography, public/private key pairs, key exchange, digital certificates, digital signatures, symmetric keys, ciphers, etc.

Thankfully the Grid automates most of it. It uses the Java Cryptography Extension (JCE), the Bouncy Castle Crypto APIs, and 2048 bit RSA key pairs. The key material is unique to each installation.

Documentation

The Infor Documentation Infocenter has an Infor ION Grid Security Administration Guide:

Disclaimer

The Infor documentation that is publicly available covers the default cryptographic properties of the Grid such as algorithms, providers, cipher suites, block cipher modes of operation, hashing functions, padding, key length, paths, file names, etc.; the Internet covers cryptography in general; and I am not revealing any secrets; therefore, I am revealing no more information than what is already available publicly. Besides, revealing cryptographic properties does not reveal any secrets, therefore Infor is not revealing any secrets either. Besides, the default properties can be changed to suit our needs. The security of a cryptosystem depends not on the knowledge of its cryptographic properties, but on its implementation and on the security of the secret key material. Thus, it is important you keep your systems up-to-date, and keep your secret key material secure. In doubt, read Auguste Kerckhoffs’s principle, “il faut qu’il puisse sans inconvénient tomber entre les mains de l’ennemi” or Claude Shannon’s maxim, “we shall assume that the enemy knows the system being used.”

Key material

For a minimalist Grid installation, we need the following four files, they are unique to each installation:

For the Grid, we need these files, where the file names must match the Grid name, e.g. Grid:

  • Grid.ks: this is the Java keystore for the Grid. It contains the Grid’s public/private key pair, and the Grid self-signed certificate which will be the root certificate authority (CA) to sign other keys.
  • Grid.pw (optional): this is the clear text password for both keystore and private key.

For each host, we need these files, where the file names are server:

  • server.ks: this is the Java keystore for the host. It contains the host’s public/private key pair, and the host certificate signed by the Grid.
  • server.pw: this is the clear text password for both keystore and private key.
  • server.key: this is a symmetric key, signed and encrypted, used to encrypt/decrypt protected Grid properties.

In a production environment, keep all these files secure.

Console tool

The Grid has a console tool that automatically creates the key material:

In addition to the console tool, I will show the equivalent command using the Java keytool, and I will inspect the result with KeyStore Explorer.

1. Create Grid material

Use this command to create new key material for the Grid (replace the parameter values with your values, and use a strong password):

java ^
 -cp resources\grid-core.jar;resources\bcprov-jdk16.jar;resources\bcmail-jdk16.jar ^
 com.lawson.grid.security.Certificates ^
 -create=gridcert ^
 -gridname Grid ^
 -gridpassword password123 ^
 -gridkeystore secure

It produces these two files:

  • Grid.der
  • Grid.ks

Note: Grid.der is the root CA that typically system administrators will push to the users computers, and then those computers will automatically trust the certificates of M3, Smart Office, etc.

Note: Unfortunately, the command does not automatically generate a strong password for this keystore, which leaves it vulnerable to user choice.

The Grid certificate has the following extensions:

  • Basic Constraints: Subject is a CA, Path Length Constraint: 1
  • Subject Key Identifier
  • Key Usage: Digital Signature, Certificate Signing
  • Extended Key Usage: TLS Web Server Authentication, Code Signing, TLS Web Client Authentication

Alternatively, instead of the console tool, we can use the Java keytool:

keytool ^
 -genkeypair ^
 -keyalg RSA ^
 -keysize 2048 ^
 -sigalg SHA256WITHRSA ^
 -dname cn=Grid ^
 -ext BasicConstraints=ca:true,pathlen:1 ^
 -ext KeyUsage=digitalSignature,keyCertSign ^
 -ext ExtendedkeyUsage=serverAuth,codeSigning,clientAuth ^
 -validity 90 ^
 -keypass password123 ^
 -keystore secure\Grid.ks ^
 -storepass password123

Then, we need to do some export/import to add the certificate as a separate entry:

keytool ^
 -exportcert ^
 -file secure\Grid.der ^
 -keystore secure\Grid.ks ^
 -storepass password123
keytool ^
 -changealias ^
 -alias mykey ^
 -destalias grid_key ^
 -keypass password123 ^
 -keystore secure\Grid.ks ^
 -storepass password123
keytool ^
 -noprompt ^
 -importcert ^
 -alias mykey ^
 -file secure\Grid.der ^
 -keypass password123 ^
 -keystore secure\Grid.ks ^
 -storepass password123
keytool ^
 -changealias ^
 -alias mykey ^
 -destalias grid_cert ^
 -keypass password123 ^
 -keystore secure\Grid.ks ^
 -storepass password123

2. Create host material

Use this command to create new key material for the host (replace the parameter values with your values, and add as many roles and addresses as needed for this host):

java ^
 -cp resources\grid-core.jar;resources\bcprov-jdk16.jar;resources\bcmail-jdk16.jar ^
 com.lawson.grid.security.Certificates ^
 -create=hostcert ^
 -gridname Grid ^
 -gridpassword password123 ^
 -hostname localhost ^
 -gridkeystore secure ^
 -hostkeystore secure ^
 -role grid-admin ^
 -address localhost ^
 -address ::1 ^
 -address 127.0.0.1 ^
 -address example.com ^
 -unresolved

It produces these two files:

  • server.ks
  • server.pw

Note: Fortunately, the command automatically generates a strong password for this keystore.

The host certificate has extensions for the role (e.g. grid-admin), for the host actor (SYSTEM), for the IP addresses and hostnames:

Alternatively, instead of the console tool, we can use the Java keytool. But it is tricky for we have to add the certificate extensions in hexadecimal. The IANA enterprise number for Lawson Software (Infor) is 10105. The OID names can be found in the OID repository. Note: Thomas Fanto registered child OID 238 for the Grid runtime information in 2009, but somehow the console tool uses child OID 237 instead, which is not reserved. Anyway, dump the OID values as hexadecimal (e.g. grid-admin is 677269642D61646D696E, and SYSTEM is 53595354454D). Prefix them with the ASN.1 UTF8String tag byte of 0x0C to encapsulate them as a UTF-8 String and with the byte length in HEX (e.g. grid-admin is 10 bytes long which is 0x0A, and SYSTEM is 6 bytes long which is 0x06). For the sequences, prefix them with the SEQUENCE tag byte of 0x30 and with the sequence byte length (e.g. 9+3+9+11+2*4 = 40 = 0x28).

keytool ^
 -genkey ^
 -alias localhost_key ^
 -keyalg RSA ^
 -keysize 2048 ^
 -sigalg SHA256WITHRSA ^
 -dname cn=localhost ^
 -ext 1.3.6.1.4.1.10105.237.0.2=300C0C0A677269642D61646D696E ^
 -ext 1.3.6.1.4.1.10105.237.0.3=0C0653595354454D ^
 -ext 1.3.6.1.4.1.10105.237.0.4=30280C096C6F63616C686F73740C033A3A310C093132372E302E302E310C0B6578616D706C652E636F6D ^
 -validity 90 ^
 -keypass password123 ^
 -keystore secure\server.ks ^
 -storepass password123

Then, we need to create a certificate signing request (CSR) for the host certificate, sign it with the Grid root CA, and import the resulting chain to the keystore:

keytool ^
 -certreq ^
 -alias localhost_key ^
 -keyalg SHA256WITHRSA ^
 -file secure\server.csr.txt ^
 -keystore secure\server.ks ^
 -storepass password123
keytool ^
 -gencert ^
 -infile secure\server.csr.txt ^
 -outfile secure\server.der ^
 -keystore secure\Grid.ks ^
 -storepass password123 ^
 -alias grid_key ^
 -ext BC=0
keytool ^
 -importcert ^
 -noprompt ^
 -trustcacerts ^
 -alias grid_key ^
 -file secure\Grid.der ^
 -keystore secure\server.ks ^
 -storepass password123
keytool ^
 -importcert ^
 -trustcacerts ^
 -alias localhost_key ^
 -file secure\server.der ^
 -keystore secure\server.ks ^
 -storepass password123

Then, save the keystore password with:

echo | set /p="password123" > secure\server.pw

3. Create symmetric material

Use this command to create new symmetric key material (replace the parameter values with your values):

java ^
 -cp resources\grid-core.jar;resources\bcprov-jdk16.jar;resources\bcmail-jdk16.jar ^
 com.lawson.grid.security.Certificates ^
 -create=symkey ^
 -gridname Grid ^
 -gridkeystore secure ^
 -gridpassword password123 ^
 -symkeypath secure ^
 -hostkeystore secure ^
 -hostname localhost

It produces this file:

  • server.key

It is used to encrypt/decrypt protected Grid properties such as passwords:

Alternatively, we can generate the server.key in Java by taking the Grid certificate’s distinguished name in ASN.1 DER encoded form, signing it with the Grid’s private key, and encrypting it with the host’s public key, but I am not allowed to show the source code for that, and I am struggling with replicating it with the OpenSSL RSA utility and AES encryption. So use the Grid command tool above to generate server.key.

Result

We now have the new unique necessary and sufficient cryptographic key material for a minimalist Grid, and the Grid successfully validates it:

successfully initialized secret key
successfully initialized server keystore

GitHub

I collected all the commands in my GitHub at keys.cmd.

Future work

Next time, I would like to:

  • Generate the symmetric key with OpenSSL
  • Continue researching security vulnerabilities
  • Use the new Grid installer
  • Setup an administrative router
  • Setup session providers
  • Install applications
  • Install the Grid on Linux and PostgreSQL

Conclusion

That was an illustration of how to manually create – for learning purposes – new cryptographic keys for a minimalist installation of the Infor ION Grid using the built-in tools, and alternatively using the Java keytool. I am learning so I probably missed a few things. Thankfully the Grid console tool automates most of it.

That’s it! Congratulations if you’ve made it so far.

Related posts

Let’s Encrypt Infor e-Commerce

Today I setup SSL/TLS for Infor e-Commerce using Let’s Encrypt, the new free, automated, and open Certificate Authority (CA).

Topology

Infor e-Commerce (f.k.a. Movex e-Sales) is a J2EE application running on IBM HTTP Server (IHS) and IBM WebSphere Application Server (WAS), where IHS is on the DMZ and has a certificate on port 443, and where WAS is on the local network and has a certificate on port 9043. That’s two certificates.

Step 1. Backup

Backup the following IHS and WAS files in case you need to restore them:

IBM
├───HTTPServer
│   ├───conf
│   │       httpd.conf
│   │
│   └───Plugins
│       └───config
│           └───webserver1
│                   plugin-cfg.xml
│                   plugin-key.crl
│                   plugin-key.kdb
│                   plugin-key.rdb
│                   plugin-key.sth
│
└───WebSphere
    └───AppServer
        └───profiles
            └───AppSrv01
                ├───config
                │   └───cells
                │       └───Node01Cell
                │           │   security.xml
                │           │
                │           └───nodes
                │               ├───AppNode01
                │               │       key.p12
                │               │       trust.p12
                │               │
                │               └───WebNode01
                │                   └───servers
                │                       └───webserver1
                │                               httpd.conf
                │                               plugin-cfg.xml
                │                               plugin-key.crl
                │                               plugin-key.kdb
                │                               plugin-key.rdb
                │                               plugin-key.sth
                │                               server.xml
                │
                └───etc
                        clientCert.arm
                        key.p12
                        serverCert.arm
                        trust.p12

Step 2. Setup IHS on DMZ

Setup IHS on the DMZ (DNS, firewall, etc.) to serve requests on the Internet:

Step 3. Key database

Let’s verify the key database.

The public/private keys, certificate signing requests (CSR), intermediate certificates, and signed certificates are managed in the IBM key database file format (KDB). Apparently, that format does not allow importing private keys that are created externally (e.g. with OpenSSL or EFF’s Certbot), so we must create them internally using either the IBM Key Management tool (iKeyman), the WAS admin console, or the gsk7cmd command. I will use iKeyman.
  1. Find the latest version of iKeyman (there are several versions of iKeyman throughout IHS and WAS); use version 8.0.399 or later for the most recent cryptographic properties (e.g. SHA256):
    C:\IBM\HTTPServer\Plugins\bin\ikeyman.bat
  2. Open the default plugin key database:
    C:\IBM\HTTPServer\Plugins\config\webserver1\plugin-key.kdb

    The default password is WebAS. You can recover a lost password by calculating the stash (plugin-key.sth) XOR 245, or you can create a new key database from scratch.
  3. Ensure the Signer Certificates contains the same signer certificates as the WAS default trust store (e.g. datapower and root); compare by fingerprints. They should already be there; otherwise, extract them from the WAS admin console, and add them to the key database. That will allow IHS to trust WAS over SSL:

Step 4. Generate key pair + CSR

Let’s generate a public/private key pair and CSR.

  1. In iKeyman, delete the default personal certificate:
  2. Create a new key pair and CSR with the FQDN and cryptographic properties of your choice, leave the email address blank or certbot will throw an error, and save to some temporary file (e.g. certreq.arm):
  3. The result is a new public/private key pair in the key database (plugin-key.kdb) and a new CSR in PKCS#10 format (certreq.arm):

Step 5. Submit CSR to Let’s Encrypt

Let’s submit the CSR to Let’s Encrypt and get a signed certificate in return.

In the ACME protocol, the Let’s Encrypt servers will issue a set of challenges, and our web server must respond correctly to prove ownership of the domain. Normally, it is all automated, but there is no certbot plugin for IHS, so I will use the manual plugin. And because I have not yet tried an ACME client for Windows, I will use certbot on my Linux virtual machine.
  1. Execute certbot with the CSR as input:
    certbot certonly --manual --csr ~/certreq.arm
  2. Enter your email address, accept the Terms of Service, enter the domain name, and select Yes to log your IP address. It will present a challenge (a signed nonce):
  3. Create the specified file with the specified content at the specified path:
    C:\IBM\HTTPServer\htdocs\.well-known\acme-challenge\
  4. Test the URL over the Internet (the Let’s Encrypt servers will request it):
  5. Back in certbot, press ENTER to complete the domain validation:
  6. The result is a signed certificate, intermediate chain, and full chain:
    0000_cert.pem
    0000_chain.pem
    0001_chain.pem

Step 5bis. Submit CSR to another CA

If you prefer, you can skip Let’s Encrypt, and submit the CSR to another CA of your choice (Verisign, Thawte, GoDaddy, Comodo, etc.).

Step 6. Add the certificate

Let’s receive the signed certificate into the key database.

  1. In iKeyman > Personal Certificates, receive the certificate 0000_cert.pem:
  2. Extract the Let’s Encrypt root certificate from one of the chains (e.g. with OpenSSL), or download it directly from IdenTrust at DST Root CA X3, and save it to a temporary file somewhere (e.g. dst_root.pem).
  3. In Signer Certificates, add the intermediate certificate 0000_chain.pem (Let’s Encrypt Authority X3), and the root certificate dst_root.pem (DST Root CA X3):
  4. Copy the key database files to WAS:
    C:\IBM\WebSphere\AppServer\profiles\AppSrv01\config\cells\Node01Cell\nodes\Node01\servers\webserver1\

Step 7. SSL in IHS

Let’s enable SSL in IHS.

  1. Open the IHS configuration file in a text editor (e.g. Notepad):
    C:\IBM\HTTPServer\conf\httpd.conf
  2. Add the following directives:
    ServerName example.com
    LoadModule ibm_ssl_module modules/mod_ibm_ssl.so
    KeyFile C:\IBM\HTTPServer\Plugins\config\webserver1\plugin-key.kdb
    SSLStashFile C:\IBM\HTTPServer\Plugins\config\webserver1\plugin-key.sth
    Listen *:443
    <VirtualHost *:443>
    SSLEnable
    SSLProtocolDisable SSLv2 SSLv3
    SSLServerCert default
    </VirtualHost>
    SSLDisable
  3. Add the following to redirect all HTTP traffic to HTTPS; it is required for at least the login page, password change, credit card, XML Gateway, and a few other sensitive pages; it is optional for the rest:
    LoadModule rewrite_module modules/mod_rewrite.so
    RewriteEngine on
    RewriteCond %{SERVER_PORT} =80
    RewriteRule ^(.*) https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
  4. Copy httpd.conf to WAS:
    C:\IBM\WebSphere\AppServer\profiles\AppSrv01\config\cells\Node01Cell\nodes\Node01\servers\webserver1\httpd.conf

Step 8. SSL in WAS

Let’s enable SSL in WAS.

  1. Ensure the default key store has a personal certificate signed by the signer certificates verified earlier:
  2. Set the default SSL configuration to use that server certificate (default):

WAS will not have the Let’s Encrypt certificate, but that’s OK for now.

Step 9. Backup + restart

Backup the files, and restart IHS and WAS.

Result

The result is that the browser now trusts the site:

Limitations

Let’s Encrypt does not provide Extended Validation (EV) certificates.

Future work

  • Use an ACME client for Windows
  • Automate the manual steps
  • Setup certificate renewal
  • Setup certificate revocation
  • Setup the new certificate in WAS too
  • Setup WAS for remote web server management
  • Replace IHS with nginx

Conclusion

That was my setup of SSL/TLS for Infor e-Commerce using Let’s Encrypt as the certificate authority. In a next post, I would like to setup the certificate in WAS too and setup automatic certificate renewal.

That’s it! Please like, comment, subscribe, share, contribute.

Infor e-Commerce XML Gateway

Here is my first test of the Infor e-Commerce XML Gateway.

It is something like https://example.com/infor-ecom/common/gateway.jsp?user=u&password=p&object=o&method=m&request=r

About

The XML Gateway is an API in Infor e-Commerce, for third-party software to make requests to e-Commerce, e.g. to create an order, to get an invoice, or to delete an item. The requests are XML documents, in the proprietary IdealXML schema, sent to e-Commerce over HTTP, targeting the e-Commerce Business Objects and methods.

History

The XML Gateway has existed since the early days of Ideal Seller and e-Sales about 20 years ago:
9 3___ 8

License

The current part number is M3C-SGX Infor e-Commerce B2B XML Application Adapter:
1

Is MEC required? No.

Despite what the Infor sales and documentation say, Infor ION, Infor M3 Enterprise Collaborator (MEC), and the e-Commerce Extension for MEC, are NOT required to use the XML Gateway; the XML Gateway is built-in e-Commerce. MEC is suggested for it provides useful features such as development tools, transaction management, persistence, XML transformation, connection pooling, logging, monitoring, management, etc. Apart from that, you can use any other software that does XML over HTTP. Besides, if you were to use MEC, it would have to be the ancient version 9.0.4.0 which is probably not compatible with the MEC you already have for M3:

Documentation

There is some documentation available. The greatest amount of information is located in the Infor e-Commerce Development Studio User’s Guide, and there is some in the Developer’s Guide, Administration Guide, and Configuration Guide for Infor ION:
5__ 6__ 7 14

Business Objects

The business objects and methods of the XML Gateway are listed in the Business Center at Gateway > Requests:

The code is automatically generated from the e-Commerce Development Studio, e.g. Business Object Item and method GatewayDetails to get the details of an item by input parameter ItemID:
40 41 42 43 44

Source code

For the curious of us, we can peak at the source code.

The source code starts at /infor-ecom/src/common/gateway.jsp and includes the automatically generated JSP fragment Gateway.jspf:
10

And the e-Commerce Java library common-10.0.0.jar includes the class com.intentia.iec.businessobject.input.XMLRequest which parses the XML input:
11

That is sufficient to start peaking at source code.

Furthermore, the e-Commerce Extension for MEC ecom-extension-9.0.0.jar includes the class com.intentia.iec.meci.http.HttpRequester which sends the HTTP request:
12

And the ION Connector’s MEC Custom Channel iecprotocol-2.0.0.jar includes the class com.intentia.ec.channel.IECGateway which also sends an HTTP request:
13

Samples

There are sample XML requests in the proprietary IdealXML schema located at C:\Program Files (x86)\Infor\Infor e-Commerce 14.9.1.0\XML Sample Documents\IdealXML 2.0\:
16 17

XSD

The XML requests are validated with the proprietary IdealXML Schema located at Infor e-Commerce Development Studio\Infor e-Commerce Extension for Enterprise Collaborator\dist\e-Commerce\request.xsd:
15

The Development Studio User’s Guide has a chapter The iXML document format.

XSLT? No.

The latest version of the XML Gateway does NOT provide XSL Transformation (XSLT); it may have been included in the early versions when it was ASP, not anymore. You can easily develop a proxy JSP that does XSLT and that forwards the request to gateway.jsp. I will explore this in a future post. Otherwise, if you use MEC and the e-Commerce Extension for MEC, you can do XSLT in MEC as usual.

Setup

To setup the XML Gateway:

Enable the desired Business Object Method (they are all enabled by default), e.g. Item.GatewayDetails:
33

In the desired Role (e.g. I created role Third-party software), select the Feature Element Gateway User:

In the desired User B2B, select that role:

Still, I am not able to reproduce the setup for another user, and I do not know why.

HTTP request

The HTTP request is of the form:

POST https://example.com:443/infor-ecom/common/gateway.jsp HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: example.com:443
Content-Length: 123

user=u&password=p&object=o&method=m&request=r

Where:

  • I recommend HTTPS (secure), not HTTP (insecure).
  • The scheme, hostname and port number are those of your e-Commerce, e.g. https://example.com:443.
  • The method can be either GET (with the parameters in the URL) or POST (with the parameters in the request body), but I advise against GET because the user and password would be in the URL, and nodes along the way may store the URL in clear text in the logs; I recommend POST instead.
  • The URL path is /infor-ecom/common/gateway.jsp
  • The media type is application/x-www-form-urlencoded
  • The input parameters user and password are for authentication. Note: the XML Gateway does not accept HTTP Basic authentication.
  • The input parameters object and method are for the business object.
  • The input parameter request is the entire <IdealXML> content.
  • All parameters must be URL-encoded.

Test

For my test, I will call Item.GatewayDetails to get the details of item 9412-0111:

Here is the corresponding IdealXML that I created from the sample XML:

<?xml version="1.0" encoding="UTF-8"?>
<idealXML version="2.0" id="Thibaud test">
   <commands>
      <command>
         <request>
            <params>
               <param name="@LanguageCode">en</param>
            </params>
            <search>
               <bindings operand="or">
                  <bindings operand="and">
                     <binding attribute="ItemID" value="9412-0111" operator="eq"/>
                  </bindings>
               </bindings>
            </search>
         </request>
      </command>
   </commands>
</idealXML>

Notes:

  • I removed the <login> and <password> from the <credential> as they are ignored.
  • I removed the <command>’s name and method attributes as they are ignored.

Result

Here is the result in raw and parsed view:

The XML response is the following, successful, with the requested item details:

<?xml version="1.0" encoding="UTF-8"?>
<resultset object="Item">
   <row Description="For ITRAN GE BLACK INKJET CART 10/CTN" GroupCode="OE" GroupName="Impact Inking" IsActive="Y" IsDangerous="0" IsEmphasized="N" ItemCode="normal" ItemCodeID="normalItemCode" ItemField1="WELLS FARG" ItemField2="201502861.00" ItemField3="" ItemField4="12/99" ItemField5="Y" ItemID="9412-0111" Key="8685" MainCategoryID="59052" MinimumQty="0.0000" ModularQty="0.0000" Name=" INK JET EQUIPMENT" SupplierID="" UnitCodeID="CTItemUnit" Weight="2.4940">
      <Category CategoryID="59052" CategoryName=" INK JET EQUIPMENT" InternalName=" INK JET EQUIPMENT (59052)"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="de" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="en" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="fr" Name=" INK JET EQUIPMENT"/>
      <Text Description="For ITRAN GE BLACK INKJET CART 10/CTN" LanguageID="it" Name=" INK JET EQUIPMENT"/>
   </row>
</resultset>

Troubleshooting

For troubleshooting:

Inspect the HTTP response headers that indicate either success:

XMLGatewayStatusCode: 200
XMLGatewayMessage: OK

Or an error:

XMLGatewayStatusCode: 401
XMLGatewayMessage: Login failed
XMLGatewayStatusCode: 403
XMLGatewayMessage: Access to requested object or method not allowed
XMLGatewayStatusCode: 500
XMLGatewayMessage: Internal error while executing Gateway method

The Development Studio User’s Guide has a chapter Gateway error messages, with codes, but the codes do not match this.

It is better to look in the logs at C:\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\server1\SystemOut.log:
22

Problems

  • The user and password are echoed in clear text in the logs, it is insecure:
    23
  • The XML Gateway accepts requests over plain HTTP (instead of HTTPS) even though the request contains the user and password and other private data in clear text, it is insecure.

Future work

  • Force HTTPS (secure) by default, disable HTTP (insecure).
  • Do XSL transformation (XSLT).
  • Finish reproducing the setup.
  • Try the e-Commerce Extension for MEC.
  • Try the WSDL and the Infor e-Commerce Web Service Specifications for Synchronous Calls.
  • Try other Business Objects and methods.
  • Try custom Business Objects and methods.
  • Understand more about the bindings.

Conclusion

That was my first test of the XML Gateway in Infor e-Commerce, for third-party software to make requests to e-Commerce, e.g. to place an order or get the details of an item. I have more work to do if I want to master the XML Gateway.

That’s it!

Please like, comment, subscribe, share, participate.

SFTP in MEC

Infor M3 Enterprise Collaborator (MEC) now includes support for SSH FTP (SFTP), a secure file transfer protocol.

FTP vs. PGP vs. SFTP vs. FTPS

Plain FTP does not provide security properties such as confidentiality (against eavesdropping) and integrity (against tampering). FTP provides authentication, but it is plain text. As such, plain FTP is insecure and strongly discouraged.

Even coupled with PGP file encryption and signature verification to protect the contents of the file, the protocol, the credentials, the files and the folders are still vulnerable.

On the other hand, SFTP provides secure file transfer over an insecure network. SFTP is part of the SSH specification. This is what I will explore in this post.

There is also FTPS (also known as FTP-SSL and FTP Secure). Maybe I will explore that in another post.

MEC 9.x, 10.x, 11.4.2.0

If you have MEC 11.4.2.0 or earlier, your MEC does not have full built-in support for SFTP or FTPS. I found some traces in MEC 10.4.2.0, 11.4.1 and 11.4.2. And I was told that support for SFTP was made as a plugin sort of, in some MEC 9.x version; maybe they meant FTPS. Anyway, if you are handy, you can make it work. Or you can manually install any SFTP/FTPS software of your choice and connect it to MEC. Do not wait to secure your file transfers.

MEC 11.4.3.0

MEC 11.4.3.0 comes with built-in support for SFTP, and I found traces of FTPS. Unfortunately, it did not yet ship with documentation. I was told a writer is documenting it now. Anyway, we can figure it out by ourselves. Let’s try.

Here are the release notes:
3

In Partner Admin > Managed > Advanced, there are two new SFTP channels, SFTPPollIn and SFTPOut, which are SFTP clients:
5 6

By looking deeper at the Java classes, we find JCraft JSch, a pure implementation of SSH2 in Java, and Apache Commons VFS2:
2 13

SFTPOut channel

In this post, I will explore the SFTPOut channel in MEC which is an SFTP client for MEC to exchange files with an existing SFTP server.

Unit tests

Prior to setting up MEC SFTPOut, we have to ensure our MEC host can connect to the SFTP server. In my case, I am connecting to example.com [11.22.33.44], on default port 22, with userid mecuser, and path /outbound. Contact the SFTP server administrator to get the values, and eventually contact the networking team to adjust firewall rules, name servers, etc.

Do the basic networking tests (ICMP ping, DNS resolution, TCP port, etc.):

Then, do an SSH test (in my example I use the OpenSSH client of Cygwin). As usual with SSH TOFU, verify the fingerprint on a side channel (e.g. via secure email, or via phone call to the administrator of the SFTP server assuming we already know their voice):

Then, do an SFTP test:
4b

Optionally, compile and execute the Sftp.java example of JSch. For that, download Ant, set JAVA_HOME and ANT_HOME in build.bat, set the user@host in Sftp.java, and execute this:
build.bat
javac -cp build examples\Sftp.java
java -cp build;examples Sftp

16

Those tests confirm our MEC host can successfully connect to the SFTP server, authenticate, and exchange files (in my case I have permissions to put and retrieve files, not to remove files).

Now, we are ready to do the same SFTP in MEC.

Partner Admin

In Partner Admin > Manage > Communication, create a new Send channel with protocol SFTPOut, hostname, port, userid, password, path, filename, extension, and other settings:
78

I have not yet played with all the file name options.

The option for private key file is for key-based client authentication (instead of password-based client authentication). For that, generate a public/private RSA key pair, for example with ssh-keygen, and send the public key to the SFTP server administrator, and keep the private key for MEC.

The button Send test message will send a file of our choice to that host/path:
10

The proxy settings are useful for troubleshooting.

A network trace in Wireshark confirms it is SSH:

Now, we are ready to use the channel as we would use any other channel in MEC.

Problems

  • The SFTPOut channel does not allow us to verify the key fingerprint it receives from the SFTP server. Depending on your threat model, this is a security vulnerability.
  • There is a lack of documentation (they are working on it)
  • At first, I could not get the Send test message to work because of the unique file name (I am not familiar with the options) and the jzlib JAR file (see below).
  • MEC is missing JAR file jzlib, and I got this Java stacktrace:
    com.jcraft.jsch.JSchException: java.lang.NoClassDefFoundError: com/jcraft/jzlib/ZStream
    at com.jcraft.jsch.Session.initDeflater(Session.java:2219)
    at com.jcraft.jsch.Session.updateKeys(Session.java:1188)
    at com.jcraft.jsch.Session.receive_newkeys(Session.java:1080)
    at com.jcraft.jsch.Session.connect(Session.java:360)
    at com.jcraft.jsch.Session.connect(Session.java:183)
    at com.intentia.ec.communication.SFTPHandler.jsch(SFTPHandler.java:238)
    at com.intentia.ec.communication.SFTPOut.send(SFTPOut.java:66)
    at com.intentia.ec.partneradmin.swt.manage.SFTPOutPanel.widgetSelected(SFTPOutPanel.java:414)

    I was told it should be resolved in the latest Infor CCSS fix. Meanwhile, download the JAR file from JCraft JZlib, copy/paste it to the following folders, and restart MEC Grid application and Partner Admin:
    MecMapGen\lib\
    MecServer\lib\
    Partner Admin\classes\
  • Passwords are stored in clear text in the database, that is a security vulnerability yikes! SELECT PropValue FROM PR_Basic_Property WHERE PropKey='Password' . I was told it should be fixed in the Infor Cloud branch, and is scheduled to be merged back.
  • With the proxy (Fiddler in my case), I was only able to intercept a CONNECT request, nothing else; I do not know if that is the intention.
  • In one of our customer environments, the SFTPOut panel threw:
    java.lang.ClassNotFoundException: com.intentia.ec.partneradmin.swt.manage.SFTPOutPanel

Future work

When I have time, I would like to:

  • Try the SFTPPollIn channel, it is an SFTP client that polls an existing SFTP server at a certain time interval
  • Try the private key-based authentication
  • Try SFTP through the proxy
  • Try FTPS
  • Keep an eye for the three fixes (documentation, jzlib JAR file, and password protection)

Conclusion

This was an introduction about MEC’s support for SFTP, and how to setup the SFTPOut channel for MEC to act as an SFTP client and securely exchange files with an existing SFTP server. There is more to explore in future posts.

Please like, comment, subscribe, share, author. Thank you.

UPDATES 2017-01-13

  • Corrected definition of SFTPPollIn (it is not an SFTP server as I had incorrectly said)
  • Added security vulnerability about lack of key fingerprint verification in MEC SFTPOut channel
  • Emphasized the security vulnerability of the passwords in clear text

X.509 Token policy for M3 Web Services

I finally tested the X.509 Token policy in Infor M3 Web Services (MWS), and I share my results here.

X.509 Token Policy in MWS has been available for at least 7 years. For the setup, we create a public-private key and digital certificate for the SOAP client, and the SOAP client and SOAP server exchange certificates to authenticate each other.

Documentation

For an overview of WS-Security (WSS) in the context of M3, see my previous post.

The MWS Designer (MWSD) User Guide has two modest chapters dedicated to WS-Security and X.509 Token policy, and snippets of source code for a Java client:
doc55 doc77

For more information about the implementation of WS-Security in MWS, read the documentation of Apache CXF and Apache WSS4J (Merlin), and explore the MWS server source code in the lws-server and lws-common JARs:
jar

Enable X.509 Token policy

First, create a web service in MWSD, of any type (API, MDP, SQL), deploy it, and test it to ensure it works correctly, e.g. CRS610MI.GetBasicData:
1

Then, go to Infor ION Grid Management Pages > MWSSecurity > Policy Settings > Service Context (e.g. services), select the web service (e.g. CRS610MI), and click the lock icon to Enable X.509 policy token:2

Server certificate

Then, go to Certificate Management, and download the server certificate, MWSServerCert.cer:
3

Note: Download it over HTTPS (secure) and not HTTP (clear text); otherwise verify in a side channel the key fingerprint received.

Now, import the server certificate into the client keystore so that the client can authenticate the server:

$ keytool -importcert -file MWSServerCert.cer -alias MwsServer -keystore keystoreClient.jks

PROBLEM: Weak crypto

MWS uses weak cryptography [1], MD5 hashing algorithm and RSA key size 1024 bit:

Nowadays, it should use SHA256 and RSA key size 2048 bit. Maybe it is possible to upgrade the keys on the server; for future work:
8

Client keys and certificate

Then, generate a public-private key and digital certificate for the SOAP client; use any tool such as JRE’s keytool or OpenSSL:

$ keytool -genkeypair -keystore keystoreClient.jks -alias trustedclient_host -keyalg RSA

$ keytool -exportcert -keystore keystoreClient.jks -alias trustedclient_host -file trustedclient_host.cer

PROBLEM 1: Do not use the weak crypto recommended by the MWSD User Guide in the parameters keyalg and sigalg. Instead, let the keytool use the default values which today for RSA is 2048 bit key size and SHA256withRSA hashing [2].

PROBLEM 2: Use RSA because with DSA the MWS server throws “java.security.InvalidKeyException: Unsupported key type: Sun DSA Public Key”

PROBLEM 3: The MWSD User Guide uses -alias myalias. But when we upload the certificate to the server, the server changes the alias to “trustedClient_” + hostName regardless. So I use that alias too.

Note: Keep the private key private! If you need to send it somewhere, do so only over a secure channel (regular email is not a secure channel). On the other hand, the public key and certificate are public, so you can shout them in the street no problem.

Here is the client certificate with stronger crypto:
7_

Now, upload the client certificate to the MWS server, so that the server can authenticate the client (peer authentication):

Note: Upload over HTTPS (secure) and not HTTP (clear text); otherwise verify in a side channel the key fingerprint the server received.

Test with SoapUI

Now, test using any SOAP client that supports WS-Security, such as SoapUI.

Create a new SOAP project as usual:
10_

Go to Project View > WS-Security Configurations > Keystores, and add keystoreClient.jks and Password:

Go to Outgoing WS-Security Configurations, and add a configuration, e.g. outgoing.

Add an action Timestamp:

PROBLEM 1: The Timestamp must be non-zero, e.g. 10; if I set it to zero the server throws “Security processing failed (actions mismatch) […] An error was discovered processing the <wsse:Security> header” and I do not know why.

Add an Signature action (it is for the client to sign the message with its private key, and for the server to use the client’s public key and verify the integrity of the message received). Select the client Keystore, select the Alias of the client, set the keystore Password, in Parts add Name Body with the Namespace of <soapenv:Body> which is http://schemas.xmlsoap.org/soap/envelope/ and Encode Content, and leave the rest default:
12

Add an Encryption action (it is for the client to encrypt the message with the server’s public key, and for the server to decrypt it with its private key). Select the client Keystore, select the Alias of the server, set the keystore Password, in Parts add the same as above, and leave the rest default:
13

PROBLEM 2: SoapUI is buggy and does not always seem to immediately pick my changes in the configurations, so I had to close and re-open it to pick my changes.

Now for decryption, go to Incoming WS-Security Configurations, add a configuration, e.g. incoming (the server will encrypt the SOAP response with the client’s public key, so this is for the client to decrypt that using its private key; and the server will sign the SOAP response with its private key, and the client will verify the signature of the message received using the server’s public key). Select the Decrypt Keystore, the Signature Keystore, and set the keystore Password:
14

PROBLEM 3: There is a bug with decryption in SoapUI 5.2.1, and I solved it by replacing the version of wss4j.jar as explained in this post:
bug2

Now, create the sample SOAP request (SoapUI already created a sample request), remove the <soapenv:Header> which we do not need, set your input parameters (e.g. CustomerNumber), add Basic authentication with the M3 Username and Password, select to Authenticate pre-emptively (optional), select the Outgoing WSS and Incoming WSS, and click Submit:
15

The client will encrypt and sign the Body, the server will decrypt it and verify the signature, the server will execute the web service (e.g. CRS610MI.GetBasicData), it will encrypt and sign the response, and return it to the client.

Result

We now have the decrypted and verified SOAP response (e.g. CustomerName, CustomerAddress):
16

PROBLEM: Plain HTTP and authentication

My understanding of WS-Security is that by design it is an option to transport the message over plain HTTP. That scenario will occur when the message passes the TLS termination point and into proxies and gateways over plain HTTP. For that, we could securely set the M3 user/password in the SOAP header at <cred:lws> and add them to the Encryption and Signature actions. However, I tried it, and I removed the user/password from the HTTP Basic authentication, but MWS throws “401 Unauthorized […] WWW-Authenticate: Basic […] fault […] missing_credentials”:
bug

I found some old documentation from 2009 that sheds more light; maybe I have to use the Username Token instead; for future work:
doc126 doc127

Grid best practice

As a general best practice for the Grid, ensure the Configuration Manager > Routers > Default Router, has WWW Authentication Methods disabled for plain HTTP, and enabled for HTTPS only, to prevent sending user/password over plain HTTP:

Troubleshooting

Here are some tips for troubleshooting.

Use SoapUI’s six tabs of logs:
logs5

Set the MWS logs to DEBUG level:
logs
logs3

Set the MWS Debug Settings to create dump files of all the encrypted and signed SOAP requests (_IN.xml) and responses (_OUT.xml) in the MWS\dumps folder:
logs4
logs2

Set your SOAP client to use a proxy like Fiddler:
Fiddler_ Fiddler

Conclusion

That was my result of testing X.509 Token policy for M3 Web Services with SoapUI. It requires quite a good understanding of the public-key cryptography concepts (public-private keys, certificates, keystores, the dance between client and server, encryption, digital signatures), and it opened more questions than it answered.

Future work

I may work on the following in the future:

  • Implement a similar test client in Java
  • Upgrade the MWS server to stronger crypto
  • Call the web service over plain HTTP (instead of HTTPS)
  • Authenticate over plain HTTP (maybe Username Token, instead of Basic authentication or <cred:lws>)
  • Test MWS against WS-Attacker

That’s it.

Please subscribe, comment, like, share with your colleagues, write the next idea with us, or start your own blog.

SOAP WS-Security in the context of M3

Here is my high-level understanding of SOAP Web Services Security (WS-Security, or WSS), at least the WSS X.509 Certificate Token Profile, and how to apply it in the context of Infor M3.

WS-Security

WS-Security is a standard by the OASIS consortium to provide message encryption and digital signature, the usual security properties to prevent eavesdropping and tampering of a message. It uses asymmetric cryptography with public-private keys and digital certificates. There is an additional property which is central to WSS: the security happens at the message level, not at the transport level, i.e. the security follows the message even across proxies and deep packet inspection gateways, for end-to-end security. WSS is common for example in financial institutions that need to inspect and route a message through several nodes that can read the non-secure part of the SOAP envelope yet not reveal the secret in the message, until it reaches the appropriate destination. If a node on the path gets compromised, the security of the message is not compromised. Despite its continued use, WSS has only had few major updates in 10 years, is not considered secure [1] [2], the Internet agrees it is complicated and design-by-committee, and there is no industry momentum behind it.
versus1_

SSL/TLS, on the other hand, provides similar security properties with encryption and digital signature, using public key cryptography as well, but the security happens at the transport level, i.e. before the message level, for point-to-point security only. Thus, intermediate proxies and deep packet inspection gateways are unable to reveal the message to inspect it and route it, unless they have a copy of the destination’s private key. The workaround is to setup a chain of TLS segments, but the compromise of a node on the path, would compromise the message. TLS has additional security properties such as cipher suite negotiation, forward secrecy, and certificate revocation. TLS is constantly being updated with the latest security properties, and is widely supported and documented.

I have seen WSS interfaces used at banks and credit card companies that still have ancient mainframes and old middleware, and WSS is always used in combination with TLS, with peer authentication, thus four sets of public/private keys and digital certificates.
versus3

Infor Grid

Several applications of the Infor Grid expose SOAP web services, but I could not find how to setup WS-Security at the Grid level, so I assume it is not supported at the Grid level, only at the application level; that’s OK as SOAP over HTTPS is sufficient for the Grid’s needs.

grid

M3 Web Services (MWS)

The MWS application does have settings to configure WS-Security (X.509 Token policy); that would be useful for an external partner to call M3 with message-level security (otherwise there is always SOAP over HTTPS); I will explore this in a future post:
MWS

M3 Enterprise Collaborator (MEC)

The MEC application on the Grid does not have built-in SOAP web services. But in MEC Partner Admin the MEC developer can setup SOAP. The SOAP client Send Web Service process does not support WS-Security; this is most unfortunate as here is precisely where I want to setup the secure interfaces with the banks and credit card companies, bummer, I will have to develop my own WS-Security client in Java. On the other hand, the SOAP server WebServiceSyncIn does support WS-Security; I will explore this in a future post:
1

Future work

In future posts, I will:

  • Explore WS-Security in MWS
  • Explore WS-Security in MEC SOAP client
  • Explore WS-Security in MEC SOAP server

Conclusion

That was my high level understanding of WS-Security, at least the WSS X.509 Certificate Token Profile, and how to apply it in the context of M3. I am no expert in WS-Security, but this understanding is sufficient for my needs with M3.

That’s it!

Please subscribe, comment, like, share, and come author with us.

–Thibaud

 

Who is the author of an M3 mod?

Today I needed to find who is the developer of an M3 customer modification. There is a bug in the MForms Bookmark of program M3 Customer. Connect Addresses – OIS002 which the developer modified for our customer’s needs, and I needed to report the bug to that developer. But I do not have the MAK training nor tool, so I cannot easily see the list of modifications and their authors. My colleague Shashank remind me of the following answer in M3 Server View.

  1. Go to M3 Server View (from the Grid Management Pages, or from LifeCycle Manager):
    0
  2. Find the interactive subsystem that is running the program (in my case OIS002), and select Tools:
    1
  3. Select Find Class:
    2
  4. Search for the M3 program (in my case OIS002):
    3
  5. The line with the customer class will give the file path, version, author, date, and unique ID (in my case I found the author, Rajesh):
  6. Note: Up to here, we can access this page anonymously, without being an authenticated user nor an administrator (security vulnerability anyone?)
  7. Now, if we have access to the M3 Business Engine file system, we can open the file itself and see the full list of developers; in my case the file is at:
    D:\Infor\M3BE\env\M3BE_15.1_TST\Fix\CUS\VFix\src\mvx\app\pgm\customer\OIS002.java:
    5

That’s it.

Let me know in the comments below if you have other tips. Click Like. Share this post with your colleagues. Click Follow to subscribe. And come write the next blog post with us. This is a volunteer-based community, and your participation keeps this blog going. And send some love to the other M3 blogs too. Thank you.

M3 Web Services from Infor Process Automation

In order to securely call Infor M3 Web Services (MWS) from Infor Process Automation (IPA) we need to import the Infor Grid’s certificate in IPA’s Java truststore; here is how.

MWS authentication

MWS works with SOAP over HTTP over SSL/TLS with the digital certificate of the Infor Grid.

The Infor Grid router for MWS must have Basic authentication enabled over HTTPS (secure) and have all authentication disabled over HTTP (insecure); you can check in the Infor Grid > Configuration Manager > Routers > Default Router:
1.8

MWS from IPA

In the IPA Configuration > Web Service Connection, we set the Basic authentication with the M3 user and password:
3.6

In Infor Process Designer (IPD), we use the SOAP Web Service activity node to the HTTPS URL of MWS:
3.1

Tip: un-hard-code the scheme://host:port and replace it by a variable <!_configuration.main.MWS> to define.

Problem

When we execute the process we get the following exception:

com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

That is because IPA does not know the Infor Grid certificate.

The IPA Configuration for the Web Service Connection does not have settings for an explicit truststore. Instead, IPA implicitly relies on the JVM’s truststore; let’s set it up.

Step 1. Infor Grid certificate

Get the Infor Grid certificate file. It is a signed public key that you can get for example from the main Grid Information at something like https∶//host123.local:26108/grid/info.html
3.2  

Note: Preferably get the certificate of the root CA as it usually signs the certificates for all environments (DEV, TST, PRD, etc.).

Step 2. IPA server truststore

Check the path of the IPA server’s JVM as given in the Landmark Grid > Landmark-LM Application > Configuration > Properties > Java executable:
2.5

Import the certificate into that JVM’s truststore using the Java keytool:

keytool -import -keystore lib\security\cacerts -file grid.cer

3.5

Note: I may have mixed up the keystore and the truststore in the command; to be verified.

Step 3. IPD truststore

The path to the Infor Process Designer (IPD) JVM is given by the IPDesigner.ini file:
3.7 3.8

Import the certificate into that JVM’s truststore as well.

Step 4. Test

Now execute the process. The Web Service activity node should not throw that exception anymore.

Notes

If you have a certificate purchased from a certificate authority that is already trusted by the JVM, such as VeriSign, this setup is not necessary.

That’s it. Let me know what you think in the comments below.

HTTP channels in MEC (part 6)

Here is how to securely receive messages in MEC from partners over the Internet, in this sixth part of the guide on HTTP channels for Infor M3 Enterprise Collaborator (MEC). I will illustrate two goals: how to setup an HTTPIn or HTTPSyncIn channels in MEC over SSL/TLS, and how to expose them securely over the Internet. Previously, for the HTTPIn channel, refer to part 2; for the HTTPSyncIn channel refer to part 3; and for MEC over HTTP Secure (HTTPS) refer to part 5.

Goal

The desired goal is to allow partners to securely send messages to MEC using HTTP over SSL/TLS over the Internet. Also, the idea is to design the architecture in such a way that adding new partners is easy.

Here is the simplified diagram:

Problem

Unfortunately, MEC does not provide incoming channels for HTTPS, there are no HTTPSIn or HTTPSSyncIn channels. There is a WebServiceSyncIn channel that uses WS-Security for XML over SOAP, but it is not what I am interested in. Ideally, I would prefer to use the Infor Grid which already communicates via HTTPS, but unfortunately it does not have a native connection handler for MEC. Surprisingly, most projects I have seen use FTP + PGP, but that is insecure because the FTP username and password transit in clear text, so even though the files are encrypted a man-in-the-middle could intercept the credentials and create havoc like delete files or fill the disk with junk.

Alternatively, I could develop my own HTTPS server in Java on top of a custom MEC channel; the Java Secure Socket Extension (JSSE) is a good reference guide for how to implement SSL/TLS in Java. I have two options. I could use SSLServerSocket, but it uses blocking I/O contrary to MEC that uses non-blocking I/O for scalability and performance, consequently I would have to forgo scalability and performance. Or I could use SSLEngine to have non-blocking I/O for scalability and performance, but I would have to implement the entire TLS state machine which is overkill for my needs.

Design

I will setup a public web server https∶//partners.example.com/ at my sample company.

For that, I will setup a reverse proxy with SSL termination upstream of HTTPIn or HTTPSyncIn channels. Thanks to Rickard Eklind for the tip on using Apache + mod_proxy; I will use nginx + ngx_http_proxy_module instead, as it uses non-blocking I/O similar to HTTPIn and HTTPSyncIn, and I think it is easier to setup; either combination will work. I will need to setup the proxy server on the DMZ, setup DNS records, and generate digital certificates.

If you cannot host your own server on the DMZ, or if you cannot create your own domain name partners.example.com in the DNS records, or if you cannot create your own digital certificate signed by a trusted certificate authority, you may be able to piggy back on an existing public web server in your company and simply add a new virtual directory, like https∶//www.example.com/partners/ that will forward requests to a content-based filtering router, decrypt, filter, re-encrypt and send the requests to your reverse proxy in the LAN.
Alternatively, I could have setup a dedicated secure line per partner – such as a VPN with a filter to restrict access to only a specific destination IP address and port number for MEC on the LAN – but for each new partner that would require a lot of paperwork, security clearance, and setup on both ends, which is possible, it is more sandboxed thus more desirable, but it may not be possible in some companies. And in some clouds it may be easier to setup web servers than VPNs.

Reverse proxy with SSL termination

A reverse proxy is an intermediate server that executes the client’s request to the destination server on behalf of the client without the client being aware of the presence of the proxy; this is unlike a forward proxy that we setup in a browser. In our case, MEC partners will connect to the reverse proxy as if it were MEC, and the proxy will make the requests to MEC.

SSL termination is where the SSL/TLS connection ends. In our case, the partner will initiate the connection to the reverse proxy using the proxy’s digital certificate (which is the proxy’s public key signed by a certificate authority), then the proxy will decrypt the SSL/TLS data using its private key, then the proxy will make the HTTP request in plain text to MEC, and the response will transit back in the opposite direction. The partner will need to previously have verified and added in its keystore the proxy’s certificate or one of the certificate authorities up the chain.

Here is the simplified nginx.conf:

http {
   server {
      server_name partners.example.com;
      listen 443 ssl;
      ssl_certificate cert;
      ssl_certificate_key key;
      location / {
         proxy_pass http://ecollaborator:8080/;
      }
   }
}

Here is the simplified diagram:

Note 1: This scenario assumes the servers are on the same network which is not true for the Internet. I will put the proxy in the DMZ. See the DMZ section below.
Note 2: This scenario assumes the data does not need to be encrypted on the second network segment which is not true either. I will install a second proxy on the same host as MEC. See the end-to-end encryption section below.

Multiplexing

I need to accommodate multiple partners, for example partnerA, partnerB, and partnerC.

I will use virtual hosting to economically share resources on a single server instead of having a dedicated physical server or virtual private server per partner.

Path-based

I will multiplex by URL path, for example /A, /B, and /C. I conjecture this is no less secure than doing it name-based or port-based. Also, I conjecture it is not subject to XSS attacks so long as we enforce client authentication (see the client authentication section below).

Here is the simplified nginx.conf:

location /A {
   # partnerA
}
location /B {
   # partnerB
}
location /C {
   # partnerC
}

Here is the simplified diagram:

Name-based

Alternatively, I could multiplex by domain name, for example partnerA.example.com, partnerB.example.com, and partnerC.example.com. But then for each new partner I would need a new network interface with a new public IP address – which is scarce to obtain – and update the A records of my DNS server. Or to share the same IP address I could use Server Name Indication (SNI) and update the CNAME records of my DNS server. In any case, I would have to issue a new digital certificate with an updated Subject Alternative Name (SAN) extension, or I could use one wildcard certificate but loose the possibility of Extended Validation Certificate, and anyway wildcard certificate is not considered secure per RFC6125#section-7.2. In the end, it is a maintenance nightmare, and relying on the respective teams could be a bottleneck in some companies.

Port-based

As another alternative, I could multiplex by port number, for example partner.example.com:81, partner.example.com:82, and partner.example.com:83, indeed the same digital certificate will work for any port number, but then for each new partner I would have to update the firewall rules, it is possible, but it is more maintenance, and relying on the respective teams could be a bottleneck in some companies.

De-multiplexing

Then, I need to de-multiplex the requests to tell the partners apart in MEC. I will setup as many HTTPIn or HTTPSyncIn channels in MEC as there are partners, for example HTTPSyncIn_A on port 8081, HTTPSyncIn_B on port 8082, and HTTPSyncIn_C on port 8083, and in nginx for each partner I will setup a location block with a proxy_pass directive.

Here is the simplified nginx.conf:

location /A {
   proxy_pass http://ecollaborator:8081/;
}
location /B {
   proxy_pass http://ecollaborator:8082/;
}
location /C {
   proxy_pass http://ecollaborator:8083/;
}

Here is the simplified diagram:

demux

Here are the receive channels in Partner Admin:

Receive

Authentication

I need the client to authenticate the server, and vice versa, I need the server to authentication the client.

One of the properties of SSL/TLS is authentication, using digital certificates to affirm the identity of the entities, where server authentication is mandatory, and client authentication is optional. In my case, client authentication is mandatory.

Server authentication

The server (the reverse proxy) will present its digital certificate to the client (the MEC partner), and the client will do its certificate validation to authenticate the server.

Client authentication

On the other hand, the server (ultimately it is MEC) needs to authenticate the client (the MEC partner).

I could setup peer authentication for the proxy to verify the client’s digital certificate, but I have not tested this.

Instead, I will setup HTTP Basic authentication per path in the proxy. The username and password will be encrypted over SSL/TLS so they will remain confidential.  I will separate the locations and I will forward to each respective HTTPSyncIn channel in MEC.

Here is the simplified nginx.conf:

location /A {
   auth_basic "A";
   auth_basic_user_file A.htpasswd;
   proxy_pass http://ecollaborator:8081/;
}
location /B {
   auth_basic "B";
   auth_basic_user_file B.htpasswd;
   proxy_pass http://ecollaborator:8082/;
}
location /C {
   auth_basic "C";
   auth_basic_user_file C.htpasswd;
   proxy_pass http://ecollaborator:8083/;
}

In addition to that, we could setup rules in the firewall to only allow the source IP addresses of the partners to access the reverse proxy, it is great if combined with Basic authentication, but insufficient on its own.

To setup peer authentication, I would use ssl_verify_client. According to the nginx documentation, the context for the ssl_client_certificate directive is http and server only, not location. So I would have to append the various client certificates into one file; to be verified. And then I could use the $ssl_client_cert variable to tell partners apart; to be tested.
As another alternative, we could setup client authentication in the MEC agreement using a flat file detector to detect a username and password defined in the HTTP request payload. But that has many problems: 1) It would require hard-coding the username and password in clear text in MEC (passwords should be hashed and salted or at least encrypted), 2) if we need to change the password we would have to change and re-deploy the agreement, and 3) it would put the burden of password verification on MEC which is not designed to thwart brute force attacks.

Channel detection

Now, we have to carry over the authentication to MEC because even though nginx can pass the Basic authentication header to MEC, MEC does not use it, and if we do not authenticate partners and tell them apart they risk crossing each other. For that I will use a Channel detector in the MEC agreement of each partner.

Here are the channel detectors in Partner Admin:

detection

A drawback emerges from this setup: the number of possible messages per channel is now limited to only one. If partner A wants to send two different messages 1 and 2, for example new customer order and new rental agreement, MEC is not able to process two messages in one agreement, and it cannot reuse the same receive channel in another agreement. To assist MEC, I would have to discriminate further by path in nginx, for instance /A/message1, and /A/message2, and have as many receive channels as possible messages. I can use nested location blocks (I have not tested this). Here is the simplified nginx.conf:

location /A {
   auth_basic "A";
   auth_basic_user_file A.htpasswd;
   location /message1 {
      proxy_pass http://ecollaborator:8001/;
   }
   location /message2 {
      proxy_pass http://ecollaborator:8002/;
   }
}

I am not trained in MEC Partner Admin so maybe there is a way around it.

…on the Internet

Once a web server is placed on the Internet it will get attacked, so consult with your network and security team to harden your servers. It should at least be in the DMZ between one or two firewalls:

Here is a simplified diagram:

DMZ

Take also into account: high availability, redundancy, fail over, disaster recovery, edge caching, DNS round robin, IDS, content-based firewall, restrict physical access to the servers, restrict permissions to the files, software updates, operating system support, etc.

Note: The HTTP channels in MEC will be the single point of failure in spite of all this setup. The MEC Server runs on the Infor Grid, and the Infor Grid is meant to be distributed, fault tolerant, load balanced, scalable, and redundant. However, the HTTP channels of MEC are not Grid enabled (the HTTPIn and HTTPSyncIn channels manage their port and HTTP server themselves), so they are not distributed, fault tolerant, load balanced, scalable, and redundant, they are a single point of failure. You can learn more about Infor Grid application development on my other post.

End-to-end encryption

Now we need end-to-end encryption to protect the data on the second network segment from the reverse proxy on the DMZ to MEC on the LAN. For that, I will chain two reverse proxies with SSL termination. I will simply install the second proxy on the same host as MEC. And I will issue a second pair of digital certificate and private key for the second proxy that the two proxies will use to encrypt/decrypt. That simplifies the rules of the internal firewall, and I can setup peer authentication between the proxies.

Here is the simplified diagram with the two proxies X and Y:

chain

How to add new partners

To add a new partner D:

  1. Setup a new Receive channel in Partner Admin with a new HTTPIn or HTTPSyncIn channel for example on port 8084
  2. Setup a new agreement with channel detector
  3. Test by making an HTTP request to MEC on port 8084
  4. Setup the inner proxy:
    1. Setup a new location block in nginx.conf for path /D with proxy_pass directive to port 8084 and basic authentication
    2. Setup a new htpasswd file
    3. Restart nginx
    4. Test by making an HTTPS request to the proxy
  5. Setup the outer proxy to pass requests to the inner proxy and test it (I do not have guidelines here as my actual setup for the outer proxy uses a content-based router, not nginx)
  6. Test by making an HTTPS request from the partner to https∶//partners.example.com/D

How to setup multiple environments

To setup multiple environments, such as DEV, TST, PRD, use nested location blocks in nginx.conf, for example /DEV, /TST, /PRD (I have not tested this).

Here is the simplified nginx.conf:

location /DEV {
   location /A {
      # Development partnerA
   }
   location /B {
      # Development partnerB
   }
}
location /TST {
   location /A {
      # Test partnerA
   }
   location /B {
      # Test partnerB
   }
}

Limitations

This is the first time I setup this architecture, I have not tested all the design variations, and I have not validated that my design is a good design nor that it is secure. I am currently using a similar architecture at a major customer of mine for their production environment where they have multiple data centers, high availability, redundancy, fail over, and disaster recovery. One of their technical people reviewed the solution, they approved it, and the only concerns were that this solution might be over engineered (plausible) and that the MEC channels are the single point of failure anyway (true). I conjecture the solution is good enough and secure enough for our needs. Of course I could be completely wrong and not see a major flaw. Nothing is fully secure anyway. Please let me know what you think in the comments below.

Upcoming version of MEC

Johan Löfgren, the component owner for MEC at Infor Product Development, said they are working on a native HTTPSIn channel for an upcoming version of MEC; it is not GA and the release may or may not occur. If and when that happens, you would not need to chain two proxies anymore, you would just keep one proxy in the DMZ and use proxy_pass to send the requests directly to the HTTPSIn channels in MEC.

UPDATE 2015-04-12: What is being released is SFTP, no plans for HTTPS at the moment.

Conclusion

This was one solution to setup incoming HTTP channels in MEC to securely receive messages over SSL/TLS over the Internet. MEC does not have an HTTPSIn or HTTPSSyncIn channel, and I did not want to implement my own HTTP server over SSL/TLS in Java. Instead, I chose to setup a reverse proxy with SSL termination in a DMZ, with digital certificate and private keys, with HTTP basic authentication, with a second proxy in the MEC host for end-to-end encryption. This solution has many properties: it uses standard HTTP and SSL/TLS, and it is easy to add new partners. Also, we simplified the architecture upstream such that we do not have to rely on other teams if we need to add a new partner, which can be a maintenance nightmare and bottleneck in some companies; we can simply add new partners downstream in our proxy and Partner Admin. I conjecture this solution is secure for our needs. But remember it has not been fully reviewed, and the MEC channels are the single point of failure.

Please let me know what you think in the comments below.

Related articles