Class AdminLoginLocation

java.lang.Object
sk.iway.iwcm.users.devices.AdminLoginLocation

public final class AdminLoginLocation extends Object
Carries an optional, browser-supplied IP location through administrator login and its session lifecycle.

The login flow has a pre-login lookup and one fallback after authentication:

  1. The login page runs /admin/scripts/login-location.js, which calls the external IP lookup URL from getLookupUrl() directly from the browser. It posts only the city and country code to /admin/logon/location/, where AdminLoginLocationController delegates to prepare(HttpSession, Input).
  2. The validated hint is stored under PENDING, with its receipt time. LogonTools explicitly copies it when replacing the HTTP session, so it remains available through additional authentication steps.
  3. After authentication succeeds, LogonTools.afterSuccessLogon calls beginLogin(HttpSession). It consumes the hint if it is at most ten minutes old and exposes it through getLocation(HttpSession) before AdminDeviceService records the device login and sends any new-device notification. SessionHolder also reads this location when updating session details.
  4. If the location is still missing, LayoutService calls takeRetryUrl(HttpSession) for the first rendered administration page, including direct editor links. The same script retries the lookup and posts to /admin/rest/security/login-location. The controller updates the current session and cluster summary through setLocation(HttpSession, String). It also asks DeviceService to fill the device's missing location only if its latest login still matches DEVICE_LOGIN_TIME; this fallback does not resend the email.

Lookup failures do not delay or prevent authentication. The location is untrusted display metadata, never evidence for authentication or device ownership. The browser supplies no account, device or session identifiers; the controller derives the target from the caller's session.

The adminLoginLocationApiKey setting selects the provider: an empty value uses ipwho.is, a key uses ipwhois.pro, and DISABLED turns lookup off. A configured key is intentionally included in the URL sent to the browser.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Contains the untrusted location fields submitted by the browser, without target identifiers.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
     
    static final String
     
  • Method Summary

    Modifier and Type
    Method
    Description
    static void
    beginLogin(jakarta.servlet.http.HttpSession session)
    Starts a successful administrator login by consuming its pending location hint once.
    static String
    getLocation(jakarta.servlet.http.HttpSession session)
     
    static String
    Builds the external IP lookup URL for the browser without making a server-side request.
    static boolean
     
    static void
    prepare(jakarta.servlet.http.HttpSession session, AdminLoginLocation.Input input)
    Validates a pre-login hint and stages it in the session with the current server time.
    static void
    setLocation(jakarta.servlet.http.HttpSession session, String location)
    Applies a location to the HTTP session and any existing session details after a fallback lookup.
    static String
    takeRetryUrl(jakarta.servlet.http.HttpSession session)
    Reserves one browser lookup retry when rendering an administration page without a location.
    static String
    Validates and normalizes browser input into display text such as Bratislava, SK.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

  • Method Details

    • isEnabled

      public static boolean isEnabled()
    • getLookupUrl

      public static String getLookupUrl()
      Builds the external IP lookup URL for the browser without making a server-side request.

      An empty API key selects the free endpoint; otherwise the URL includes the encoded paid key, which is visible to the browser. Only success, city and country code are requested.

      Returns:
      lookup URL, or null when the configuration is DISABLED
    • prepare

      public static void prepare(jakarta.servlet.http.HttpSession session, AdminLoginLocation.Input input)
      Validates a pre-login hint and stages it in the session with the current server time.

      The controller calls this for an unauthenticated session. A valid hint replaces any pending hint; disabled lookup or invalid input leaves the session unchanged. The hint becomes the login location only when beginLogin(HttpSession) consumes it.

      Parameters:
      session - non-null pre-login session to hold the pending hint
      input - browser-supplied city and country code; null or invalid input is ignored
    • beginLogin

      public static void beginLogin(jakarta.servlet.http.HttpSession session)
      Starts a successful administrator login by consuming its pending location hint once.

      Called after all required authentication steps and before device recording and notification. The pending hint is removed regardless of validity. It becomes the current location only if lookup is enabled and it is at most ten minutes old; otherwise any previous location is cleared. The retry marker and device login timestamp are also cleared for the new login.

      Parameters:
      session - non-null authenticated session containing any preserved pre-login hint
    • getLocation

      public static String getLocation(jakarta.servlet.http.HttpSession session)
    • takeRetryUrl

      public static String takeRetryUrl(jakarta.servlet.http.HttpSession session)
      Reserves one browser lookup retry when rendering an administration page without a location.

      The reservation is recorded before returning the URL, so later page renders do not retry even if the browser lookup fails. beginLogin(HttpSession) resets this marker for the next successful login.

      Parameters:
      session - current administrator session, or null when no session exists
      Returns:
      lookup URL for the reserved attempt, or null if the session is absent, lookup is disabled, a location is already present or a retry was already reserved
    • validate

      public static String validate(AdminLoginLocation.Input input)
      Validates and normalizes browser input into display text such as Bratislava, SK.

      The trimmed city must contain 1 to 156 characters and no ISO control characters. The trimmed, uppercased country code must contain exactly two ASCII letters. These checks bound the input but do not verify the location or escape HTML; callers must render it as text.

      Parameters:
      input - untrusted city and country code; may be null
      Returns:
      normalized city, CC text, or null if either field is missing or invalid
    • setLocation

      public static void setLocation(jakarta.servlet.http.HttpSession session, String location)
      Applies a location to the HTTP session and any existing session details after a fallback lookup.

      If session details exist, their location is updated and administrator details trigger a cluster summary update. This method does not validate input or update the persisted device; the controller handles validation and delegates the device update to DeviceService.

      Parameters:
      session - non-null session whose location is being updated
      location - validated display text, or null to clear the location