All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.api.auth.DefaultKeyUriSupplier Maven / Gradle / Ivy

/*
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.api.auth;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Default implementation of {@link KeyUriSupplier}.
 *
 * @author [email protected]
 *
 */
public class DefaultKeyUriSupplier implements KeyUriSupplier {
  private static final String HTTPS_PROTOCOL_PREFIX = "https://";
  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  private static final String OPEN_ID_CONFIG_PATH = ".well-known/openid-configuration";

  private final HttpRequestFactory httpRequestFactory;
  private final Map issuerKeyUrls;

  /**
   * Constructor.
   *
   * @param httpRequestFactory is the factory used to make HTTP requests.
   * @param issuerKeyUrls is the configurations that map an issuer to the verification key URL.
   */
  public DefaultKeyUriSupplier(
      HttpRequestFactory httpRequestFactory,
      Map issuerKeyUrls) {
    Preconditions.checkNotNull(httpRequestFactory);
    Preconditions.checkNotNull(issuerKeyUrls);

    this.httpRequestFactory = httpRequestFactory;
    this.issuerKeyUrls = new ConcurrentHashMap<>(issuerKeyUrls);
  }

  @Override
  public Optional supply(String issuer) {
    Preconditions.checkNotNull(issuer);

    if (!this.issuerKeyUrls.containsKey(issuer)) {
      // The issuer is unknown.
      return Optional.absent();
    }

    IssuerKeyUrlConfig issuerKeyUrlConfig = this.issuerKeyUrls.get(issuer);
    Optional jwksUri = issuerKeyUrlConfig.getJwksUri();
    if (jwksUri.isPresent()) {
      // When jwksUri already exists, we return it directly.
      return jwksUri;
    }

    // When jwksUri is empty, we try to retrieve it through the OpenID discovery.
    boolean openIdValid = issuerKeyUrlConfig.isOpenIdValid();
    if (openIdValid) {
      // Start the OpenId discovery process only when openIdValid is true, i.e.
      // there is no previous failed attempt.
      Optional discoveredJwksUri = discoverJwksUri(issuer);
      // Update the record.
      this.issuerKeyUrls.put(issuer, new IssuerKeyUrlConfig(false, discoveredJwksUri));

      return discoveredJwksUri;
    }

    return Optional.absent();
  }

  private Optional discoverJwksUri(String issuer) {
    // Construct the discovery URI based on the issuer.
    String openIdUrl = constructOpenIdUrl(issuer);
    GenericUrl jwksUri = this.retrieveRemoteJwksUri(openIdUrl);
    return Optional.of(jwksUri);
  }

  private GenericUrl retrieveRemoteJwksUri(String openIdUrl) {
    try {
      GenericUrl genericUrl = new GenericUrl(openIdUrl);
      HttpResponse httpResponse = this.httpRequestFactory.buildGetRequest(genericUrl).execute();
      String json = httpResponse.parseAsString();
      ProviderMetadata metadata = OBJECT_MAPPER.readValue(json, ProviderMetadata.class);
      return new GenericUrl(metadata.getJwksUri());
    } catch (IOException exception) {
      throw new UnauthenticatedException("Cannot retrieve or parse OpenId Provider Metadata",
          exception);
    }
  }

  // Construct the OpenID discovery URL based on the issuer.
  private static String constructOpenIdUrl(String issuer) {
    String url = issuer;
    if (!URI.create(issuer).isAbsolute()) {
      // Use HTTPS if the protocol scheme is not specified in the URL.
      url = HTTPS_PROTOCOL_PREFIX + issuer;
    }
    if (!url.endsWith("/")) {
      url += "/";
    }
    return url + OPEN_ID_CONFIG_PATH;
  }

  private static final class ProviderMetadata {
    private final String jwksUri;

    @SuppressWarnings("unused")
    ProviderMetadata(@JsonProperty("jwks_uri") String jwksUri) {
      Preconditions.checkArgument(!Strings.isNullOrEmpty(jwksUri));

      this.jwksUri = jwksUri;
    }

    String getJwksUri() {
      return this.jwksUri;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy