Pages

Sunday, 7 December 2014

Creating WADL friendly RESTFul Service using JDeveloper

Usecase:

This blog post talks about creating RESTful services from a java class in JDeveloper. The service is an Employee information service consisting of various operations involving GET, PUT, POST and DELETE verbs & parameters.

Pre-requisites:

JDeveloper 12.1.3.0.0

Steps:
  • Create a new custom application 'EmployeeService' in JDeveloper.
  • Createa a java class. Call it Employee.java. This class will be a bean holding the fields and getters and setters required for the employee.
  1. package project1;
    import javax.xml.bind.annotation.XmlRootElement;
    @XmlRootElement
    public class Employee {
        String name;
        int id;
       
        public Employee() {
            super();
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getId() {
            return id;
        }
    }

  • Create another java class called EmployeeWrapper.java. This is a wrapper class. The purpose of having the wrapper class is that it will ensure that a clean and complete WADL is generated at the end.
  1. package project1;
    import java.net.URI;
    import java.util.ArrayList;
    import java.util.List;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlElement;
    
    @XmlRootElement
    public class EmployeeList {
    
        private List<Employee> list = new ArrayList<Employee>();
    
    
        public EmployeeList() {
    
        }
    
        public EmployeeList(List<Employee> list) {
            super();
            this.list = list;
        }
    
     @XmlElement
        public List<Employee> getList() {
            return list;
        }
    }

  • Finally, we need another java class called the EmployeeService.java. This will be main service class in which we will configure the various operations of the service. You can copy the below code into your class and use the lightbulb next to @Path annotation to configure project for JAXRS service. Select the option JAXRS 2.0 style on being prompted. JDev will take care of the library configurations for you.
  1. package project1;
    import java.util.Iterator;
    import java.util.List;
    import java.util.concurrent.CopyOnWriteArrayList;
    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.QueryParam;
    
    @Path("project1")
    public class EmployeeService {
        private static List<Employee> employeeList = new CopyOnWriteArrayList<Employee>();
    
        public EmployeeService() {
            addEmp();
        }
    
        @GET
        @Produces("application/xml")
        public EmployeeList getEmpList() {       
            return new EmployeeList(employeeList);
        }
    
        @PUT
        @Consumes("application/xml")
        @Produces("application/xml")
        public EmployeeList addEmployee(Employee emp) {
            employeeList.add(emp);
            return new EmployeeList(employeeList);
        }
    
        @DELETE
        @Consumes("application/xml")
        @Produces("application/xml")
        public EmployeeList deleteEmployee(@QueryParam("name") String name) {
            employeeList.remove(getEmp(name));
            return new EmployeeList(employeeList);
        }
    
        @POST
        @Consumes("application/xml")
        @Produces("application/xml")
        public EmployeeList updateEmployee(@QueryParam("id") int id, @QueryParam("name") String name) {
            Employee emp1 = new Employee();
            emp1 = getEmpById(id);
            if(emp1 != null)
                emp1.setName(name);
            return new EmployeeList(employeeList);
        }
        
        public Employee getEmp(String name) {
            Iterator i = employeeList.iterator();
            while (i.hasNext()) {
                Employee e = (Employee)i.next();
                if (e.getName().equalsIgnoreCase(name))
                    return e;
            }
            return null;
        }
        
        public Employee getEmpById(int id) {
            Iterator i = employeeList.iterator();
            while (i.hasNext()) {
                Employee e = (Employee)i.next();
                if (e.getId() == id)
                    return e;
            }
            return null;
        }
    
        public void addEmp() {
            if (employeeList.isEmpty()) {
                Employee emp1 = new Employee();
                emp1.setId(1);
                emp1.setName("Arnold");
                employeeList.add(emp1);
                
                Employee emp2 = new Employee();
                emp2.setId(2);
                emp2.setName("Andy");
                employeeList.add(emp2);
            }
        }
    }
  • Run EmployeeService.java.
  • Click on the generated WADL URL. The Jdev internal tester - HTTP analyzer opens up. It shows you the WADL in a well defined manner with the various operations, input types, output types and parameters. It also provides a link to the XSD.

  • Click on Test button corresponding to the operation you want to invoke. HTTP analyzer window opens up in the REST Structure tab for you. As we have structured our service with wrapper classes, the REST structure renders data in a readable form. Below are snippets of the outputs obtained for GET and POST operations. To see the XML structure, you can navigate to the HTTP Content tab.



Using the approach of having a wrapper class while you are dealing with lists will ensure a good WADL structure. Also, it gets easier to test the service in analyzer as you are presented with a neat form for input, and structured data in the output. Give it a try!!

Wednesday, 29 October 2014

Partial Form Validation With Spring/Hibernate Validator (Using the Validated Annotation)

Use Case:
The default behavior of the @Valid annotation in a spring controller is to validate all the annotation. This works well when we need to validate all the input received from the form. This is true for most of the cases. But there can arise a scenario when we need to implement a multistep form, where the data is captured in multiple steps. For example lets take an scenario where we want to capture user details where the user detail can be split into multiple forms namely:
  • User Personal Details
  • User Address
  • Additional Details
Now if we define a single model for capturing all the details we would have to build our model catering to these three details separately. Instead we can have a single model containing all the details, and Group the validation for each type. This will enable us to capture the details into the same model in multiple steps and on each submission only the relevant fields can be validated.
User Details
Address
Contact Detail
First name
Hose Number
Mobile Number
Middle Name
Street
email id
Last Name
Locality
Phone Number
Date of Birth
City
Zip Code
Spring Version Required:
Springframework -- 4.1.1.RELEASE
Hibernate Validator -- 5.1.2.Final

Annotate with the Validator.

public class CustomerDetailsModel {
 
 public interface PersonalDetails{}
 public interface AddressDetails{}
        public interface ContacDetails{}


 long customerId;
 @NotNull(groups={PersonalDetails.class})
 @NotBlank(groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 String firstName;
 @NotNull(groups={PersonalDetails.class})
 @NotBlank(groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 @Size(max=35,groups={PersonalDetails.class})
 String middleName;
 String lastName;
 @Past(groups={PersonalDetails.class})
 Date dateOfBirth;

 @Size(max=20,groups={ContacDetails.class})
 String mobileNumber;
 @NotNull(groups={ContacDetails.class})
 @NotBlank(groups={ContacDetails.class})
 @Email(groups={ContacDetails.class})
 @Size(max=100,groups={ContacDetails.class})
 String emailId;

 @Size(max=20,groups=AddressDetails.class)
 String houseNumber;
 @Size(max=20,groups=AddressDetails.class)
 String street;
 int zipCode;
 @Size(max=30,groups=AddressDetails.class)
 String city;
 
        //..... Gettrs and setters goes here

        
}

One can notice that there are three validation groups defined in the model and corresponding to each an interface is defined in the class.

  • PersonalDetails
  • AddressDetails
  • ContactDetails
The interface can be defined either within the class or it can be defined independently. The purpose of the  Interface is to differentiate the various groups.

Using the Group Validation in a Controller:
Using the controller group validation with the controller is very simple. 

        //Capture and Validate personal Detail
 @RequestMapping(value = "/customer/updatepersonalDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updatePersonalDetail(
   @RequestBody @Validated({CustomerDetailsModel.PersonalDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }
        //Capture and Validate Address Detail
 @RequestMapping(value = "/customer/updateaddressDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updateAddressDetail(
   @RequestBody @Validated({CustomerDetailsModel.AddressDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }
        //Capture and Validate Contact Detail Only
 @RequestMapping(value = "/customer/updatecontactDetails", method = RequestMethod.POST)
 @ResponseBody
 public CustomerDetailsModel updateAddressDetail(
   @RequestBody @Validated({CustomerDetailsModel.ContactDetails.class}) CustomerDetailsModel  customerDetails) {
  
 }


Note: More than one validation group can be grouped together by just including the same, e.g  ContactDetails and AddressDetails can be grouped in the Controller using the below mentioned syntax:
@Validated({CustomerDetailsModel.AddressDetails.class,CustomerDetailsModel.ContactDetails.class})
Conclusion:
Using @Validated along with the Group validator can provide you with a partial validation of the model instead of the full model.

Reference:

  1. https://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html/validator-usingvalidator.html#example-group-interfaces



Tuesday, 16 September 2014

Handling HTTPS (one-way SSL) requests in ADF Mobile

Usecase:
This usecase shows how ADF Mobile applications can be configured to handle one-way SSL.
The service runs on weblogic server, in which one way SSL has been enabled.
The weblogic server has been configured to use custom identity and custom trust. I have referred to the post to do this. Its a very good post and gives in-depth details about the various steps. To give a complete idea w.r.t mobile, I have just consolidated the commands and put them under the Server End section.

Pre-requisites:
JDeveloper 12.1.3.0.0 with Mobile Application Framework installed; Weblogic server.

Steps:
Server End:
1) Create a folder in any location, say Desktop. Let us call the folder ServerCerts.
Next, open a terminal from <MW_HOME>\jdeveloper\system12.1......\DefaultDomain\bin.
Run the command setDomainEnv.cmd. (assuming that you are using Jdeveloper on a windows system).
2) From the same terminal, cd and navigate to the newly created folder. Run the below command:
java utils.CertGen -certfile ServerCert -keyfile ServerKey -keyfilepass keypass -cn <<IP or hostname>>

This will generate a public certificate as well as a private key for you. The common name that you give here will be the common name in the certificate. So, ensure that the common name matches with the server's hostname. In case your server's hostname is localhost or 127.0.0.1, provide the system IP as the common name. 

3) Copy CertGenCA manually from <<MW_HOME>>\wlserver\server\lib to the folder ServerCerts. Run the below two commands:
java utils.der2pem CertGenCA.der

type serverCert.pem CertGenCA.pem >> myCert.pem

Since we used CertGen to generate our public-private key pair, it would have been signed by the certifying authority CertGenCA. Thus, we need to append the public certificate of this certifying authority to our public certificate. Using the first command, we convert the format of the CerGenCA certificate to der format. Next, we append it to the public certificate and create a new pem certificate, called myCert.pem. If you look inside myCert.pem, you will be able to see two certificates, one is the server's certificate, and the other is that of CertGenCA's. To take a look, use
keytool -printcert -file myCert.pem

myCert.pem is the file that we will be using at the mobile end, to establish trust.

4)  Weblogic requires jks or kss formats for keystores. Thus, we add the private key and public certificate to a jks keystore using the below command.
java utils.ImportPrivateKey -keystore  SeverIdentity.jks -storepass storepass -storetype JKS -keypass keypass -alias mykey -certfile myCert.pem -keyfile ServerKey.pem -keyfilepass keypass

ServerIdentity.jks will now have the private certificate as well as the public certificate along with the CA’s public certificate. The identity keystore for the server is now ready. For the server truststore, we will use DemoTrust.jks, which comes by default with weblogic. Copy DemoTrust.jks from <<MW_HOME>>\wlserver\server\lib to myCert folder.

5) Go to <<MW_HOME>>\jdeveloper\system12....\DefaultDomain (or the relevant domain location, if it is standalone). Paste ServerIdentity.jks and the DemoTrust.jks files here. Now, start weblogic server and go to weblogic console in the browser. Navigate to Servers->DefaultServer. Under Keystores tab, change the Keystores to Custom Identity and Custom Trust. Set the below details:
Custom Identity Keystore:SeverIdentity.jks
Custom Identity Keystore Type:JKS
Custom Identity Keystore Passphrase: Storepass

Custom Trust Keystore:DemoTrust.jks
Custom Identity Keystore Type:JKS
Custom Identity Keystore Passphrase: DemoTrustKeyStorePassPhrase

Go to the SSL tab
Private Key Alias: mykey
Private Key Passphrase: keypass

In the same tab, go to Advanced, and set Hostname verification to None. Set Two Way Client Cert Behavior: Client Certs Requested But Not Enforced. 
Save all and restart the server. Run the REST service. Access it using https url and port in the browser, and verify the certificate. 

Mobile End: 
1) Create a new ADF Mobile application.
2) Expand Application Resources -> Resources -> Security. You will find cacerts file there. Copy the location of this file using Edit -> Copy Path. The default password for cacerts is 'changeit'. 
3) From the terminal, run the below command:
keytool -import -v trustcacerts -alias mykey -file "location of myCert.pem" -keystore <<location of cacerts>> -keystore changeit -storepass changeit

For e.g., in my case the command looked as below:

keytool -import -v -trustcacerts -alias mykey -file "Desktop\ServerCerts\myCert.pem" -keystore jdev_home\jdeveloper\mywork\SSLApp\resources\security\cacerts -keypass changeit -storepass changeit

When prompted to trust the certificate, say yes. On successful run of the command, you will be able to see the line in the terminal.

Certificate was added to keystore
[Storing jdev_home\jdeveloper\mywork\SSLApp\resources\security\cacerts]

The server's public certificate has now been added to cacerts. Create Data Control for the REST service and design the pages. Deploy to the emulator.
Your application should be able to trust the server and render the web service data.

Note:
If you are redirecting your HTTP requests through HTTP analyzer, or some other tool, you may end up with 'certificate issued by unrecognized entity' error. This is because cacert would require the certificate of the analyzer as well. So, its better to switch off packet sniffing in SSL cases. :)

References:
http://www.weblogic-tips.com/2010/05/20/two-way-ssl-on-weblogic-server/
https://blogs.oracle.com/blogbypuneeth/entry/steps_to_create_a_self

Sunday, 10 August 2014

Accessing REST Service secured with Basic Authentication in ADF Mobile

Usecase:
This usecase talks about how a REST service secured with basic authentication can be accessed in ADF Mobile. For this demo, I have used a REST service which returns employee information, and the service itself has been secured with basic authentication.

Pre-requisites:
JDeveloper 11.1.2.4.0

Steps:
At the service end
Create a REST Service and secure it with basic authentication. Deploy the service to integrated weblogic server and note down the target URL.
Configure ADF Security:
To configure security in ADF Mobile, first create an ADF app and secure it with basic authentication.
1)   Create a new ADF Fusion application.
2)   Create a jspx page in the ViewController project. Go to the menu item: Application -> Secure -> Configure ADF Security. Select ADF Authentication. Keep the defaults and select ‘Redirect upon successful authentication’ and click ‘Generate default’. Finish the wizard. Deploy the app or run the page in the integrated server and note down the URL.These are the same steps as my previous post.

Mobile app configuration:
1)   Create a new ADF Mobile application.
2)   In the ApplicationController, invoke the Web Service Data control wizard. Create the connection by specifying authentication type as Basic and supplying the username/password/realm details. Supply the resource URL and after the method configurations, finish the wizard to create the DC.

3)   Next, go to adfmf-application.xml under Application Resources -> Descriptors -> ADF META-INF. Go to the Security tab and add a new Application Login Server. In the dialog for 'Edit ADF Mobile Login Connection', provide the Login URL and Logout URL as the URL generated in step 2. Remember to use IP address instead of localhost. Also, add a cookie 'JSESSIONID'. Test Connection to ensure the connection is fine. Also, check the checkbox 'Include login server cookie in REST calls'. This will ensure that the JSESSIONID cookie value flows through to the REST service. Close the wizard.
    

4)   To ensure that the basic auth credentials entered in the login page flow through to the REST service call, there is one last step required.
      Go to connections.xml file present under Application Resources -> Descriptors -> ADF META-INF. Look for the adfCredentialStoreKey attribute set for the login window. Set the adfCredentialStoreKey attribute for the service's reference tag with the same value, either manually or through the PI, as shown. 
     


5)   Design the amx pages by D&D an operation of the secure service from DC palette to the page. Deploy the app. The user must be prompted for login credentials on feature load. After the credentials are entered, user should be able to view responses from the secure service without the need to enter credentials again.
      Some snapshots from my app are shown below. Both features are secure in my case, with 'Welcome' being the default one. On app load, user is prompted for credentials. Entering valid  credentials takes the user to the Welcome page. If he then tries to access BasicAuthREST feature,  he is not prompted for credentials again, although the data in this page comes from a secure REST  service.
     


Monday, 4 August 2014

Configuring authentication using remote server in ADF Mobile

Usecase:
This usecase shows how basic authentication can be configured using a remote login server in ADF Mobile.

Pre-requisites:
JDeveloper 11.1.2.4.0.
For Jdeveloper 12.1.3.0.0, check Updates section below.

Steps:
1) Create a new ADF Fusion application.
2) Create a jspx page in the ViewController project. Go to the menu item: Application -> Secure -> Configure ADF Security. Select ADF Authentication. Select HTTP Basic Authentication. Keep the defaults and select 'Redirect upon successful authentication' and click 'Generate Default'. Finish the wizard. Deploy the app or run the page in the integrated server and note down the URL.
3) Create a new ADF Mobile application. Create two new features in it. Let us secure one feature, feature1 and leave the other feature, feature2 unsecure. Create AMX pages for this feature with some basic text content such as hello.
In adfmf-feature.xml, select feature1. Go to Security tab. Select 'Enable Feature Security'. Select Credential Authentication as 'remote'.



4) Go to adfmf-application.xml under Application Resources -> Descriptors -> ADF META-INF. Go to the Security tab and add a new Application Login Server. In the dialog for 'Edit ADF Mobile Login Connection', provide the Login URL and Logout URL as the URL generated in step 2. Remember to use IP address instead of localhost. Also, add a cookie 'JSESSIONID'. Test Connection to ensure the connection is fine. Close the wizard.

5) Deploy the app to an emulator/device.
A login screen as shown below will be seen. On entering the user credentials, the feature gets rendered.

References:
http://docs.oracle.com/cd/E35521_01/doc.111230/e24475/security.htm#CDDGDFGJ

Updates:
For 12.1.3.0.0 with MAF, the configuration is a bit different. Follow steps 1 and 2 as mentioned for 11.1.2.4 above. To enable security for a feature in MAF, do the following:



Go to maf-application.xml under Application Resources -> Descriptors -> ADF META-INF. Go to the Security tab and add a new Application Login Server. In the dialog for 'Create MAF Login Connection', select Connection mode as 'Remote' and provide connection name. Uncheck the two checkboxes. In HTTP Basic tab, provide URL of the secured ADF app(use IP address).

                 

Deploy the app.

Friday, 1 August 2014

Passing Custom SOAP Headers in ADF Mobile

Usecase:
This document shows how custom SOAP Headers can be passed in ADF Mobile to make web service calls. 

Pre-requisites:
JDeveloper Version - 11.1.2.4.0 with Mobile support
For the purpose of this demo, I am using a basic Hello service secured with the OWSM policy ‘oracle/wss_username_token_service_policy’. Additionally, the service responds to only those clients who send a custom SOAP Header with value ‘ClientABC’. Any other value in the header will receive “Invalid Client---Access denied.” as response. You may create the service on similar lines or use the attached service from here (Note that this service has been created in 12.1.2.0.0 build)

Steps:
  1. Create a new ADF Mobile application.
  2. In the ApplicationController project, create a data control for the WSDL URL of the above service.
  3. Since we need to pass some additional header information in the SOAP Envelope, we need to implement the method public SoapHeader[] getAdditionalSoapHeaders() in our own way.
To do this, in the ApplicationController project, create a new Java Class. Call it ‘CustomHeaderClass.java’. Let the class extend SOAPProvider from the package oracle.adfinternal.model.adapter.webservice.provider.soap.SOAPProvider.




Implement the getAdditionalSoapHeaders() method as shown:

    public SoapHeader[] getAdditionalSoapHeaders() {
        System.out.println("In getAdditionalSoapHeaders");
        SoapHeader header[] = new SoapHeader[2];
        SoapHeader token = null;
        SoapHeader user = null;
        SoapHeader pass = null;
    
        header[0] = new SoapHeader(
                    "www-testNamespace.com","ClientName","ClientABC"); //specify the namespace, tag name and the client value
        header[1] = new SoapHeader(
                    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Security");
        token = new SoapHeader(
                   "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","UsernameToken");
        user = new SoapHeader(
                   "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Username","weblogic");
        pass = new SoapHeader(
                   "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Password","weblogic1");
        header[1].addChild(token);
        token.addChild(user);
        token.addChild(pass); 
        return header;
}
In my case, a valid request structure was as below. Thus, the above code was based on this structure.


<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns2="http://project1/"> 
<env:Header>
<ClientName xmlns="www-testNamespace.com">ClientABC</ClientName>
 <ns1:Security>
<ns1:UsernameToken>
<ns1:Username>weblogic</ns1:Username>
<ns1:Password>weblogic1</ns1:Password>
  </ns1:UsernameToken>
 </ns1:Security>
</env:Header>
<env:Body>
 <ns2:helloWorld/>
 </env:Body>
</env:Envelope>


  1. Also, open the DataControls.dcx file and search for provider="oracle.adfinternal.model.adapter.webservice.provider.soap.SOAPProvider". Change this default provider to point to the Provider class we just implemented. In this case, change the line to provider=" application.CustomHeaderClass”.

   5. D&D the method in the DC to an AMX page along with an output text box. If you invoke the method and check the request in the analyzer, you should be able to see the headers being passed.



References:





Tuesday, 22 July 2014

3DES Encryption of a Credit Card Pin Using ASNI 9.8 Format 01 Pin Block Using Java

The first step in encrypting the card pin is to generate the Pin block using the card Number and and pin.

This method of encryption is also referred by the following names:

  1. ECI 4
  2. ISO 9564-1 - Format 0

The format combines the the Customer PIN and account number using the below process.

  • A 16 digit block (Hex) is made using the right most 12 digits of the card/account number excluding the check digit and left padding with 0. For a Card Number 5259 5134 8115 5074
    • The check digit is 4
    • Right most 12 digits are 9513 4811 5507
    • The output is 0000 9513 4811 5507
  • Another 16 digit (Hex representation) is made using the Length of the Pin, Pin digits and right padding with F. For a Pin say 12345
    • First two chars would be the length of the Pin (Left padded with 0) would be 05
    • Append it with the Pin characters. In this case this will occupy 5 chars (12345)
    • Pad it wth F to take the total Length to 16. 
    • Final Output 05 12345 FFFFFFFFF
  • Convert the two output to a 8 byte array represented by converting the 16 char block into bytes (consider two chars each as a Hex)
  • XOR the two arrays to get the pin block.
The code below illustrates the generation of the Pin block and then encrypting it to using "DESede" algorithm to get the desired encrypted PIN block.



Code:

package com.gt.stick2code.pinblockencryption;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class PinBlockEncryptionUtil {

 
 public static void main(String[] args) throws InvalidKeyException,
   NoSuchAlgorithmException, NoSuchPaddingException,
   IllegalBlockSizeException, BadPaddingException {
  String key = "1234567890123456123456789012345612345678901234FF";
  System.out
    .println(encryptPinBlock("1234567890123456", "1234", key, 168));

 }

 /**
  * Encrypts the security pin for a card and gives the Hex representation of the encrypted pin block.
  * @param cardNumber Card number for which the Pin is encrypted
  * @param pin Pin to be encrypted
  * @param key Clear Key to be used for encryption
  * @param keySize Key strnght
  * @return The Hex representation of the encrypted pin block bytes
  * @throws NoSuchAlgorithmException
  * @throws NoSuchPaddingException
  * @throws InvalidKeyException
  * @throws IllegalBlockSizeException
  * @throws BadPaddingException
  */
 public static String encryptPinBlock(String cardNumber, String pin,
   String key, int keySize) throws NoSuchAlgorithmException,
   NoSuchPaddingException, InvalidKeyException,
   IllegalBlockSizeException, BadPaddingException {
  byte[] keyBytes = getEncryptionKey(key, keySize);
  byte[] pinBlock = getPinBlock(cardNumber, pin);
  SecretKey secretKey = new SecretKeySpec(keyBytes, "DESede");

  Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
  cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  byte[] encryptedPinBlock = cipher.doFinal(pinBlock);

  return getHexString(encryptedPinBlock);

 }

 /**
  * Takes the Card number and Pin as input and generates the Pin Block Out of it.
  * First get the card padded (16 Char) which when converted to Hex gives an array of 8
  * Get the Pin Padded (16 Char) which when converted to Hex gives an array of 8
  * XOR the resulting arrays to get the pin block 
  * @param cardNumber
  * @param pin
  * @return
  * @throws IllegalBlockSizeException
  */
 private static byte[] getPinBlock(String cardNumber, String pin)
   throws IllegalBlockSizeException {
  int[] paddedPin = padPin(pin);
  int[] paddedCard = padCard(cardNumber);

  byte[] pinBlock = new byte[8];
  for (int cnt = 0; cnt < 8; cnt++) {
   pinBlock[cnt] = (byte) (paddedPin[cnt] ^ paddedCard[cnt]);
  }
  return pinBlock;
 }

 private static final String PIN_PAD = "FFFFFFFFFFFFFF";

 /**
  * Generates a 16 digit block, with following Components
  * Two digit pin length (left padded with zero if length less than 10)
  * Pin Number 
  * Right padded with F to make it 16 char long.
  * FOr example for a 5 digit Pin 12345 the outout would be 
  * 0512 345F FFFF FFFF
  * @param pin
  * @return
  * @throws IllegalBlockSizeException
  */
 private static int[] padPin(String pin) throws IllegalBlockSizeException {
  String pinBlockString = "0" + pin.length() + pin + PIN_PAD;
  pinBlockString = pinBlockString.substring(0, 16);
  return getHexIntArray(pinBlockString);

 }

 private static final String ZERO_PAD = "0000000000000000";

 /**
  * Using the Card Number it generates a 16-digit block with 4 zeroes and and
  * the 12 right most digits of the card number, excluding the check digit
  * (which is the last digit of the card number. 
  * For Example for a Card 5259 5134 8115 5074
  * 4 Will be the check digit
  * Right most 12 digits would be 951348115507
  * Hence the output would be 0000 9513 4811 5507
  * @param cardNumber
  * @return
  * @throws IllegalBlockSizeException
  */
 private static int[] padCard(String cardNumber)
   throws IllegalBlockSizeException {
  cardNumber = ZERO_PAD + cardNumber;
  int cardNumberLength = cardNumber.length();
  int beginIndex = cardNumberLength - 13;
  String acctNumber = "0000"
    + cardNumber.substring(beginIndex, cardNumberLength - 1);
  return getHexIntArray(acctNumber);
 }

 /**
  * Takes Hex representation of the key, validates the length and returns the
  * equivallent bytes
  * 
  * @param keyString
  *            Hex representation of the key. THe allowed length of the
  *            string are 16 (56 bit), 32 (112 bit), 32 or 48 (for 168 bit).
  *            If the key Strength is 168 bit and the key length is 32 the
  *            first 16 chars are repeated.
  * @param keySize
  *            Valid values are 56, 112, 168
  * @return
  * @throws IllegalBlockSizeException
  * @throws InvalidKeyException
  * 
  */
 private static byte[] getEncryptionKey(String keyString, int keySize)
   throws IllegalBlockSizeException, InvalidKeyException {
  int keyLength = keyString.length();
  switch (keySize) {
  case 56:
   if (keyLength != 16)
    throw new InvalidKeyException(
      "Hex Key length should be 16 for a 56 Bit Encryption, found ["
        + keyLength + "]");
   break;
  case 112:
   if (keyLength != 32)
    throw new InvalidKeyException(
      "Hex Key length should be 32 for a 112 Bit Encryption, found["
        + keyLength + "]");
   break;
  case 168:
   if (keyLength != 32 && keyLength != 48)
    throw new InvalidKeyException(
      "Hex Key length should be 32 or 48 for a 168 Bit Encryption, found["
        + keyLength + "]");
   if (keyLength == 32) {
    keyString = keyString + keyString.substring(0, 16);
   }
   break;
  default:
   throw new InvalidKeyException(
     "Invalid Key Size, expected one of [56, 112, 168], found["
       + keySize + "]");
  }

  byte[] keyBytes = getHexByteArray(keyString);
  return keyBytes;

 }

 /**
  * Takes a byte array as input and provides a Hex String reporesentation
  * 
  * @param input
  * @return
  */
 private static String getHexString(byte[] input) {
  StringBuilder strBuilder = new StringBuilder();
  for (byte hexByte : input) {
   int res = 0xFF & hexByte;
   String hexString = Integer.toHexString(res);
   if (hexString.length() == 1) {
    strBuilder.append(0);
   }
   strBuilder.append(hexString);

  }

  return strBuilder.toString();
 }

 /**
  * Converts a Hex string representation to an int array
  * 
  * @param input
  *            Every two character of the string is assumed to be
  * @return int array containing the Hex String input
  * @throws IllegalBlockSizeException
  */
 private static int[] getHexIntArray(String input)
   throws IllegalBlockSizeException {
  if (input.length() % 2 != 0) {
   throw new IllegalBlockSizeException(
     "Invalid Hex String, Hex representation length is not a multiple of 2");
  }
  int[] resultHex = new int[input.length() / 2];
  for (int iCnt1 = 0; iCnt1 < input.length(); iCnt1++) {
   String byteString = input.substring(iCnt1, ++iCnt1 + 1);
   int hexOut = Integer.parseInt(byteString, 16);
   resultHex[iCnt1 / 2] = (hexOut & 0x000000ff);
  }
  return resultHex;
 }

 /**
  * Converts a Hex string representation to an byte array
  * 
  * @param input
  *            Every two character of the string is assumed to be
  * @return byte array containing the Hex String input
  * @throws IllegalBlockSizeException
  */
 private static byte[] getHexByteArray(String input)
   throws IllegalBlockSizeException {

  int[] resultHex = getHexIntArray(input);
  byte[] returnBytes = new byte[resultHex.length];
  for (int cnt = 0; cnt < resultHex.length; cnt++) {
   returnBytes[cnt] = (byte) resultHex[cnt];
  }
  return returnBytes;
 }

}



Reference:
1) http://pic.dhe.ibm.com/infocenter/zos/v1r11/index.jsp?topic=/com.ibm.zos.r11.csfb400/pinbf.htm

Thursday, 3 July 2014

Using ClientRequestFilters in JDeveloper REST Clients

Usecase:
This sample demonstrates the use of ClientRequestFilters in REST Clients developed using JDeveloper.
For this, we will be creating a JAXRS client with a ClientRequestFilter which sets the header param ‘Client-Name’ and passes it on in the request.
Pre-Requisite:
JDev 12.1.3.0.0 and JAXRS 2.0 support
Steps:
Download the service here and run EmployeeService.java. Copy the WADL URL thus obtained.
Here, I will explain just the key points in the service.
This is a JAXRS 2.0 based service with a single GET method (as shown), which fetches employee details. 
    @HeaderParam("Client-Name") String client;    
    @GET
    @Produces("application/xml")
    public Response getEmpList() {
        if (client == null || client == "") {
            System.out.println("Client :" + client);
            return Response.status(404).entity("Client details required").build();
        } else if (client.equalsIgnoreCase("My Client")) {
            System.out.println("Client-Name:" + client);
            return Response.status(200).entity(new EmployeeList(employeeList)).build();
        } else {
            return Response.status(401).entity("Not authorized to view the details").build();
        }
}
@HeaderParam is used here to extract the value of the header field ‘Client-Name’ received in the request. Based on this value, the service returns the status of the response as:
               404 – header value missing
               200 – header value matches ‘My Client’
               401 – Some invalid value has been supplied

Creating the client:
Create a new custom application. Call it ‘ClientFilterDemo’.




Invoke the RESTful Client and Proxy wizard.

Select JAXRS 2.0 style.

Paste the WADL URL copied previously.


Click Next. Change the Class name to a more convenient name ‘ClientDemoClass’.


Finish the wizard to create the client.
Open ClientDemoClassClient.java. Add the following code to invoke the GET operation of the service where it says //add your code here.
 System.out.println(clientdemoclassemployee.getAsXml(String.class));

Next, create a new Java class called ‘HeaderSetFilter’ which implements ‘ClientRequestFilter’.






Write the following code in this HeaderSetFilter class.
package project1;
import java.io.IOException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.ext.Provider;
@Provider
public class HeaderSetFilter implements ClientRequestFilter {
    public HeaderSetFilter() {
        super();
    }
    @Override
    public void filter(ClientRequestContext clientRequestContext) throws IOException {
        // TODO Implement this method
        if (clientRequestContext.getHeaders().get("Client-Name") == null) {
            clientRequestContext.getHeaders().putSingle("Client-Name", "My Client");
        }
    }
}
In this code, we have implemented the filter method. If Client-Name has not been set, we are setting it to ‘My Client’. We have also added the @Provider annotation to ensure that this class is auto-discovered. This class will be executed just before the request is sent by the client. Hence, the header Client-Name will be added to the request before transmitting it.
However, we need to register this class to the client code. This is done in ClientDemoClass.java. Find the method customizeClientConfiguration. Add the following line to it to register the filter class:
   cc.register(HeaderSetFilter.class);    
That’s it.
Now, run the client and you will see the employee data in the console.
If you change the value of Client-Name in filter() method of HeaderSetFilter, 401 will be seen.

Friday, 27 June 2014

Secure Copy of Files over a non Standard Port

This is a continuation of my blog on Transfer Files Between two Systems Over User Defined Ports. Felt the need to use SSL for the transfer. This is the first step in securing the transfer. As long as we ensure that the certificate on the server is not available to others, our transmission is secure. Will provide the changes for securing the transmission with a password later in another blog.

Setup for execution is available here.

Git available with the source code here.

Step 1: Create the certificate and the Keystore
Key can be generated using keystore. Execute the below command. Script to execute this on windows is available here.


keytool -genkey -alias filecopy -keyalg RSA  -keystore filecopykeystore.jks -storepass password -keypass password -validity 1000 -keysize 1024
Step 2: Code On Server Side to Accept Encrypted Socket


SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory
     .getDefault();
Step 3: Code On Client to initiated an SSL Connection



SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault()
    .createSocket();
socket.setSoTimeout(timeout);
socket.connect(new InetSocketAddress(host, port));
try {
 socket.startHandshake();
 return socket;
} catch (SSLException s) {
 socket.close();
 logger.info("Error in SSL Socket. Hence loading the socket to keystore::");
}

This is all it takes to establish a secure tcp connection. Refer the getSocket method in FileCopySocketConnectionUtil to fetch the public certificate of terver and add into the clientKeystore for establishing the SSL.

Saturday, 7 June 2014

ISO8583 BitMap Explained To be Used with JPOS


The Bitmap in the message provides information on the presence of other fields in the message. While using jpos, one does not have to populate it, as this gets populated based on the fields added automatically.
Refer this wiki for more details.

The BitMap in the message can be represented either as a Binary BitMap (e.g IFB_BITMAP) or an Asci/Hex BitMap(e.g IFA_BITMAP). When the message is packed using a binary representation, the bitmap would occupy 16 bytes of the message, whereas in the ASCII representation it would occupy 32 charachters. It can be explained with the following Simple example. 

Assume a message containing the following fields 2,3,6,11,12, 17, 64, 101 (including 0 as this is usually sent in all messages)
There are 8 bitmaps available, each bitmap representing the 128 fields available(ie 0 to 127)
The first 64 fields are considered as the primary bitmap and the next 64 to be the secondary, representing fields from 64 to 127. In many a message where we do not have to send the fields above 64 we do not even have to form the secondary bitmap. 
8 * 16 = 128

So each byte in the bitmap can hold information of 8 fields. Lets arrive at the position for the fields selected.
The nearest multiple of 8 for 2 ,3, 6  is 8 and 8/8 = 1
The nearest multiple of 8 for 11 and 12 is 16 and 16/8 = 2
The nearest multiple of 8 for 17 is 24 and 24/8 = 3
The nearest multiple of 8 for 64 is 64 and 64/8 = 8
The nearest multiple of 8 for 101 is 104 and 104 = 13


The table below provides the Binary represenation of each byte for the above example. It can be noticed that there are a total of 128 0 and 1s which indicates the presence and absence of the field.

BitMap PositionBinary RepresentationHex Code
101(F2)1(F3)001(F6)0064
2001(F11)1(F12)000030
31(F17)000000080
40000000000
50000000000
60000000000
70000000000
800000001(F64)01
90000000000
100000000000
110000000000
120000000000
13000001(F101)0004
140000000000
150000000000
160000000000

To visualize the representation of the filds in the bitmap, lets consider the first 16 fields and represent the value of field as 0 (not present) and 1 (present). The first two row in the table illustrates the first two bytes of the bitmap and an indicator whether the field exists or not. A byte contains 8 bits, thus 8 fields can be represented in a byte using either 0 or 1.


While the binary representation can go in as byte, the ASCII/Hex packaging of the bitmap will result in this using up 32 characters instead of 16 bytes in the message.

Consider a message packed using the byte representation having the above mentioned fields (assume for simplicity that all other fields contain char and not bytes). The bitmap usually falls outside the printable ASCII representation, hence have provided the hexadecimal equivalent of the field only for the BitMaps.



64308000000000010000000004000000

In the event that the same message is unpacked using an IFA_BITMAP instead of IFB_BITMAP, the parser expects 32 chars instead of 64 and for example would take the chars, in message 5 and 6 and take the byte equivalent, thus resulting in a parsing fields that would be totally different than what was actually passed, resulting in a failure on unpacking the message using JPOS.

Hope this helps someone looking at it in some way. Will be writing further on what needs to be done and care to be taken for packing and unpacking the ISO message using jpos.