Class CaldavServerUrlValidator

java.lang.Object
org.exoplatform.caldav.service.CaldavServerUrlValidator

@Component public class CaldavServerUrlValidator extends Object
Checks the address of a CalDAV server BEFORE the platform is made to connect to it.

Why this exists. Once a server is declared, connected users drive requests at that address from the platform, with server-side credentials, over the verbs the relay allows. Every other guard in the relay is client-facing, so before this class the effective trust boundary was whatever an administrator typed — and an address pointing inside the deployment's own network turned eXo into the thing that reaches it. That is a server-side request forgery surface, open by omission rather than by decision.

What it decides. Scheme (https, http only where the deployment opts in), host (loopback, link-local and private ranges refused by default), and shape (no credentials in the URL, no fragment, no port outside the allowed set). It refuses; it never rewrites what it was given, because a sanitised address is an address nobody typed and nobody can reason about.

What it does not close — say it plainly. The host check resolves the name and judges the addresses it gets back at declaration time. A name that resolves inside the allowed set now can resolve to a blocked address a second later, and nothing here would know: that is DNS rebinding, and validating at declaration time reduces the surface without closing it. Closing it needs the check to move to connection time, per connection, on the address actually dialled — which the JDK HTTP client does not offer a hook for. Nothing in this class should be read as claiming otherwise.

The {username} placeholder. A declared URL may carry one; it is substituted per connecting user. It is refused in the scheme or authority position, where a substituted value could move the request to another host, and accepted after it, where it cannot. The rest of the URL is then checked with the placeholder replaced by a plain sentinel, so the template is validated in the shape it will actually be used in rather than rejected for carrying a brace.

  • Field Details

    • MALFORMED_MESSAGE

      public static final String MALFORMED_MESSAGE
      Refused: the string is not a usable absolute http(s) URL at all.
      See Also:
    • SCHEME_NOT_ALLOWED_MESSAGE

      public static final String SCHEME_NOT_ALLOWED_MESSAGE
      Refused: the scheme is outside the allowed set.
      See Also:
    • CREDENTIALS_MESSAGE

      public static final String CREDENTIALS_MESSAGE
      Refused: the URL carries a user name or password in its authority.
      See Also:
    • FRAGMENT_MESSAGE

      public static final String FRAGMENT_MESSAGE
      Refused: the URL carries a fragment.
      See Also:
    • PORT_NOT_ALLOWED_MESSAGE

      public static final String PORT_NOT_ALLOWED_MESSAGE
      Refused: the port is outside the allowed set.
      See Also:
    • USERNAME_IN_AUTHORITY_MESSAGE

      public static final String USERNAME_IN_AUTHORITY_MESSAGE
      Refused: the {username} placeholder sits in the authority.
      See Also:
    • PRIVATE_ADDRESS_MESSAGE

      public static final String PRIVATE_ADDRESS_MESSAGE
      Refused: the host points at a loopback, link-local or private address.
      See Also:
    • UNRESOLVABLE_MESSAGE

      public static final String UNRESOLVABLE_MESSAGE
      Refused: the host resolves to nothing.
      See Also:
    • USERNAME_PLACEHOLDER

      public static final String USERNAME_PLACEHOLDER
      The placeholder a declared URL may carry, substituted per user.
      See Also:
  • Constructor Details

    • CaldavServerUrlValidator

      @Autowired public CaldavServerUrlValidator(@Value("${exo.agenda.caldav.server.allowedSchemes:https}") String allowedSchemes, @Value("${exo.agenda.caldav.server.allowedPorts:80,443}") String allowedPorts, @Value("${exo.agenda.caldav.server.allowedHosts:}") String allowedHosts, @Value("${exo.agenda.caldav.server.allowPrivateAddresses:false}") boolean allowPrivateAddresses)
      The validator Spring builds, reading the deployment's configuration and resolving names through the JDK.
      Parameters:
      allowedSchemes - comma-separated URL schemes an administrator may declare; https alone by default, so a deployment fronting a plain-http CalDAV server has to say so
      allowedPorts - comma-separated ports a declared URL may reach, implicit default ports included; 80,443 by default
      allowedHosts - comma-separated hosts exempted from the private-address block — the narrow opt-out, for the deployment whose CalDAV server genuinely is internal; empty by default
      allowPrivateAddresses - whether ANY private, loopback or link-local address may be declared; false by default, and the blunt instrument next to the host list above
  • Method Details

    • validate

      public void validate(String declaredUrl)
      Refuses a declared CalDAV server address the platform must not be made to connect to, with the message code the REST layer answers 400 with — at declaration time, where an administrator reads the reason, rather than at synchronisation time, where the same refusal is an unexplained sync failure.
      Parameters:
      declaredUrl - the address as the administrator typed it, placeholder included
      Throws:
      IllegalArgumentException - carrying a translatable message code when the address is refused