public MtlsClientAttributes getVerifiedClientAttributes()

in token-service/src/main/java/com/google/solutions/tokenservice/oauth/mtls/XlbMtlsClientCredentialsFlow.java [146:221]


  public MtlsClientAttributes getVerifiedClientAttributes(AuthenticationRequest request)
  {
    Preconditions.checkNotNull(request, "request");

    //
    // Verify that the client presented a certificate and that the
    // load balancer reported it as "verified".
    //
    var headers = this.request.headers();
    if (!canAuthenticate(request))
    {
      throw new ForbiddenException(
        "The request did not include a client certificate");
    }

    if (!"true".equalsIgnoreCase(headers.get(this.options.clientCertChainVerifiedHeaderName())))
    {
      this.logAdapter
        .newErrorEntry(
          LogEvents.API_TOKEN,
          "The client certificate did not pass verification")
        .addLabels(this::addHeaderLabels)
        .write();

      throw new ForbiddenException("The client certificate did not pass verification");
    }

    this.logAdapter
      .newInfoEntry(
        LogEvents.API_TOKEN,
        "The client certificate was verified by the load balancer")
      .addLabels(this::addHeaderLabels)
      .write();

    //
    // The load balancer verified the certificate, and we can now read the other
    // headers to obtain the certificate attributes.
    //
    // NB. There's no way for us to confirm that it was really the load balancer
    // that added the header. But if the application has been deployed correctly,
    // then there shouldn't be any way for clients to sidestep the load balancer.
    //

    //
    // Read whatever header has been configured to contain the OAuth client ID.
    //
    var clientId = headers.get(this.options.clientIdHeaderName());
    if (Strings.isNullOrEmpty(clientId)) {
      throw new ForbiddenException(
        String.format(
          "The client presented a valid certificate, but the header '%s' does not contain a client ID",
          this.options.clientIdHeaderName()));
    }

    this.logAdapter
      .newInfoEntry(
        LogEvents.API_TOKEN,
        String.format("Authenticated client '%s' using mTLS headers", clientId))
      .addLabels(this::addHeaderLabels)
      .write();


    //
    // Return all attributes from HTTP headers. Note that some
    // attributes might be empty.
    //
    return new MtlsClientAttributes(
      clientId,
      headers.get(this.options.clientCertSpiffeIdHeaderName),
      decodeSanHeader(headers.get(this.options.clientCertDnsSansHeaderName)),
      decodeSanHeader(headers.get(this.options.clientCertUriSansHeaderName)),
      headers.get(this.options.clientCertHashHeaderName),
      headers.get(this.options.clientCertSerialNumberHeaderName),
      parseIfNotNull(headers.get(this.options.clientCertNotBeforeHeaderName)),
      parseIfNotNull(headers.get(this.options.clientCertNotAfterHeaderName)));
  }