Class FragmentFilter

  • All Implemented Interfaces:
    Filter

    public class FragmentFilter
    extends Object
    implements Filter
    The FragmentFilter supports URIs that contain fragments, keeping track of the fragment part when a request triggers a login redirect. The browser does not include the fragment (also referred to as an anchor) in the request that is sent to IG which means it can't be included when redirecting as part of a login process and is lost when the login process completes.

    The general flow with this filter in place is as follows:

    • When an incoming request is received by this filter, it adds an AuthRedirectContext for the downstream filters to be able to mark response as redirected when needed.
    • When the response message is intercepted, and if it has been marked as a login redirect (thanks to the AuthRedirectContext), this filter captures both the Location header value (the original login URI) and the original request URI (the target of the original request) and finally returns a new response object containing an auto-submit HTML form and all of the cookies set on the original response (otherwise they would be lost). The HTML form contains the original login URI and the original request URI plus some Javascript used to capture fragments on the client side and send them to the server.
    • The User-Agent either runs the javascript or displays the form's submit button for the user to click on. Effectively, this POST back to the fragment endpoint URI a form request with both the original login URI, the original request URI and the captured fragments.
    • POSTed parameters are received by the fragment filter's endpoint and stored in a dedicated cookie that we expect to receive back when the user-agent perform the last redirect on the original request URI.
    • This filter then returns a redirect response to the original/captured login URI, in order to resume the authentication flow.
    • The required authentication flow takes place between the user-agent and the IDP before eventually completing with a final redirect to the original request URI.
    • If there is a fragment cookie in the request, and if the request URI matches the original request URI (read from the cookie), then this filter intercepts the flow and redirects the UA a final time on an URI composed of the original request URI and the captured fragments. The fragment cookie is expired during that step.
    • On following this final redirect, the UA can use the fragments.
     {
        "type": "FragmentFilter",
        "config": {
          "fragmentCaptureEndpoint"   : URI Path              [REQUIRED - the IG endpoint URI used to capture any
                                                                          fragment that may have been part of the
                                                                          original request URI. This should match
                                                                          the condition that triggers the route this
                                                                          filter is used in to ensure the form data
                                                                          holding the fragment is captured correctly.]
          "noJavaScriptMessage:       : stringExpression      [OPTIONAL - the message to show when the user-agent does
                                                                          not support JavaScript. JavaScript is used to
                                                                          capture the fragment by the generated HTML
                                                                          page sent to the browser. Defaults to
                                                                          {@literal NO_JAVASCRIPT_MESSAGE}
          "cookie": {
            "name"                    : Name of cookie containing the IG fragment details. Defaults to
                                        {@value DEFAULT_FRAGMENT_COOKIE_NAME }.
            "domain"                  : Domain that cookie is applicable to. If unset, defaults to domain of IG host.
            "path"                    : Path protected by this authentication. Defaults to
                                        {@value DEFAULT_FRAGMENT_COOKIE_PATH }.
            "secure"                  : Determines if the cookie should be set to be secure. Defaults to {@code false}.
            "httpOnly"                : Determines if the cookie should be set to be httpOnly. Defaults to {@code true}.
            "sameSite"                : SameSite cookie configuration. Default is {@code null}.
            "maxAge"                  : Max-Age cookie configuration. Default is {@literal 1 hour}
           }
        }
      }
     
     
    // @Checkstyle:off LineLength
    See Also:
    URI Fragment // @Checkstyle:on LineLength, Fragment RFC
    • Constructor Detail

      • FragmentFilter

        public FragmentFilter​(String fragmentCaptureEndpoint,
                              String noJavaScriptMessage,
                              org.forgerock.openig.filter.FragmentFilter.ExtendedCookieBuilder cookieBuilder)
        Creates a new FragmentFilter.
        Parameters:
        fragmentCaptureEndpoint - the IG endpoint that is used to capture POSTed fragment form data
        noJavaScriptMessage - the message to show on fragment capture form when JavaScript is not enabled
        cookieBuilder - the FragmentFilter.ExtendedCookieBuilder used to build the fragment cookie
    • Method Detail

      • filter

        public Promise<Response,​NeverThrowsException> filter​(Context context,
                                                                   Request request,
                                                                   Handler next)
        Description copied from interface: Filter
        Filters the request and/or response of an exchange. To pass the request to the next filter or handler in the chain, the filter calls next.handle(context, request).

        This method may elect not to pass the request to the next filter or handler, and instead handle the request itself. It can achieve this by merely avoiding a call to next.handle(context, request) and creating its own response object. The filter is also at liberty to replace a response with another of its own by intercepting the response returned by the next handler.

        Specified by:
        filter in interface Filter
        Parameters:
        context - The request context.
        request - The request.
        next - The next filter or handler in the chain to handle the request.
        Returns:
        A Promise representing the response to be returned to the client.