Changeset 7411


Ignore:
Timestamp:
Oct 10, 2017, 9:48:11 AM (5 years ago)
Author:
Nicklas Nordborg
Message:

References #2097: Implement support for device verification

Added a "User-Agent" analyzer library (https://github.com/nielsbasjes/yauaa). It is used to automatically generate the name of new devices. For example: Firefox 55 on Windows 10.0 (Desktop)

Added UserDeviceData.lastRemoteId property to store the ip address of the device the last time it was used.

Location:
trunk
Files:
5 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/.classpath

    r7400 r7411  
    3232  <classpathentry kind="lib" path="lib/dist/hibernate-jpa-2.1-api-1.0.0.Final.jar"/>
    3333  <classpathentry kind="lib" path="lib/dist/parallelgzip-1.0.5.jar"/>
     34  <classpathentry kind="lib" path="lib/dist/yauaa-2.2.jar"/>
    3435  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
    3536  <classpathentry kind="output" path="xbin"/>
  • trunk/doc/3rd-party-components.txt

    r7400 r7411  
    348348License   : javasysmon-LICENSE.txt
    349349Files     : javasysmon-0.3.5.jar
     350
     351Yauaa: Yet Another UserAgent Analyzer
     352-------------------------------------
     353A library for extracting information from the User-Agent header sent
     354by browsers.
     355
     356More info : https://github.com/nielsbasjes/yauaa
     357Version   : 2.2
     358License   : Apache License, Version 2.0 (yauaa-LICENSE.txt)
     359Files     : yauaa-2.2.jar, snakeyaml-1.18.jar, commons-collections4-4.1.jar
     360            commons-lang3-3.6.jar
     361
  • trunk/src/core/net/sf/basedb/core/SessionControl.java

    r7410 r7411  
    4545import net.sf.basedb.util.EmailUtil;
    4646import net.sf.basedb.util.Enumeration;
     47import net.sf.basedb.util.HttpUtil;
    4748import net.sf.basedb.util.MD5;
    4849import net.sf.basedb.util.extensions.ExtensionsInvoker;
     
    793794    String deviceToken = loginRequest.getDeviceToken();
    794795    String userAgent = loginRequest.getAttribute("user-agent");
     796    String userAgentSummary = userAgent == null ? null : HttpUtil.getSummaryOfUserAgent(userAgent);
    795797    UserDeviceData device = null;
    796798   
     
    815817        // This device is already verified
    816818        // We update the user agent string since it may be different due to version upgrade
    817         if (userAgent != null) device.setUserAgent(userAgent);
     819        String oldUserAgent = device.getUserAgent();
     820        if (userAgent != null && !userAgent.equals(oldUserAgent))
     821        {
     822          device.setUserAgent(userAgent);
     823          // If the current name was auto-generated from the old "User-Agent" we update the name as well!
     824          if (device.getName().equals(HttpUtil.getSummaryOfUserAgent(oldUserAgent)))
     825          {
     826            device.setName(userAgentSummary);
     827          }
     828        }
    818829        // And the lastUsed date
    819         device.setLastUsed(new Date());         
     830        device.setLastUsed(new Date());
     831        device.setLastRemoteId(getRemoteId());
    820832      }
    821833    }
     
    843855      Date now = new Date();
    844856      device = new UserDeviceData();
    845       device.setName("New device");
     857      device.setName(userAgentSummary == null ? "New device" : userAgentSummary);
    846858      device.setUser(user);
    847859      device.setClient(client);
    848860      device.setEntryDate(now);
    849861      device.setLastUsed(now);
     862      device.setLastRemoteId(getRemoteId());
    850863      device.setToken(deviceToken);
    851864      device.setUserAgent(userAgent);
  • trunk/src/core/net/sf/basedb/core/UserDevice.java

    r7406 r7411  
    224224    return getData().getUserAgent();
    225225  }
    226 
    227 
     226 
     227  /**
     228    Get the remote ID of the host the user used for this device the last time.
     229    Typically it is the IP-address of the user's computer.
     230    @return A <code>String</code> object with remote ID
     231  */
     232  public String getLastRemoteId()
     233  {
     234    return getData().getLastRemoteId();
     235  }
     236 
    228237}
    229238
  • trunk/src/core/net/sf/basedb/core/data/UserDeviceData.java

    r7406 r7411  
    170170  }
    171171
     172  /**
     173    The maximum length of the remote ID that can be stored in the database.
     174    @see #setRemoteId(String)
     175  */
     176  public static final int MAX_REMOTE_ID_LENGTH = 255;
     177  private String remoteId;
     178  /**
     179    Get the remote id (=ip address) of the last login from this device.
     180    @hibernate.property column="`lastremote_id`" type="string" length="255" not-null="false"
     181  */
     182  public String getLastRemoteId()
     183  {
     184    return remoteId;
     185  }
     186  public void setLastRemoteId(String remoteId)
     187  {
     188    this.remoteId = remoteId;
     189  }
     190
     191 
    172192  private Set<SessionData> sessions;
    173193  /**
  • trunk/src/core/net/sf/basedb/util/HttpUtil.java

    r6657 r7411  
    3333import org.apache.http.impl.client.CloseableHttpClient;
    3434
     35import nl.basjes.parse.useragent.UserAgent;
     36import nl.basjes.parse.useragent.UserAgentAnalyzer;
     37
    3538/**
    3639  Useful methods related to HTTP stuff in general and
     
    4649  private static final SimpleDateFormat HTTP_DATE_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.ENGLISH);
    4750
     51  private static UserAgentAnalyzer userAgentAnalyzer;
     52 
    4853  /**
    4954    Get the content length from the headers in the response.
     
    131136  }
    132137 
     138  /**
     139    Parse the User-Agent string from a HTTP request and return
     140    information about what it actually means.
     141    @see https://github.com/nielsbasjes/yauaa
     142    @since 3.12
     143  */
     144  public static synchronized UserAgent analyzeUserAgent(String userAgent)
     145  {
     146    if (userAgentAnalyzer == null)
     147    {
     148      userAgentAnalyzer = UserAgentAnalyzer.newBuilder().build();
     149    }
     150    return userAgentAnalyzer.parse(userAgent);
     151  }
     152 
     153  /**
     154    Get a summary of the user agent:
     155   
     156    * Browser with major version
     157    * Operating system with version
     158    * Typy of device (eg. desktop, phone, etc.)
     159   
     160    @since 3.12
     161  */
     162  public static String getSummaryOfUserAgent(String userAgent)
     163  {
     164    UserAgent ua = analyzeUserAgent(userAgent);
     165    return ua == null ? null : ua.getValue("AgentNameVersionMajor") +
     166        " on " + ua.getValue("OperatingSystemNameVersion") +
     167        " (" + ua.getValue("DeviceName") + ")";
     168  }
     169 
    133170}
  • trunk/www/views/devices/devices.js

    r7407 r7411  
    3838      Buttons.addClickHandler('close', App.closeWindow);
    3939
     40      Events.addEventHandler('use-user-agent', 'click', devices.copyUserAgentToName);
     41     
    4042      // Tab validation
    4143      TabControl.addTabValidator('settings.info', devices.validateDevice);
     
    7577    return true;
    7678  }
     79 
     80  devices.copyUserAgentToName = function(event)
     81  {
     82    var frm = document.forms['device'];
     83    frm.name.value = Data.get(event.currentTarget, 'summary') || frm.name.value;
     84  }
    7785
    7886  devices.save = function()
  • trunk/www/views/devices/edit_device.jsp

    r7407 r7411  
    2222  @author Nicklas
    2323--%>
     24<%@page import="net.sf.basedb.util.HttpUtil"%>
    2425<%@ page pageEncoding="UTF-8" session="false"
    2526  import="net.sf.basedb.core.SessionControl"
     
    5455try
    5556{
    56   String title = null;
    57   UserDevice device = null;
    58 
    5957  if (itemId == 0)
    6058  {
    6159    throw new PermissionDeniedException(Permission.CREATE, "device");
    6260  }
    63   else
    64   {
    65     device = UserDevice.getById(dc, itemId);
    66     device.checkPermission(Permission.WRITE);
    67     cc.setObject("item", device);
    68     title = "Edit device -- " + HTML.encodeTags(device.getName());
    69   }
     61  UserDevice device = UserDevice.getById(dc, itemId);
     62  device.checkPermission(Permission.WRITE);
     63  cc.setObject("item", device);
     64  String title = "Edit device -- " + HTML.encodeTags(device.getName());
     65  String summary = HTML.encodeTags(HttpUtil.getSummaryOfUserAgent(device.getUserAgent()));
    7066  JspContext jspContext = ExtensionsControl.createContext(dc, pageContext, GuiContext.item(itemType), device);
    7167  ExtensionsInvoker invoker = EditUtil.useEditExtensions(jspContext);
     
    9389          value="<%=HTML.encodeTags(device.getName())%>"
    9490          maxlength="<%=UserDevice.MAX_NAME_LENGTH%>"></td>
     91        <td></td>
     92      </tr>
     93      <tr>
     94        <th class="subprompt">User-agent</th>
     95        <td>
     96          <span title="<%=HTML.encodeTags(device.getUserAgent())%>"><%=summary %></span>
     97          [<span id="use-user-agent" class="link" title="Use this as the name" data-summary="<%=summary%>">copy</span>]
     98        </td>
    9599        <td></td>
    96100      </tr>
  • trunk/www/views/devices/index.jsp

    r7407 r7411  
    6060<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
    6161<%!
    62   private static final ItemContext defaultContext = Base.createDefaultContext("name", "name,client,lastUsed,description");
     62  private static final ItemContext defaultContext = Base.createDefaultContext("name", "name,client,lastUsed,lastRemoteId,description");
    6363  private static final Item itemType = Item.USERDEVICE;
    6464%>
  • trunk/www/views/devices/list_devices.jsp

    r7408 r7411  
    192192        exportable="true"
    193193        formatter="<%=dateTimeFormatter%>"
     194      />
     195      <tbl:columndef
     196        id="lastRemoteId"
     197        property="lastRemoteId"
     198        datatype="string"
     199        title="Last remote ID"
     200        sortable="true"
     201        filterable="true"
     202        exportable="true"
    194203      />
    195204      <tbl:columndef
     
    393402                <tbl:cell column="entryDate" value="<%=item.getEntryDate()%>" />
    394403                <tbl:cell column="lastUsed" value="<%=item.getLastUsed()%>" />
     404                <tbl:cell column="lastRemoteId"><%=HTML.encodeTags(item.getLastRemoteId())%></tbl:cell>
    395405                <tbl:cell column="description"><%=HTML.encodeTags(item.getDescription())%></tbl:cell>
    396406                <tbl:cell column="permission"><%=PermissionUtil.getShortPermissions(item)%></tbl:cell>
  • trunk/www/views/devices/view_device.jsp

    r7407 r7411  
    3535  import="net.sf.basedb.core.Project"
    3636  import="net.sf.basedb.util.Values"
     37  import="net.sf.basedb.util.HttpUtil"
    3738  import="net.sf.basedb.clients.web.Base"
    3839  import="net.sf.basedb.clients.web.PermissionUtil"
     
    162163      </tr>
    163164      <tr>
     165        <th>Last remote ID</th>
     166        <td><%=HTML.encodeTags(device.getLastRemoteId())%></td>
     167      </tr>
     168      <tr>
    164169        <th>User</th>
    165170        <td><base:propertyvalue item="<%=device%>" property="user" /></td>
     
    171176      <tr>
    172177        <th>User agent</th>
    173         <td><%=HTML.niceFormat(device.getUserAgent())%></td>
     178        <td><%=HTML.encodeTags(HttpUtil.getSummaryOfUserAgent(device.getUserAgent()))%></td>
     179      </tr>
     180      <tr>
     181        <th>User agent (raw)</th>
     182        <td><%=HTML.encodeTags(device.getUserAgent())%></td>
    174183      </tr>
    175184      <tr>
Note: See TracChangeset for help on using the changeset viewer.