Dude, where is my client sessionID ?
We came across something interesting while testing on the development of a web plugin for vCenter. This time, we leave pure C# because C# API method has become obsolete as shown by documentation on the VC-SDK available here : http://www.vmware.com/support/developer/vc-sdk/vcplugin/
This plug-in style is deprecated. In the future, the C# API will not be used by VMware products
Based on vCenter plugins documentation (applicable for both vSphere 4.1 and 5.0) available on http://www.vmware.com/support/developer/vc-sdk/vcplugin/vSphere_Plugin_4_1_Technote.pdf, we ran some tests to better understand how it works.
Basically, it’s simple, when accessing a plugin from the vSphere Client, an URL is passed to it with some parameters that can be reused in the plugin, eg:
- sessionId = identifier allowing to reuse the security token of the current user for the execution of action
- moref = identifies the selected object when the plugin is activated
- serviceUrl = vCenter WebServices access, usually https : //serverFQDN/sdk
For our example, we just wanted to show the content of all variables passed to the plugin to see what we could do with it.
Here’s just the basic plugin used for example, it’s composed of XML definition file for vSphere client and a ASP.NET file and its C # code :
<scriptConfiguration version="4.0">
<key>vmdude</key>
<description>vmdude Sample vSphere Client Plug-in</description>
<name>vmdude Plug-in</name>
<vendor>vmdude.fr</vendor>
<multiVCsupported>false</multiVCsupported>
<extension parent="InventoryView.VirtualMachine">
<title locale="en">vmdude debug</title>
<url display="window">http://localhost/index.aspx</url>
</extension>
</scriptConfiguration>
This xml file have to be in the viclient Plugins folder, usually in
C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Plugins
The <extension parent=InventoryView.VirtualMachine
> part determines the location where the plugin is active, here it will be an additional tab when selecting a VM :
During plugin activation, the page http : //localhost/index.aspx will be called, which will display all parameters :
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="index.aspx.cs" Inherits="vmdudedebug.index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript">
function refresh() {
window.location.reload();
}
</script>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<p>URL : <asp:label id="txt_URL" runat="server" /></p>
<p>MoRef : <asp:label id="txt_moref" runat="server" /></p>
<p>Type : <asp:label id="txt_type" runat="server" /></p>
<p>Value : <asp:label id="txt_value" runat="server" /></p>
<p>sessionId : <asp:label id="txt_sessionId" runat="server" /></p>
<p>serverGuid : <asp:label id="txt_serverGuid" runat="server" /></p>
<p>locale : <asp:label id="txt_locale" runat="server" /></p>
<p>webServicesSessionId : <asp:label id="txt_wsSessionId" runat="server" /></p>
<p>serviceUrl : <asp:label id="txt_serviceUrl" runat="server" /></p>
<button onclick='refresh();'>Refresh Da Page !</button>
</form>
</body>
</html>
And the C# code for this page (it just explode the received URL and fill fields with values) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace vmdudedebug
{
public partial class index : System.Web.UI.Page
{
public static string MOREF = "moref";
public static string SESSION_ID = "sessionId";
public static string SERVER_GUID = "serverGuid";
public static string SERVICE_URL = "serviceUrl";
public static string LOCALE = "locale";
public static string WS_SESSION_ID = "webServicesSessionId";
public static char[] splitter = { ':' };
protected void Page_Load(object sender, EventArgs e)
{
Uri SvcURL = new Uri(Request.Url.ToString());
string MoRefArg = HttpUtility.ParseQueryString(SvcURL.Query).Get(MOREF);
string typeMoRef = MoRefArg.Split(splitter)[0];
string valueMoRef = MoRefArg.Split(splitter)[1];
string session_ID = HttpUtility.ParseQueryString(SvcURL.Query).Get(SESSION_ID);
string server_GUID = HttpUtility.ParseQueryString(SvcURL.Query).Get(SERVER_GUID);
string serviceUrl = HttpUtility.ParseQueryString(SvcURL.Query).Get(SERVICE_URL);
string locale = HttpUtility.ParseQueryString(SvcURL.Query).Get(LOCALE);
string webServicesSessionId = HttpUtility.ParseQueryString(SvcURL.Query).Get(WS_SESSION_ID);
txt_URL.Text = SvcURL.ToString();
txt_moref.Text = MoRefArg;
txt_type.Text = typeMoRef;
txt_sessionId.Text = session_ID;
txt_serverGuid.Text = server_GUID;
txt_value.Text = valueMoRef;
txt_locale.Text = locale;
txt_serviceUrl.Text = serviceUrl;
txt_wsSessionId.Text = webServicesSessionId;
}
}
}
The problem we had (since it’s still the goal of this post) is that some values were not broadcasted.
The RTFM rule applies everywhere, so it’s still in the plugins documentation we found the explanation :
supportNonSecureCommunication > Optional. For non‐secure HTTP connections between the vSphere Client and and the plug‐in Web server that is identified by the url element of an extension element. See the description of the url element below. When the vSphere Client establishes a secure connection to a plug‐in Web server, the Client will pass sessionId and webServicesSessionId values in the HTTPS request. If the extension element specifies a standard HTTP connection, by default the vSphere Client does not pass the session identifiers to the plug‐in server. To include session identifiers in a standard HTTP request, use the following statement in your configuration file.
<supportNonSecureCommunication>true</supportNonSecureCommunication>
For the sessionId and webServicesSessionId elements to be transmit through URL, you need to add it.
<scriptConfiguration version="4.0">
<key>vmdude</key>
<description>vmdude Sample vSphere Client Plug-in</description>
<name>vmdude Plug-in</name>
<vendor>vmdude.fr</vendor>
<multiVCsupported>false</multiVCsupported>
<extension parent="InventoryView.VirtualMachine">
<title locale="en">vmdude debug</title>
<url display="window">http://localhost/index.aspx</url>
<supportNonSecureCommunication>true</supportNonSecureCommunication>
</extension>
</scriptConfiguration>
So we must never forget the N°1 rule :