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

org.apache.shindig.gadgets.HashLockedDomainService Maven / Gradle / Ivy

Go to download

Renders gadgets, provides the gadget metadata service, and serves all javascript required by the OpenSocial specification.

The 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.shindig.gadgets;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.shindig.common.logging.i18n.MessageKeys;
import org.apache.shindig.common.servlet.Authority;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.uri.Uri.UriException;
import org.apache.shindig.config.ContainerConfig;
import org.apache.shindig.gadgets.spec.Feature;
import org.apache.shindig.gadgets.uri.LockedDomainPrefixGenerator;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;

/**
 * Locked domain implementation based on sha1.
 *
 * The generated domain takes the form:
 *
 * base32(sha1(gadget url)).
 *
 * Other domain locking schemes are possible as well.
 */
@Singleton
public class HashLockedDomainService extends AbstractLockedDomainService {

  /**
   * Used to observer locked domain suffixes for this class
   */
  private class HashLockedDomainObserver implements ContainerConfig.ConfigObserver {

    public void containersChanged(ContainerConfig config, Collection changed,
            Collection removed) {
      for (String container : changed) {
        String suffix = config.getString(container, LOCKED_DOMAIN_SUFFIX_KEY);
        if (suffix == null) {
          if (LOG.isLoggable(Level.WARNING)) {
            LOG.logp(Level.WARNING, classname, "containersChanged",
                    MessageKeys.NO_LOCKED_DOMAIN_CONFIG, new Object[] { container });
          }
        } else {
          HashLockedDomainService.this.lockedSuffixes.put(container, checkSuffix(suffix));
        }
      }
      for (String container : removed) {
        HashLockedDomainService.this.lockedSuffixes.remove(container);
      }
    }
  }

  // class name for logging purpose
  private static final String classname = HashLockedDomainService.class.getName();

  private static final Logger LOG = Logger.getLogger(classname, MessageKeys.MESSAGES);
  private final Map lockedSuffixes;
  private Authority authority;
  private LockedDomainPrefixGenerator ldGen;
  private final Pattern authpattern = Pattern.compile("%authority%");

  private HashLockedDomainObserver ldObserver;

  public static final String LOCKED_DOMAIN_SUFFIX_KEY = "gadgets.uri.iframe.lockedDomainSuffix";

  /*
   * Injected methods
   */

  /**
   * Create a LockedDomainService
   *
   * @param config
   *          per-container configuration
   * @param enabled
   *          whether this service should do anything at all.
   */
  @Inject
  public HashLockedDomainService(ContainerConfig config,
          @Named("shindig.locked-domain.enabled") boolean enabled, LockedDomainPrefixGenerator ldGen) {
    super(config, enabled);
    this.lockedSuffixes = Maps.newHashMap();
    this.ldGen = ldGen;
    if (enabled) {
      this.ldObserver = new HashLockedDomainObserver();
      config.addConfigObserver(this.ldObserver, true);
    }
  }

  @Override
  public String getLockedDomainForGadget(Gadget gadget, String container) throws GadgetException {
    container = getContainer(container);
    if (this.enabled && !isExcludedFromLockedDomain(gadget, container)) {
      if (isGadgetReqestingLocking(gadget) || isDomainLockingEnforced(container)) {
        return getLockedDomain(gadget, container);
      }
    }
    return null;
  }

  /**
   * Generates a locked domain prefix given a gadget Uri.
   *
   * @param gadget The uri of the gadget.
   * @return A locked domain prefix for the gadgetUri.
   *         Returns empty string if locked domains are not enabled on the server.
   */
  private String getLockedDomainPrefix(Gadget gadget) throws GadgetException {
    String ret = "";
    if (this.enabled) {
      ret = this.ldGen.getLockedDomainPrefix(getLockedDomainParticipants(gadget));
    }
    // Lower-case to prevent casing from being relevant.
    return ret.toLowerCase();
  }

  @Override
  public boolean isGadgetValidForHost(String host, Gadget gadget, String container) {
    container = getContainer(container);
    if (this.enabled) {
      if (isGadgetReqestingLocking(gadget) || isHostUsingLockedDomain(host)
              || isDomainLockingEnforced(container)) {
        String neededHost;
        try {
          neededHost = getLockedDomain(gadget, container);
        } catch (GadgetException e) {
          if (LOG.isLoggable(Level.WARNING)) {
            LOG.log(Level.WARNING, "Invalid host for call.", e);
          }
          return false;
        }
        return host.equals(neededHost);
      }
    }
    return true;
  }

  @Override
  public boolean isHostUsingLockedDomain(String host) {
    if (this.enabled) {
      for (String suffix : this.lockedSuffixes.values()) {
        if (host.endsWith(suffix)) {
          return true;
        }
      }
    }
    return false;
  }

  @Inject(optional = true)
  public void setAuthority(Authority authority) {
    this.authority = authority;
  }

  private String checkSuffix(String suffix) {
    if (suffix != null) {
      Matcher m = this.authpattern.matcher(suffix);
      if (m.matches()) {
        if (LOG.isLoggable(Level.WARNING)) {
          LOG.warning("You should not be using %authority% replacement in a running environment!");
          LOG.warning("Check your config and specify an explicit locked domain suffix.");
          LOG.warning("Found suffix: " + suffix);
        }
        if (this.authority != null) {
          suffix = m.replaceAll(this.authority.getAuthority());
        }
      }
    }
    return suffix;
  }

  private String getContainer(String container) {
    if (this.required.containsKey(container)) {
      return container;
    }
    return ContainerConfig.DEFAULT_CONTAINER;
  }

  private String getLockedDomain(Gadget gadget, String container) throws GadgetException {
    String suffix = this.lockedSuffixes.get(container);
    if (suffix == null) {
      return null;
    }
    return getLockedDomainPrefix(gadget) + suffix;
  }

  private String getLockedDomainParticipants(Gadget gadget) throws GadgetException {
    Map features = gadget.getSpec().getModulePrefs().getFeatures();
    Feature ldFeature = features.get("locked-domain");

    // This gadget is always a participant.
    Set filtered = new TreeSet();
    filtered.add(gadget.getSpec().getUrl().toString().toLowerCase());

    if (ldFeature != null) {
      Collection participants = ldFeature.getParamCollection("participant");
      for (String participant : participants) {
        // be picky, this should be a valid uri
        try {
          Uri.parse(participant);
        } catch (UriException e) {
          throw new GadgetException(GadgetException.Code.INVALID_PARAMETER,
                  "Participant param must be a valid uri", e);
        }
        filtered.add(participant.toLowerCase());
      }
    }

    StringBuilder buffer = new StringBuilder();
    for (String participant : filtered) {
      buffer.append(participant);
    }
    return buffer.toString();
  }

  @VisibleForTesting
  ContainerConfig.ConfigObserver getConfigObserver() {
    return this.ldObserver;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy