From b825bac845b0bbfedbabf7c6a8e2f9124798d16e Mon Sep 17 00:00:00 2001 From: Wuyunfan-BUPT <30968107+Wuyunfan-BUPT@users.noreply.github.com> Date: Tue, 14 Sep 2021 22:55:31 -0500 Subject: [PATCH] Add auth client: plugin and implement (#6883) --- .../auth/AbstractClientAuthService.java | 37 ++++ .../client/auth/ClientAuthPluginManager.java | 70 ++++++++ .../nacos/client/auth/ClientAuthService.java | 60 +++++++ .../nacos/client/auth/LoginAuthConstant.java | 36 ++++ .../client/auth/LoginIdentityContext.java | 54 ++++++ .../auth/NacosClientAuthServiceImpl.java | 107 +++++++++++ .../auth/process/HttpLoginProcessor.java | 95 ++++++++++ .../client/auth/process/LoginProcessor.java | 31 ++++ ...acos.client.auth.AbstractClientAuthService | 18 ++ .../auth/ClientAuthPluginManagerTest.java | 60 +++++++ .../auth/NacosClientAuthServiceImplTest.java | 166 ++++++++++++++++++ 11 files changed, 734 insertions(+) create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/AbstractClientAuthService.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthPluginManager.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthService.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/LoginAuthConstant.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/LoginIdentityContext.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImpl.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/process/HttpLoginProcessor.java create mode 100644 client/src/main/java/com/alibaba/nacos/client/auth/process/LoginProcessor.java create mode 100644 client/src/main/resources/META-INF/services/com.alibaba.nacos.client.auth.AbstractClientAuthService create mode 100644 client/src/test/java/com/alibaba/nacos/client/auth/ClientAuthPluginManagerTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImplTest.java diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/AbstractClientAuthService.java b/client/src/main/java/com/alibaba/nacos/client/auth/AbstractClientAuthService.java new file mode 100644 index 000000000..0dc5aa6cf --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/AbstractClientAuthService.java @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.common.http.client.NacosRestTemplate; +import java.util.List; + +public abstract class AbstractClientAuthService implements ClientAuthService { + + protected List serverList; + + protected NacosRestTemplate nacosRestTemplate; + + @Override + public void setServerList(List serverList) { + this.serverList = serverList; + } + + @Override + public void setNacosRestTemplate(NacosRestTemplate nacosRestTemplate) { + this.nacosRestTemplate = nacosRestTemplate; + } +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthPluginManager.java b/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthPluginManager.java new file mode 100644 index 000000000..f3cc60cea --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthPluginManager.java @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.common.http.client.NacosRestTemplate; +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * ClientAuthService classLoader. + * + * @author wuyfee + */ +public class ClientAuthPluginManager { + + private static final Logger AUTHPLUGIN_LOGGER = LoggerFactory.getLogger(ClientAuthPluginManager.class); + + /** + * The relationship of context type and {@link ClientAuthService}. + */ + private final Set clientAuthServiceHashSet = new HashSet<>(); + + /** + * init ClientAuthService. + */ + public void init(List serverList, NacosRestTemplate nacosRestTemplate) { + + Collection clientAuthServices = NacosServiceLoader + .load(AbstractClientAuthService.class); + for (ClientAuthService clientAuthService : clientAuthServices) { + clientAuthService.setServerList(serverList); + clientAuthService.setNacosRestTemplate(nacosRestTemplate); + clientAuthServiceHashSet.add(clientAuthService); + } + if (clientAuthServiceHashSet.isEmpty()) { + AUTHPLUGIN_LOGGER + .warn("[ClientAuthPluginManager] Load ClientAuthService fail, No ClientAuthService implements"); + } + } + + /** + * get all ClientAuthService instance. + * + * @return ClientAuthService Set. + */ + public Set getAuthServiceSpiImplSet() { + return clientAuthServiceHashSet; + } + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthService.java b/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthService.java new file mode 100644 index 000000000..8684e1591 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/ClientAuthService.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.common.http.client.NacosRestTemplate; + +import java.util.List; +import java.util.Properties; + +/** + * Client AuthService. + * + * @author wuyfee + */ +public interface ClientAuthService { + + /** + * login(request) to service and get response. + * + * @param properties login auth information. + * @return boolean whether login success. + */ + Boolean login(Properties properties); + + /** + * set login serverList. + * + * @param serverList login server list; + */ + void setServerList(List serverList); + + /** + * http request template. + * + * @param nacosRestTemplate nacos http request template. + */ + void setNacosRestTemplate(NacosRestTemplate nacosRestTemplate); + + /** + * get login identity context. + * + * @return LoginIdentityContext this plugin loginIdentityContext. + */ + LoginIdentityContext getLoginIdentityContext(); + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/LoginAuthConstant.java b/client/src/main/java/com/alibaba/nacos/client/auth/LoginAuthConstant.java new file mode 100644 index 000000000..541741f0e --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/LoginAuthConstant.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +public class LoginAuthConstant { + + public static final String ACCESSTOKEN = "accessToken"; + + public static final String TOKENTTL = "tokenTtl"; + + public static final String TOKENREFRESHWINDOW = "tokenRefreshWindow"; + + public static final String USERNAME = "username"; + + public static final String PASSWORD = "password"; + + public static final String COLON = ":"; + + public static final String SERVER = "server"; + + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/LoginIdentityContext.java b/client/src/main/java/com/alibaba/nacos/client/auth/LoginIdentityContext.java new file mode 100644 index 000000000..a3c520f7a --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/LoginIdentityContext.java @@ -0,0 +1,54 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class LoginIdentityContext { + + /** + * get context from request. + */ + private final Map param = new HashMap(); + + /** + * get key from context. + * @param key key of request + * @return value of param key + */ + public Object getParameter(String key) { + return param.get(key); } + + /** + * put key and value to param. + * @param key key of request + * @param value value of request's key + */ + public void setParameter(String key, Object value) { + param.put(key, value); } + + /** + * get all keys of param map. + * @return set all param keys. + */ + public Set getAllKey() { + return param.keySet(); + } + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImpl.java b/client/src/main/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImpl.java new file mode 100644 index 000000000..38477ef49 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImpl.java @@ -0,0 +1,107 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.client.auth.process.HttpLoginProcessor; +import com.alibaba.nacos.common.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +/** + * a ClientAuthService implement. + * + * @author wuyfee + */ + +public class NacosClientAuthServiceImpl extends AbstractClientAuthService { + + private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger(NacosClientAuthServiceImpl.class); + + /** + * TTL of token in seconds. + */ + private long tokenTtl; + + /** + * Last timestamp refresh security info from server. + */ + private long lastRefreshTime; + + /** + * time window to refresh security info in seconds. + */ + private long tokenRefreshWindow; + + /** + * A context to take with when sending request to Nacos server. + */ + private volatile LoginIdentityContext loginIdentityContext; + + + /** + * Login to servers. + * + * @return true if login successfully + */ + + @Override + public Boolean login(Properties properties) { + try { + if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS + .toMillis(tokenTtl - tokenRefreshWindow)) { + return true; + } + + if (StringUtils.isBlank(properties.getProperty(PropertyKeyConst.USERNAME))) { + lastRefreshTime = System.currentTimeMillis(); + return true; + } + + for (String server : this.serverList) { + HttpLoginProcessor httpLoginProcessor = new HttpLoginProcessor(nacosRestTemplate); + properties.setProperty(LoginAuthConstant.SERVER, server); + LoginIdentityContext identityContext = httpLoginProcessor.getResponse(properties); + if (identityContext != null) { + if (StringUtils.isNotBlank((String) identityContext.getParameter(LoginAuthConstant.ACCESSTOKEN))) { + tokenTtl = Long.parseLong((String) identityContext.getParameter(LoginAuthConstant.TOKENTTL)); + tokenRefreshWindow = tokenTtl / 10; + lastRefreshTime = System.currentTimeMillis(); + + loginIdentityContext = new LoginIdentityContext(); + loginIdentityContext.setParameter(LoginAuthConstant.ACCESSTOKEN, + identityContext.getParameter(LoginAuthConstant.ACCESSTOKEN)); + } + return true; + } + } + } catch (Throwable throwable) { + SECURITY_LOGGER.warn("[SecurityProxy] login failed, error: ", throwable); + return false; + } + return false; + } + + @Override + public LoginIdentityContext getLoginIdentityContext() { + return this.loginIdentityContext; + } + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/process/HttpLoginProcessor.java b/client/src/main/java/com/alibaba/nacos/client/auth/process/HttpLoginProcessor.java new file mode 100644 index 000000000..1f4464972 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/process/HttpLoginProcessor.java @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth.process; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.client.auth.LoginAuthConstant; +import com.alibaba.nacos.client.auth.LoginIdentityContext; +import com.alibaba.nacos.client.utils.ContextPathUtil; +import com.alibaba.nacos.common.http.HttpRestResult; +import com.alibaba.nacos.common.http.client.NacosRestTemplate; +import com.alibaba.nacos.common.http.param.Header; +import com.alibaba.nacos.common.http.param.Query; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.StringUtils; +import com.fasterxml.jackson.databind.JsonNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static com.alibaba.nacos.client.naming.utils.UtilAndComs.HTTP; +import static com.alibaba.nacos.client.naming.utils.UtilAndComs.webContext; + +public class HttpLoginProcessor implements LoginProcessor { + + private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger(HttpLoginProcessor.class); + + private static final String LOGIN_URL = "/v1/auth/users/login"; + + private final NacosRestTemplate nacosRestTemplate; + + public HttpLoginProcessor(NacosRestTemplate nacosRestTemplate) { + this.nacosRestTemplate = nacosRestTemplate; + } + + @Override + public LoginIdentityContext getResponse(Properties properties) { + + String contextPath = ContextPathUtil + .normalizeContextPath(properties.getProperty(PropertyKeyConst.CONTEXT_PATH, webContext)); + String server = properties.getProperty(LoginAuthConstant.SERVER, StringUtils.EMPTY); + String url = HTTP + server + contextPath + LOGIN_URL; + + if (server.contains(Constants.HTTP_PREFIX)) { + url = server + contextPath + LOGIN_URL; + } + + Map params = new HashMap(2); + Map bodyMap = new HashMap(2); + params.put(PropertyKeyConst.USERNAME, properties.getProperty(PropertyKeyConst.USERNAME, StringUtils.EMPTY)); + bodyMap.put(PropertyKeyConst.PASSWORD, properties.getProperty(PropertyKeyConst.PASSWORD, StringUtils.EMPTY)); + try { + HttpRestResult restResult = nacosRestTemplate + .postForm(url, Header.EMPTY, Query.newInstance().initParams(params), bodyMap, String.class); + if (!restResult.ok()) { + SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(restResult)); + return null; + } + JsonNode obj = JacksonUtils.toObj(restResult.getData()); + + LoginIdentityContext loginIdentityContext = new LoginIdentityContext(); + + if (obj.has(Constants.ACCESS_TOKEN)) { + loginIdentityContext + .setParameter(LoginAuthConstant.ACCESSTOKEN, obj.get(Constants.ACCESS_TOKEN).asText()); + loginIdentityContext.setParameter(LoginAuthConstant.TOKENTTL, obj.get(Constants.TOKEN_TTL).asText()); + } else { + SECURITY_LOGGER.info("[NacosClientAuthServiceImpl] ACCESS_TOKEN is empty from response"); + } + return loginIdentityContext; + } catch (Exception e) { + SECURITY_LOGGER.error("[ NacosClientAuthServiceImpl] login http request failed" + + " url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage()); + return null; + } + } + +} diff --git a/client/src/main/java/com/alibaba/nacos/client/auth/process/LoginProcessor.java b/client/src/main/java/com/alibaba/nacos/client/auth/process/LoginProcessor.java new file mode 100644 index 000000000..0d638a6f9 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/auth/process/LoginProcessor.java @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth.process; + +import com.alibaba.nacos.client.auth.LoginIdentityContext; +import java.util.Properties; + +public interface LoginProcessor { + /** + * send request to server and get result. + * + * @param properties request properties. + * @return login identity context. + */ + LoginIdentityContext getResponse(Properties properties); + +} diff --git a/client/src/main/resources/META-INF/services/com.alibaba.nacos.client.auth.AbstractClientAuthService b/client/src/main/resources/META-INF/services/com.alibaba.nacos.client.auth.AbstractClientAuthService new file mode 100644 index 000000000..28b75a2e6 --- /dev/null +++ b/client/src/main/resources/META-INF/services/com.alibaba.nacos.client.auth.AbstractClientAuthService @@ -0,0 +1,18 @@ +# +# Copyright 1999-2021 Alibaba Group Holding 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. +# +# + +com.alibaba.nacos.client.auth.NacosClientAuthServiceImpl \ No newline at end of file diff --git a/client/src/test/java/com/alibaba/nacos/client/auth/ClientAuthPluginManagerTest.java b/client/src/test/java/com/alibaba/nacos/client/auth/ClientAuthPluginManagerTest.java new file mode 100644 index 000000000..f717c5c58 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/auth/ClientAuthPluginManagerTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.common.http.client.NacosRestTemplate; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.List; +import java.util.Set; + +/** + * {@link com.alibaba.nacos.client.auth.ClientAuthPluginManager} unit test. + * + * @author wuyfee + * @date 2021-08-12 12:56 + */ + +@RunWith(MockitoJUnitRunner.class) +public class ClientAuthPluginManagerTest { + + private ClientAuthPluginManager clientAuthPluginManager; + + @Mock + private List serverlist; + + @Mock + private NacosRestTemplate nacosRestTemplate; + + @Before + public void setUp() throws NoSuchFieldException, IllegalAccessException { + clientAuthPluginManager = new ClientAuthPluginManager(); + clientAuthPluginManager.init(serverlist, nacosRestTemplate); + } + + @Test + public void testGetAuthServiceSpiImplSet() { + Set clientAuthServiceSet = clientAuthPluginManager.getAuthServiceSpiImplSet(); + Assert.assertFalse(clientAuthServiceSet.isEmpty()); + } + +} diff --git a/client/src/test/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImplTest.java b/client/src/test/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImplTest.java new file mode 100644 index 000000000..335bd0df0 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/auth/NacosClientAuthServiceImplTest.java @@ -0,0 +1,166 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding 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 com.alibaba.nacos.client.auth; + +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.common.http.HttpRestResult; +import com.alibaba.nacos.common.http.client.NacosRestTemplate; +import com.alibaba.nacos.common.http.param.Header; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NacosClientAuthServiceImplTest { + + @Test + public void testLoginSuccess() throws Exception { + //given + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + HttpRestResult result = new HttpRestResult<>(); + result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}"); + result.setCode(200); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenReturn(result); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + List serverList = new ArrayList<>(); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + //when + boolean ret = nacosClientAuthService.login(properties); + //then + Assert.assertTrue(ret); + } + + @Test + public void testTestLoginFailCode() throws Exception { + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + HttpRestResult result = new HttpRestResult<>(); + result.setCode(400); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenReturn(result); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + List serverList = new ArrayList<>(); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + boolean ret = nacosClientAuthService.login(properties); + Assert.assertFalse(ret); + } + + @Test + public void testTestLoginFailHttp() throws Exception { + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenThrow(new Exception()); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + List serverList = new ArrayList<>(); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + boolean ret = nacosClientAuthService.login(properties); + Assert.assertFalse(ret); + + } + + @Test + public void testTestLoginServerListSuccess() throws Exception { + //given + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + HttpRestResult result = new HttpRestResult<>(); + result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}"); + result.setCode(200); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenReturn(result); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + List serverList = new ArrayList<>(); + serverList.add("localhost"); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + boolean ret = nacosClientAuthService.login(properties); + Assert.assertTrue(ret); + } + + @Test + public void testTestLoginServerListLoginInWindow() throws Exception { + //given + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + HttpRestResult result = new HttpRestResult<>(); + result.setData("{\"accessToken\":\"ttttttttttttttttt\",\"tokenTtl\":1000}"); + result.setCode(200); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenReturn(result); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + List serverList = new ArrayList<>(); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + //when + nacosClientAuthService.login(properties); + //then + boolean ret = nacosClientAuthService.login(properties); + Assert.assertTrue(ret); + + } + + @Test + public void testGetAccessToken() throws Exception { + NacosRestTemplate nacosRestTemplate = mock(NacosRestTemplate.class); + HttpRestResult result = new HttpRestResult<>(); + result.setData("{\"accessToken\":\"abc\",\"tokenTtl\":1000}"); + result.setCode(200); + when(nacosRestTemplate.postForm(any(), (Header) any(), any(), any(), any())).thenReturn(result); + Properties properties = new Properties(); + properties.setProperty(PropertyKeyConst.USERNAME, "aaa"); + properties.setProperty(PropertyKeyConst.PASSWORD, "123456"); + + List serverList = new ArrayList<>(); + serverList.add("localhost"); + + NacosClientAuthServiceImpl nacosClientAuthService = new NacosClientAuthServiceImpl(); + nacosClientAuthService.setServerList(serverList); + nacosClientAuthService.setNacosRestTemplate(nacosRestTemplate); + //when + Assert.assertTrue(nacosClientAuthService.login(properties)); + //then + Assert.assertEquals("abc", nacosClientAuthService.getLoginIdentityContext().getParameter(LoginAuthConstant.ACCESSTOKEN)); + } + +}