Skip to content

Commit

Permalink
Use Dockerized LDAP server for LdapAuthenticator UTs
Browse files Browse the repository at this point in the history
  • Loading branch information
Praveen2112 committed Feb 9, 2022
1 parent ca5d3a6 commit f9b2bf9
Show file tree
Hide file tree
Showing 5 changed files with 558 additions and 157 deletions.
12 changes: 12 additions & 0 deletions plugin/trino-password-authenticators/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@
</dependency>

<!-- for testing -->
<dependency>
<groupId>io.trino</groupId>
<artifactId>trino-testing-services</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.airlift</groupId>
<artifactId>testing</artifactId>
Expand All @@ -122,6 +128,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* 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.trino.plugin.password.ldap;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import java.util.List;
import java.util.Map;

import static java.util.Objects.requireNonNull;

public class LdapObjectDefinition
{
private final String id;
private final String distinguishedName;
private final Map<String, String> attributes;
private final List<String> objectClasses;

private LdapObjectDefinition(String id, String distinguishedName, Map<String, String> attributes, List<String> objectClasses)
{
this.id = requireNonNull(id, "id is null");
this.distinguishedName = requireNonNull(distinguishedName, "distinguishedName is null");
this.attributes = ImmutableMap.copyOf(requireNonNull(attributes, "attributes is null"));
this.objectClasses = ImmutableList.copyOf(requireNonNull(objectClasses, "objectClasses is null"));
}

public static LdapObjectDefinitionBuilder builder(String id)
{
return new LdapObjectDefinitionBuilder(id);
}

public List<String> getObjectClasses()
{
return objectClasses;
}

public Map<String, String> getAttributes()
{
return attributes;
}

public String getId()
{
return id;
}

public String getDistinguishedName()
{
return distinguishedName;
}

public static class LdapObjectDefinitionBuilder
{
private String id;
private String distinguishedName;
private List<String> objectClasses;
private Map<String, String> attributes;

private LdapObjectDefinitionBuilder(String id)
{
this.id = requireNonNull(id, "id is null");
}

public LdapObjectDefinition build()
{
return new LdapObjectDefinition(id, distinguishedName, attributes, objectClasses);
}

public LdapObjectDefinitionBuilder setDistinguishedName(String distinguishedName)
{
this.distinguishedName = distinguishedName;
return this;
}

public LdapObjectDefinitionBuilder setAttributes(Map<String, String> attributes)
{
this.attributes = ImmutableMap.copyOf(attributes);
return this;
}

public LdapObjectDefinitionBuilder setObjectClasses(List<String> objectClasses)
{
this.objectClasses = ImmutableList.copyOf(objectClasses);
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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.trino.plugin.password.ldap;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;

import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static java.lang.Character.MAX_RADIX;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

final class LdapUtil
{
private static final SecureRandom random = new SecureRandom();
private static final int RANDOM_SUFFIX_LENGTH = 10;

public static final String MEMBER = "member";

private LdapUtil()
{}

public static String addLdapDefinition(LdapObjectDefinition ldapObjectDefinition, DirContext context)
{
requireNonNull(ldapObjectDefinition, "LDAP Object Definition is null");

Attributes entries = new BasicAttributes();
Attribute objectClass = new BasicAttribute("objectClass");

ldapObjectDefinition.getAttributes()
.forEach((key, value) -> entries.put(new BasicAttribute(key, value)));

ldapObjectDefinition.getObjectClasses()
.forEach(objectClass::add);
entries.put(objectClass);

try {
context.createSubcontext(ldapObjectDefinition.getDistinguishedName(), entries);
}
catch (NamingException e) {
throw new RuntimeException("LDAP Entry addition failed", e);
}

return ldapObjectDefinition.getDistinguishedName();
}

public static void addAttributesToExistingLdapObjects(String distinguishedName, Map<String, List<String>> modifiedAttributes, DirContext context)
{
requireNonNull(distinguishedName, "distinguishedName is null");
requireNonNull(modifiedAttributes, "modifiedAttributes is null");

ModificationItem[] modificationItems = modifiedAttributes.entrySet().stream()
.flatMap(entry -> entry.getValue().stream()
.map(attribute -> new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute(entry.getKey(), attribute))))
.toArray(ModificationItem[]::new);

try {
context.modifyAttributes(distinguishedName, modificationItems);
}
catch (NamingException e) {
throw new RuntimeException("LDAP Entry updation failed", e);
}
}

public static LdapObjectDefinition buildLdapOrganizationObject(String name, String baseDistinguisedName)
{
return LdapObjectDefinition.builder(name)
.setDistinguishedName(format("ou=%s,%s", name, baseDistinguisedName))
.setAttributes(ImmutableMap.of("ou", name))
.setObjectClasses(ImmutableList.of("top", "organizationalUnit"))
.build();
}

public static LdapObjectDefinition buildLdapGroupObject(String organizationName, String groupName)
{
return LdapObjectDefinition.builder(groupName)
.setDistinguishedName(format("cn=%s,%s", groupName, organizationName))
.setAttributes(ImmutableMap.of(
"cn", groupName,
MEMBER, format("uid=default-%s,%s", groupName, organizationName)))
.setObjectClasses(ImmutableList.of("groupOfNames"))
.build();
}

public static LdapObjectDefinition buildLdapUserObject(String organizationName, String userName, String password)
{
return LdapObjectDefinition.builder(userName)
.setDistinguishedName(format("uid=%s,%s", userName, organizationName))
.setAttributes(ImmutableMap.of(
"cn", userName,
"sn", userName,
"userPassword", password))
.setObjectClasses(Arrays.asList("person", "inetOrgPerson"))
.build();
}

public static String randomSuffix()
{
String randomSuffix = Long.toString(abs(random.nextLong()), MAX_RADIX);
return randomSuffix.substring(0, min(RANDOM_SUFFIX_LENGTH, randomSuffix.length()));
}
}
Loading

0 comments on commit f9b2bf9

Please sign in to comment.