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

com.google.api.server.spi.auth.EndpointsPeerAuthenticator Maven / Gradle / Ivy

There is a newer version: 2.2.2
Show newest version
/*
 * 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.server.spi.auth;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
import com.google.api.server.spi.Client;
import com.google.api.server.spi.EnvUtil;
import com.google.api.server.spi.config.PeerAuthenticator;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;

import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

/**
 * The default peer authenticator. It verify the request is from Google Cloud Endpoints frontend. It
 * is different from EndpointsAuthenticator, which authenticates the end user.
 */
public class EndpointsPeerAuthenticator implements PeerAuthenticator {
  @VisibleForTesting
  static final String ISSUER = "https://www.cloudendpointsapis.com";
  @VisibleForTesting
  static final String SIGNER = "[email protected]";
  @VisibleForTesting
  static final String HEADER_APPENGINE_PEER = "X-Appengine-Peer";
  @VisibleForTesting
  static final String APPENGINE_PEER = "apiserving";
  @VisibleForTesting
  static final String HEADER_PEER_AUTHORIZATION = "Peer-Authorization";

  private static final String PUBLIC_CERT_URL =
      "https://www.googleapis.com/service_accounts/v1/metadata/x509/" + SIGNER;
  private static final Logger logger = Logger.getLogger(EndpointsPeerAuthenticator.class.getName());
  private static final ImmutableSet localHostAddresses = getLocalHostAddresses();

  private final GoogleJwtAuthenticator jwtAuthenticator;

  private static ImmutableSet getLocalHostAddresses() {
    ImmutableSet.Builder builder = new ImmutableSet.Builder<>();
    try {
      builder.add(InetAddress.getLocalHost().getHostAddress());
    } catch (IOException e) {
      // try next.
    }
    try {
      builder.add(InetAddress.getByName(null).getHostAddress());
    } catch (IOException e) {
      // try next.
    }
    try {
      for (InetAddress inetAddress : InetAddress.getAllByName("localhost")) {
        builder.add(inetAddress.getHostAddress());
      }
    } catch (IOException e) {
      // check at the end.
    }
    ImmutableSet localHostSet = builder.build();
    if (localHostSet.isEmpty()) {
      logger.warning("Unable to lookup local addresses.");
    }
    return localHostSet;
  }

  public EndpointsPeerAuthenticator() {
    Client client = Client.getInstance();
    GooglePublicKeysManager keyManager = new GooglePublicKeysManager.Builder(
        client.getHttpTransport(), client.getJsonFactory()).setPublicCertsEncodedUrl(
        PUBLIC_CERT_URL).build();
    GoogleIdTokenVerifier verifier =
        new GoogleIdTokenVerifier.Builder(keyManager).setIssuer(ISSUER).build();
    jwtAuthenticator = new GoogleJwtAuthenticator(verifier);
  }

  @VisibleForTesting
  public EndpointsPeerAuthenticator(GoogleJwtAuthenticator jwtAuthenticator) {
    this.jwtAuthenticator = jwtAuthenticator;
  }

  @Override
  public boolean authenticate(HttpServletRequest request) {
    // Preserve current check for App Engine Env.
    if (EnvUtil.isRunningOnAppEngine()) {
      return APPENGINE_PEER.equals(request.getHeader(HEADER_APPENGINE_PEER));
    }

    // Skip peer verification for localhost request.
    if (localHostAddresses.contains(request.getRemoteAddr())) {
      logger.fine("Skip endpoints peer verication from localhost.");
      return true;
    }
    // Verify peer token, signer and audience.
    GoogleIdToken idToken =
        jwtAuthenticator.verifyToken(request.getHeader(HEADER_PEER_AUTHORIZATION));
    if (idToken == null || !SIGNER.equals(idToken.getPayload().getEmail())
        || !matchHostAndPort(idToken, request)) {
      return false;
    }
    return true;
  }

  private boolean matchHostAndPort(GoogleIdToken idToken, HttpServletRequest request) {
    URL urlFromIdToken;
    URL urlFromRequest;
    try {
      urlFromIdToken = new URL((String) idToken.getPayload().getAudience());
      urlFromRequest = new URL(request.getRequestURL().toString());
      return urlFromIdToken.getHost().equals(urlFromRequest.getHost())
          && getPort(urlFromIdToken) == getPort(urlFromRequest);
    } catch (MalformedURLException e) {
      logger.warning("Invalid URL from request");
      return false;
    }
  }

  private int getPort(URL url) {
    int port = url.getPort();
    return port == -1 ? url.getDefaultPort() : port;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy