Saturday, July 5, 2008

Making GeoWebCache authenticate to a WMS

GeoWebCache is a java implementation of TileCache.  Geowebcache does not connect to secured a WMS, so I added support for it (yay! for open source).
The WMS GetMap requests are in WMSMetaTile.java (../geowebcache-0.8.3/src/main/java/org/geowebcache/layer/wms).  I thought that the best place to put the username and password was in the WMS service url, which is set in the properties file for the layer (../geowebcache/WEB-INF).  This takes the form of http://username:password@www.mapserver.com/ .  
Alternatively you can also put username and password in the vendor parameters, but that could get dodgy if you have other vendor parameters.
From googling RFC 2716 related documents, the username and password has to be sent in the http Authorization request header in the form of username:password encoded in base64.  Real secure, huh?
So here's the code:
    private void forwardRequest(WMSParameters wmsparams, String backendURL,
        WMSLayerProfile profile) throws IOException, ConnectException,
        ServiceException {

    // extract username and password from service url if there
    String encoding = null;
    int upTest = backendURL.indexOf("@");
    if (upTest>0) {
     String[] temp = backendURL.split("@");
     backendURL = "http://"+temp[1];
     String usernamePassword = temp[0].substring(temp[0].lastIndexOf("/")+1,temp[0].length());
     encoding = new sun.misc.BASE64Encoder().encode (usernamePassword.getBytes());    
    }

    //Get user name and password from vendor parameters
    //Vendor parameter key is "logon"
    //Need to add iterator in case of multiple vendor parameters
    /*
    if (profile.vendorParameters!=null) {
       String[] temp =profile.vendorParameters.split("=");
       if (temp[0].equalsIgnoreCase("logon") {
          String usernamePassword= temp[1];
          //usernamePassword = usernamePassword.substring(usernamePassword.indexOf("=")+1,usernamePassword.length());
          String encoding = new sun.misc.BASE64Encoder().encode (usernamePassword.getBytes());    
       }
    }
    */
         
    // Create an outgoing WMS request to the server
    Request wmsrequest = new Request(backendURL, wmsparams);
    URL wmsBackendUrl = new URL(wmsrequest.toString());
    log.info("the request: "+wmsrequest.toString());
    URLConnection wmsBackendCon = wmsBackendUrl.openConnection();

    //if username and password required set header
    if (!(encoding==null)) {
       wmsBackendCon.setRequestProperty  ("Authorization", "Basic " + encoding);
    }
...