[ISSUE #9366] Support Ldaps authentication (#9371)

* support ldaps auth

* add ldaps IT test.

* add ldaps IT test.

* add ldaps IT test.

* add ldaps IT test.
This commit is contained in:
Karson 2022-10-24 09:34:47 +08:00 committed by GitHub
parent 864b1f1852
commit 1076d5cf61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 172 additions and 23 deletions

View File

@ -29,11 +29,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import java.util.HashMap;
import java.util.Map;
/**
* ldap auth config.
*
* @author onewe
*/
@Configuration
@ -60,20 +58,13 @@ public class LdapAuthConfig {
@Bean
@Conditional(ConditionOnLdapAuth.class)
public LdapTemplate ldapTemplate() {
LdapContextSource contextSource = new LdapContextSource();
final Map<String, Object> config = new HashMap<>(16);
contextSource.setUrl(ldapUrl);
contextSource.setBase(ldapBaseDc);
contextSource.setUserDn(userDn);
contextSource.setPassword(password);
config.put("java.naming.ldap.attributes.binary", "objectGUID");
config.put("com.sun.jndi.ldap.connect.timeout", ldapTimeOut);
contextSource.setPooled(true);
contextSource.setBaseEnvironmentProperties(config);
contextSource.afterPropertiesSet();
return new LdapTemplate(contextSource);
public LdapTemplate ldapTemplate(LdapContextSource ldapContextSource) {
return new LdapTemplate(ldapContextSource);
}
@Bean
public LdapContextSource ldapContextSource() {
return new NacosLdapContextSource(ldapUrl, ldapBaseDc, userDn, password, ldapTimeOut);
}
@Bean

View File

@ -0,0 +1,130 @@
/*
* Copyright 1999-2018 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.plugin.auth.impl;
import com.alibaba.nacos.common.tls.TlsHelper;
import com.alibaba.nacos.core.utils.Loggers;
import org.springframework.ldap.core.support.LdapContextSource;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import javax.naming.Context;
import javax.net.ssl.SSLSocketFactory;
/**
* NacosLdapContextSource.
*
* @author karsonto
*/
public class NacosLdapContextSource extends LdapContextSource {
private final Map<String, Object> config = new HashMap<>(16);
private boolean useTsl = false;
private static final String LDAPS = "ldaps";
public NacosLdapContextSource(String ldapUrl, String ldapBaseDc, String userDn, String password,
String ldapTimeOut) {
this.setUrl(ldapUrl);
this.setBase(ldapBaseDc);
this.setUserDn(userDn);
this.setPassword(password);
if (ldapUrl.toLowerCase().startsWith(LDAPS)) {
useTsl = true;
}
this.setPooled(true);
init(ldapTimeOut);
}
/**
* init LdapContextSource config.
*
* @param ldapTimeOut ldap connection time out.
*/
public void init(String ldapTimeOut) {
if (useTsl) {
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
config.put("java.naming.security.protocol", "ssl");
config.put("java.naming.ldap.factory.socket", LdapSslSocketFactory.class.getName());
config.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
}
config.put("java.naming.ldap.attributes.binary", "objectGUID");
config.put("com.sun.jndi.ldap.connect.timeout", ldapTimeOut);
this.setBaseEnvironmentProperties(config);
this.afterPropertiesSet();
}
@SuppressWarnings("checkstyle:EmptyLineSeparator")
public static class LdapSslSocketFactory extends SSLSocketFactory {
private SSLSocketFactory socketFactory;
public LdapSslSocketFactory() {
try {
this.socketFactory = TlsHelper.buildSslContext(true).getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Loggers.AUTH.error("Failed to create SSLContext", e);
}
}
@Override
public String[] getDefaultCipherSuites() {
return socketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return socketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
return socketFactory.createSocket(socket, s, i, b);
}
@Override
public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return socketFactory.createSocket(s, i);
}
@Override
public Socket createSocket(String s, int i, InetAddress inetAddress, int i1)
throws IOException, UnknownHostException {
return socketFactory.createSocket(s, i, inetAddress, i1);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return socketFactory.createSocket(inetAddress, i);
}
@Override
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1)
throws IOException {
return socketFactory.createSocket(inetAddress, i, inetAddress1, i1);
}
}
}

View File

@ -17,9 +17,11 @@
package com.alibaba.nacos.test.core.auth;
import com.alibaba.nacos.Nacos;
import com.alibaba.nacos.auth.config.AuthConfigs;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@ -27,9 +29,11 @@ import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Nacos.class, properties = {"server.servlet.context-path=/nacos",
"nacos.core.auth.system.type=ldap"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
import java.net.URL;
import java.util.concurrent.TimeUnit;
@RunWith(Suite.class)
@Suite.SuiteClasses({ LdapAuth_ITCase.NonTlsTest.class,LdapAuth_ITCase.TlsTest.class})
public class LdapAuth_ITCase extends AuthBase {
@LocalServerPort
@ -44,11 +48,35 @@ public class LdapAuth_ITCase extends AuthBase {
public void init() throws Exception {
Mockito.when(ldapTemplate.authenticate("", "(" + filterPrefix + "=" + "karson" + ")", "karson"))
.thenReturn(true);
AuthConfigs.setCachingEnabled(false);
TimeUnit.SECONDS.sleep(5L);
String url = String.format("http://localhost:%d/", port);
System.setProperty("nacos.core.auth.enabled", "true");
this.base = new URL(url);
}
@Test
public void testLdapAuth() throws Exception {
super.login("karson", "karson");
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Nacos.class, properties = {"server.servlet.context-path=/nacos",
"nacos.core.auth.system.type=ldap"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public static class NonTlsTest extends LdapAuth_ITCase {
@Test
public void testLdapAuth() throws Exception {
super.login("karson", "karson");
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Nacos.class, properties = {"server.servlet.context-path=/nacos",
"nacos.core.auth.system.type=ldap",
"nacos.core.auth.ldap.url=ldaps://localhost:636"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public static class TlsTest extends LdapAuth_ITCase {
@Test
public void testLdapAuth() throws Exception {
super.login("karson", "karson");
}
}
}