BasicAuthFilter.java

package cn.home1.oss.environment.admin;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.context.RequestContext;
import cn.home1.oss.lib.common.BasicAuthUtils;
import cn.home1.oss.lib.common.crypto.EncodeDecryptor;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

/**
 * Description: This filter is to add basic authentication headers to requests for management endpoints
 * from the admin client.
 * Created by Yuliang Jin on 16/10/26.
 */
@Slf4j
public class BasicAuthFilter extends AbstractZuulFilter{

  @Autowired
  private ClientKeyStore clientKeyStore;

  @Autowired
  private RestTemplate restTemplate;

  @Autowired
  private ObjectMapper objectMapper;

  @Autowired
  private EncodeDecryptor decryptor;

  public BasicAuthFilter() {
    super(0, "pre");
  }

  @SneakyThrows
  @Override
  public Object run() {
    final RequestContext currentContext = RequestContext.getCurrentContext();
    final String requestUri = currentContext.getRequest().getRequestURI();
    if (requestUri.contains("/info")) {
      log.info(requestUri + " passed basic auth filter.");
      return null;
    }
    log.info("Basic Auth Filter is working...");
    log.info("Request URI is {}.", requestUri);
    log.debug("Path info for RUI {} is: {}.", requestUri, currentContext.getRequest().getPathInfo());

    final String serviceId = ClientKey.serviceIdFrom(requestUri);
    ClientKey clientKey = this.clientKeyStore.find(serviceId);
    if (clientKey == null) {
      log.debug("Service '{}' is requesting for client key.", serviceId);
      final String infoUrl = getInfoUrl(currentContext.getRequest().getRequestURL().toString());
      try {
        clientKey = requestForClientKey(serviceId, infoUrl);
      } catch (final Exception ex) {
        log.debug("Service '{}' got error when requesting for client key.", serviceId, ex);
      }
      this.clientKeyStore.save(clientKey);
    }

    if (clientKey != null) {
      String basicAuthCode = BasicAuthUtils.basicAuthHeader(clientKey.getUserName(), clientKey.getPassword());
      currentContext.addZuulRequestHeader("Authorization", basicAuthCode);
    }
    return null;
  }

  /**
   * @param serviceId serviceId
   * @param infoUrl   url for /info endpoint
   * @return ClientKey of the target admin client.
   */
  public ClientKey requestForClientKey(final String serviceId, final String infoUrl) throws IOException {
    final String json = restTemplate.getForObject(infoUrl, String.class);
    final Map<String, Object> infoObject = this.objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {
    });

    final String[] usernamePassword = ClientKey.usernamePasswordFromInfoObject(infoObject, this.decryptor);
    final ClientKey clientKey;
    if (usernamePassword != null) {
      clientKey = new ClientKey(serviceId, usernamePassword[0], usernamePassword[1]);
    } else {
      clientKey = new ClientKey(serviceId, "", "");
    }
    return clientKey;
  }

  private String getInfoUrl(String requestUri) {
    return requestUri.substring(0, requestUri.lastIndexOf('/') + 1) + "info";
  }
}