Thursday, April 25, 2013

RC Car Tear Down and Control Using Arduino

In a previous post I showed the RC Car I bought and the internals of it. As I mentioned, there was a RX 2 Chip inside the Car but the pin layout was not exactly same as it is mentioned in the datasheet. So I had to ask my wife for help in controlling the car from the remote control and used a multimeter to find out which pins are being activated for each command. The datasheet mentioned that;


  1. Pin No 11 = Forward
  2. Pin No 12 = Backward
  3. Pin No 6 = Right
  4. Pin No 7 = Left
But as it turns out 

Pin No 6 is Left and Pin No 7 is Right. So after finding those out I soldered required wires to the Circuit and hoping to work more on that. 

The video of the testing is below

Wednesday, April 10, 2013

Best Practice in Web Services Usage

Web Services are everywhere and so widely used today. There are several types of Web Services but most widely used ones are SOAP based, REST based web services. I am not going to defferentiate the two here but SOAP based Web Services are much more widely used than REST based mainly because of their reliability and security.

I am not going to implement a fully fledged web service here but just to provide some additional security measures that can be implemented to secure your web services. Nope this not about Authentication and Authorization. Those needs to be implemented anyhow.

According to the famous US based Internet Application security vulnerability testing company Veracode, web services must only expose their WSDL, XSD only to their intended and authorized consumers. This enables the information web services expose to be really limited to people who are intended to use those. But by default web services allow to see the WSDL and XSD by calling the below url.

http://<host>:<port>/MyApplication/services/MyService?wsdl

or

http://<host>:<port>/MyApplication/services/MyService?xsd

This can be restricted by writing a Servlet Filter similar to the below one which Expects Query Strings to be Base64 Encoded and have the format like below

ServiceDefinition#1234567890

1234567890 can be replaced with a timestamp in milli seconds so that the Encoded string will be different each time.

When encoded it will look like the following

U2VydmljZURlZmluaXRpb24jMTIzNDU2Nzg5MA==

The implementation of the Filter is as follows

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.axiom.om.util.Base64;
import org.apache.commons.io.FilenameUtils;

public class InvalidUrlFilter implements Filter {
    
    private Map<String, byte[]> wsdlMap = new HashMap<String, byte[]>();    
    
    private Map<String, byte[]> secureWsdlMap = new HashMap<String, byte[]>();

    @Override
    public void destroy() {
        wsdlMap.clear();
        wsdlMap = null;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain filterChain) throws IOException, ServletException {
        doFilter((HttpServletRequest) request, (HttpServletResponse) response, filterChain);        
    }
    
    public void doFilter(HttpServletRequest request, HttpServletResponse response,
            FilterChain filterChain) throws IOException, ServletException {
        String queryString = request.getQueryString();
        boolean isError = false;
        boolean isWsdlProcessed = false;
        if(queryString != null) {
            queryString = queryString.toUpperCase();            
            if(queryString.endsWith("WSDL") || queryString.endsWith("XSD")) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            if(isValidWSDLRequest(request.getQueryString())) {
                String serviceName = FilenameUtils.getBaseName(request.getRequestURI().toString());
                
                byte[] wsdlbytes = secureWsdlMap.get(serviceName);
                if(wsdlbytes == null) {
                    wsdlbytes = wsdlMap.get(serviceName);
                    if(request.isSecure()) {                    
                        String wsdl = new String(wsdlbytes, "UTF-8");
                        wsdl = wsdl.replaceAll("location=\"http\"", "location=\"https\"");
                        wsdlbytes = wsdl.getBytes();
                        secureWsdlMap.put(serviceName, wsdlbytes);
                    } 
                }        
                
                try {                
                    response.setContentType("text/xml");            
                    response.getOutputStream().write(wsdlbytes);
                    isWsdlProcessed = true;
                } catch(Exception e) {
                    isError = true;
                } finally {
                    if(!isError && isWsdlProcessed) {
                        response.getOutputStream().flush();
                        response.getOutputStream().close();
                    }
                }
            } 
        }
        
        if(!isWsdlProcessed) {
            filterChain.doFilter(request, response);
        }
                
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ServletContext servletContext = filterConfig.getServletContext();
        File servicesDir = new File(servletContext.getRealPath("/WEB-INF/services"));
        
        loadWsdl(servicesDir);
        
    }
    
    private String decoder(String value) {
        String result = "";
        try {
            if(value != null && !value.equals("")) {
                String tmpResult = new String(new Base64().decode(value), "UTF-8");
                
                String[] vals = tmpResult.split("#");
                if(vals.length > 1) {
                    result = vals[0];
                }                
            } 
        } catch (UnsupportedEncodingException e) {
            // Must be Logged
        }
        return result;
    }
    
    private void loadWsdl(File servicesDir) {
        for(File directory:servicesDir.listFiles()) {
            if(directory.isDirectory()) {
                String serviceName = FilenameUtils.getBaseName(directory.getName());
                InputStream is = null;
                ByteArrayOutputStream os = null;
                try {
                    is = new FileInputStream(directory.getAbsolutePath()+"/META-INF/"+serviceName+".wsdl");
                    os = new ByteArrayOutputStream();
                    
                    byte[] data = new byte[1024];
                    int read = 0;
                    while((read = is.read(data)) > 0) {
                        os.write(data, 0, read);
                    }
                    os.flush();                
                    
                    wsdlMap.put(serviceName, os.toByteArray());
                    
                } catch (Exception e) {
                    // Must log                    
                } finally {
                    if(os != null) {
                        try {
                            os.close();
                        } catch (IOException e) {
                            
                        }
                    }
                    
                    if(is != null) {
                        try {
                            is.close();
                        } catch(IOException e) {
                            
                        }
                    }
                }
                
            }
        }
    }
    
    private boolean isValidWSDLRequest(String queryString) {
        boolean result = false;
        String[] values = queryString.split("&");
        for(String value:values) {
            if(decoder(value).equals("ServiceDefinition")) {
                result = true;
                break;
            }
        }
        return result;
    }
    
    
    
    
}


And web.xml will have the following

    <filter>
        <filter-name>InvalidUrlFilter</filter-name>
        <filter-class>com.shazin.filters.InvalidUrlFilter</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>InvalidUrlFilter</filter-name>
        <servlet-name>AxisServlet</servlet-name>
    </filter-mapping>

Now the WSDL can be accessed by using a URL similar to

http://<host>:<port>/MyApplication/services/MyService?U2VydmljZURlZmluaXRpb24jMTIzNDU2Nzg5MA==

Restricts the exposure of the Web Service WSDL to intended consumers only. But for this to work the web services must use HTTPS. If not just Base64 encoding wouldn't suffice. Then it needs to be encrypted before Base64 encoded.