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

org.italiangrid.voms.request.impl.DefaultVOMSACService Maven / Gradle / Ivy

There is a newer version: 3.3.2
Show newest version
/**
 * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2006-2014.
 *
 * 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 org.italiangrid.voms.request.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.italiangrid.voms.VOMSError;
import org.italiangrid.voms.request.VOMSACRequest;
import org.italiangrid.voms.request.VOMSACService;
import org.italiangrid.voms.request.VOMSESLookupStrategy;
import org.italiangrid.voms.request.VOMSProtocol;
import org.italiangrid.voms.request.VOMSProtocolError;
import org.italiangrid.voms.request.VOMSProtocolListener;
import org.italiangrid.voms.request.VOMSRequestListener;
import org.italiangrid.voms.request.VOMSResponse;
import org.italiangrid.voms.request.VOMSServerInfo;
import org.italiangrid.voms.request.VOMSServerInfoStore;
import org.italiangrid.voms.request.VOMSServerInfoStoreListener;
import org.italiangrid.voms.util.NullListener;

import eu.emi.security.authn.x509.X509CertChainValidatorExt;
import eu.emi.security.authn.x509.X509Credential;

/**
 * The default implementation of the {@link VOMSACService}.
 * 
 * 
 * @author Valerio Venturi
 * @author Andrea Ceccanti
 * 
 */
public class DefaultVOMSACService implements VOMSACService {

  /**
   * The listener that will be informed about request events
   */
  protected VOMSRequestListener requestListener;

  /**
   * The listener that will be informed about low-level protocol details
   */
  protected VOMSProtocolListener protocolListener;

  /**
   * The validator used for the SSL handshake
   */
  protected X509CertChainValidatorExt validator;

  /**
   * The store used to keep VOMS server contact information.
   */
  protected VOMSServerInfoStore serverInfoStore;

  /**
   * The http protocol implementation
   */
  protected VOMSProtocol httpProtocol;

  /**
   * The voms legacy protocol implementation
   */
  protected VOMSProtocol legacyProtocol;

  /**
   * Constructor which builds a {@link DefaultVOMSACService} from a
   * {@link Builder}
   * 
   * @param builder
   *          the builder object that provides the settings for this
   *          {@link VOMSACService}
   */
  protected DefaultVOMSACService(Builder builder) {

    this.validator = builder.validator;
    this.requestListener = builder.requestListener;
    this.protocolListener = builder.protocolListener;
    this.serverInfoStore = builder.serverInfoStore;
    this.httpProtocol = builder.httpProtocol;
    this.legacyProtocol = builder.legacyProtocol;
  }

  /**
   * Extracts an AC from a VOMS response
   * 
   * @param request
   *          the request
   * @param response
   *          the received response
   * @return a possibly null {@link AttributeCertificate} object
   */
  protected AttributeCertificate getACFromResponse(VOMSACRequest request,
    VOMSResponse response) {

    byte[] acBytes = response.getAC();

    if (acBytes == null)
      return null;

    ASN1InputStream asn1InputStream = new ASN1InputStream(acBytes);

    AttributeCertificate attributeCertificate = null;

    try {

      attributeCertificate = AttributeCertificate.getInstance(asn1InputStream
        .readObject());

      asn1InputStream.close();
      return attributeCertificate;

    } catch (Throwable e) {

      requestListener.notifyVOMSRequestFailure(request, null, new VOMSError(
        "Error unmarshalling VOMS AC. Cause: " + e.getMessage(), e));

      return null;
    }
  }

  private VOMSResponse doRequest(VOMSProtocol protocol,
    VOMSServerInfo endpoint, X509Credential cred, VOMSACRequest req) {

    VOMSResponse response = null;

    try {

      response = protocol.doRequest(endpoint, cred, req);

    } catch (VOMSProtocolError e) {
      requestListener.notifyVOMSRequestFailure(req, endpoint, e);
    }

    return response;

  }

  /**
   * Handles errors included in the VOMS response
   * 
   * @param request
   *          the request
   * @param si
   *          the VOMS server endpoint information
   * @param response
   *          the received {@link VOMSResponse}
   */
  protected void handleErrorsInResponse(VOMSACRequest request,
    VOMSServerInfo si, VOMSResponse response) {

    if (response.hasErrors())
      requestListener.notifyErrorsInVOMSReponse(request, si,
        response.errorMessages());

  }

  /**
   * Handles warnings included in the VOMS response
   * 
   * @param request
   *          the request
   * @param si
   *          the VOMS server endpoint information
   * @param response
   *          the received {@link VOMSResponse}
   */
  protected void handleWarningsInResponse(VOMSACRequest request,
    VOMSServerInfo si, VOMSResponse response) {

    if (response.hasWarnings())
      requestListener.notifyWarningsInVOMSResponse(request, si,
        response.warningMessages());
  }

  public AttributeCertificate getVOMSAttributeCertificate(
    X509Credential credential, VOMSACRequest request) {

    List vomsServerInfos = getVOMSServerInfos(request);

    if (vomsServerInfos.isEmpty())
      throw new VOMSError("VOMS server for VO " + request.getVoName() + " "
        + "is not known! Check your vomses configuration.");

    VOMSResponse response = null;

    AttributeCertificate vomsAC = null;

    for (VOMSServerInfo vomsServerInfo : vomsServerInfos) {

      requestListener.notifyVOMSRequestStart(request, vomsServerInfo);

      // Try HTTP request first
      response = doRequest(httpProtocol, vomsServerInfo, credential, request);

      // If failed, try legacy request
      if (response == null) {
        response = doRequest(legacyProtocol, vomsServerInfo, credential,
          request);
      }

      // We had failures with both requests
      if (response == null) {
        requestListener.notifyVOMSRequestFailure(request, vomsServerInfo,
          new VOMSError("REST and legacy VOMS endpoints failed."));

        // continue to next server
        continue;
      }

      // Notify that the server was contacted successfully
      requestListener.notifyVOMSRequestSuccess(request, vomsServerInfo);

      // Notify errors
      handleErrorsInResponse(request, vomsServerInfo, response);

      // Notify warnings
      handleWarningsInResponse(request, vomsServerInfo, response);

      vomsAC = getACFromResponse(request, response);

      // Exit the loop only when succesfully get an AC
      // out of the VOMS server
      if (!response.hasErrors() && vomsAC != null) {
        return vomsAC;
      }

    }

    // if we reach this point we had failures in contacting
    // all known voms server for the VO
    requestListener.notifyVOMSRequestFailure(request, null, null);
    return null;
    
  }

  /**
   * Get VOMS server endpoint information that matches with the
   * {@link VOMSACRequest} passed as argument.
   * 
   * This method returns a random shuffle of the {@link VOMSServerInfo} objects
   * that match the input request.
   * 
   * @param request
   *          the request
   * @return a possibly empty {@link List} of {@link VOMSServerInfo} objects
   */
  protected List getVOMSServerInfos(VOMSACRequest request) {

    List vomsServerInfos = new ArrayList(
      serverInfoStore.getVOMSServerInfo(request.getVoName()));

    if (!vomsServerInfos.isEmpty()) {
      Collections.shuffle(vomsServerInfos);
    }
    return vomsServerInfos;
  }

