How To - Sample Multi-Tenant WebClient Solution

Sample Multi-tenant Webclient solution

A multi-tenant solution allows more than one company to use the same solution at the same time. Multi_Tenant.servoy is a bare bones multi-tenant webclient solution that includes a simple receipts form and a list. It is intended to demonstrate some of the basic incredients of a SaaS solution. In addition to being multi-tenant, this sample solution also includes a login system that allows outside users to access the solution for a period of 30 days. The solution is unprotected and can be downloaded now at:

http://multi-tenant-download.hopto.org

Important: Change first form to be shown to “login_email”.

If name of download file is changed by the browser to multi-tenant.zip be sure to change it to multi-tenant.servoy before attempting to import the solution.

It can also be viewed at:

http://multi-tenant.hopto.org

Dean Westover
Choices Software, Inc.

You may be able to easily wrap other webclient solutions with the login password system of the above multi-tenant solution.
Try the following with the “Servoy Sample CRM” solution:

  1. From File/Repository import and load multi_tenant.servoy
  2. From File/Solutions Settings add “Servoy Sample CRM” as a module
  3. Close and re-open to “multi_tenant” solution
  4. From the Method Editor open the “login_password” form “check_password” method and change:
    forms.receipt_form.controller.show() to
    forms.main.controller.show()
  5. Repeat step 4 in the “login_register” form “register” method
  6. Close the editor and click the green “Web Client Launch” button.

To also make a solution multi-tenant try doing the above, plus

  1. add a “company_id” integer column to each table
  2. add the following line to all new record methods:
    “company_id = globals.bb_company_id”

Always make a backup before trying the above on your own webclient solution.

Dean Westover
Choices Software, Inc.

Thanks for taking time to post this. I love being able to learn from other people’s work. This is much appreciated.

Anyone have any thoughts why this little app would choke on Mac/Firefox, but work fine on XP/IE7? I was at the site above where he has it hosted.

This error came up a few times just clicking on the Search button, or on a link to a record in the list:

WicketMessage: Markup of type ‘html’ for component ‘com.servoy.j2db.server.headlessclient.ServoyErrorPage’ not found. Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried:
[Page class = com.servoy.j2db.server.headlessclient.ServoyErrorPage, id = 10, version = 0]

Root cause:

org.apache.wicket.markup.MarkupNotFoundException: Markup not found. Component class: com.servoy.j2db.server.headlessclient.ServoyErrorPage Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried
at org.apache.wicket.markup.MarkupCache.getMarkupStream(MarkupCache.java:215)
at org.apache.wicket.MarkupContainer.getAssociatedMarkupStream(MarkupContainer.java:342)
at org.apache.wicket.Page.onRender(Page.java:1447)
at org.apache.wicket.Component.render(Component.java:2308)
at org.apache.wicket.Page.renderPage(Page.java:897)
at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.respond(BookmarkablePageRequestTarget.java:231)
at org.apache.wicket.request.AbstractRequestCycleProcessor.respond(AbstractRequestCycleProcessor.java:103)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1172)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1241)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1316)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:354)
at org.apache.wicket.protocol.http.WicketServlet.doGet(WicketServlet.java:121)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:896)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:705)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2049)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Complete stack:

org.apache.wicket.markup.MarkupNotFoundException: Markup of type ‘html’ for component ‘com.servoy.j2db.server.headlessclient.ServoyErrorPage’ not found. Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried:
[Page class = com.servoy.j2db.server.headlessclient.ServoyErrorPage, id = 10, version = 0]
at org.apache.wicket.MarkupContainer.getAssociatedMarkupStream(MarkupContainer.java:354)
at org.apache.wicket.Page.onRender(Page.java:1447)
at org.apache.wicket.Component.render(Component.java:2308)
at org.apache.wicket.Page.renderPage(Page.java:897)
at org.apache.wicket.request.target.component.BookmarkablePageRequestTarget.respond(BookmarkablePageRequestTarget.java:231)
at org.apache.wicket.request.AbstractRequestCycleProcessor.respond(AbstractRequestCycleProcessor.java:103)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1172)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1241)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1316)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:493)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:354)

I downloaded the solution and linked it to example_crm as you described. That all worked great.

I logged in, it put a record in the users table for me, and things worked great.

I closed my browser window (I’m in developer mode), then reopened it. Surprisingly, it went straight to the CRM screens and skipped login.

What I think is happening is that it is storing login info in globals, so when a 2nd person logs in, they will get logged in as the first person without a chance to log themselves in.

Am I smoking crack (entirely possible), or is this true? If I’m thinking right, the login info for a user should be stored some other way in memory, rather than a global, so they don’t step on each other.

I’m interested in building a multi-tenant solution, so I’m really trying to understand the foundational components of security and make sure I don’t leave holes open.

Anyone want to comment on this and help me understand why a 2nd user just logged right in without credential checks?

popdizzle:
I downloaded the solution and linked it to example_crm …

Hi Jason,

You bring up some good questions and I do not have all the answers. Perhaps some others will chime in and we can all learn.

What platform and browser were you using?
Did you click the “Exit” button when leaving the solution to kill the session?

Dean Westover
Choices Software, Inc.

Let me play with it some more and get more experience before I say too much.

I’ve got one machine with XP connected to your site. Then I’ve got my Mac connected as well. If I login on both browsers, I seem to be able to have separate sessions working okay, seeing their own records. But then if I do hit Exit on my Mac browser to exit your app, it logs out, goes to a blank screen, then the PC browser window goes blank too, and I didn’t even touch the XP machine. Seems like something is stepping on sessions.

This is a good troubleshooting opportunity for both of us. Don’t think I’m trying to pick it apart. I really just want to learn what’s going on so my knowledge increases. With that said, let’s just see what we can learn as a group.

popdizzle:
…just want to learn what’s going on so my knowledge increases…

Good. Me too!

We may have collided on the above solution that I am hosting, because I just went in and changed the “Exit” button to point to http://www.google.com instead of going back to the login screen. Now the “Exit” button does appear to be killing the session. Before, it appears that it was killing the session and then restarting a new session.

Dean Westover
Choices Software, Inc.

I think I got my question answered as I watched Scott Butler’s webinar on servoy security.

I believe that globals variables are in scope for the current user. Each user would get their own full set of globals, so they wouldn’t overwrite each other. I was confused how it would work if you put the username and password in global variables. I didn’t know if other users would overwrite each other.

Yes, globals are limited to one session.

Scott’s webinar on security was excellent!

Dean

I have reset the links at the top of this thread; so they should now be working again.

Dean