Changeset 7158


Ignore:
Timestamp:
May 25, 2016, 3:25:41 PM (6 years ago)
Author:
Nicklas Nordborg
Message:

References #2011: Check that session id and client id match every time a new page is requested

This has now been implemented in the BASE Core API by adding a new Application.getSessionControl() method with 3 string arguments. The older 2-argument version will behave as if net.sf.basedb.clients.web is used.

This is change may break existing clients that are not built on top of the current web client. The only such client we currently know of is the FTP server extension but this is not affected since it doesn't use the Application.getSessionControl() method.

Fixing existing code that is affected should be relatively easy by replacing the old method call with a call to the new method and using the same client id as when the session was created.

Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/clients/web/net/sf/basedb/clients/web/Base.java

    r7120 r7158  
    111111
    112112  /**
     113    The external ID of the web client application.
     114    @since 3.9
     115  */
     116  public static final String WEBCLIENT_ID = "net.sf.basedb.clients.web";
     117 
     118  /**
    113119    Get a new or existing <code>SessionControl</code> object
    114120    given a <code>PageContext</code>. This method will get
     
    156162    try
    157163    {
    158       sc = Application.getSessionControl(id, remoteId);
     164      sc = Application.getSessionControl(id, Base.WEBCLIENT_ID, remoteId);
    159165      if (sc.isImpersonated())
    160166      {
     
    166172    catch (ItemNotFoundException ex)
    167173    {}
    168     return sc == null && create ? Application.newSessionControl("net.sf.basedb.clients.web", remoteId, id) : sc;
     174    return sc == null && create ? Application.newSessionControl(WEBCLIENT_ID, remoteId, id) : sc;
    169175  }
    170176 
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/Download.java

    r7154 r7158  
    2525package net.sf.basedb.clients.web.servlet;
    2626
     27import net.sf.basedb.clients.web.Base;
    2728import net.sf.basedb.core.AbsoluteProgressReporter;
    2829import net.sf.basedb.core.Application;
     
    168169      try
    169170      {
    170         sc = Application.getSessionControl(ID, request.getRemoteAddr());
     171        sc = Application.getSessionControl(ID, Base.WEBCLIENT_ID, request.getRemoteAddr());
    171172      }
    172173      catch (ItemNotFoundException ex)
    173174      {
    174         sc = Application.newSessionControl("net.sf.basedb.clients.web", request.getRemoteAddr(), null);
     175        sc = Application.newSessionControl(Base.WEBCLIENT_ID, request.getRemoteAddr(), null);
    175176        ID = sc.getId();
    176177      }
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/ExperimentExplorerPlotServlet.java

    r6875 r7158  
    6868import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;
    6969
     70import net.sf.basedb.clients.web.Base;
    7071import net.sf.basedb.clients.web.ExperimentExplorer;
    7172import net.sf.basedb.clients.web.ExperimentExplorer.AnnotationGroup;
     
    180181    final int annotationTypeId = Values.getInt(request.getParameter("annotationTypeId"));
    181182   
    182     final SessionControl sc = Application.getSessionControl(ID, request.getRemoteAddr());
     183    final SessionControl sc = Application.getSessionControl(ID, Base.WEBCLIENT_ID, request.getRemoteAddr());
    183184    DbControl dc = null;
    184185    BufferedImage image = null;
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/PlotServlet.java

    r6898 r7158  
    4949import net.sf.basedb.core.query.WhenStatement;
    5050import net.sf.basedb.core.snapshot.SnapshotManager;
     51import net.sf.basedb.clients.web.Base;
    5152import net.sf.basedb.clients.web.formatter.FormatterFactory;
    5253import net.sf.basedb.clients.web.util.HTML;
     
    392393        {
    393394          // Only reload the image if there is no cached version
    394           final SessionControl sc = Application.getSessionControl(ID, request.getRemoteAddr());
     395          final SessionControl sc = Application.getSessionControl(ID, Base.WEBCLIENT_ID, request.getRemoteAddr());
    395396          dc = sc.newDbControl();
    396397          BioAssay ba = bioAssayId == 0 ? null : BioAssay.getById(dc, bioAssayId);
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/RssNewsFeed.java

    r6473 r7158  
    4040import org.jdom2.output.XMLOutputter;
    4141
     42import net.sf.basedb.clients.web.Base;
    4243import net.sf.basedb.core.Application;
    4344import net.sf.basedb.core.DbControl;
     
    165166    try
    166167    {
    167       sc = Application.newSessionControl("net.sf.basedb.clients.web", null, null);
     168      sc = Application.newSessionControl(Base.WEBCLIENT_ID, null, null);
    168169      dc = sc.newDbControl();
    169170     
  • trunk/src/clients/web/net/sf/basedb/clients/web/servlet/ViewSpotImage.java

    r6127 r7158  
    2525package net.sf.basedb.clients.web.servlet;
    2626
     27import net.sf.basedb.clients.web.Base;
    2728import net.sf.basedb.core.Application;
    2829import net.sf.basedb.core.SessionControl;
     
    8384    try
    8485    {
    85       final SessionControl sc = Application.getSessionControl(ID, request.getRemoteAddr());
     86      final SessionControl sc = Application.getSessionControl(ID, Base.WEBCLIENT_ID, request.getRemoteAddr());
    8687      dc = sc.newDbControl();
    8788     
  • trunk/src/core/net/sf/basedb/core/Application.java

    r7052 r7158  
    999999  /**
    10001000    Get an existing <code>SessionControl</code> object if you know
    1001     the id.
     1001    the id. 
    10021002
    10031003    @param sessionControlId The id of the <code>SessionControl</code> object
     1004    @param externalClientId The external id for a registered client
     1005      application, or null if not important
    10041006    @param remoteId If this parameter was passed to the <code>newSessionControl</code>
    10051007      method, the same value must be passed here. Use, for example, the IP address
     
    10081010    @return The <code>SessionControl</code> object
    10091011    @throws ItemNotFoundException If an object with the specified id could not be found
    1010     @throws PermissionDeniedException If the remote id is different from the remote id
    1011       that was passed when the <code>SessionControl</code> object was created
     1012    @throws PermissionDeniedException If the remote or external client id is different from the
     1013      remote/external client id that was passed when the <code>SessionControl</code> object
     1014      was created
     1015     
    10121016    @throws BaseException If there is another error
    10131017    @see #newSessionControl(String,String,String)
    10141018    @see SessionControl#getId()
    1015   */
    1016   public static SessionControl getSessionControl(String sessionControlId, String remoteId)
     1019    @since 3.9
     1020  */
     1021  public static SessionControl getSessionControl(String sessionControlId, String externalClientId, String remoteId)
    10171022    throws ItemNotFoundException, BaseException
    10181023  {
     
    10251030      throw new PermissionDeniedException("Invalid remoteId ("+remoteId+"; expected: "+sc.getRemoteId()+")");
    10261031    }
     1032    if (!sc.isAllowedToUseClient(externalClientId))
     1033    {
     1034      log.warn("getSessionControl: Invalid externalClientId: "+externalClientId+"; expected: "+sc.getExternalClientId());
     1035      throw new PermissionDeniedException(Permission.USE, "Client[externalId="+externalClientId+"]");
     1036    }
    10271037    sc.updateLastAccess();
    10281038    return sc;
    10291039  }
    10301040
     1041  /**
     1042    Get an existing <code>SessionControl</code> object if you know
     1043    the id.
     1044   
     1045    NOTE! For maximum backwards compatibility calling this method
     1046    is equivalent to using "net.sf.basedb.clients.web" as the
     1047    external client id. Existing applications that use a different id
     1048    MUST be updated to use the new method or they will no longer
     1049    work in BASE 3.9.
     1050 
     1051    @deprecated In 3.9, use {@link #getSessionControl(String, String, String)} instead
     1052  */
     1053  @Deprecated
     1054  public static SessionControl getSessionControl(String sessionControlId, String remoteId)
     1055    throws ItemNotFoundException, BaseException
     1056  {
     1057    return getSessionControl(sessionControlId, "net.sf.basedb.clients.web", remoteId);
     1058  }
     1059 
    10311060  /**
    10321061    Clean the cache from unused <code>SessionControl</code> objects.
  • trunk/src/core/net/sf/basedb/core/SessionControl.java

    r7015 r7158  
    136136  private final Map<ContextKey, ItemContext> currentContexts;
    137137 
     138  private final Map<String, Boolean> allowedClients;
     139 
    138140  private int pluginId;
    139141 
     
    163165    li.keyring = new Keyring(li.keyring, pluginId, plugin != null && plugin.getUsePermissions());
    164166    this.loginInfo = li;
     167    this.allowedClients = Collections.synchronizedMap(new HashMap<String, Boolean>(parent.allowedClients));
    165168  }
    166169 
     
    181184    this.dbControlCache = Collections.synchronizedMap(new WeakHashMap<DbControl,String>());
    182185    this.currentContexts = Collections.synchronizedMap(new HashMap<ContextKey, ItemContext>());
     186    this.allowedClients = Collections.synchronizedMap(new HashMap<String, Boolean>());
    183187    int tempClientId = 0;
    184188    if (externalClientId != null)
     
    394398      HibernateUtil.commit(tx);
    395399      currentContexts.clear();
     400      allowedClients.clear();
    396401      loginInfo = li;
    397402    }
     
    661666 
    662667  /**
     668    Checks if this session control can be used by the given client application.
     669    It is allowed if the given id is the same as when this session control was
     670    created, or if there is a logged in user that is allowed to use the given
     671    client.
     672    @param externalClientId The external id of the client to check
     673    @return TRUE if the client can be used, FALSE if not
     674  */
     675  boolean isAllowedToUseClient(String externalClientId)
     676  {
     677    // The root user is always allowed
     678    if (getLoggedInUserId() == SystemItems.getId(User.ROOT)) return true;
     679   
     680    // Check if same client as when SessionControl was created
     681    if (StringUtil.isEqualOrNull(externalClientId, this.externalClientId)) return true;
     682   
     683    // If no external ID or no user is logged in we do not allow it
     684    if (externalClientId == null || !isLoggedIn()) return false;
     685   
     686    // Check the cached info
     687    Boolean allowed = allowedClients.get(externalClientId);
     688    if (allowed != null) return allowed;
     689   
     690    // Check the database
     691    allowed = false;
     692    ClientData clientData = getClientWithExternalId(externalClientId);
     693    if (clientData != null)
     694    {
     695      int permissions = loginInfo.keyring.getAllPermissions(
     696        Item.CLIENT, clientData.getOwner(), clientData.getItemKey(), clientData.getProjectKey());
     697      allowed = Permission.hasPermission(permissions, Permission.USE);
     698    }
     699   
     700    allowedClients.put(externalClientId, allowed);
     701    return allowed;
     702  }
     703 
     704  private ClientData getClientWithExternalId(String externalId)
     705  {
     706    ClientData clientData = null;
     707    org.hibernate.Session session = null;
     708    org.hibernate.Transaction tx = null;
     709    try
     710    {
     711      session = HibernateUtil.newSession();
     712      tx = HibernateUtil.newTransaction(session);
     713     
     714      // Find the internal client id for the given external id
     715      org.hibernate.Query query = HibernateUtil.getPredefinedQuery(session, "GET_CLIENT_FOR_EXTERNAL_ID");
     716      /*
     717        SELECT cli
     718        FROM ClientData cli
     719        WHERE cli.externalId = :externalId
     720      */
     721      query.setString("externalId", externalId);
     722      clientData = HibernateUtil.loadData(ClientData.class, query);
     723    }
     724    finally
     725    {
     726      if (tx != null) HibernateUtil.commit(tx);
     727      if (session != null) HibernateUtil.close(session);
     728    }
     729    return clientData;
     730  }
     731 
     732  /**
    663733    Create a LoginInfo object and load all information that it needs.
    664734  */
     
    762832    }
    763833    currentContexts.clear();
     834    allowedClients.clear();
    764835    loginInfo = null;
    765836  }
  • trunk/src/install/net/sf/basedb/install/Webclient.java

    r6424 r7158  
    2626import net.sf.basedb.core.Config;
    2727import net.sf.basedb.core.SessionControl;
     28import net.sf.basedb.clients.web.Base;
    2829import net.sf.basedb.core.Application;
    2930import net.sf.basedb.core.DbControl;
     
    106107      try
    107108      {
    108         client = Client.getByExternalId(dc, "net.sf.basedb.clients.web");
     109        client = Client.getByExternalId(dc, Base.WEBCLIENT_ID);
    109110      }
    110111      catch (ItemNotFoundException ex)
    111112      {
    112         client = Client.getNew(dc, "net.sf.basedb.clients.web");
     113        client = Client.getNew(dc, Base.WEBCLIENT_ID);
    113114        client.setName("Web client");
    114115        client.setDescription("The web interface to BASE");
  • trunk/src/test/TestSessionControl.java

    r5827 r7158  
    5454    try
    5555    {
    56       Application.getSessionControl(sc.getId(), remoteId);
     56      Application.getSessionControl(sc.getId(), sc.getExternalClientId(), remoteId);
    5757      if (shouldFail)
    5858      {
  • trunk/www/exception/exception.jsp

    r7108 r7158  
    5454  taglib prefix="base" uri="/WEB-INF/base.tld" %>
    5555<%
    56   final SessionControl sc = Application.isRunning() ? Base.getSessionControl(pageContext, false) : null;
     56  SessionControl sc = null;
     57  try
     58  {
     59    sc = Application.isRunning() ? Base.getSessionControl(pageContext, false) : null;
     60  }
     61  catch (RuntimeException ex)
     62  {}
    5763  final String reportbuglink = sc == null ? "" : Values.getStringOrNull(sc.getClientDefaultSetting("server.links.reportbug"));
    5864  Throwable ex = exception;
  • trunk/www/include/menu.jsp

    r7108 r7158  
    8585<%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %>
    8686<%
    87 final SessionControl sc = Application.isRunning() ? Base.getSessionControl(pageContext, false) : null;
     87SessionControl sc = null;
     88try
     89{
     90  sc = Application.isRunning() ? Base.getSessionControl(pageContext, false) : null;
     91}
     92catch (RuntimeException ex)
     93{}
    8894final String ID = sc == null ? "" : sc.getId();
    8995String name = Values.getString(request.getParameter("name"), "login");
Note: See TracChangeset for help on using the changeset viewer.