diff --git a/core/src/main/java/io/servicecomb/core/Const.java b/core/src/main/java/io/servicecomb/core/Const.java
index 801ca1bcc4d..0e493aa6b79 100644
--- a/core/src/main/java/io/servicecomb/core/Const.java
+++ b/core/src/main/java/io/servicecomb/core/Const.java
@@ -39,4 +39,6 @@ private Const() {
public static final String TARGET_MICROSERVICE = "x-cse-target-microservice";
public static final String REMOTE_ADDRESS = "x-cse-remote-address";
+
+ public static final String AUTH_TOKEN = "x-cse-auth-rsatoken";
}
diff --git a/coverage-reports/pom.xml b/coverage-reports/pom.xml
index 19f9815f2ed..15ba758b5a6 100644
--- a/coverage-reports/pom.xml
+++ b/coverage-reports/pom.xml
@@ -62,6 +62,10 @@
io.servicecomb
handler-loadbalance
+
+ io.servicecomb
+ handler-publickey-auth
+
io.servicecomb
handler-flowcontrol-qps
diff --git a/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAKeyPairEntry.java b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAKeyPairEntry.java
new file mode 100644
index 00000000000..5f152f19904
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAKeyPairEntry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.foundation.common.utils;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+public final class RSAKeyPairEntry {
+
+ private PrivateKey privateKey;
+
+ private PublicKey publicKey;
+
+ private String publicKeyEncoded;
+
+ public RSAKeyPairEntry(PrivateKey privateKey, PublicKey publicKey, String publicKeyEncoded) {
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
+ this.publicKeyEncoded = publicKeyEncoded;
+ }
+
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public String getPublicKeyEncoded() {
+ return publicKeyEncoded;
+ }
+
+}
diff --git a/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAUtils.java b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAUtils.java
new file mode 100644
index 00000000000..004e0122895
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/common/utils/RSAUtils.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.foundation.common.utils;
+
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RSAUtils {
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);
+
+ private final static String RSA_ALG = "RSA";
+
+ private final static String SIGN_ALG = "SHA256withRSA";
+
+ private final static int KEY_SIZE = 2048;
+
+ private static Base64.Encoder encoder = Base64.getEncoder();
+
+ private static Base64.Decoder decoder = Base64.getDecoder();
+
+ private static KeyFactory kf = null;
+
+ static {
+
+ try {
+ kf = KeyFactory.getInstance(RSA_ALG);
+ } catch (NoSuchAlgorithmException e) {
+ LOGGER.error("init keyfactory error");
+ }
+ }
+
+ public static RSAKeyPairEntry generateRSAKeyPair() {
+ try {
+ KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(RSA_ALG);
+ keyGenerator.initialize(KEY_SIZE, new SecureRandom());
+ KeyPair keyPair = keyGenerator.generateKeyPair();
+ PublicKey pubKey = keyPair.getPublic();
+ PrivateKey privKey = keyPair.getPrivate();
+ return new RSAKeyPairEntry(privKey, pubKey, encoder.encodeToString(pubKey.getEncoded()));
+ } catch (NoSuchAlgorithmException e) {
+ LOGGER.error("generate rsa keypair faild");
+ throw new IllegalStateException("perhaps error occurred on jre");
+ }
+ }
+
+ /**
+ * if has performance problem ,change Signature to ThreadLocal instance
+ */
+ public static String sign(String content, PrivateKey privateKey)
+ throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException {
+ Signature signature = Signature.getInstance(SIGN_ALG);
+ signature.initSign(privateKey);
+ signature.update(content.getBytes());
+ byte[] signByte = signature.sign();
+ return encoder.encodeToString(signByte);
+ }
+
+ /**
+ *
+ * if has performance problem ,change Signature to ThreadLocal instance
+ * @param publicKey public key after base64 encode
+ * @param sign 签名
+ * @param content original content
+ * @return verify result
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeySpecException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ */
+ public static boolean verify(String publicKey, String sign, String content)
+ throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
+ if (null == kf )
+ {
+ throw new NoSuchAlgorithmException(RSA_ALG + " KeyFactory not available");
+ }
+ byte[] bytes = decoder.decode(publicKey);
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
+ PublicKey pubKey = kf.generatePublic(keySpec);
+ Signature signature = Signature.getInstance(SIGN_ALG);
+ signature.initVerify(pubKey);
+ signature.update(content.getBytes());
+ return signature.verify(decoder.decode(sign));
+ }
+
+}
diff --git a/foundations/foundation-common/src/main/java/io/servicecomb/foundation/token/RSAKeypair4Auth.java b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/token/RSAKeypair4Auth.java
new file mode 100644
index 00000000000..84000e5ded0
--- /dev/null
+++ b/foundations/foundation-common/src/main/java/io/servicecomb/foundation/token/RSAKeypair4Auth.java
@@ -0,0 +1,52 @@
+package io.servicecomb.foundation.token;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * 进程级别公私钥对
+ *
+ */
+public class RSAKeypair4Auth {
+
+ private RSAKeypair4Auth() {
+ };
+
+ private PrivateKey privateKey;
+
+ private PublicKey publicKey;
+
+ private String publicKeyEncoded;
+
+
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+
+ public void setPrivateKey(PrivateKey privateKey) {
+ this.privateKey = privateKey;
+ }
+
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+
+ public void setPublicKey(PublicKey publicKey) {
+ this.publicKey = publicKey;
+ }
+
+
+ public String getPublicKeyEncoded() {
+ return publicKeyEncoded;
+ }
+
+
+ public void setPublicKeyEncoded(String publicKeyEncoded) {
+ this.publicKeyEncoded = publicKeyEncoded;
+ }
+
+ public static RSAKeypair4Auth INSTANCE = new RSAKeypair4Auth();
+}
diff --git a/foundations/foundation-common/src/test/java/io/servicecomb/foundation/common/utils/TestRSAUtil.java b/foundations/foundation-common/src/test/java/io/servicecomb/foundation/common/utils/TestRSAUtil.java
new file mode 100644
index 00000000000..72a27d6d236
--- /dev/null
+++ b/foundations/foundation-common/src/test/java/io/servicecomb/foundation/common/utils/TestRSAUtil.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.foundation.common.utils;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestRSAUtil {
+
+ @Test
+ public void testSignVerify()
+ throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException {
+ RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair();
+
+ Assert.assertNotNull(rsaKeyPairEntry.getPublicKeyEncoded());
+ Assert.assertNotNull(rsaKeyPairEntry.getPrivateKey());
+ Assert.assertNotNull(rsaKeyPairEntry.getPublicKey());
+ String testContent = "instance-id@201711201930@randomstr";
+ String signstr = RSAUtils.sign(testContent, rsaKeyPairEntry.getPrivateKey());
+ Assert.assertTrue(RSAUtils.verify(rsaKeyPairEntry.getPublicKeyEncoded(), signstr, testContent));
+
+ }
+
+ @Test
+ public void testSignVerify2()
+ throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException {
+ String sign =
+ "WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=";
+ String content =
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ";
+ String pubKey =
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB";
+ Assert.assertTrue(RSAUtils.verify(pubKey, sign, content));
+
+ }
+
+}
diff --git a/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsConfig.java b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsConfig.java
index afef3585322..7d462883eca 100644
--- a/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsConfig.java
+++ b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsConfig.java
@@ -24,6 +24,6 @@ public class TestMetricsConfig {
@Test
public void test() {
Assert.assertEquals(60000, MetricsConfig.getMsCycle());
- Assert.assertEquals( false, MetricsConfig.isEnable());
+ Assert.assertEquals(false, MetricsConfig.isEnable());
}
}
diff --git a/handlers/handler-publickey-auth/pom.xml b/handlers/handler-publickey-auth/pom.xml
new file mode 100644
index 00000000000..2ffb8f692d5
--- /dev/null
+++ b/handlers/handler-publickey-auth/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+ 4.0.0
+
+ io.servicecomb
+ handlers
+ 0.4.1-SNAPSHOT
+
+
+ handler-publickey-auth
+
+
+ UTF-8
+
+
+
+
+ io.servicecomb
+ java-chassis-core
+
+
+ org.slf4j
+ slf4j-log4j12
+ test
+
+
+ log4j
+ log4j
+ test
+
+
+
+
+
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/AuthHandlerBoot.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/AuthHandlerBoot.java
new file mode 100644
index 00000000000..f0ccc547190
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/AuthHandlerBoot.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb;
+
+import io.servicecomb.core.BootListener;
+import io.servicecomb.foundation.common.utils.RSAKeyPairEntry;
+import io.servicecomb.foundation.common.utils.RSAUtils;
+import io.servicecomb.foundation.token.RSAKeypair4Auth;
+import io.servicecomb.serviceregistry.RegistryUtils;
+import io.servicecomb.serviceregistry.api.Const;
+
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * initialize public and private key pair when system boot before registry instance to service center
+ *
+ *
+ */
+@Component
+public class AuthHandlerBoot implements BootListener {
+
+
+ @Override
+ public void onBootEvent(BootEvent event) {
+ if (EventType.BEFORE_REGISTRY.equals(event.getEventType())) {
+ RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair();
+ RSAKeypair4Auth.INSTANCE.setPrivateKey(rsaKeyPairEntry.getPrivateKey());
+ RSAKeypair4Auth.INSTANCE.setPublicKey(rsaKeyPairEntry.getPublicKey());
+ RSAKeypair4Auth.INSTANCE.setPublicKeyEncoded(rsaKeyPairEntry.getPublicKeyEncoded());
+ RegistryUtils.getMicroserviceInstance().getProperties().put(Const.INSTANCE_PUBKEY_PRO, rsaKeyPairEntry.getPublicKeyEncoded());
+ }
+
+ }
+
+
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/RSAAuthenticationToken.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/RSAAuthenticationToken.java
new file mode 100644
index 00000000000..89a849c0320
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/RSAAuthenticationToken.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+
+/**
+ * token 组成部分:
+ * token: instanceId@@generateTime@randomCode@sign(instanceId@@generateTime@randomCode)
+ *
+ */
+public class RSAAuthenticationToken {
+
+ public final static long TOKEN_ACTIVE_TIME = 24 * 60 * 60 * 1000;
+
+ private String instanceId;
+
+ private String serviceId;
+
+ private long generateTime;
+
+ private String randomCode;
+
+ private String sign;
+
+ private String tokenFormat;
+
+ public RSAAuthenticationToken(String instanceId, String serviceId, long generateTime,
+ String randomCode, String sign) {
+ this.instanceId = instanceId;
+ this.generateTime = generateTime;
+ this.randomCode = randomCode;
+ this.serviceId = serviceId;
+ this.sign = sign;
+ this.tokenFormat = String.format("%s@%s@%s@%s@%s",
+ instanceId,
+ serviceId,
+ generateTime,
+ randomCode,
+ sign);
+ }
+
+ public String plainToken() {
+ return String.format("%s@%s@%s@%s", this.instanceId, this.serviceId, this.generateTime, this.randomCode);
+ }
+
+
+ public String getInstanceId() {
+ return instanceId;
+ }
+
+
+ public long getGenerateTime() {
+ return generateTime;
+ }
+
+
+ public String getSign() {
+ return sign;
+ }
+
+
+ public String format() {
+ return tokenFormat;
+ }
+
+ public static RSAAuthenticationToken fromStr(String token) {
+ String[] tokenArr = token.split("@");
+ if (tokenArr.length != 5) {
+ return null;
+ }
+ return new RSAAuthenticationToken(tokenArr[0], tokenArr[1],
+ Long.valueOf(tokenArr[2]), tokenArr[3], tokenArr[4]);
+ }
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ public void setServiceId(String serviceId) {
+ this.serviceId = serviceId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof RSAAuthenticationToken)) {
+ return false;
+ }
+ RSAAuthenticationToken token = (RSAAuthenticationToken) obj;
+ if (!token.plainToken().equals(this.plainToken())) {
+ return false;
+ }
+ if (!token.getSign().equals(this.sign)) {
+ return false;
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ return this.plainToken().hashCode() + this.sign.hashCode();
+ }
+
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/ConsumerAuthHandler.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/ConsumerAuthHandler.java
new file mode 100644
index 00000000000..148143fcb71
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/ConsumerAuthHandler.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication.consumer;
+
+import java.util.Optional;
+
+import io.servicecomb.core.Const;
+import io.servicecomb.core.Handler;
+import io.servicecomb.core.Invocation;
+import io.servicecomb.swagger.invocation.AsyncResponse;
+
+/**
+ *
+ * add token to context
+ * Provider will get token for authentication
+ *
+ */
+public class ConsumerAuthHandler implements Handler {
+
+ private RSAConsumerTokenManager athenticationTokenManager = new RSAConsumerTokenManager();
+
+ @Override
+ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
+
+ Optional token = Optional.ofNullable(athenticationTokenManager.getToken());
+ if(!token.isPresent())
+ {
+ asyncResp.consumerFail(
+ new IllegalStateException("rejected by consumer authentication handler"));
+ return ;
+ }
+ invocation.addContext(Const.AUTH_TOKEN, token.get());
+ invocation.next(asyncResp);
+ }
+
+ public void setAuthenticationTokenManager(RSAConsumerTokenManager authenticationTokenManager) {
+ this.athenticationTokenManager = authenticationTokenManager;
+ }
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/RSAConsumerTokenManager.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/RSAConsumerTokenManager.java
new file mode 100644
index 00000000000..6b7328af0cd
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/consumer/RSAConsumerTokenManager.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication.consumer;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.servicecomb.authentication.RSAAuthenticationToken;
+import io.servicecomb.foundation.common.utils.RSAUtils;
+import io.servicecomb.foundation.token.RSAKeypair4Auth;
+import io.servicecomb.serviceregistry.RegistryUtils;
+
+public class RSAConsumerTokenManager {
+
+ private static final Logger logger = LoggerFactory.getLogger(RSAConsumerTokenManager.class);
+
+ private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+
+ private RSAAuthenticationToken token;
+
+ public String getToken() {
+ readWriteLock.readLock().lock();
+ if (!isExpired(token)) {
+ String tokenStr = token.format();
+ readWriteLock.readLock().unlock();
+ return tokenStr;
+ } else {
+ readWriteLock.readLock().unlock();
+ return createToken();
+ }
+ }
+
+ public String createToken() {
+ PrivateKey privateKey = RSAKeypair4Auth.INSTANCE.getPrivateKey();
+ readWriteLock.writeLock().lock();
+ if (!isExpired(token)) {
+ logger.debug("Token had been recreated by another thread");
+ readWriteLock.writeLock().unlock();
+ return token.format();
+ }
+ String instanceId = RegistryUtils.getMicroserviceInstance().getInstanceId();
+ String serviceId = RegistryUtils.getMicroservice().getServiceId();
+ String randomCode = RandomStringUtils.randomAlphanumeric(128);
+ long generateTime = System.currentTimeMillis();
+ try {
+ String plain = String.format("%s@%s@%s@%s", instanceId, serviceId, generateTime, randomCode);
+ String sign = RSAUtils.sign(plain, privateKey);
+ token = RSAAuthenticationToken.fromStr(String.format("%s@%s", plain, sign));
+ return token.format();
+ } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException e) {
+ logger.error("create token error", e);
+ throw new Error("create token error");
+ } finally {
+ readWriteLock.writeLock().unlock();
+ }
+
+ }
+
+ /**
+ * the TTL of Token is 24 hours
+ * client token will expired 15 minutes early
+ */
+ public boolean isExpired(RSAAuthenticationToken token) {
+ if (null == token) {
+ return true;
+ }
+ long generateTime = token.getGenerateTime();
+ long expiredDate = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME - 15 * 60 * 1000;
+ long now = System.currentTimeMillis();
+ return now > expiredDate;
+ }
+
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/ProviderAuthHanlder.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/ProviderAuthHanlder.java
new file mode 100644
index 00000000000..068002b9faa
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/ProviderAuthHanlder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication.provider;
+
+import io.servicecomb.core.Const;
+import io.servicecomb.core.Handler;
+import io.servicecomb.core.Invocation;
+import io.servicecomb.swagger.invocation.AsyncResponse;
+import io.servicecomb.swagger.invocation.context.HttpStatus;
+import io.servicecomb.swagger.invocation.exception.InvocationException;
+
+public class ProviderAuthHanlder implements Handler {
+
+ private RSAProviderTokenManager authenticationTokenManager = new RSAProviderTokenManager();
+
+ @Override
+ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
+
+ String token = invocation.getContext(Const.AUTH_TOKEN);
+ if (null != token && authenticationTokenManager.valid(token)) {
+ invocation.next(asyncResp);
+ } else {
+ asyncResp.producerFail(new InvocationException(new HttpStatus(401, "UNAUTHORIZED"), "UNAUTHORIZED"));
+ }
+
+ }
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/RSAProviderTokenManager.java b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/RSAProviderTokenManager.java
new file mode 100644
index 00000000000..d7826e8fe68
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/java/io/servicecomb/authentication/provider/RSAProviderTokenManager.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication.provider;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.servicecomb.authentication.RSAAuthenticationToken;
+import io.servicecomb.foundation.common.utils.RSAUtils;
+import io.servicecomb.serviceregistry.api.Const;
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import io.servicecomb.serviceregistry.cache.MicroserviceInstanceCache;
+
+public class RSAProviderTokenManager {
+
+ private final static Logger LOGGER = LoggerFactory.getLogger(RSAProviderTokenManager.class);
+
+ private Set validatedToken = ConcurrentHashMap.newKeySet(1000);
+
+ public boolean valid(String token) {
+ try {
+ RSAAuthenticationToken rsaToken = RSAAuthenticationToken.fromStr(token);
+ if (null == rsaToken) {
+ LOGGER.error("token format is error, perhaps you need to set auth handler at consumer");
+ return false;
+ }
+ if (tokenExprired(rsaToken)) {
+ LOGGER.error("token is expired");
+ return false;
+ }
+ if (validatedToken.contains(rsaToken)) {
+ LOGGER.info("found vaildate token in vaildate pool");
+ return true;
+ }
+
+ String sign = rsaToken.getSign();
+ String content = rsaToken.plainToken();
+ String publicKey = getPublicKey(rsaToken.getInstanceId(), rsaToken.getServiceId());
+ boolean verify = RSAUtils.verify(publicKey, sign, content);
+ if (verify && !tokenExprired(rsaToken)) {
+ validatedToken.add(rsaToken);
+ return true;
+ }
+
+ LOGGER.error("token verify error");
+ return false;
+
+ } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | SignatureException e) {
+ LOGGER.error("verfiy error", e);
+ return false;
+ }
+ }
+
+ private boolean tokenExprired(RSAAuthenticationToken rsaToken) {
+ long generateTime = rsaToken.getGenerateTime();
+ long expired = generateTime + RSAAuthenticationToken.TOKEN_ACTIVE_TIME + 15 * 60 * 1000;
+ long now = System.currentTimeMillis();
+ return now > expired;
+ }
+
+ private String getPublicKey(String instanceId, String serviceId) {
+ MicroserviceInstance instances = MicroserviceInstanceCache.getOrCreate(serviceId, instanceId);
+ if (instances != null) {
+ return instances.getProperties().get(Const.INSTANCE_PUBKEY_PRO);
+ } else {
+ LOGGER.error("not instance found {}-{}, maybe attack", instanceId, serviceId);
+ return "";
+ }
+ }
+
+}
diff --git a/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml b/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml
new file mode 100644
index 00000000000..8b3d1a39251
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestAuthHandlerBoot.java b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestAuthHandlerBoot.java
new file mode 100644
index 00000000000..047885b58ec
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestAuthHandlerBoot.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+import io.servicecomb.AuthHandlerBoot;
+import io.servicecomb.core.BootListener;
+import io.servicecomb.core.BootListener.BootEvent;
+import io.servicecomb.foundation.token.RSAKeypair4Auth;
+import io.servicecomb.serviceregistry.RegistryUtils;
+import io.servicecomb.serviceregistry.api.registry.Microservice;
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import mockit.Expectations;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestAuthHandlerBoot {
+
+
+ @Test
+ public void testGenerateRSAKey() {
+ MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+ Microservice microservice = new Microservice();
+ microservice.setIntance(microserviceInstance);
+ new Expectations(RegistryUtils.class) {
+ {
+
+ RegistryUtils.getMicroserviceInstance();
+ result = microserviceInstance;
+ }
+ };
+
+ AuthHandlerBoot authHandlerBoot = new AuthHandlerBoot();
+ BootEvent bootEvent = new BootEvent();
+ bootEvent.setEventType(BootListener.EventType.BEFORE_REGISTRY);
+ authHandlerBoot.onBootEvent(bootEvent);
+ Assert.assertNotNull(RSAKeypair4Auth.INSTANCE.getPrivateKey());
+ Assert.assertNotNull(RSAKeypair4Auth.INSTANCE.getPublicKey());
+ }
+}
diff --git a/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestConsumerAuthHandler.java b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestConsumerAuthHandler.java
new file mode 100644
index 00000000000..42f01b03722
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestConsumerAuthHandler.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+import io.servicecomb.authentication.consumer.ConsumerAuthHandler;
+import io.servicecomb.authentication.consumer.RSAConsumerTokenManager;
+import io.servicecomb.core.Invocation;
+import io.servicecomb.swagger.invocation.AsyncResponse;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestConsumerAuthHandler {
+
+ Invocation invocation = null;
+
+ AsyncResponse asyncResp = null;
+
+ RSAConsumerTokenManager tokenManager = null;
+
+ @Test
+ public void testHandler() throws Exception {
+ tokenManager = Mockito.mock(RSAConsumerTokenManager.class);
+ Mockito.when(tokenManager.getToken()).thenReturn("testtoken");
+ ConsumerAuthHandler consumerAuthHandler = new ConsumerAuthHandler();
+ consumerAuthHandler.setAuthenticationTokenManager(tokenManager);
+ consumerAuthHandler.handle(invocation, asyncResp);
+ Assert.assertTrue(true);
+ }
+
+
+ @Test
+ public void testHandlerException() throws Exception {
+ tokenManager = Mockito.mock(RSAConsumerTokenManager.class);
+ Mockito.when(tokenManager.getToken()).thenReturn(null);
+ ConsumerAuthHandler consumerAuthHandler = new ConsumerAuthHandler();
+ consumerAuthHandler.setAuthenticationTokenManager(tokenManager);
+ consumerAuthHandler.handle(invocation, asyncResp);
+
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ invocation = Mockito.mock(Invocation.class);
+ asyncResp = Mockito.mock(AsyncResponse.class);
+
+
+ }
+}
diff --git a/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestProviderAuthHanlder.java b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestProviderAuthHanlder.java
new file mode 100644
index 00000000000..80bf5555157
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestProviderAuthHanlder.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+import io.servicecomb.authentication.provider.ProviderAuthHanlder;
+import io.servicecomb.core.Const;
+import io.servicecomb.core.Invocation;
+import io.servicecomb.swagger.invocation.AsyncResponse;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TestProviderAuthHanlder {
+ Invocation invocation = null;
+
+ AsyncResponse asyncResp = null;
+
+ @Before
+ public void setUp() throws Exception {
+ invocation = Mockito.mock(Invocation.class);
+ asyncResp = Mockito.mock(AsyncResponse.class);
+ Mockito.when(invocation.getContext(Const.AUTH_TOKEN)).thenReturn("testtoken");
+ }
+
+ @Test
+ public void testHandle() throws Exception {
+ ProviderAuthHanlder providerAuthHanlder = new ProviderAuthHanlder();
+ providerAuthHanlder.handle(invocation, asyncResp);
+ Assert.assertTrue(true);
+ }
+}
diff --git a/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAAuthenticationToken.java b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAAuthenticationToken.java
new file mode 100644
index 00000000000..b50fc824682
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAAuthenticationToken.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import io.servicecomb.foundation.common.utils.RSAUtils;
+
+
+public class TestRSAAuthenticationToken {
+
+
+ @Test
+ public void testRSAAuthenticationToken()
+ throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException {
+ String tokenstr =
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=";
+ RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr);
+ String contents = token.plainToken();
+ Assert.assertEquals(
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ",
+ contents);
+ String sign = token.getSign();
+ Assert.assertEquals(
+ "WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=",
+ sign);
+ String pubKey =
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB";
+ Assert.assertTrue(RSAUtils.verify(pubKey, sign, contents));
+ }
+
+
+ @Test
+ public void testRSAAuthenticationTokenError() {
+ String tokenstr =
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=";
+ RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr);
+ Assert.assertNull(token);
+ }
+
+
+ @Test
+ public void testEqual() {
+ String tokenstr =
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=";
+ RSAAuthenticationToken token = RSAAuthenticationToken.fromStr(tokenstr);
+ Assert.assertNotEquals(token, null);
+ RSAAuthenticationToken token2 = RSAAuthenticationToken.fromStr(
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk");
+ Assert.assertNotEquals(token2, token);
+
+ RSAAuthenticationToken token3 = RSAAuthenticationToken.fromStr(
+ "e8a0a4b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk");
+ Assert.assertNotEquals(token3, token);
+
+ RSAAuthenticationToken token4 = RSAAuthenticationToken.fromStr(
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=");
+ Assert.assertEquals(token4, token);
+ }
+}
diff --git a/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAProviderTokenManager.java b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAProviderTokenManager.java
new file mode 100644
index 00000000000..17139b62ad1
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/java/io/servicecomb/authentication/TestRSAProviderTokenManager.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.authentication;
+
+import io.servicecomb.authentication.consumer.RSAConsumerTokenManager;
+import io.servicecomb.authentication.provider.RSAProviderTokenManager;
+import io.servicecomb.foundation.common.utils.RSAKeyPairEntry;
+import io.servicecomb.foundation.common.utils.RSAUtils;
+import io.servicecomb.foundation.token.RSAKeypair4Auth;
+import io.servicecomb.serviceregistry.RegistryUtils;
+import io.servicecomb.serviceregistry.api.Const;
+import io.servicecomb.serviceregistry.api.registry.Microservice;
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+import io.servicecomb.serviceregistry.cache.MicroserviceInstanceCache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import mockit.Expectations;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestRSAProviderTokenManager {
+
+
+ @Test
+ public void testTokenExpried() {
+ String tokenStr =
+ "e8a04b54cf2711e7b701286ed488fc20@c8636e5acf1f11e7b701286ed488fc20@1511315597475@9t0tp8ce80SUM5ts6iRGjFJMvCdQ7uvhpyh0RM7smKm3p4wYOrojr4oT1Pnwx7xwgcgEFbQdwPJxIMfivpQ1rHGqiLp67cjACvJ3Ke39pmeAVhybsLADfid6oSjscFaJ@WBYouF6hXYrXzBA31HC3VX8Bw9PNgJUtVqOPAaeW9ye3q/D7WWb0M+XMouBIWxWY6v9Un1dGu5Rkjlx6gZbnlHkb2VO8qFR3Y6lppooWCirzpvEBRjlJQu8LPBur0BCfYGq8XYrEZA2NU6sg2zXieqCSiX6BnMnBHNn4cR9iZpk=";
+ RSAProviderTokenManager tokenManager = new RSAProviderTokenManager();
+ MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+ Map properties = new HashMap();
+ microserviceInstance.setProperties(properties);
+ properties.put(Const.INSTANCE_PUBKEY_PRO,
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxKl5TNUTec7fL2degQcCk6vKf3c0wsfNK5V6elKzjWxm0MwbRj/UeR20VSnicBmVIOWrBS9LiERPPvjmmWUOSS2vxwr5XfhBhZ07gCAUNxBOTzgMo5nE45DhhZu5Jzt5qSV6o10Kq7+fCCBlDZ1UoWxZceHkUt5AxcrhEDulFjQIDAQAB");
+ Assert.assertFalse(tokenManager.valid(tokenStr));
+ }
+
+ @Test
+ public void testTokenFromVaidatePool() {
+ RSAKeyPairEntry rsaKeyPairEntry = RSAUtils.generateRSAKeyPair();
+ RSAKeypair4Auth.INSTANCE.setPrivateKey(rsaKeyPairEntry.getPrivateKey());
+ RSAKeypair4Auth.INSTANCE.setPublicKey(rsaKeyPairEntry.getPublicKey());
+ RSAKeypair4Auth.INSTANCE.setPublicKeyEncoded(rsaKeyPairEntry.getPublicKeyEncoded());
+ String serviceId = "c8636e5acf1f11e7b701286ed488fc20";
+ String instanceId = "e8a04b54cf2711e7b701286ed488fc20";
+ RSAConsumerTokenManager rsaCoumserTokenManager = new RSAConsumerTokenManager();
+ MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+ microserviceInstance.setInstanceId(instanceId);
+ Map properties = new HashMap();
+ microserviceInstance.setProperties(properties);
+ properties.put(Const.INSTANCE_PUBKEY_PRO, rsaKeyPairEntry.getPublicKeyEncoded());
+ Microservice microservice = new Microservice();
+ microservice.setServiceId(serviceId);
+ new Expectations(RegistryUtils.class) {
+ {
+ RegistryUtils.getMicroservice();
+ result = microservice;
+ RegistryUtils.getMicroserviceInstance();
+ result = microserviceInstance;
+
+ }
+ };
+
+ //Test Consumer first create token
+ String token = rsaCoumserTokenManager.getToken();
+ Assert.assertNotNull(token);
+ // use cache token
+ Assert.assertEquals(token, rsaCoumserTokenManager.getToken());
+ new Expectations(MicroserviceInstanceCache.class) {
+ {
+ MicroserviceInstanceCache.getOrCreate(serviceId, instanceId);
+ result = microserviceInstance;
+
+ }
+ };
+ RSAProviderTokenManager rsaProviderTokenManager = new RSAProviderTokenManager();
+ //first validate need to verify use RSA
+ Assert.assertTrue(rsaProviderTokenManager.valid(token));
+ // second validate use validated pool
+ Assert.assertTrue(rsaProviderTokenManager.valid(token));
+ }
+
+}
diff --git a/handlers/handler-publickey-auth/src/test/resources/log4j.properties b/handlers/handler-publickey-auth/src/test/resources/log4j.properties
new file mode 100644
index 00000000000..82ef8a6612c
--- /dev/null
+++ b/handlers/handler-publickey-auth/src/test/resources/log4j.properties
@@ -0,0 +1,29 @@
+#
+# Copyright 2017 Huawei Technologies Co., Ltd
+#
+# 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.
+#
+
+log4j.rootLogger=INFO, out, stdout
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git a/handlers/pom.xml b/handlers/pom.xml
index 071e6405e60..ad6913c2ca5 100644
--- a/handlers/pom.xml
+++ b/handlers/pom.xml
@@ -34,6 +34,7 @@
handler-bizkeeper
handler-flowcontrol-qps
handler-loadbalance
+ handler-publickey-auth
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index c5e8dff11b0..75271a624e4 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -1,7 +1,5 @@
-
+
io.servicecomb
java-chassis-parent
@@ -100,4 +98,4 @@
-
+
\ No newline at end of file
diff --git a/java-chassis-dependencies/pom.xml b/java-chassis-dependencies/pom.xml
index 7683c6a41bb..cabfac75f09 100644
--- a/java-chassis-dependencies/pom.xml
+++ b/java-chassis-dependencies/pom.xml
@@ -764,6 +764,11 @@
io.servicecomb
handler-flowcontrol-qps
0.4.1-SNAPSHOT
+
+
+ io.servicecomb
+ handler-publickey-auth
+ 0.4.1-SNAPSHOT
io.servicecomb
diff --git a/samples/auth-sample/auth-consumer/pom.xml b/samples/auth-sample/auth-consumer/pom.xml
new file mode 100644
index 00000000000..7f7bedf1890
--- /dev/null
+++ b/samples/auth-sample/auth-consumer/pom.xml
@@ -0,0 +1,59 @@
+
+
+
+ 4.0.0
+
+ io.servicecomb.samples
+ auth-sample
+ 0.4.1-SNAPSHOT
+
+ auth-consumer
+
+
+ io.servicecomb
+ transport-highway
+
+
+ io.servicecomb
+ transport-rest-vertx
+
+
+ io.servicecomb
+ handler-loadbalance
+
+
+ io.servicecomb
+ provider-springmvc
+
+
+ io.servicecomb
+ provider-pojo
+
+
+ io.servicecomb
+ handler-publickey-auth
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ io.servicecomb.samples
+ commmon-schema
+
+
+
\ No newline at end of file
diff --git a/samples/auth-sample/auth-consumer/src/main/java/io/servicecomb/samples/springmvc/consumer/AuthConsumerMain.java b/samples/auth-sample/auth-consumer/src/main/java/io/servicecomb/samples/springmvc/consumer/AuthConsumerMain.java
new file mode 100644
index 00000000000..8f348904b15
--- /dev/null
+++ b/samples/auth-sample/auth-consumer/src/main/java/io/servicecomb/samples/springmvc/consumer/AuthConsumerMain.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.samples.springmvc.consumer;
+
+import io.servicecomb.foundation.common.utils.BeanUtils;
+import io.servicecomb.foundation.common.utils.Log4jUtils;
+import io.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import io.servicecomb.samples.common.schema.models.Person;
+
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class AuthConsumerMain {
+
+ private static RestTemplate restTemplate = RestTemplateBuilder.create();
+
+ public static void main(String[] args) throws Exception {
+ init();
+ Person person = new Person();
+ person.setName("ServiceComb/Authenticate");
+ System.out
+ .println("RestTemplate Consumer or POJO Consumer. You can choose whatever you like.");
+ String sayHiResult = restTemplate
+ .postForObject(
+ "cse://auth-provider/springmvchello/sayhi?name=Authenticate",
+ null,
+ String.class);
+ String sayHelloResult = restTemplate.postForObject(
+ "cse://auth-provider/springmvchello/sayhello",
+ person,
+ String.class);
+ Assert.isTrue("Hello Authenticate".equals(sayHiResult));
+ Assert.isTrue("Hello person ServiceComb/Authenticate".equals(sayHelloResult));
+ }
+
+ public static void init() throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
diff --git a/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties b/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties
new file mode 100644
index 00000000000..0324fbb1032
--- /dev/null
+++ b/samples/auth-sample/auth-consumer/src/main/resources/config/log4j.properties
@@ -0,0 +1,20 @@
+#
+# Copyright 2017 Huawei Technologies Co., Ltd
+#
+# 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.
+#
+
+paas.logs.dir=target/logs/
+paas.logs.file=sample.log
+
+log4j.rootLogger=INFO,paas,stdout
diff --git a/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml b/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml
new file mode 100644
index 00000000000..1956f054e06
--- /dev/null
+++ b/samples/auth-sample/auth-consumer/src/main/resources/microservice.yaml
@@ -0,0 +1,15 @@
+APPLICATION_ID: auth-sample
+service_description:
+ name: authConsumer
+ version: 0.0.1
+cse:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+ handler:
+ chain:
+ Consumer:
+ default: auth-consumer, loadbalance
+ references:
+ auth-provider:
+ version-rule: 0.0.1
diff --git a/samples/auth-sample/auth-provider/pom.xml b/samples/auth-sample/auth-provider/pom.xml
new file mode 100644
index 00000000000..713850339f1
--- /dev/null
+++ b/samples/auth-sample/auth-provider/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+ 4.0.0
+
+ io.servicecomb.samples
+ auth-sample
+ 0.4.1-SNAPSHOT
+
+ auth-provider
+
+
+ io.servicecomb
+ transport-highway
+
+
+ io.servicecomb
+ transport-rest-vertx
+
+
+ io.servicecomb
+ handler-publickey-auth
+
+
+ io.servicecomb
+ provider-springmvc
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ io.servicecomb.samples
+ commmon-schema
+
+
+
\ No newline at end of file
diff --git a/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/AuthProviderMain.java b/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/AuthProviderMain.java
new file mode 100644
index 00000000000..1929037a36c
--- /dev/null
+++ b/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/AuthProviderMain.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.samples.springmvc.provider;
+
+import io.servicecomb.foundation.common.utils.BeanUtils;
+import io.servicecomb.foundation.common.utils.Log4jUtils;
+
+public class AuthProviderMain {
+
+ public static void main(String[] args) throws Exception {
+ Log4jUtils.init();
+ BeanUtils.init();
+ }
+}
diff --git a/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java b/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java
new file mode 100644
index 00000000000..46a9ce5689b
--- /dev/null
+++ b/samples/auth-sample/auth-provider/src/main/java/io/servicecomb/samples/springmvc/provider/SpringmvcHelloImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.samples.springmvc.provider;
+
+
+import io.servicecomb.provider.rest.common.RestSchema;
+import io.servicecomb.samples.common.schema.Hello;
+import io.servicecomb.samples.common.schema.models.Person;
+
+import javax.ws.rs.core.MediaType;
+
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@RestSchema(schemaId = "springmvcHello")
+@RequestMapping(path = "/springmvchello", produces = MediaType.APPLICATION_JSON)
+public class SpringmvcHelloImpl implements Hello {
+
+ @Override
+ @RequestMapping(path = "/sayhi", method = RequestMethod.POST)
+ public String sayHi(@RequestParam(name = "name") String name) {
+ return "Hello " + name;
+ }
+
+ @Override
+ @RequestMapping(path = "/sayhello", method = RequestMethod.POST)
+ public String sayHello(@RequestBody Person person) {
+ return "Hello person " + person.getName();
+ }
+}
diff --git a/samples/auth-sample/auth-provider/src/main/resources/META-INF/spring/pojo.provider.bean.xml b/samples/auth-sample/auth-provider/src/main/resources/META-INF/spring/pojo.provider.bean.xml
new file mode 100644
index 00000000000..2acd82877ea
--- /dev/null
+++ b/samples/auth-sample/auth-provider/src/main/resources/META-INF/spring/pojo.provider.bean.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties b/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties
new file mode 100644
index 00000000000..0324fbb1032
--- /dev/null
+++ b/samples/auth-sample/auth-provider/src/main/resources/config/log4j.properties
@@ -0,0 +1,20 @@
+#
+# Copyright 2017 Huawei Technologies Co., Ltd
+#
+# 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.
+#
+
+paas.logs.dir=target/logs/
+paas.logs.file=sample.log
+
+log4j.rootLogger=INFO,paas,stdout
diff --git a/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml b/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml
new file mode 100644
index 00000000000..1b7856729a0
--- /dev/null
+++ b/samples/auth-sample/auth-provider/src/main/resources/microservice.yaml
@@ -0,0 +1,16 @@
+APPLICATION_ID: auth-sample
+service_description:
+ name: auth-provider
+ version: 0.0.1
+cse:
+ service:
+ registry:
+ address: http://127.0.0.1:30100
+ handler:
+ chain:
+ Provider:
+ default: auth-provider
+ rest:
+ address: 0.0.0.0:8082
+ highway:
+ address: 0.0.0.0:7070
diff --git a/samples/auth-sample/pom.xml b/samples/auth-sample/pom.xml
new file mode 100644
index 00000000000..f978e24278b
--- /dev/null
+++ b/samples/auth-sample/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+
+ io.servicecomb.samples
+ samples
+ 0.4.1-SNAPSHOT
+
+ auth-sample
+ pom
+
+ auth-provider
+ auth-consumer
+
+
\ No newline at end of file
diff --git a/samples/pom.xml b/samples/pom.xml
index 9ec04d71035..772404f960a 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -30,7 +30,10 @@
pojo-sample
springmvc-sample
commmon-schema
+ auth-sample
bmi
+ dubbo-to-servicecomb-sample
+
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/api/Const.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/api/Const.java
index 88668697e5f..6081115cd8e 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/api/Const.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/api/Const.java
@@ -147,4 +147,6 @@ public static final class REGISTRY_API {
public static final String PATH_CHECKSESSION = "checksession";
public static final String URL_PREFIX = "urlPrefix";
+
+ public static final String INSTANCE_PUBKEY_PRO = "publickey";
}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java
new file mode 100644
index 00000000000..76f801b409e
--- /dev/null
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/api/response/MicroserviceInstanceResponse.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.serviceregistry.api.response;
+
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+public class MicroserviceInstanceResponse {
+
+ private MicroserviceInstance instance;
+
+ public MicroserviceInstance getInstance() {
+ return instance;
+ }
+
+ public void setInstance(MicroserviceInstance instance) {
+ this.instance = instance;
+ }
+
+
+}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/InstanceCacheManager.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/InstanceCacheManager.java
index 38d6828dce1..38b127f2c7b 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/InstanceCacheManager.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/InstanceCacheManager.java
@@ -22,4 +22,5 @@ public interface InstanceCacheManager {
InstanceCache getOrCreate(String appId, String microserviceName, String microserviceVersionRule);
VersionedCache getOrCreateVersionedCache(String appId, String microserviceName, String microserviceVersionRule);
+
}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java
new file mode 100644
index 00000000000..1f0aca05f6b
--- /dev/null
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/cache/MicroserviceInstanceCache.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.serviceregistry.cache;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import io.servicecomb.serviceregistry.RegistryUtils;
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+/**
+ * 微服务实例缓存 key为:serviceId@instanceId 缓存limit:1000 缓存老化策略:30分钟没有访问就过期。
+ *
+ */
+public class MicroserviceInstanceCache {
+
+ private static final Logger logger = LoggerFactory.getLogger(MicroserviceInstanceCache.class);
+
+ private static Cache instances = CacheBuilder.newBuilder()
+ .maximumSize(1000)
+ .expireAfterAccess(30, TimeUnit.MINUTES)
+ .build();
+
+ public static MicroserviceInstance getOrCreate(String serviceId, String instanceId) {
+ try {
+ String key = String.format("%s@%s", serviceId, instanceId);
+ return instances.get(key, new Callable() {
+
+ @Override
+ public MicroserviceInstance call() throws Exception {
+ logger.debug("get microservice instance from SC");
+ return getMicroserviceInstanceFromSC(serviceId, instanceId);
+ }
+
+ });
+ } catch (ExecutionException e) {
+ logger.error("get microservice from cache failed:" + String.format("%s@%s", serviceId, instanceId));
+ return null;
+ }
+ }
+
+ private static MicroserviceInstance getMicroserviceInstanceFromSC(String serviceId, String instanceId) {
+ return RegistryUtils.getServiceRegistryClient().findServiceInstance(serviceId, instanceId);
+ }
+
+}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
index 139cd6e6fe5..d9107a293f6 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImpl.java
@@ -334,4 +334,12 @@ public boolean updateInstanceProperties(String microserviceId, String microservi
}
return true;
}
+
+ @Override
+ public MicroserviceInstance findServiceInstance(String serviceId, String instanceId) {
+ Map instances = microserviceInstanceMap.get(serviceId);
+ return instances.get(instanceId);
+ }
+
+
}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/ServiceRegistryClient.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/ServiceRegistryClient.java
index c67be3dc727..4666f0a1b5d 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/ServiceRegistryClient.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/ServiceRegistryClient.java
@@ -123,4 +123,12 @@ void watch(String selfMicroserviceId, AsyncResultCallback findServiceInstance(String consumerId, String appId, String serviceName,
String versionRule);
+
+ /**
+ * 通过serviceid, instanceid 获取instance对象。
+ * @param serviceId
+ * @param instanceId
+ * @return MicroserviceInstance
+ */
+ MicroserviceInstance findServiceInstance(String serviceId, String instanceId);
}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
index e1fbe085afe..9b2c1497f00 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/client/http/ServiceRegistryClientImpl.java
@@ -49,6 +49,7 @@
import io.servicecomb.serviceregistry.api.response.GetSchemaResponse;
import io.servicecomb.serviceregistry.api.response.GetServiceResponse;
import io.servicecomb.serviceregistry.api.response.HeartbeatResponse;
+import io.servicecomb.serviceregistry.api.response.MicroserviceInstanceResponse;
import io.servicecomb.serviceregistry.api.response.MicroserviceInstanceChangedEvent;
import io.servicecomb.serviceregistry.api.response.RegisterInstanceResponse;
import io.servicecomb.serviceregistry.client.ClientException;
@@ -628,4 +629,28 @@ public boolean updateInstanceProperties(String microserviceId, String microservi
}
return false;
}
+
+ @Override
+ public MicroserviceInstance findServiceInstance(String serviceId, String instanceId) {
+ try {
+ Holder holder = new Holder<>();
+ IpPort ipPort = ipPortManager.getAvailableAddress(false);
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ RestUtils.get(ipPort,
+ String.format(Const.REGISTRY_API.MICROSERVICE_INSTANCE_OPERATION_ONE, serviceId, instanceId),
+ new RequestParam().addHeader("X-ConsumerId", serviceId),
+ syncHandler(countDownLatch, MicroserviceInstanceResponse.class, holder));
+ countDownLatch.await();
+ if (null != holder.value) {
+ return holder.value.getInstance();
+ }
+ return null;
+ } catch (Exception e) {
+ LOGGER.error("get instance from sc failed");
+ return null;
+ }
+
+ }
+
+
}
diff --git a/service-registry/src/main/java/io/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java b/service-registry/src/main/java/io/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java
index d6250c8e603..8e886070c14 100644
--- a/service-registry/src/main/java/io/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java
+++ b/service-registry/src/main/java/io/servicecomb/serviceregistry/task/MicroserviceInstanceRegisterTask.java
@@ -66,7 +66,7 @@ protected boolean doRegister() {
microserviceInstance.setHostName(hostName);
microserviceInstance.getHealthCheck().setInterval(serviceRegistryConfig.getHeartbeatInterval());
microserviceInstance.getHealthCheck().setTimes(serviceRegistryConfig.getResendHeartBeatTimes());
-
+
String instanceId = srClient.registerMicroserviceInstance(microserviceInstance);
if (StringUtils.isEmpty(instanceId)) {
LOGGER.error("Register microservice instance failed. microserviceId={}",
diff --git a/service-registry/src/test/java/io/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java b/service-registry/src/test/java/io/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java
new file mode 100644
index 00000000000..fe4a5fb7196
--- /dev/null
+++ b/service-registry/src/test/java/io/servicecomb/serviceregistry/api/response/TestMicroserviceInstanceResponse.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * 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 io.servicecomb.serviceregistry.api.response;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import io.servicecomb.serviceregistry.api.registry.MicroserviceInstance;
+
+public class TestMicroserviceInstanceResponse {
+
+
+ @Test
+ public void testMicroserviceInstanceResponse()
+ {
+ MicroserviceInstance microserviceInstance = new MicroserviceInstance();
+ MicroserviceInstanceResponse microserviceInstanceResponse = new MicroserviceInstanceResponse();
+ microserviceInstanceResponse.setInstance(microserviceInstance);
+ Assert.assertNotNull(microserviceInstanceResponse.getInstance());
+ }
+}
diff --git a/service-registry/src/test/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java b/service-registry/src/test/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
index e6b8ae582fc..6cb4b4b4de9 100644
--- a/service-registry/src/test/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
+++ b/service-registry/src/test/java/io/servicecomb/serviceregistry/client/LocalServiceRegistryClientImplTest.java
@@ -145,4 +145,14 @@ public void registerSchema_normal() {
Assert.assertTrue(registryClient.registerSchema(v1.getServiceId(), "sid", "content"));
}
+
+ @Test
+ public void testFindServiceInstance()
+ {
+ Microservice microservice = mockRegisterMicroservice(appId, microserviceName, "1.0.0");
+ MicroserviceInstance instance = new MicroserviceInstance();
+ instance.setServiceId(microservice.getServiceId());
+ String instanceId = registryClient.registerMicroserviceInstance(instance);
+ Assert.assertNotNull(registryClient.findServiceInstance(microservice.getServiceId(), instanceId));
+ }
}
diff --git a/service-registry/src/test/java/io/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java b/service-registry/src/test/java/io/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
index 43835b7cfba..2dd6227fa09 100644
--- a/service-registry/src/test/java/io/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
+++ b/service-registry/src/test/java/io/servicecomb/serviceregistry/client/http/TestServiceRegistryClientImpl.java
@@ -248,4 +248,11 @@ void doRun(java.util.List events) {
}
}.run();
}
+
+
+ @Test
+ public void testFindServiceInstance()
+ {
+ Assert.assertNull(oClient.findServiceInstance("aaa","bbb"));
+ }
}