class ClientAuthFactory {

  public Client provide(ContainerRequest containerRequest,
      HttpServletRequest httpServletRequest) {
    // Ports must either always send an x-forwarded-client-cert header, or
    // never send this header. This also throws an error if a single port
    // has multiple configurations.
    int requestPort = httpServletRequest.getLocalPort();
    Optional<XfccSourceConfig> possibleXfccConfig =
        getXfccConfigForPort(requestPort);

    List<String> xfccHeaderValues =
        Optional.ofNullable(containerRequest.getRequestHeader(XFCC_HEADER_NAME)).orElse(List.of());

    if (possibleXfccConfig.isEmpty() != xfccHeaderValues.isEmpty()) {
      throw new NotAuthorizedException(format(
          "Port %d is configured to %s receive traffic with the %s header set",
          requestPort, possibleXfccConfig.isEmpty() ? "never" : "only", XFCC_HEADER_NAME));
    }

    // Extract information about the requester. This may be a Keywhiz client, or it may be a proxy
    // forwarding the real Keywhiz client information in the x-forwarded-client-certs header
    Principal requestPrincipal = getPrincipal(containerRequest).orElseThrow(
        () -> new NotAuthorizedException("Not authorized as Keywhiz client"));

    // Extract client information based on the x-forwarded-client-cert header or
    // on the security context of this request
    if (possibleXfccConfig.isEmpty()) {
      // The XFCC header is not used; use the security context of this request to identify the client
      return authenticateClientFromCertificate(requestPrincipal);
    } else {
      return authorizeClientFromXfccHeader(possibleXfccConfig.get(), xfccHeaderValues,
          requestPrincipal);
    }
  }

  @Inject public  ClientAuthFactory(ClientDAOFactory clientDAOFactory, KeywhizConfig keywhizConfig);
  @VisibleForTesting  ClientAuthFactory(ClientDAO clientDAO, ClientAuthConfig clientAuthConfig);

}