SOAP request using Lua

Lua is a short and simple language exposing the power of C in clean syntax. In recent project I had to make lua talk to SOAP Server on a payment gateway. I was able to do this successfully. The lua code is based on LuaSoap. You can down the full sample code from here. It required three libraries to be built on the *nix system before the actual soap request is made. Happy tweaking with Lua.

http://onlinepaymentprocessing.com/downloads/lua/agms_lua_example_1_0_0.zip
README.md

## Dependencies

LuaSOAP version >= 3.0.0 (https://github.com/tomasguisasola/luasoap)
LuaExpat version >= 1.3.0 (http://matthewwild.co.uk/projects/luaexpat)
LuaSocketgit version >= 3.0-rc1 (https://github.com/diegonehab/luasocket)
LuaSec version >= 0.4.1 (https://github.com/brunoos/luasec)

The libraries are included in the lib folder. Please note the luasec-0.5.0 do not work on Centos environment.


## Package Dependencies:
Ubuntu:lua-dev, libexpat-dev, openssl-devel
CentOS: lua-devel, expat-devel, openssl-dev


## Compile Instructions

The libexpat can be built using the `make`. Upload the libexpat folder on your developement server and issue `make` command.

The luasocket can be built and installed using make. Upload the luasocket library on your development machine and issue `make {PLATEFORM}` and then `make install`. Please note the path of CDIR - path to *.so files and LDIR - path to lua files. These need to be updated in the lua script

The luasec can be built using the make. Upload the libsec-0.4 folder on your developement server and issue `make` command



## Path Lua and C Libraries

The correct path of these libraries (Lua & C) needs to be set in the run.lua for them to work. 

agms.lua

#!/usr/bin/lua
-- Agms Module to interact with the Agms Gateway

-- @author: Maanas Royy
-- @copyright: Avant-Garde Marketing Solutions, Inc.

agms = {}

 -- Request Object
 agms.Request = {}
 agms.Request.TransactionType = ""
 agms.Request.GatewayUserName = ""
 agms.Request.GatewayPassword = ""
 agms.Request.PaymentType = ""
 agms.Request.Amount = ""
 agms.Request.Tax = ""
 agms.Request.Shipping = ""
 agms.Request.OrderDescription = ""
 agms.Request.OrderID = ""
 agms.Request.PONumber = ""
 agms.Request.CCNumber = ""
 agms.Request.CCExpDate = ""
 agms.Request.CVV = ""
 agms.Request.CheckName = ""
 agms.Request.CheckABA = ""
 agms.Request.CheckAccount = ""
 agms.Request.AccountHolderType = ""
 agms.Request.AccountType = ""
 agms.Request.SecCode = ""
 agms.Request.FirstName = ""
 agms.Request.LastName = ""
 agms.Request.Company = ""
 agms.Request.Address1 = ""
 agms.Request.Address2 = ""
 agms.Request.City = ""
 agms.Request.State = ""
 agms.Request.Zip = ""
 agms.Request.Country = ""
 agms.Request.Phone = ""
 agms.Request.Fax = ""
 agms.Request.EMail = ""
 agms.Request.Website = ""
 agms.Request.ShippingFirstName = ""
 agms.Request.ShippingLastName = ""
 agms.Request.ShippingCompany = ""
 agms.Request.ShippingAddress1 = ""
 agms.Request.ShippingAddress2 = ""
 agms.Request.ShippingCity = ""
 agms.Request.ShippingState = ""
 agms.Request.ShippingZip = ""
 agms.Request.ShippingCountry = ""
 agms.Request.ShippingEmail = ""
 agms.Request.ShippingPhone = ""
 agms.Request.ShippingFax = ""
 agms.Request.ProcessorID = ""
 agms.Request.TransactionID = ""
 agms.Request.Tracking_Number = ""
 agms.Request.Shipping_Carrier = ""
 agms.Request.IPAddress = ""
 agms.Request.Track1 = ""
 agms.Request.Track2 = ""
 agms.Request.Track3 = ""
 agms.Request.Track_Type = ""
 agms.Request.Custom_Field_1 = ""
 agms.Request.Custom_Field_2 = ""
 agms.Request.Custom_Field_3 = ""
 agms.Request.Custom_Field_4 = ""
 agms.Request.Custom_Field_5 = ""
 agms.Request.Custom_Field_6 = ""
 agms.Request.Custom_Field_7 = ""
 agms.Request.Custom_Field_8 = ""
 agms.Request.Custom_Field_9 = ""
 agms.Request.Custom_Field_10 = ""
 agms.Request.SAFE_Action = ""
 agms.Request.SAFE_ID = ""
 agms.Request.ReceiptType = ""
 agms.Request.MICR = ""
 agms.Request.MICRSymbolSet = ""
 agms.Request.CheckFrontTIFF = ""
 agms.Request.CheckBackTIFF = ""
 agms.Request.CheckNumber = ""
 agms.Request.Terminal_ID = ""
 agms.Request.CCNumber2 = ""
 agms.Request.Clerk_ID = ""
 agms.Request.Billing_Code = ""
 agms.Request.InvoiceID = ""
 agms.Request.BatchID = ""
 agms.Request.DLNumber = ""
 agms.Request.DLState = ""
 agms.Request.IdentityVerification = ""
 agms.Request.CourtesyCardID = ""
 agms.Request.MagData = ""

 -- Response Object
 agms.Response = {}
 agms.Response.STATUS_CODE = ""
 agms.Response.STATUS_MSG = ""
 agms.Response.TRANS_ID = ""
 agms.Response.AUTH_CODE = ""
 agms.Response.AVS_CODE = ""
 agms.Response.AVS_MSG = ""
 agms.Response.CVV2_CODE = ""
 agms.Response.CVV2_MSG = ""
 agms.Response.ORDERID = ""
 agms.Response.SAFE_ID = ""
 agms.Response.FULLRESPONSE = ""
 agms.Response.POSTSTRING = ""
 agms.Response.BALANCE = ""
 agms.Response.GIFTRESPONSE = ""
 agms.Response.MERCHANT_ID = ""
 agms.Response.CUSTOMER_MESSAGE = ""


 -- AgmsAPI method
 agms.AgmsAPI = {}
 agms.AgmsAPI.url = "https://gateway.agms.com/roxapi/agms.asmx"

 function agms.AgmsAPI.ProcessTransaction (request)

 -- Fabricate the SOAP Request Body
 local request_body = {tag = "objparameters"}
 for key, val in pairs(request) do
 if val ~= "" then
 table.insert(request_body, { tag = key, val})
 end
 end
 
 -- Soap Call, Important part add the namespace
 local ns, meth, ent = agms.soap_client.call(
 {url = agms.AgmsAPI.url,
 namespace = "https://gateway.agms.com/roxapi/",
 soapaction = "https://gateway.agms.com/roxapi/ProcessTransaction",
 method = "ProcessTransaction",
 entries = {request_body}
 })
 
 return ns, meth, ent
 
 end


return agms






run.lua

#!/usr/bin/lua
-- Lua code to interact with the Agms Gateway

-- @author: Maanas Royy
-- @copyright: Avant-Garde Marketing Solutions, Inc.

-- Define package path to load libraries
package.path = './lib/luasoap-3.0/src/?.lua;' .. package.path -- luasoap
package.path = './lib/luaexpat-1.3.0/src/?.lua;' .. package.path -- luaexpat
package.path = '/usr/local/share/lua/5.1/?.lua;' .. package.path -- luasocket
package.path = './lib/luasec-0.4.1/src/?.lua;' .. package.path -- luasec

-- Define package path to load C libraries
package.cpath = './lib/luaexpat-1.3.0/src/?.so;' .. package.cpath -- luaexpat
package.cpath = '/usr/local/lib/lua/5.1/?.so;' .. package.cpath -- luasocket
package.cpath = './lib/luasec-0.4.1/src/?.so;' .. package.cpath -- luasec

-- Import agms 
local agms = require "agms"
-- Import helper function to print lua table
local print_r = require "helper"

-- Import LuaSoap
agms.soap_client = require "client"
-- Import SSL, Version 0.4 require you to call https before we can actually load ssl.https.
-- It exports module as ssl.https
require "https"
local https = require "ssl.https"

-- Assign the https protocol in SOAP client
agms.soap_client.https = https

-- Prepare Request
agms.Request.GatewayUserName = "##########";
agms.Request.GatewayPassword = "##########";
agms.Request.TransactionType = "sale";
agms.Request.PaymentType = "creditcard";
agms.Request.Amount = "1.00";
agms.Request.CCNumber = "4111111111111111";
agms.Request.CCExpDate = "0120";
agms.Request.CVV = "123";

-- Debug request
-- print_r(agms.Request)

local ns, meth, ent = agms.AgmsAPI.ProcessTransaction(agms.Request);
print("namespace = ", ns, "element name = ", meth)
for i, elem in ipairs (ent[1]) do
 print (elem['tag'], '=', elem[1])
end

Install Oracle Java 8 (JDK 8u25) on CentOS/RHEL 6/5 and Fedora

Step 1: Download JAVA Archive

Download latest Java SE Development Kit 8 release from its official download page or use following commands to download from shell.

For 64Bit

# cd /opt/
# wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.tar.gz"

# tar xzf jdk-8u25-linux-x64.tar.gz

For 32Bit

# cd /opt/
# wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-i586.tar.gz"

# tar jdk-8u25-linux-i586.tar.gz

Note: If Above wget command doesn’t not worked for you watch this screencast to downloadJDK from terminal.

Step 2: Install JAVA using Alternatives

After extracting archive file use alternatives command to install it. alternatives command is available in chkconfig package.

# cd /opt/jdk1.8.0_25/
# alternatives --install /usr/bin/java java /opt/jdk1.8.0_25/bin/java 2
# alternatives --config java


There are 3 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*  1           /opt/jdk1.8.0/bin/java
 + 2           /opt/jdk1.7.0_55/bin/java
   3           /opt/jdk1.8.0_25/bin/java

Enter to keep the current selection[+], or type selection number: 3

At this point JAVA 8 has been successfully installed on your system. We also recommend to setup javac and jar commands path using alternatives

# alternatives --install /usr/bin/jar jar /opt/jdk1.8.0_25/bin/jar 2
# alternatives --install /usr/bin/javac javac /opt/jdk1.8.0_25/bin/javac 2
# alternatives --set jar /opt/jdk1.8.0_25/bin/jar
# alternatives --set javac /opt/jdk1.8.0_25/bin/javac 
Step 3: Check Version of JAVA .

Check the installed version of java using following command.

# java -version 

java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

Step 4: Setup Environment Variables

Most of java based application’s uses environment variables to work. Set the java environment variables using following commands

    • Setup JAVA_HOME Variable
# export JAVA_HOME=/opt/jdk1.8.0_25
    • Setup JRE_HOME Variable
# export JRE_HOME=/opt/jdk1.8.0_25/jre
    • Setup PATH Variable
# export PATH=$PATH:/opt/jdk1.8.0_25/bin:/opt/jdk1.8.0_25/jre/bin

Enabling e1000 Gigabit device emulation in Citrix XenServer

The following howto describes modification to critical system software. If you choose to follow this guide, you do so at your own risk.

The problem

The commercial version of the Citrix XenServer does not allow you to choose the type of ethernet adapter to emulate within your VM. The standard device that is emulated is a Realtek 8139 (RTL8139), which is a 100Mbit/sec Fast Ethernet card.

Citrix themselves do not view this as a major issue, as they expect you to install paravirtualised drivers within your guest operating system. This is usually a very good idea and just fine if you’re using Windows, or a major supported OS such as Red Hat, CentOS or Ubuntu. Under these Linux operating systems, your entire kernel must be replaced by a Citrix supplied kernel. The paravirtualised drivers will outperform any emulated device.

However, if you’re running a system with a customised non-standard kernel that doesn’t support Citrix Xen paravirtualisation, you’ll be stuck with a 100Mbit/sec bottleneck in your network. Sure, you can go and rebuild your kernel with the right paravirtualised drivers, but that’s not always an option.

Those familiar with the open source version of Xen will know that the underlying QEMU device emulation that Xen uses can emulate an Intel 1Gbit/sec adapter, called “e1000”. Apart of the additional speed, this device also supports jumbo ethernet frames. This emulation mode is available under Citrix XenServer, but is a hidden feature, due to hard-coding of the Realtek driver option.

Enabling e1000 emulation

You’ll need to ssh into your Citrix server and become root. Then do the following:

First rename /usr/lib/xen/bin/qemu-dm to /usr/lib/xen/bin/qemu-dm.orig

# mv /usr/lib/xen/bin/qemu-dm /usr/lib/xen/bin/qemu-dm.orig

Then make a replacement /usr/lib/xen/bin/qemu-dm file like this

#!/bin/bash
oldstring=$@
newstring=${oldstring//rtl8139/e1000}
exec /usr/lib/xen/bin/qemu-dm.orig $newstring

Then chmod (to make it executable) and chattr it (to stop it being overwritten):

# chmod 755 /usr/lib/xen/bin/qemu-dm
# chattr +i /usr/lib/xen/bin/qemu-dm

If you now shutdown and re-start your Citrix virtual machines, they will have an emulated e1000 device.

Warning

The “chattr” line above makes the replacement file “immutable”. This means that the file cannot be overwritten, prevents the loss of this modification in the event of a system update.

However, this may cause updates provided by Citrix to fail at the point of installation. An alternative approach would be leave the file unprotected, and re-applying this modification after Citrix-supplied updates have been applied.

The remove the protection from the file, do the following:

 

# chattr -i /usr/lib/xen/bin/qemu-dm

Relocating an Apache DocumentRoot under Selinux

Selinux works pretty well straight out of the box, but I have learnt that when application reconfigurations mysteriously result in failures to startup – then Selinux is generally the culprit. In particular, if any file locations are customised from what’s installed, Selinux will lock it down, and for the uninitiated, the debugging process can be quite confusing. Apache webserver (HTTPD) provides a good example of what happens in this scenario, and I’ll demonstrate how to make it work with the Document Root in a different location.

Selinux can be distinctly daunting for Linux sysadmins, and often seems to be more trouble than it’s worth. However it is an extremely powerful tool which increases security and encourages rigour in configuration. Essentially, Selinux augments the usual Unix file permissions and ownership by adding more granular application-specific contexts as well. I won’t go into the details here, as it’s well documented elsewhere.

What I’ll aim to show here is two ways for relocating the Apache DocumentRoot directory – the proper way, and a quicker dirtier way.

Say, you decide to situate the Apache webserver root under /home/apache/www instead of the default /var/www/html. You edit the /etc/httpd/conf/httpd.conf and change the DocumentRoot line to:

DocumentRoot /home/apache/www

Copy your HTML files into place, change the directory and file onwerships, and permissions:

# chown -R apache. /home/apache/www
# chmod 755 /home/apache/www
# chmod 644 /home/apache/www/*

(NB: That’s not a typo – you can type “apache.”, with the dot at the end, in chown rather than “apache:apache” and save yourself a few keystrokes).

Restart httpd to make sure, and browse to your web page. You’ll get something like this in your browser:

Forbidden
You don't have permission to access / on this server.

And in /var/log/httpd/error_log:

[client 10.65.140.97] (13)Permission denied: access to /index.html denied

This is because the Apache back-end process, running as user “apache”, can’t access the file /home/apache/www/index.html – even though we granted all the correct permissions. What gives? Turns out, with Selinux, having regular old permissions and ownership isn’t enough.

Here’s how you can fix this, nice and quickly.

First things first, check that you’ve got Selinux running, and that this is in fact the source of your problem:

  # getenforce
Enforcing

Yep. Next, check the Selinux context of the original HTTPD DocumentRoot directory. The ls command has the “-Z” switch which displays this:

# ls -ldZ /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

Take note of the colon-delimited string “system_u:object_r:httpd_sys_content_t:s0″. Take note of this string; you’ll need it later. Each field is:

  • User: system_u
  • Role: object_r
  • Type: httpd_sys_content_t
  • Level: s0

Checking the Selinux context on our new erroneously configured folder, we see this:

# ls -Z file1
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /home/apache/www

So this explains why Apache can’t read the index.html file – it’s got the wrong Selinux context for Apache to read it. You can see how this enhances security. Apache can never server up a page unless it has explicitly got a context set that matches Apache privilege.

To reset the directory and file contexts, you need to ensure that the semanage software is installed (it may not be, depending on what package groups you have):

  # yum whatprovides */semanage
  # yum -y install policycoreutils-python

A very full discussion of how to change Selinux policies and file contexts is given here, but briefly, the steps are:

  # semanage fcontext -a -t httpd_sys_content_t "/home/apache/(/.*)?"
  # restorecon -Rv /home/apache
restorecon reset /home/apache context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/apache/www context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/apache/www/index.html context unconfined_u:object_r:var_t:s0->system_u:object_r:httpd_sys_content_t:s0

The semanage argument “/home/apache/(/.*)?” is a regular expression indicating the context should apply to the directory “/home/apache” and everything under it. Yes you need to do this for the home directory as that stays in user_sys_content. Unless you change that the https will still complain.

Quick and Dirty Fix
If, however you don’t have access to the semanage program or if you just need to make a small ad hoc change to a file context, you can simply set this manually. Remember that string coloured red earlier? Grab the relevant text from it.

  # chcon -R -u system_u -t httpd_sys_content_t /home/apache/

This command uses the “-R” switch so will apply recursively to all files under the directory. Note that the difference between this command and the semanage command is that chcon will not update the Selinux policy.

So the proof of the pudding will be in the reloading. Ctrl-R your browser and BOOM! Your page is back and being happily server up.

Install gnupg php extension in centos

All commands ran via SSH as root from /root. If you get “No package available” errors, you probably need to install the EPEL repositories.

yum install libgpg-error yum install libgpg-error-devel yum install gpgme yum install gpgme-devel yum install pygpgme pecl install gnupg

You will then need to edit your /usr/local/lib/php.ini file and verify/insert the extension=gnupg.so line. If this line isn’t already in the file, just add it at the bottom. Run php -m and look for a gnupg line. Next run php -r "phpinfo();". You should see something like:

gnupg support => enabled GPGme Version => 1.1.8 Extension Version => 1.3.2-dev

Then you’ll just need to restart the web server .

Device eth0 does not seem to be present, delaying initialization

Recently I’ve been deploying quite a few VMs for a wide range of different services.

When adding the new ethernet card or if you want to switch eth0 and eth1, the issue is there’s a hard preset storage of the MAC address to system network device. When trying to bring up eth0 I got this error message.

Device eth0 does not seem to be present, delaying initialization  

This became quite common when working with cloning images.
Dmesg revealed that eth0 has been renamed to eth1 (udev: renamed network interface eth0 to eth1)

The simple fix is to remove the persistent rule and give it a reboot. Don’t forget to update the networks file /etc/sysconfig/network-scripts/ifcfg-ethx

Comment or Modify UUID and MAC Address

nano /etc/sysconfig/network-scripts/ifcfg-eth0  
rm -f /etc/udev/rules.d/70-persistent-net.rules  
reboot  

Now when the server reboots, these persistent-net.rules will be regenerated again on boot with the new mac addresses.