  /**
   * Creates a {@link DefaultVOMSACService} object. The
   * {@link DefaultVOMSACService} parameters can be set with the appropriate
   * methods. Example:
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * 
   * {
   *   @code
   *   VOMSACService acService = new DefaultVOMSACService.Builder(certChainValidator)
   *     .requestListener(requestListener)
   *     .serverInfoStoreListener(serverInfoStoreListener)
   *     .protocolListener(protocolListener).build();
   * }
   * 
* * */ public static class Builder { /** * The listener that will be informed about request events */ private VOMSRequestListener requestListener = NullListener.INSTANCE; /** * The listener that will be informed about low-level protocol details */ private VOMSProtocolListener protocolListener = NullListener.INSTANCE; /** * The listener that will be informed about server info store events */ private VOMSServerInfoStoreListener storeListener = NullListener.INSTANCE; /** * The validator used for the SSL handshake */ private X509CertChainValidatorExt validator; /** * The store used to keep VOMS server contact information. */ private VOMSServerInfoStore serverInfoStore; /** * The provided strategy to lookup vomses information. */ private VOMSESLookupStrategy vomsesLookupStrategy; /** * A list of paths where vomses information will be looked for, used to * create the server info store. */ private List vomsesLocations; /** * The connect timeout value */ private int connectTimeout = AbstractVOMSProtocol.DEFAULT_CONNECT_TIMEOUT; /** * The read timeout used */ private int readTimeout = AbstractVOMSProtocol.DEFAULT_READ_TIMEOUT; /** * Whether the client should skip hostname checking */ private boolean skipHostnameChecks = true; /** * The http protocol implementation */ protected VOMSProtocol httpProtocol; /** * The voms legacy protocol implementation */ protected VOMSProtocol legacyProtocol; /** * Creates a Builder for a {@link DefaultVOMSACService}. * * @param certChainValidator * the validator to use to setup the SSL connection and validate * the certificates */ public Builder(X509CertChainValidatorExt certChainValidator) { if (certChainValidator == null) throw new NullPointerException( "Please provide a non-null certificate chain validator"); this.validator = certChainValidator; } /** * Sets the request listener for the {@link DefaultVOMSACService} that this * builder is creating * * @param l * the request listener that will receive notifications about * request events * @return this {@link Builder} instance */ public Builder requestListener(VOMSRequestListener l) { this.requestListener = l; return this; } /** * Sets the {@link VOMSServerInfoStoreListener} for the * {@link DefaultVOMSACService} that this builder is creating * * @param sl * the store listener that will receive notifications about store * events * @return this {@link Builder} instance */ public Builder serverInfoStoreListener(VOMSServerInfoStoreListener sl) { this.storeListener = sl; return this; } /** * Sets the {@link VOMSServerInfoStore} for the {@link DefaultVOMSACService} * that this builder is creating * * @param sis * a {@link VOMSServerInfoStore} object * @return this {@link Builder} instance */ public Builder serverInfoStore(VOMSServerInfoStore sis) { this.serverInfoStore = sis; return this; } /** * Sets the {@link VOMSProtocolListener} for the * {@link DefaultVOMSACService} that this builder is creating * * @param pl * the {@link VOMSProtocolListener} that will receive notifications * about protocol events * @return this {@link Builder} instance */ public Builder protocolListener(VOMSProtocolListener pl) { this.protocolListener = pl; return this; } /** * Sets the connect timeout (in millisecods) for the * {@link DefaultVOMSACService} that this builder is creating * * @param timeout * the timeout value in milliseconds * @return this {@link Builder} instance */ public Builder connectTimeout(int timeout) { this.connectTimeout = timeout; return this; } /** * Sets the read timeout (in milliseconds) for the * {@link DefaultVOMSACService} that this builder is creating * * @param timeout * the timeout value in milliseconds * @return this {@link Builder} instance */ public Builder readTimeout(int timeout) { this.readTimeout = timeout; return this; } /** * Sets a flag to skip VOMS hostname checking. Allows for creative VOMS * server side certificate configuration. * * @param s * true to skip the checks, false * otherwise * * @return this {@link Builder} instance */ public Builder skipHostnameChecks(boolean s) { this.skipHostnameChecks = s; return this; } /** * Sets the vomses lookup strategy for the {@link DefaultVOMSACService} that * this builder is creating * * @param strategy * the {@link VOMSESLookupStrategy} object * @return this {@link Builder} instance */ public Builder vomsesLookupStrategy(VOMSESLookupStrategy strategy) { this.vomsesLookupStrategy = strategy; return this; } /** * Sets a list of locations that will be used to build a * {@link VOMSESLookupStrategy} for the {@link DefaultVOMSACService} that * this builder is creating * * @param vomsesLocations * a list of paths where vomses information will be looked for * @return this {@link Builder} instance */ public Builder vomsesLocations(List vomsesLocations) { this.vomsesLocations = vomsesLocations; return this; } /** * Sets the http protocol implementation * * @param httpProtocol * the http protocol implementatino * @return this {@link Builder} instance */ public Builder httpProtocol(VOMSProtocol httpProtocol) { this.httpProtocol = httpProtocol; return this; } /** * Sets the legacy protocol implementation * * @param legacyProtocol * the legacy protocol implementation * * @return * the {@link Builder} */ public Builder legacyProtocol(VOMSProtocol legacyProtocol) { this.legacyProtocol = legacyProtocol; return this; } /** * Builds the server info store */ protected void buildServerInfoStore() { if (serverInfoStore != null) return; serverInfoStore = new DefaultVOMSServerInfoStore.Builder() .lookupStrategy(vomsesLookupStrategy).storeListener(storeListener) .vomsesPaths(vomsesLocations).build(); } /** * Builds default protocols if needed */ protected void buildProtocols() { if (httpProtocol == null) { RESTProtocol p = new RESTProtocol(validator, protocolListener, connectTimeout, readTimeout); p.setSkipHostnameChecks(skipHostnameChecks); httpProtocol = p; } if (legacyProtocol == null) { LegacyProtocol p = new LegacyProtocol(validator, protocolListener, connectTimeout, readTimeout); p.setSkipHostnameChecks(skipHostnameChecks); legacyProtocol = p; } } /** * Builds the {@link DefaultVOMSACService} * * @return a {@link DefaultVOMSACService} configured as required by this * builder */ public DefaultVOMSACService build() { buildServerInfoStore(); buildProtocols(); return new DefaultVOMSACService(this); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy