MicroStrategy ONE

Code Explanation for Scenario: Displaying Different Start Pages based on User Group

In this customization scenario, you create both a custom ESM and a custom log-in page. The custom ESM overrides the handlesAuthenticationRequest method with custom code that invokes a custom login page. It also overrides the getCustomLoginURL method so that it returns a URL that points to the custom login page. The custom login page contains the logic to determines the user group to which the current user belongs and to open the appropriate start page for that user group.

  • In the custom ESM, you must include code to invoke a custom login page and provide the URL that points to the custom log-in page.  

  • In the custom log-in page, you must collect all of the information needed to create a session (the user ID and password, authentication mode, server name and port, project, and locale), create the session on Intelligence Server, determine the appropriate start page to display by determining the group to which the logged-in user belongs, and pass the session state and other required information back to MicroStrategy Web.

Custom ExternalSecurity java class  (calledDiffStartPages.javain the corresponding scenario)

A generic explanation of how to create the custom ESM code required to perform this customization is provided below. The code is explained in sections, with the explanation preceding each section of code.

  • Explanation: Specify the package in which this class will reside and import the necessary classes, including AbstractExternalSecurity (which contains default implementations for all of the methods). Declare that this custom External Security class (compiled from the sample java file called CustSessionCreation.java in the corresponding scenario) extends AbstractExternalSecurity.:

    Copy
    package com.microstrategy.sdk.samples.externalsecurity;
    import com.microstrategy.web.app.AbstractExternalSecurity;
    import com.microstrategy.web.app.ExternalSecurity;
    import com.microstrategy.web.beans.RequestKeys;
    import com.microstrategy.web.platform.ContainerServices;
    public class DiffStartPages extends AbstractExternalSecurity {
  • Explanation: Override the handlesAuthenticationRequest method so that it returns USE_CUSTOM_LOGIN_PAGE.:

    Copy
      /**
       * Override handleAuthenticationRequest to return ExternalSecurity.USE_CUSTOM_LOGIN_PAGE;
       */
      public int handlesAuthenticationRequest(RequestKeys reqKeys, ContainerServices cntSvcs, int reason)
        {
          return ExternalSecurity.USE_CUSTOM_LOGIN_PAGE;
        }
  • Explanation: Override the getCustomLoginURL method so that it returns a URL that points to the custom login page used in this scenario, DiffStartPageLoginPage.jsp.:

    Copy
      /**
       * Return the URL of the custom login page.
       */
      public String getCustomLoginURL(String originalURL, String desiredServer, int desiredPort, String desiredProject)
        {
     
          /* The custom login page should have a login form where user can input login credentials.
           * After user submit the login form, the custom login page should create MicroStrategy Web IServer Session,
           * redirect to MicroStrategy page and have the session manager state in the URL using "usrSmgr" parameter.
           */
           return "http://localhost:8080/MicroStrategy/_custom/jsp/DiffStartPagesCustLoginPage.jsp";
       }
     
    }

Custom login page   (calledDiffStartPagesCustLoginPage.jspin the corresponding scenario)

