Calling a secured WMS / WFS service from mapserver

Mapserver can be used in a cascading manner to call to other services, potentially combining them and maybe re-projecting before serving out again.

Reasons for this might include:

  • Re-projecting the map
  • Accessing a secured WMS/WFS and then protecting it a different way
  • Serving a WMS / WFS map out in a different way

This is all relatively simple using standard mapserver .MAP file if the WMS / WFS services you are calling to are unsecured.  Then its simply a case of a layer like:

 
LAYER

NAME "MyLayer"
DEBUG 5
  TYPE RASTER
  STATUS ON
  CONNECTION http://somedomain.com/WMSServer
  CONNECTIONTYPE WMS
  METADATA
    "wms_title"              "OSI"
    "wms_srs"             "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:3978 EPSG:3857 EPSG:900913"
    "wms_name"            "1,2,3,4,5,6,7,8,9"
    "wms_server_version"  "1.1.1"
    "wms_format"          "image/png"
    "wms_enable_request"  "*"
  END
  PROJECTION
     "init=epsg:900913"
  END
 
END

However if the service you are calling is secured it gets a whole load more complicated.  You might (as I did initially) think that all you have to do is change the map file to include the authorisation details such as

 
LAYER

NAME "MySecuredLayer"
DEBUG 5
  TYPE RASTER
  STATUS ON
  CONNECTION https://somedomain.com/WMSServer
  CONNECTIONTYPE WMS
  METADATA
    "wms_title"              "OSI"
    "wms_srs"             "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:3978 EPSG:3857 EPSG:900913"
    "wms_name"            "1,2,3,4,5,6,7,8,9"
    "wms_server_version"  "1.1.1"
    "wms_format"          "image/jpeg"
    "wms_auth_username"   "myUserName"
    "wms_auth_password"   "myPassword"   
    "wms_auth_type"       "basic"
    "wms_enable_request"  "*"
  END
  PROJECTION
     "init=epsg:900913"
  END
 
END

Unfortunately that in itself doesn’t work (though the map file itself is correct).  You are very strongly recommended to make sure you have DEBUG setup – at least while testing.  So in addition to specifying the DEBUG level in the layer – you also need to include in the overall header of the MAP file a path to the log file

CONFIG "MS_ERRORFILE" "C:\\Mapserver\\ms_log.txt"
DEBUG 5

Running the above map file will create errors in the log file:

HTTP: request failed with curl error code 60 (SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed) for
https://somedomain.com/WMSServer

(If you get an error:

 msHTTPExecuteRequests(): HTTP request error. HTTP: request failed with curl error code 1 (Protocol https not supported or disabled in libcurl)

Then you have a version of mapserver that is not compiled with the correct support and you need to change your version of mapserver (see below))

Basically the secure WMS call uses cURL libraries to do the call – and you have to register the certificate from the service you are calling.

What you need to do:

Make sure your version of mapserver supports https

Make sure you have a version of mapserver that supports https calls.  Tamas builds (http://www.gisinternals.com/sdk/) seem to include the required libraries. I used release-1500-gdal-1-10-0-mapserver-6-2-1.zip though I’m sure other versions would work as well

Get the security certificate

Use OpenSSL (whcih is included in the mapserver distribution in bin\curl)

openssl s_client –connect somedomain:443 > c:\Temp\cert.txt

If all goes well – the cert.txt file will look something like this – and you need the bits from -----BEGIN CERTIFICATE-----  to  -----END CERTIFICATE-----

CONNECTED(00000190)
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=COMODO SSL Wildcard/CN=*.osi.ie
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO SSL CA
1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO SSL CA
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIE5DCCA8ygAwIBAgIQOhI8AlhJBZcVfKqx4ruAnzANBgkqhkiG9w0BAQUFADBw
.
9WspBdI6j1t8l+ZZGe1PXBIBaHlpXuazvlC5FpU93bKt7zaEJ1iU5XjIwB/H4ys1
Hsch6g7YXnw=
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/OU=COMODO SSL Wildcard/CN=*.osi.ie
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO SSL CA
---
No client certificate CA names sent
---
SSL handshake has read 2675 bytes and written 536 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: 5F65EE6F4E78B564620101A5A706E7A259375B2277F430BC4578395780D14458
    Session-ID-ctx:
    Master-Key: 1C992E7CC5DFE1AF7B2D87295954D6A73A740E71BD81A2DB68546E61C055D0089FF1C91FB761F64CFE1BBD20B8411AE3
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1391380021
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---

Add the security certificate to your local store

I copied the default file from bin\curl\curl-ca-bundle.crt into the main mapserver cgi-bin (or scripts) folder

Edit the curl-ca-bundle.crt file and add in your certificate (the bits from -----BEGIN CERTIFICATE-----  to  -----END CERTIFICATE-----)

Test your certificate

Check Curl.exe is in the same folder as your curl-ca-bundle.crt

1) I tested first with a call to getCapabilities:

curl -u MyUsername:MyPassword https://SomeDomain.com:443/WMSServer?REQUEST=GetCapabilities%26SERVICE=WMS

(Note I had to swap & for %26 0 i.e. url encode)

If this has worked you should see a normal getCapabilities text response

2) I then tested with an image call:

curl -u MyUsername:MyPassword https://SomeDomain.com:443/WMSServer?LAYERS=1%26REQUEST=GetMap%26SERVICE=WMS ……

If this works you should see a load of extended characters returned (i.e. an image displayed in the command window!)

Set a windows environment variable to point at the certificate store file

Previous tests have simply used the file in the same folder as the curl.exe, but when running for real mapserver must know where to find the certificate file.

Set the CURL_CA_BUNDLE environment variable to point at the certificate file

e.g. C:\Mapserver\cgi-bin\curl-ca-bundle.crt

Then you need to reboot the server to make sure the new environment setting is correctly used

Then test your map file

Now – at last – the map file which you thought should work originally should actually work and return you an image.

 
LAYER

NAME "MySecuredLayer"
DEBUG 5
  TYPE RASTER
  STATUS ON
  CONNECTION https://somedomain.com/WMSServer
  CONNECTIONTYPE WMS
  METADATA
    "wms_title"              "OSI"
    "wms_srs"             "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:3978 EPSG:3857 EPSG:900913"
    "wms_name"            "1,2,3,4,5,6,7,8,9"
    "wms_server_version"  "1.1.1"
    "wms_format"          "image/jpeg"
    "wms_auth_username"   "myUserName"
    "wms_auth_password"   "myPassword"   
    "wms_auth_type"       "basic"
    "wms_enable_request"  "*"
  END
  PROJECTION
     "init=epsg:900913"
  END
 
END

If you look in the log file you should see:

Using CURL_CA_BUNDLE=C:\Mapserver\cgi-bin\curl-ca-bundle.crt

If not – check your environment variable setting

Other references

The above was put together from a variety of sources – including those below– useful additional refs include:

http://geographika.co.uk/setting-up-a-secure-cascading-wms-on-mapserver

http://www.mapserver.org/ogc/wxs_secure.html

http://trac.osgeo.org/mapserver/ticket/3070

Comments

Find out more