
------=_Part_14076039_700554763.1346074851578 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi George,=20
If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin d= efinitions? Or do I provide 1 plugin definition with multiple =E2=80=9Curls= =E2=80=9D where each one points to a distinct path?=20
The JSON plugin definition file (maybe we should call it "plugin descriptor= ") should contain basic information about the plugin and how it's supposed = to be loaded by WebAdmin, for example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/start.html", // Invokes the actual p= lugin code=20 ... more attributes ...=20 }=20 You can do many things inside one plugin (add multiple tabs, context menu i= tems, etc.) - you just need to add multiple event handler functions inside = the actual plugin code, for example:=20 pluginApi.plugins['test'] =3D {=20 // UiInit event handler function, the first function to be called on the pl= ugin=20 UiInit: function() {=20 pluginApi.ui.addMainTab('Custom Tab One', 'custom-tab-1', 'http://www.examp= le.com/1');=20 pluginApi.ui.addMainTab('Custom Tab Two', 'custom-tab-2', 'http://www.examp= le.com/2');=20 } ,=20 // HostContextMenu event handler function, just an example (not implemented= yet)=20 HostContextMenu: function(ctx) {=20 // 'ctx' represents the context of this event handler function, containing:= =20 // - information about host(s) currently selected=20 // - API (functions) to add custom context menu items=20 }=20 // Similarly, we could define VmContextMenu, etc. (everything inside one pl= ugin)=20 };=20
If =E2=80=9Curl=E2=80=9D is configured to point to an external applicatio= n server hosting my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? F= or example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps= ://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applic= ation server will render the page it needs as a main tab or context menu. I= t would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies woul= d be resolved by the application server.=20
You're right, the "path" attribute makes sense only when serving plugin res= ources (most importantly, plugin HTML page) through a special oVirt Engine = servlet (currently called PluginSourcePageServlet , should be renamed to so= mething like "PluginResourceServlet"). If "url" points to some external app= lication server, the "path" attribute can be omitted (optional attribute). = However, the "url" attribute denotes the location from which plugin HTML pa= ge will be requested by the plugin's iframe.=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "George Costea" <George.Costea@netapp.com>=20 To: "Vojtech Szocs" <vszocs@redhat.com>, "Chris Frantz" <Chris.Frantz@hp.co= m>=20 Cc: "engine-devel" <engine-devel@ovirt.org>=20 Sent: Thursday, August 23, 2012 3:09:05 PM=20 Subject: RE: [Engine-devel] UI Plugins configuration=20 Thanks Chris and Vojtech for continuing this discussion. I think I=E2=80=99= m missing the link between providing the plugin definition file and definin= g the plugins. If I want to add 3 main tabs and 6 context menus, do I provi= de 9 plugin definitions? Or do I provide 1 plugin definition with multiple = =E2=80=9Curls=E2=80=9D where each one points to a distinct path?=20 If =E2=80=9Curl=E2=80=9D is configured to point to an external application = server hosting my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For= example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps:/= /10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applicat= ion server will render the page it needs as a main tab or context menu. It = would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies would = be resolved by the application server.=20 George=20 From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org= ] On Behalf Of Vojtech Szocs=20 Sent: Thursday, August 23, 2012 8:14 AM=20 To: Chris Frantz=20 Cc: engine-devel=20 Subject: Re: [Engine-devel] UI Plugins configuration=20 Hi Chris,=20 thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)=20 First of all, I really like the way you designed plugin source page URLs (g= oing through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pl= uginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribu= te.=20 WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.j= son files), and directly embeds them into WebAdmin host page as pluginDefin= itions JavaScript object. I'm assuming that pluginDefinitions object will n= ow look like this:=20 var pluginDefinitions =3D {=20 "test": {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c":3}=20 }=20 }=20 Originally, the pluginDefinitions object looked like this:=20 var pluginDefinitions =3D {=20 "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> p= luginSourcePageUrl mappings=20 }=20 This is because PluginManager (WebAdmin) only needs pluginName ("name") and= pluginSourcePageUrl ("url") during startup, when creating plugin iframe. B= ut this can be changed :)=20 Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:=20 Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:=20 (function (pluginApi, pluginConfig) { // JavaScript IIFE=20 // ... actual plugin code ...=20 })(=20 parent.pluginApi, /* reference to global pluginApi object */=20 {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object= */=20 );=20 The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin co= de into HTML, so that users don't need to write HTML pages for their plugin= s manually. PluginSourcePageServlet would handle any plugin dependencies (p= laced into HTML head), with actual plugin code being wrapped into IIFE, as = shown above. Plugin configuration was meant to be stored in a separate file= , e.g. <pluginName>-config.json , so that users could change the default pl= ugin configuration to suit their needs.=20 Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page ( PluginSourcePageServlet ), it's even better= to have the plugin configuration embedded directly into WebAdmin host page= , along with introducing new pluginApi function to retrieve the plugin conf= iguration object.=20 Based on this, I suggest following modifications to the original concept:= =20 - modify original pluginDefinitions structure, from pluginName -> pluginSou= rcePageUrl , to pluginName -> pluginDefObject=20 - pluginDefObject is basically a subset of physical plugin definition ( tes= t.json , see below), suitable for use on the client=20 - add following attributes to pluginDefObject : version , url , config=20 * note #1: name is not needed, since it's already the key of pluginName -> = pluginDefObject mapping=20 * note #2: path is not needed on the client (more on this below)=20 - introduce pluginApi.config(pluginName) function for plugins to retrieve t= heir configuration object, and remove pluginConfig parameter from main IIFE= (as shown above)=20 [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/start.html",=20 "path": "/tmp",=20 "config": "test-config.json"=20 }=20 [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:=20 {=20 "a":1, "b":2, "c":3=20 }=20 [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at /tmp (as show= n in [a]), for example:=20 /tmp/start.html -> plugin source page, used to load actual plugin code=20 /tmp/test.js -> actual plugin code=20 /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency=20 For example:=20 "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.ht= ml=20 "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/= deps/jquery-min.js=20 This approach has some pros and cons:=20 (+) plugin static resources can be served through PluginSourcePageServlet (= pretty much like oVirt documentation resources, served through oVirt Engine= root war's FileServlet )=20 (+) plugin author has complete control over plugin source page=20 (-) plugin author actually needs to write plugin source page=20 Overall, I think this approach is better than the previous one (where Plugi= nSourcePageServlet took care of rendering plugin source page, but sacrifice= d some flexibility).=20 By the way, here's what would happen behind the scenes:=20 1. user requests WebAdmin host page, WebadminDynamicHostingServlet load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate pluginDefinitions JavaScript object=20 2. during WebAdmin startup, PluginManager registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously=20 3. PluginSourcePageServlet handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client=20
1. The plugin configuration files should probably have an "enabled" field= and an "apiVersion" field that should be examined to determine whether or = not to use the plugin.=20
Sounds good, we can implement these later on :)=20
2. I suspect the way I've modified PluginSourcePage makes it vulnerable t= o directory climbing attacks.=20
Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.=20
3. Is /usr/share/ovirt-engine the right place for the plugin config files= ?=20
I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)=20 Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "Chris Frantz" < Chris.Frantz@hp.com >=20 To: vszocs@redhat.com=20 Sent: Wednesday, August 22, 2012 7:56:45 PM=20 Subject: UI Plugins configuration=20 Vojtech,=20 I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.=20 Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.=20 Example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c": 3}=20 }=20 The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.=20 When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will translat= e the first part of the path ("test") into whatever path is stored in plugi= nConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/f= oo.html").=20 I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a plugin= may want to store static resources at "path" and have the engine serve tho= se resources. By just serving files through PluginSourcePage, we don't need= any other servlets to provide those resources.=20 There is still a bit of work to do:=20 1. The plugin configuration files should probably have an "enabled" field a= nd an "apiVersion" field that should be examined to determine whether or no= t to use the plugin.=20 2. I suspect the way I've modified PluginSourcePage makes it vulnerable to = directory climbing attacks.=20 3. Is /usr/share/ovirt-engine the right place for the plugin config files?= =20 Let me know what you think,=20 --Chris=20 ------=_Part_14076039_700554763.1346074851578 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <html><head><style type=3D'text/css'>p { margin: 0; }</style></head><body><= div style=3D'font-family: times new roman,new york,times,serif; font-size: = 12pt; color: #000000'>Hi George,<br><br><span style=3D"font-size:11.0pt;fon= t-family:"Calibri","sans-serif";color:#1F497D">> If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin=20 definitions? Or do I provide 1 plugin definition with multiple =E2=80= =9Curls=E2=80=9D=20 where each one points to a distinct path?</span><br><br>The JSON plugin def= inition file (maybe we should call it "plugin descriptor") should contain b= asic information about the plugin and how it's supposed to be loaded by Web= Admin, for example:<br><br style=3D"font-family: courier new,courier,monaco= ,monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mon= aco,monospace,sans-serif;">{</span><br style=3D"font-family: courier new,co= urier,monaco,monospace,sans-serif;"><span style=3D"font-family: courier new= ,courier,monaco,monospace,sans-serif;"> "name": "test",</span><br sty= le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span = style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&nb= sp; "version": "1.0",</span><br style=3D"font-family: courier new,courier,m= onaco,monospace,sans-serif;"><span style=3D"font-family: courier new,courie= r,monaco,monospace,sans-serif;"> "url": "/webadmin/webadmin/plugin/te= st/start.html", // Invokes the actual plugin code</span><br style=3D"font-f= amily: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"fon= t-family: courier new,courier,monaco,monospace,sans-serif;"> ... more= attributes ...</span><br style=3D"font-family: courier new,courier,monaco,= monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mona= co,monospace,sans-serif;">}</span><br><br>You can do many things inside one= plugin (add multiple tabs, context menu items, etc.) - you just need to ad= d multiple event handler functions inside the actual plugin code, for examp= le:<br><br><span style=3D"font-family: courier new,courier,monaco,monospace= ,sans-serif;">pluginApi.plugins['test'] =3D {</span><br><br style=3D"font-f= amily: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"fon= t-family: courier new,courier,monaco,monospace,sans-serif;"> // UiIni= t event handler function, the first function to be called on the plugin</sp= an><br style=3D"font-family: courier new,courier,monaco,monospace,sans-seri= f;"><span style=3D"font-family: courier new,courier,monaco,monospace,sans-s= erif;"> UiInit: function() {</span><br style=3D"font-family: courier = new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: couri= er new,courier,monaco,monospace,sans-serif;"> pluginApi.u= i.addMainTab('Custom Tab One', 'custom-tab-1', 'http://www.example.com/1');= </span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-= serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,sa= ns-serif;"> pluginApi.ui.addMainTab('Custom Tab Two', 'cu= stom-tab-2', 'http://www.example.com/2');</span><br style=3D"font-family: c= ourier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family= : courier new,courier,monaco,monospace,sans-serif;"> },</span><br sty= le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><br st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span= style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&n= bsp; // HostContextMenu event handler function, just an example (not implem= ented yet)</span><br style=3D"font-family: courier new,courier,monaco,monos= pace,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,mo= nospace,sans-serif;"> HostContextMenu: function(ctx) {</span><br><spa= n style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&= nbsp; // 'ctx' represents the context of this event handler fun= ction, containing:<br> // - information about host(s) cur= rently selected<br style=3D"font-family: courier new,courier,monaco,monospa= ce,sans-serif;"></span><span style=3D"font-family: courier new,courier,mona= co,monospace,sans-serif;"></span><span style=3D"font-family: courier new,co= urier,monaco,monospace,sans-serif;"> // - API (functions) to a= dd custom context menu items<br></span><span style=3D"font-family: courier = new,courier,monaco,monospace,sans-serif;"> }</span><br style=3D"font-= family: courier new,courier,monaco,monospace,sans-serif;"><br style=3D"font= -family: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"f= ont-family: courier new,courier,monaco,monospace,sans-serif;"> // Sim= ilarly, we could define VmContextMenu, etc. (everything inside one plugin)<= /span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-s= erif;"><br style=3D"font-family: courier new,courier,monaco,monospace,sans-= serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,sa= ns-serif;">};</span><br><br><span style=3D"font-size:11.0pt;font-family:&qu= ot;Calibri","sans-serif";color:#1F497D">> If =E2=80=9Curl=E2=80=9D is configured to point to an external application se= rver hosting=20 my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For example,= if I configure=20 =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre= sumably the application server will render the page it needs as a main tab = or=20 context menu. It would have no need for =E2=80=9Cpath=E2=80=9D since = all dependencies=20 would be resolved by the application server.</span><br><br>You're right, th= e "path" attribute makes sense only when serving plugin resources (most imp= ortantly, plugin HTML page) through a special oVirt Engine servlet (current= ly called <em>PluginSourcePageServlet</em>, should be renamed to something = like "PluginResourceServlet"). If "url" points to some external application= server, the "path" attribute can be omitted (optional attribute). However,= the "url" attribute denotes the location from which plugin HTML page will = be requested by the plugin's iframe.<br><br>Regards,<br>Vojtech<br><br><br>= <hr id=3D"zwchr"><div style=3D"color:#000;font-weight:normal;font-style:nor= mal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:1= 2pt;"><b>From: </b>"George Costea" <George.Costea@netapp.com><br><b>T= o: </b>"Vojtech Szocs" <vszocs@redhat.com>, "Chris Frantz" <Chris.= Frantz@hp.com><br><b>Cc: </b>"engine-devel" <engine-devel@ovirt.org&g= t;<br><b>Sent: </b>Thursday, August 23, 2012 3:09:05 PM<br><b>Subject: </b>= RE: [Engine-devel] UI Plugins configuration<br><br> <style><!-- @font-face =09{font-family:Calibri; =09panose-1:2 15 5 2 2 2 4 3 2 4;} @font-face =09{font-family:Tahoma; =09panose-1:2 11 6 4 3 5 4 4 2 4;} p.MsoNormal, li.MsoNormal, div.MsoNormal =09{margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} a:link, span.MsoHyperlink =09{mso-style-priority:99; =09color:blue; =09text-decoration:underline;} a:visited, span.MsoHyperlinkFollowed =09{mso-style-priority:99; =09color:purple; =09text-decoration:underline;} p =09{mso-style-priority:99; =09margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} span.EmailStyle19 =09{mso-style-type:personal-reply; =09font-family:"Calibri","sans-serif"; =09color:#1F497D;} .MsoChpDefault =09{mso-style-type:export-only; =09font-size:10.0pt;} @page WordSection1 =09{size:8.5in 11.0in; =09margin:1.0in 1.0in 1.0in 1.0in;} div.WordSection1 =09{page:WordSection1;} @list l0 =09{mso-list-id:306739626; =09mso-list-template-ids:-2112482452;} ol =09{margin-bottom:0in;} ul =09{margin-bottom:0in;} --></style> <div class=3D"WordSection1"> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Thanks Chris and Vojtech = for continuing this discussion. I think I=E2=80=99m missing the link = between providing the plugin definition file and defining the plugins. = ; If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin de= finitions? Or do I provide 1 plugin definition with multiple =E2=80= =9Curls=E2=80=9D where each one points to a distinct path?</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">If =E2=80=9Curl=E2=80=9D = is configured to point to an external application server hosting my plugin,= what is the intent of =E2=80=9Cpath=E2=80=9D? For example, if I conf= igure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre= sumably the application server will render the page it needs as a main tab = or context menu. It would have no need for =E2=80=9Cpath=E2=80=9D sin= ce all dependencies would be resolved by the application server.</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">George</span></p> <p class=3D"MsoNormal"><a name=3D"_MailEndCompose"><span style=3D"font-size= :11.0pt;font-family:"Calibri","sans-serif";color:#1F497= D"> </span></a></p> <div> <div style=3D"border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in = 0in 0in"> <p class=3D"MsoNormal"><b><span style=3D"font-size:10.0pt;font-family:"= ;Tahoma","sans-serif"">From:</span></b><span style=3D"font-s= ize:10.0pt;font-family:"Tahoma","sans-serif""> engine-d= evel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] <b>On Behalf Of </b>Vojtech Szocs<br> <b>Sent:</b> Thursday, August 23, 2012 8:14 AM<br> <b>To:</b> Chris Frantz<br> <b>Cc:</b> engine-devel<br> <b>Subject:</b> Re: [Engine-devel] UI Plugins configuration</span></p> </div> </div> <p class=3D"MsoNormal"> </p> <div> <p class=3D"MsoNormal"><span style=3D"color:black">Hi Chris,<br> <br> thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)<br> <br> First of all, I really like the way you designed plugin source page URLs (g= oing through <em>PluginSourcePageServlet</em>), e.g. "/webadmin/webadmin/plugin/<plug= inName>/<pluginSourcePage>.html", plus the concept of "path" JSON = attribute.<br> <br> <i>WebadminDynamicHostingServlet</i> loads and caches all plugin definition= s (<i>*.json</i> files), and directly embeds them into WebAdmin host page a= s <i>pluginDefinitions</i> JavaScript object. I'm assuming that <i>pluginDefi= nitions</i> object will now look like this:<br> <br> </span><span style=3D"font-family:"Courier New";color:black">var = pluginDefinitions =3D {<br> "test": {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c":3}<br> }<br> }</span><span style=3D"color:black"><br> <br> Originally, the <i>pluginDefinitions</i> object looked like this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> var pluginDefinitions =3D {<br> "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple plu= ginName -> pluginSourcePageUrl mappings<br> }</span><span style=3D"color:black"><br> <br> This is because PluginManager (WebAdmin) only needs <i>pluginName</i> ("nam= e") and <i>pluginSourcePageUrl</i> ("url") during startup, when creating plugin ifr= ame. But this can be changed :)<br> <br> Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:<br> <br> Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> (function (pluginApi, pluginConfig) { // JavaScript IIFE<br> // ... actual plugin code ...<br> })(<br> parent.pluginApi, /* reference to global pluginApi object */<br=
{"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaS= cript object */<br> );</span><span style=3D"color:black"><br> <br> The whole purpose of <i>PluginSourcePageServlet</i> was to "wrap" actual pl= ugin code into HTML, so that users don't need to write HTML pages for their= plugins manually. <i>PluginSourcePageServlet</i> would handle any plugin dependencies (placed= into HTML head), with actual plugin code being wrapped into IIFE, as shown= above. Plugin configuration was meant to be stored in a separate file, e.g= . <i><pluginName>-config.json</i>, so that users could change the defau= lt plugin configuration to suit their needs.<br> <br> Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page (<i>PluginSourcePageServlet</i>), it's even b= etter to have the plugin configuration embedded directly into WebAdmin host= page, along with introducing new <i>pluginApi</i> function to retrieve the plugin configuration object.<br> <br> Based on this, I suggest following modifications to the original concept:<b= r> <br> - modify original <i>pluginDefinitions</i> structure, from <i>pluginName -&= gt; pluginSourcePageUrl</i>, to <i>pluginName -> pluginDefObject</i><br> - <i>pluginDefObject</i> is basically a subset of physical plugin definitio= n (<i>test.json</i>, see below), suitable for use on the client<br> - add following attributes to <i>pluginDefObject</i>: <i>version</i>, <i>ur= l</i>, <i>config</i><br> * note #1: <i>name</i> is not needed, since it's already the ke= y of <i>pluginName -> pluginDefObject</i> mapping<br> * note #2: <i>path</i> is not needed on the client (more on thi= s below)<br> - introduce <i>pluginApi.config(pluginName)</i> function for plugins to ret= rieve their configuration object, and remove <i>pluginConfig</i> parameter from main IIFE (as shown above)<br> <br> [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. <i>/usr/share/ovirt-engine/ui-plugins/test.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/start.html",<br> "path": "/tmp",<br> "config": "test-config.json"<br> }</span><span style=3D"color:black"><br> <br> [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. <i> /etc/ovirt-engine/ui-plugins/test-config.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "a":1, "b":2, "c":3<br> }</span><span style=3D"color:black"><br> <br> [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at <i>/tmp</i> (as shown in [a]), for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> /tmp/start.html -> plugin source page, used to load actual plugin code<b= r> /tmp/test.js -> actual plugin code<br> /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency</span><s= pan style=3D"color:black"><br> <br> For example:<br> "/webadmin/webadmin/plugin/test/start.html" will be mapped to <i>/tmp/start= .html</i><br> "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to <i>/t= mp/deps/jquery-min.js</i><br> <br> This approach has some pros and cons:<br> (+) plugin static resources can be served through <i>PluginSourcePageServle= t</i> (pretty much like oVirt documentation resources, served through oVirt= Engine root war's <i>FileServlet</i>)<br> (+) plugin author has complete control over plugin source page<br> (-) plugin author actually needs to write plugin source page<br> <br> Overall, I think this approach is better than the previous one (where <i>Pl= uginSourcePageServlet</i> took care of rendering plugin source page, but sa= crificed some flexibility).<br> <br> By the way, here's what would happen behind the scenes:</span></p> <ol start=3D"1" type=3D"1"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;margin= -bottom:12.0pt;mso-list:l0 level1 lfo1"> user requests WebAdmin host page, <i>WebadminDynamicHostingServlet</i> load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate <i>pluginDefinitions</i> JavaScript object</li><li class=3D"MsoNormal" styl= e=3D"color:black;mso-margin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 l= evel1 lfo1"> during WebAdmin startup, <i>PluginManager</i> registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously</li><li class=3D"MsoNormal" style=3D"color:black;mso-ma= rgin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 level1 lfo1"> <i>PluginSourcePageServlet</i> handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client</li>= </ol> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black">> 1. The plugin configuration files should probably have an= "enabled" field and an "apiVersion" field that should be examined to deter= mine whether or not to use the plugin.<br> <br> Sounds good, we can implement these later on :)<br> <br> > 2. I suspect the way I've modified PluginSourcePage makes it vul= nerable to directory climbing attacks.<br> <br> Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.<br> <br> > 3. Is /usr/share/ovirt-engine the right place for the plugin con= fig files?<br> <br> I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)<br> <br> <br> Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!<br> <br> <br> Regards,<br> Vojtech<br> <br> </span></p> <div class=3D"MsoNormal" style=3D"text-align:center" align=3D"center"><span= style=3D"color:black"> <hr id=3D"zwchr" size=3D"2" width=3D"100%" align=3D"center"> </span></div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black"><br> From: "Chris Frantz" <<a href=3D"mailto:Chris.Frantz@hp.com" target=3D"_= blank">Chris.Frantz@hp.com</a>><br> To: <a href=3D"mailto:vszocs@redhat.com" target=3D"_blank">vszocs@redhat.co= m</a><br> Sent: Wednesday, August 22, 2012 7:56:45 PM<br> Subject: UI Plugins configuration<br> <br> Vojtech,<br> <br> I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.<br> <br> Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.<br> <br> Example:<br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/= plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c= ": 3}<br> }<br> <br> The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.<br> <br> When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will tr= anslate the first part of the path ("test") into whatever path is stored in= pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").<br> <br> I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a = plugin may want to store static resources at "path" and have the engine ser= ve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provid= e those resources.<br> <br> There is still a bit of work to do:<br> <br> 1. The plugin configuration files should probably have an "enabled" f= ield and an "apiVersion" field that should be examined to determine whether= or not to use the plugin.<br> <br> 2. I suspect the way I've modified PluginSourcePage makes it vulnerab= le to directory climbing attacks.<br> <br> 3. Is /usr/share/ovirt-engine the right place for the plugin config f= iles?<br> <br> Let me know what you think,<br> --Chris</span></p> </div> </div> </div><br></div></body></html> ------=_Part_14076039_700554763.1346074851578--