Package org.platformlayer.auth.system

Source Code of org.platformlayer.auth.system.CachingAuthenticationTokenValidator$CachedResult

package org.platformlayer.auth.system;

import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.platformlayer.auth.AuthenticationToken;
import org.platformlayer.auth.AuthenticationTokenValidator;
import org.platformlayer.crypto.CertificateUtils;
import org.platformlayer.metrics.CacheMetricsReporter;
import org.platformlayer.metrics.HasMetrics;
import org.platformlayer.metrics.MetricKey;
import org.platformlayer.metrics.MetricRegistry;
import org.platformlayer.model.ProjectAuthorization;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class CachingAuthenticationTokenValidator implements AuthenticationTokenValidator, HasMetrics {
  static final int CACHE_MAX_SIZE = 1000;
  static final int CACHE_VALIDITY_MINUTES = 5;

  final AuthenticationTokenValidator inner;

  public CachingAuthenticationTokenValidator(AuthenticationTokenValidator inner) {
    this.inner = inner;
  }

  static class CertificateChainData {
    final byte[] data;

    public CertificateChainData(X509Certificate[] chain) {
      this.data = CertificateUtils.serialize(chain);
    }

    public X509Certificate[] buildCertificates() {
      return CertificateUtils.deserialize(data);
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + Arrays.hashCode(data);
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (getClass() != obj.getClass()) {
        return false;
      }
      CertificateChainData other = (CertificateChainData) obj;
      if (!Arrays.equals(data, other.data)) {
        return false;
      }
      return true;
    }

  };

  static class CacheKey {
    final String projectKey;
    final AuthenticationToken token;
    final CertificateChainData chain;

    CacheKey(String projectKey, AuthenticationToken token) {
      this.projectKey = projectKey;
      this.token = token;
      this.chain = null;
    }

    CacheKey(String projectKey, X509Certificate[] chain) {
      this.projectKey = projectKey;
      this.token = null;
      this.chain = new CertificateChainData(chain);
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((chain == null) ? 0 : chain.hashCode());
      result = prime * result + ((projectKey == null) ? 0 : projectKey.hashCode());
      result = prime * result + ((token == null) ? 0 : token.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null) {
        return false;
      }
      if (getClass() != obj.getClass()) {
        return false;
      }
      CacheKey other = (CacheKey) obj;
      if (chain == null) {
        if (other.chain != null) {
          return false;
        }
      } else if (!chain.equals(other.chain)) {
        return false;
      }
      if (projectKey == null) {
        if (other.projectKey != null) {
          return false;
        }
      } else if (!projectKey.equals(other.projectKey)) {
        return false;
      }
      if (token == null) {
        if (other.token != null) {
          return false;
        }
      } else if (!token.equals(other.token)) {
        return false;
      }
      return true;
    }

  };

  static class CachedResult {
    final ProjectAuthorization authorization;

    public CachedResult(ProjectAuthorization authorization) {
      this.authorization = authorization;
    }

  };

  final LoadingCache<CacheKey, CachedResult> cache = CacheBuilder.newBuilder()
  // limit size
      .maximumSize(CACHE_MAX_SIZE)
      // max validity
      .expireAfterWrite(CACHE_VALIDITY_MINUTES, TimeUnit.MINUTES)

      // We want stats
      .recordStats()

      // Load on demand
      .build(new CacheLoader<CacheKey, CachedResult>() {
        @Override
        public CachedResult load(CacheKey key) throws Exception {
          return loadForCache(key);
        }
      });

  @Override
  public ProjectAuthorization validateToken(AuthenticationToken token, String projectKey) {
    CacheKey key = new CacheKey(projectKey, token);

    return authenticate(key);
  }

  private ProjectAuthorization authenticate(CacheKey key) {
    CachedResult result;
    try {
      result = cache.get(key);
    } catch (ExecutionException e) {
      throw new IllegalStateException("Error authenticating credentials", e);
    }
    return result.authorization;
  }

  protected CachedResult loadForCache(CacheKey key) {
    ProjectAuthorization authorization;
    if (key.token != null) {
      authorization = inner.validateToken(key.token, key.projectKey);
    } else {
      authorization = inner.validateChain(key.chain.buildCertificates(), key.projectKey);
    }

    // TODO: Different cache validity for "access denied"?
    return new CachedResult(authorization);
  }

  @Override
  public ProjectAuthorization validateChain(X509Certificate[] chain, String projectKey) {
    CacheKey key = new CacheKey(projectKey, chain);

    return authenticate(key);
  }

  public AuthenticationTokenValidator getInner() {
    return inner;
  }

  @Override
  public void discoverMetrics(MetricRegistry system) {
    MetricKey key = MetricKey.build(getClass(), "cache");
    system.add(new CacheMetricsReporter(key, cache));
    system.discoverMetrics(inner);
  }
}
TOP

Related Classes of org.platformlayer.auth.system.CachingAuthenticationTokenValidator$CachedResult

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.