A generic explanation of how to create the custom login page required to perform this customization is provided below. The code is explained in sections, with the explanation preceding each section of code.

  • Explanation: Import com.microstrategy.web.objects. :

    Copy
    <%@ page import="com.microstrategy.web.objects.*" %>
    <html>
    <%
  • Explanation: Create and instantiate a variable to represent the URL of the start page. This URL must point to a folder. To do this, you must set the evt (event) parameter in the URL to "2001", the event ID that opens a folder.:

    Copy
      //This url points to your MicroStrategy Web's desktop page.
      String mstrDesktopURL="http://localhost:8080/MicroStrategy/servlet/mstrWeb?evt=2001";
  • Explanation: Create and instantiate variables for the error message and the session state.:

    Copy
      String errorMsg = "";
      String sessionState="";
  • Explanation: Create and instantiate variables that represent the information collected from the custom login page and used to create an Intelligence Server session. Each parameter is read from the incoming request object. These user parameters will be used to build the Intelligence Server session.:

    Copy
      if("CustomLogin".equals(request.getParameter("CustomLogin"))) {
     
      //If the request comes from the custom login form, create session.
          String server = request.getParameter("Server");
          String project = request.getParameter("Project");
          String uid = request.getParameter("Uid");
          String pwd = request.getParameter("Pwd");
  • Explanation: Create an Intelligence Server session object. A WebObjectsFactory can be used to create other types of web objects, but in this case it is used to create an Intelligence Server session object that will be populated below.:

    Copy
          WebObjectsFactory lFactory = WebObjectsFactory.getInstance();
          WebIServerSession lISS = lFactory.getIServerSession();
  • Explanation: Set the user parameters that were read above onto the newly created Intelligence Server session. For exception handling purposes, these actions are wrapped in a try-catch block.:

    Copy
          try {
                lISS.setServerName(server);
                lISS.setProjectName(project);
                lISS.setLogin(uid);
                lISS.setPassword(pwd);
  • Explanation: Create the Intelligence Server session in standard authentication mode (MicroStrategy login and password) and save the minimal session state.:

    Copy
                //standard authentication
                lISS.setAuthMode(1);
                lISS.getSessionID();
                //save the minimal session state
                sessionState=lISS.saveState(0);
  • Explanation: Once the session has been created, you get the WebUser from it.  The WebUser is the user for whom the session was just created. From the WebUser you get the list of parents for this user, which is the list of groups to which this user belongs. :

    Since groups can be nested, to fully enumerate every group to which this user belongs, you would need to recursively go up the tree of parents.  However, to keep this sample simple, we have not done that here.

    Copy
                WebObjectInfo lUserOI = lISS.getUserInfo();
                WebUser lUser = (WebUser) lUserOI;
                WebUserList lParents = lUser.getParents();
  • Explanation: Loop through the list of groups to determine if any of them have their own custom folder.  You start by setting up a for() loop that will enumerate each group and get the group name.:

    Copy
                for(Enumeration lEnum = lParents.elements() ; lEnum.hasMoreElements() ;)
                {
                  WebUserEntity lUserEntity = (WebUserEntity) lEnum.nextElement();
                  String lGroupName = lUserEntity.getName();
  • Explanation: The next step is to set up a search to see if the user group has a folder that shares its name.  You use the WebObjectsFactory from above to get a WebSearch. You set it to be asynchronous so that you don’t need to poll for completion.  You use the group name as the name of the object (folder) you are seeking.  The search flags tell the search process to start at the project root and search recursively through the entire project. The SimpleList of types tells the search process to return only folders.  Since you are using the folder as the start page, you don’t care about other objects that may share the group’s name. Finally, you submit the search to Intelligence Server.:

    Because search time depends on project size, the recommended practice is to limit this search to a subset if possible.

    Copy
                  WebSearch lWS = lFactory.getObjectSource().getNewSearchObject();
                  lWS.setAsync(false);
                  lWS.setNamePattern(lGroupName);
                  lWS.setSearchFlags(EnumDSSXMLSearchFlags.DssXmlSearchRootRecursive);
                  SimpleList lTypes = lWS.types();
                  lTypes.clear();
                  lTypes.add(EnumDSSXMLObjectTypes.DssXmlTypeFolder);
                  lWS.submit();
  • Explanation: Now you process the search results. First you get them in the form of a WebFolder. If this folder is empty, you move on to the next result.  (Note that while this will trigger the default page, a real application may want to handle this case more intelligently.)  If the search finds a folder, you use its ID to build the desired start page URL.:

    It is possible that the search will return several entries with the target name. In this simple sample, the first one is picked arbitrarily. However, a real application would need to have a more intelligent process for selecting the appropriate match.

    Copy
                  WebFolder lWF = lWS.getResults();
                  if(!lWF.isEmpty())
                    {
                    mstrDesktopURL += "&folderID=" + lWF.get(0).getID();
                    }
                }
              }
  • Explanation: A simple bit of error handling rounds out the try-catch block.  :

    A real application would handle errors more intelligently.

    Copy
          catch(WebObjectsException e)
              {
              errorMsg = e.getMessage();
              }
          }
  • Explanation: Finally, add code to show the login form if the request is not coming from the custom login form or there is error during creating session.

    Copy
      if (!"CustomLogin".equals(request.getParameter("CustomLogin")) || !"".equals(errorMsg)) {
      //If the request is not coming from the custom login form, or there is error during creating session, show the login form.
    %>
            <body>
            <h3>My Custom Login Form </h3>
            <h4><%=errorMsg%></h4></br>
            <form action="" id="loginForm" name="loginForm" method="post">
            <input type="hidden" name="CustomLogin" value="CustomLogin" />
            <label for="Server">Server name:</label> <input value="" type="text" class="txt" name="Server" id="Server"/><br/>
            <label for="Project">Project name:</label> <input value="" type="text" class="txt" name="Project" id="Project"/><br/>
            <label for="Uid">User name:</label> <input value="" type="text" class="txt" name="Uid" id="Uid"/><br/>
            <label for="Pwd">Password:</label> <input type="password" class="txt" name="Pwd" id="Pwd"/>
            <input value="1" type="hidden" name="ConnMode" id="ConnMode"/> <br>
            <input value="Login" type="submit" class="btn" name="3054" id="3054"/>
            </form>
            </body>
    <%
            }
         else
            {
            //If the session is created successfully.
    %>
            <body  onload="submitform()">
     
            <%-- hidden form --%>
            <form name='loginForm' action='<%=mstrDesktopURL%>' method='post' >
     
                <input type='hidden' name='usrSmgr' value='<%=sessionState%>' >
            </form>
     
            <%-- the JavaScript does the submit action on the hidden login form--%>
            <SCRIPT language="JavaScript">
            function submitform()
            {
              document.loginForm.submit();
            }
            </SCRIPT>
            </body>
    <%
            }
    %>
    </html>