Changeset 7529


Ignore:
Timestamp:
Nov 26, 2018, 8:30:41 AM (3 years ago)
Author:
Nicklas Nordborg
Message:

References #2131: Add support for installing multiple authentication managers

If there are more than one installed login manager the login page now displays a selection list with the ability to switch between them.

One "problem" is that the CSS and javascript for all login managers are loaded and CSS rules may not work well together. For example, if the Yubikey and OTP extensions are both enabled, the yubikey icon is displayed in the "Login" field also for the OTP login. On the other hand, the OTP icon is always displayed in the help text...

To fix this the extensions need to update their CSS rules so that they only apply when their own login form is active. To help with this, BASE will set an attribute on the <body> tag:

  <body data-login-form="id-of-login-form">

where id-of-login-form' is the value returned by the LoginFormAction?.getId()` method. Scripts should also check this value.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/login/LoginFormAction.java

    r7500 r7529  
    2222package net.sf.basedb.clients.web.extensions.login;
    2323
     24import net.sf.basedb.core.authentication.LoginRequest;
    2425import net.sf.basedb.util.extensions.Action;
    2526
     
    3435{
    3536
     37  /**
     38    Get the ID of this login form. It's main use it to
     39    enable support for multiple installed authentication
     40    managers. Clients that supports this should submit the
     41    id of the login form via the "login-form" {@link LoginRequest}
     42    attribute. Authentication managers should check this id
     43    before determining if they should handle the login request
     44    or not.
     45   
     46    Since this is a new method in BASE 3.14 a default
     47    implementation that returns null is provided for backwards
     48    compatibility. If this method returns null, the id from
     49    the extension is used instead.
     50    @since 3.14
     51  */
     52  public default String getId()
     53  {
     54    return null;
     55  }
     56 
     57  /**
     58    Get a name that can be displayed for users in a selection list
     59    or similar to switch between different login methods.
     60   
     61    Since this is a new method in BASE 3.14 a default
     62    implementation that returns null is provided for backwards
     63    compatibility. If this method returns null, the name from
     64    the extension is used instead.
     65    @since 3.14
     66  */
     67  public default String getDisplayName()
     68  {
     69    return null;
     70  }
     71 
    3672  /**
    3773    Optional help text that is displayed on the login form to aid the
  • trunk/src/clients/web/net/sf/basedb/clients/web/extensions/login/LoginFormBean.java

    r7500 r7529  
    3131  implements LoginFormAction
    3232{
     33  private String id;
     34  private String displayName;
    3335 
    3436  private String help;
     
    4042  public LoginFormBean()
    4143  {}
     44 
     45  @Override
     46  public String getId()
     47  {
     48    return id;
     49  }
     50  public void setId(String id)
     51  {
     52    this.id = id;
     53  }
     54
     55  @Override
     56  public String getDisplayName()
     57  {
     58    return displayName;
     59  }
     60  public void setDisplayName(String displayName)
     61  {
     62    this.displayName = displayName;
     63  }
     64
    4265 
    4366  @Override
  • trunk/www/login.js

    r7500 r7529  
    4444    Buttons.addClickHandler('close', App.closeWindow);
    4545   
     46    Events.addEventHandler('loginForm', 'change', login.switchLoginForm);
     47   
    4648    var extraField = Doc.element('extraField');
    4749    if (extraField == null)
     
    6668   
    6769    if (window.Exception) Exception.fixWindow();
     70  }
     71 
     72  login.switchLoginForm = function(event)
     73  {
     74    // TODO -- will not work when login form is in a different jsp
     75    var url = 'main.jsp?ID='+App.getSessionId();
     76    url += '&loginForm='+event.currentTarget.value;
     77    location.replace(url);
    6878  }
    6979 
     
    192202    }
    193203   
     204    alert(frm.loginForm.value);
     205   
    194206    // On the impersonate form, check that a user has been selected
    195207    if (frm.user_id && !frm.user_id.value)
     
    204216      Login.saveLastLogin(frm.login.value);
    205217    }
     218    // TODO -- save the login form
    206219   
    207220    // Check 'remain on page' and 'redirect' options
     
    233246      var frm2 = Forms.cloneAsHidden(frm);
    234247      document.body.appendChild(frm2);
     248      alert(frm2.loginForm.value);
    235249      frm2.submit();
    236250      document.body.removeChild(frm2);
  • trunk/www/login.jsp

    r7500 r7529  
    6767    String deviceToken = Values.getStringOrNull(request.getParameter("deviceToken"));
    6868    String extraValue = Values.getStringOrNull(request.getParameter("extraField"));
     69    String loginForm = Values.getStringOrNull(request.getParameter("loginForm"));
    6970    try
    7071    {
     
    7273      LoginRequest loginRequest = new LoginRequest(login, password, deviceToken);
    7374      if (extraValue != null) loginRequest.setAttribute("extraValue", extraValue);
     75      if (loginForm != null) loginRequest.setAttribute("login-form", loginForm);
    7476      loginRequest.setAttribute("user-agent", request.getHeader("User-Agent"));
    7577      String serverUrl = request.getRequestURL().toString().replace(request.getRequestURI(), root);
  • trunk/www/main.jsp

    r7500 r7529  
    4141  import="net.sf.basedb.core.query.Hql"
    4242  import="net.sf.basedb.util.extensions.ExtensionsInvoker"
     43  import="net.sf.basedb.util.extensions.ActionIterator"
    4344  import="net.sf.basedb.clients.web.Base"
    4445  import="net.sf.basedb.clients.web.util.HTML"
     
    5354  import="net.sf.basedb.util.Values"
    5455  import="java.util.Date"
     56  import="java.util.Map"
     57  import="java.util.TreeMap"
    5558%>
    5659<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
     
    6669final String login = Values.getString(request.getParameter("login"), "");
    6770final String error = Values.getString(request.getParameter("error"), null);
     71final String requestedLoginForm = Values.getString(request.getParameter("loginForm"), null);
    6872final String root = request.getContextPath()+"/";
    6973
     
    8387
    8488  LoginFormAction loginAction = null;
    85   for (LoginFormAction action : invoker)
     89  String selectedLoginForm = null;
     90  Map<String, String> allForms = new TreeMap<String, String>();
     91 
     92  ActionIterator<LoginFormAction> it = invoker.iterate();
     93  while (it.hasNext())
    8694  {
     95    LoginFormAction action = it.next();
    8796    if (action != null)
    8897    {
    89       loginAction = action;
    90       break;
     98      String formId = action.getId();
     99      if (formId == null) formId = it.getExtension().getId();
     100      String displayName = action.getDisplayName();
     101      if (displayName == null) displayName = it.getExtension().getAbout().getName();
     102      allForms.put(formId, displayName);
     103     
     104      if (loginAction == null || formId.equals(requestedLoginForm))
     105      {
     106        loginAction = action;
     107        selectedLoginForm = formId;
     108      }
    91109    }
    92110  }
     
    109127    <ext:stylesheets context="<%=jspContext%>" />
    110128  </base:head>
    111   <base:body style="padding-top: 5em;">
     129  <base:body style="padding-top: 5em;" data-login-form="<%=Values.getString(selectedLoginForm)%>">
    112130    <form name="login" action="login.jsp" method="post">
    113131    <input type="hidden" name="ID" value="<%=ID%>">
     
    122140      {
    123141        %>
    124         <div class="messagecontainer help" style="font-style: italic;" id="login-help">
     142        <div class="messagecontainer help" style="margin-bottom: 1em; font-style: italic;" id="login-help">
    125143        <%=loginAction.getHelp() %>
    126144        </div>
     
    130148      {
    131149        %>
    132         <div class="messagecontainer error" style="margin-top: 1em;"><%=error%></div>
    133         <%
    134       }
    135       %>
    136       <table style="width: 100%; margin-top: 1em; border-collapse: separate;">
     150        <div class="messagecontainer error" style="margin-top: 1em; margin-bottom: 1em;"><%=error%></div>
     151        <%
     152      }
     153      if (allForms.size() > 1)
     154      {
     155        %>
     156        <div style="text-align: right; margin-bottom: 0.25em;">
     157          <b>Login with</b>
     158          <select name="loginForm" id="loginForm" style="min-width: 10em;">
     159          <%
     160          for (Map.Entry<String, String> entry : allForms.entrySet())
     161          {
     162            String formId = entry.getKey();
     163            %>
     164            <option value="<%=formId%>" <%=formId.equals(selectedLoginForm) ? "selected" : ""%>><%=HTML.encodeTags(entry.getValue()) %>
     165            <%
     166          }
     167          %>
     168          </select>
     169        </div>
     170        <%
     171      }
     172      else if (selectedLoginForm != null)
     173      {
     174        %>
     175        <input type="hidden" name="loginForm" value="<%=selectedLoginForm%>">
     176        <%
     177      }
     178      %>
     179      <table style="width: 100%; border-collapse: separate;">
    137180      <tr>
    138181        <td class="base-logo"><img src="images/baselogo.png" alt="BASE logo"></td>
Note: See TracChangeset for help on using the changeset viewer.