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

org.apache.solr.security.AuthenticationPlugin Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.solr.security;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Timer;
import java.security.Principal;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpRequest;
import org.apache.http.protocol.HttpContext;
import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.metrics.SolrMetricsContext;
import org.eclipse.jetty.client.api.Request;

/**
 * @lucene.experimental
 */
public abstract class AuthenticationPlugin implements SolrInfoBean {

  public static final String AUTHENTICATION_PLUGIN_PROP = "authenticationPlugin";
  public static final String HTTP_HEADER_X_SOLR_AUTHDATA = "X-Solr-AuthData";

  // Metrics
  private Set metricNames = ConcurrentHashMap.newKeySet();
  protected SolrMetricsContext solrMetricsContext;

  protected Meter numErrors = new Meter();
  protected Counter requests = new Counter();
  protected Timer requestTimes = new Timer();
  protected Counter totalTime = new Counter();
  protected Counter numAuthenticated = new Counter();
  protected Counter numPassThrough = new Counter();
  protected Counter numWrongCredentials = new Counter();
  protected Counter numMissingCredentials = new Counter();

  /**
   * This is called upon loading up of a plugin, used for setting it up.
   *
   * @param pluginConfig Config parameters, possibly from a ZK source
   */
  public abstract void init(Map pluginConfig);

  /**
   * This method attempts to authenticate the request. Upon a successful authentication, this must
   * call the next filter in the filter chain and set the user principal of the request, or else,
   * upon an error or an authentication failure, throw an exception.
   *
   * @param request the http request
   * @param response the http response
   * @param filterChain the servlet filter chain
   * @return false if the request not be processed by Solr (not continue), i.e. the response and
   *     status code have already been sent.
   * @throws Exception any exception thrown during the authentication, e.g.
   *     PrivilegedActionException
   */
  public abstract boolean doAuthenticate(
      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws Exception;

  /**
   * This method is called by SolrDispatchFilter in order to initiate authentication. It does some
   * standard metrics counting.
   */
  public final boolean authenticate(
      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws Exception {
    Timer.Context timer = requestTimes.time();
    requests.inc();
    try {
      return doAuthenticate(request, response, filterChain);
    } catch (Exception e) {
      numErrors.mark();
      throw e;
    } finally {
      long elapsed = timer.stop();
      totalTime.inc(elapsed);
    }
  }

  protected HttpServletRequest wrapWithPrincipal(HttpServletRequest request, Principal principal) {
    return wrapWithPrincipal(request, principal, principal.getName());
  }

  protected HttpServletRequest wrapWithPrincipal(
      HttpServletRequest request, Principal principal, String username) {
    return new HttpServletRequestWrapper(request) {
      @Override
      public Principal getUserPrincipal() {
        return principal;
      }

      @Override
      public String getRemoteUser() {
        return username;
      }
    };
  }

  /**
   * Override this method to intercept internode requests. This allows your authentication plugin to
   * decide on per-request basis whether it should handle inter-node requests or delegate to {@link
   * PKIAuthenticationPlugin}. Return true to indicate that your plugin did handle the request, or
   * false to signal that PKI plugin should handle it. This method will be called by {@link
   * PKIAuthenticationPlugin}'s interceptor.
   *
   * 

If not overridden, this method will return true for plugins implementing {@link * HttpClientBuilderPlugin}. This method can be overridden by subclasses e.g. to set HTTP headers, * even if you don't use a clientBuilder. * * @param httpRequest the httpRequest that is about to be sent to another internal Solr node * @param httpContext the context of that request. * @return true if this plugin handled authentication for the request, else false */ protected boolean interceptInternodeRequest(HttpRequest httpRequest, HttpContext httpContext) { return this instanceof HttpClientBuilderPlugin; } /** * Override this method to intercept internode requests. This allows your authentication plugin to * decide on per-request basis whether it should handle inter-node requests or delegate to {@link * PKIAuthenticationPlugin}. Return true to indicate that your plugin did handle the request, or * false to signal that PKI plugin should handle it. This method will be called by {@link * PKIAuthenticationPlugin}'s interceptor. * *

If not overridden, this method will return true for plugins implementing {@link * HttpClientBuilderPlugin}. This method can be overridden by subclasses e.g. to set HTTP headers, * even if you don't use a clientBuilder. * * @param request the httpRequest that is about to be sent to another internal Solr node * @return true if this plugin handled authentication for the request, else false */ protected boolean interceptInternodeRequest(Request request) { return this instanceof HttpClientBuilderPlugin; } /** Cleanup any per request data */ public void closeRequest() {} @Override public SolrMetricsContext getSolrMetricsContext() { return solrMetricsContext; } @Override public void initializeMetrics(SolrMetricsContext parentContext, String scope) { this.solrMetricsContext = parentContext.getChildContext(this); // Metrics numErrors = this.solrMetricsContext.meter("errors", getCategory().toString(), scope); requests = this.solrMetricsContext.counter("requests", getCategory().toString(), scope); numAuthenticated = this.solrMetricsContext.counter("authenticated", getCategory().toString(), scope); numPassThrough = this.solrMetricsContext.counter("passThrough", getCategory().toString(), scope); numWrongCredentials = this.solrMetricsContext.counter("failWrongCredentials", getCategory().toString(), scope); numMissingCredentials = this.solrMetricsContext.counter("failMissingCredentials", getCategory().toString(), scope); requestTimes = this.solrMetricsContext.timer("requestTimes", getCategory().toString(), scope); totalTime = this.solrMetricsContext.counter("totalTime", getCategory().toString(), scope); } @Override public String getName() { return this.getClass().getName(); } @Override public String getDescription() { return "Authentication Plugin " + this.getClass().getName(); } @Override public Category getCategory() { return Category.SECURITY; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy