/** * Dianping.com Inc. * Copyright (c) 2003-2013 All Rights Reserved. */ package com.dianping.pigeon.remoting.invoker.process.filter; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.StringUtils; import com.dianping.pigeon.config.ConfigChangeListener; import com.dianping.pigeon.config.ConfigManager; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.registry.RegistryManager; import com.dianping.pigeon.remoting.common.domain.InvocationContext.TimePhase; import com.dianping.pigeon.remoting.common.domain.InvocationContext.TimePoint; import com.dianping.pigeon.remoting.common.domain.InvocationRequest; import com.dianping.pigeon.remoting.common.domain.InvocationResponse; import com.dianping.pigeon.remoting.common.domain.generic.UnifiedRequest; import com.dianping.pigeon.remoting.common.process.ServiceInvocationHandler; import com.dianping.pigeon.remoting.common.util.Constants; import com.dianping.pigeon.remoting.common.util.SecurityUtils; import com.dianping.pigeon.remoting.invoker.config.InvokerConfig; import com.dianping.pigeon.remoting.invoker.domain.InvokerContext; /** * @author xiangwu */ public class SecurityFilter extends InvocationInvokeFilter { private static final Logger logger = LoggerLoader.getLogger(SecurityFilter.class); private static final ConfigManager configManager = ConfigManagerLoader.getConfigManager(); private static final String KEY_APP_SECRETS = "pigeon.invoker.token.app.secrets"; private static final String KEY_TOKEN_ENABLE = "pigeon.invoker.token.enable"; private static volatile ConcurrentHashMap<String, String> appSecrets = new ConcurrentHashMap<String, String>(); private static volatile boolean isTokenEnable = configManager.getBooleanValue(KEY_TOKEN_ENABLE, true); public SecurityFilter() { parseAppSecrets(configManager.getStringValue(KEY_APP_SECRETS, "")); ConfigManagerLoader.getConfigManager().registerConfigChangeListener(new InnerConfigChangeListener()); } private static void parseAppSecrets(String config) { if (StringUtils.isNotBlank(config)) { ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>(); try { String[] pairArray = config.split(","); for (String str : pairArray) { if (StringUtils.isNotBlank(str)) { String[] pair = str.split(":"); if (pair != null && pair.length == 2) { map.put(pair[0].trim(), pair[1].trim()); } } } ConcurrentHashMap<String, String> old = appSecrets; appSecrets = map; old.clear(); } catch (RuntimeException e) { logger.error("error while parsing app secret configuration:" + config, e); } } else { appSecrets.clear(); } } private static class InnerConfigChangeListener implements ConfigChangeListener { @Override public void onKeyUpdated(String key, String value) { if (key.endsWith(KEY_APP_SECRETS)) { parseAppSecrets(value); } else if (key.endsWith(KEY_TOKEN_ENABLE)) { try { isTokenEnable = Boolean.valueOf(value); } catch (RuntimeException e) { logger.warn("invalid value for key " + key, e); } } } @Override public void onKeyAdded(String key, String value) { } @Override public void onKeyRemoved(String key) { } } private static int getCurrentTime() { return (int) (System.currentTimeMillis() / 1000); } @Override public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext) throws Throwable { invocationContext.getTimeline().add(new TimePoint(TimePhase.A)); InvocationRequest request = invocationContext.getRequest(); if (request.getMessageType() == Constants.MESSAGE_TYPE_SERVICE) { InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig(); String secret = invokerConfig.getSecret(); if (StringUtils.isBlank(secret) && isTokenEnable) { String targetApp = RegistryManager.getInstance() .getReferencedAppFromCache(invocationContext.getClient().getAddress()); if (StringUtils.isNotEmpty(targetApp)) { secret = appSecrets.get(targetApp); } } if (StringUtils.isNotBlank(secret)) { transferSecretValueToRequest(request, secret); } } return handler.handle(invocationContext); } private void transferSecretValueToRequest(final InvocationRequest request, String secret) { int timestamp = getCurrentTime(); if (request instanceof UnifiedRequest) { UnifiedRequest _request = (UnifiedRequest) request; transferSecretValueToRequest0(_request, timestamp, secret); } else { transferSecretValueToRequest0(request, timestamp, secret); } } private void transferSecretValueToRequest0(final InvocationRequest request, int timestamp, String secret) { request.getRequestValues().put(Constants.REQUEST_KEY_TIMESTAMP, timestamp); request.getRequestValues().put(Constants.REQUEST_KEY_VERSION, 0); String data = request.getServiceName() + "#" + request.getMethodName() + "#" + timestamp; request.getRequestValues().put(Constants.REQUEST_KEY_TOKEN, SecurityUtils.encrypt(data, secret)); } private void transferSecretValueToRequest0(final UnifiedRequest request, int timestamp, String secret) { request.getLocalContext().put(Constants.REQUEST_KEY_TIMESTAMP, Integer.toString(timestamp)); request.getLocalContext().put(Constants.REQUEST_KEY_VERSION, Integer.toString(0)); String data = request.getServiceName() + "#" + request.getMethodName() + "#" + timestamp; request.getLocalContext().put(Constants.REQUEST_KEY_TOKEN, SecurityUtils.encrypt(data, secret)); } }