Skip to content

Commit

Permalink
Change the way leaders are selected for request acceptance (#244)
Browse files Browse the repository at this point in the history
Co-authored-by: witold.brzozowski <[email protected]>
Co-authored-by: mateusz.uzarek <[email protected]>
  • Loading branch information
3 people authored Oct 11, 2024
1 parent bb0723b commit 0339204
Show file tree
Hide file tree
Showing 27 changed files with 1,010 additions and 483 deletions.
2 changes: 0 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,9 @@ ldap.security.principal= (Active directory username)
ldap.security.credentials= (Active directory password)
ldap.provider.url= (Active directory url)
ad.containers.main= (Main container)
ad.groups.users= (Main user group)
ad.groups.ec= (Group for employees)
ad.groups.b2b= (Group for associates)
ad.groups.admin= (Group for admins)
ad.identifiers.team=Team,Guild (Postfixes for group names. Here we have distinction for teams and guilds)
azure.ad.clientId= (Client Id from azure AD registration)
azure.ad.tenantId= (Tenant Id from azure AD registration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,12 @@ private Set<TeamInfo> pickTeamsInfo(User user) {
Set<TeamInfo> teams = new HashSet<>();
for (var team : user.getTeams()) {
var teamName = team.getName();
var allUsersLeader = userService.getAllUsersLeader();
var leader = user.equals(team.getLeader()) ? allUsersLeader : team.getLeader();

if (leader != null) {
var leaderName = leader.getFirstName() + " " + leader.getLastName();
var teamInfo = new TeamInfo(teamName, leaderName);
teams.add(teamInfo);
}
var leader = userService.getTeamLeader(user, team);
var leaderName = leader != null
? leader.getFirstName() + " " + leader.getLastName()
: "-";
var teamInfo = new TeamInfo(teamName, leaderName);
teams.add(teamInfo);
}
return teams;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package info.fingo.urlopia.config.ad;

public enum ActiveDirectoryObjectClass {
Person, Group
PERSON("person"),
GROUP("group"),
ORGANIZATIONAL_UNIT("organizationalUnit");

private final String key;

ActiveDirectoryObjectClass(String key) {
this.key = key;
}

public String getKey() {
return key;
}
}
218 changes: 121 additions & 97 deletions src/main/java/info/fingo/urlopia/config/ad/ActiveDirectorySearcher.java
Original file line number Diff line number Diff line change
@@ -1,97 +1,121 @@
package info.fingo.urlopia.config.ad;

import info.fingo.urlopia.config.authentication.LDAPConnectionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class ActiveDirectorySearcher {
private static final Logger LOGGER = LoggerFactory.getLogger(ActiveDirectorySearcher.class);

private final StringBuilder filter = new StringBuilder("(&");
private final String mainContainer;
private final LDAPConnectionService ldapConnectionService;

public ActiveDirectorySearcher(String mainContainer,
LDAPConnectionService ldapConnectionService) {
this.mainContainer = mainContainer;
this.ldapConnectionService = ldapConnectionService;
}

public ActiveDirectorySearcher objectClass(ActiveDirectoryObjectClass objectClass) {
var value = String.format("(objectClass=%s)", objectClass.name());
filter.append(value);
return this;
}

public ActiveDirectorySearcher memberOf(String group) {
var value = String.format("(memberOf=%s)", group);
filter.append(value);
return this;
}

public ActiveDirectorySearcher mail(String mail) {
var value = String.format("(mail=%s)", mail);
filter.append(value);
return this;
}

public ActiveDirectorySearcher name(String name) {
var value = String.format("(name=%s)", name);
filter.append(value);
return this;
}

public ActiveDirectorySearcher distinguishedName(String distinguishedName) {
var value = String.format("(distinguishedName=%s)", distinguishedName);
filter.append(value);
return this;
}

public ActiveDirectorySearcher isDisabled(){
var builder = new StringBuilder("(|");
for (var disableKey: ActiveDirectoryUtils.DISABLED_STATUS){
var value = String.format("(%s=%s)",Attribute.USER_ACCOUNT_CONTROL.getKey(), disableKey);
builder.append(value);
}
builder.append(")");
filter.append(builder);
return this;
}

public List<SearchResult> search() {
var filter = this.filter.append(")").toString();
List<SearchResult> result = new LinkedList<>();

var controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// connecting to AD and getting data
DirContext ad = null;
try {
ad = ldapConnectionService.getContext();
result = Collections.list(ad.search(mainContainer, filter, controls));
} catch (NamingException e) {
LOGGER.error("Exception when trying to search in Active Directory", e);
} finally {
try {
if (ad != null) {
ad.close();
}
} catch (NamingException e) {
LOGGER.error("Exception when trying to close the LDAP connection", e);
}
}

return result;
}
}
package info.fingo.urlopia.config.ad;

import info.fingo.urlopia.config.authentication.LDAPConnectionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@ConditionalOnProperty(name = "ad.configuration.enabled", havingValue = "true", matchIfMissing = true)
public class ActiveDirectorySearcher {
private static final Logger LOGGER = LoggerFactory.getLogger(ActiveDirectorySearcher.class);

private final StringBuilder filter = new StringBuilder("(&");
private final String mainContainer;
private final LDAPConnectionService ldapConnectionService;

public ActiveDirectorySearcher(String mainContainer,
LDAPConnectionService ldapConnectionService) {
this.mainContainer = mainContainer;
this.ldapConnectionService = ldapConnectionService;
}

public ActiveDirectorySearcher objectClass(ActiveDirectoryObjectClass objectClass) {
var value = String.format("(objectClass=%s)", objectClass.getKey());
filter.append(value);
return this;
}

public ActiveDirectorySearcher objectClasses(List<ActiveDirectoryObjectClass> objectClasses) {
var value = objectClasses.stream()
.map(objClass -> String.format("(objectClass=%s)", objClass.getKey()))
.collect(Collectors.joining("", "(|", ")"));
filter.append(value);
return this;
}

public ActiveDirectorySearcher memberOf(String group) {
var value = String.format("(memberOf=%s)", group);
filter.append(value);
return this;
}

public ActiveDirectorySearcher principalName(String principalName) {
var value = String.format("(userPrincipalName=%s)", principalName);
filter.append(value);
return this;
}

public ActiveDirectorySearcher mail(String mail) {
var value = String.format("(mail=%s)", mail);
filter.append(value);
return this;
}

public ActiveDirectorySearcher name(String name) {
var value = String.format("(name=%s)", name);
filter.append(value);
return this;
}

public ActiveDirectorySearcher distinguishedName(String distinguishedName) {
var value = String.format("(distinguishedName=%s)", distinguishedName);
filter.append(value);
return this;
}

public ActiveDirectorySearcher excludeDistinguishedName(String distinguishedName) {
var value = String.format("(!(distinguishedName=%s))", distinguishedName);
filter.append(value);
return this;
}

public ActiveDirectorySearcher isDisabled(){
var builder = new StringBuilder("(|");
for (var disableKey: ActiveDirectoryUtils.DISABLED_STATUS){
var value = String.format("(%s=%s)",Attribute.USER_ACCOUNT_CONTROL.getKey(), disableKey);
builder.append(value);
}
builder.append(")");
filter.append(builder);
return this;
}

public List<SearchResult> search() {
var controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
return search(controls);
}

public List<SearchResult> search(SearchControls controls) {
var filter = this.filter.append(")").toString();
List<SearchResult> result = new LinkedList<>();

// connecting to AD and getting data
DirContext ad = null;
try {
ad = ldapConnectionService.getContext();
result = Collections.list(ad.search(mainContainer, filter, controls));
} catch (NamingException e) {
LOGGER.error("Exception when trying to search in Active Directory", e);
} finally {
try {
if (ad != null) {
ad.close();
}
} catch (NamingException e) {
LOGGER.error("Exception when trying to close the LDAP connection", e);
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import javax.naming.directory.SearchResult;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -43,4 +44,39 @@ public static boolean isDisabled(SearchResult searchResult){
return DISABLED_STATUS.contains(accountStatus);
}

public static String getRelativeDN(String distinguishedName,
String base) {
if (distinguishedName.equals(base)) {
return "";
} else if(distinguishedName.endsWith(base) && !base.isBlank()) {
return distinguishedName.substring(0, distinguishedName.length() - base.length() - 1); // -1 for comma
} else {
return distinguishedName;
}
}

public static String getParentDN(String distinguishedName) {
var dnParts = Arrays.stream(distinguishedName.split(",")).toList();
if (dnParts.size() == 1) {
return "";
} else {
return String.join(",", dnParts.subList(1, dnParts.size()));
}
}

public static boolean isOU(SearchResult object) {
return isObjectClass(object, ActiveDirectoryObjectClass.ORGANIZATIONAL_UNIT);
}

public static boolean isPerson(SearchResult object) {
return isObjectClass(object, ActiveDirectoryObjectClass.PERSON);
}

public static boolean isObjectClass(SearchResult object, ActiveDirectoryObjectClass objectClass) {
var objectClasses = pickAttribute(object, info.fingo.urlopia.config.ad.Attribute.OBJECT_CLASS);
return Arrays.stream(objectClasses.split(","))
.map(String::trim)
.anyMatch(oc -> oc.equalsIgnoreCase(objectClass.getKey()));
}

}
3 changes: 2 additions & 1 deletion src/main/java/info/fingo/urlopia/config/ad/Attribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public enum Attribute {
CREATED_TIME("whenCreated"),
CHANGED_TIME("whenChanged"),
USER_ACCOUNT_CONTROL("userAccountControl"),
ACCOUNT_NAME("sAMAccountName");
ACCOUNT_NAME("sAMAccountName"),
OBJECT_CLASS("objectClass");

private String key;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package info.fingo.urlopia.config.ad.tree;

import info.fingo.urlopia.config.ad.ActiveDirectoryUtils;
import info.fingo.urlopia.config.ad.Attribute;

import javax.naming.directory.SearchResult;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class ActiveDirectoryNode {

private final String relativeDN;
private final SearchResult object;
private final Map<String, ActiveDirectoryNode> children;

protected ActiveDirectoryNode(SearchResult object) {
this.relativeDN = getRDN(object);
this.object = object;
this.children = new HashMap<>();
}

protected ActiveDirectoryNode(String distinguishedName) {
this.relativeDN = getRDN(distinguishedName);
this.object = null;
this.children = new HashMap<>();
}

public void add(ActiveDirectoryNode child) {
children.put(child.relativeDN, child);
}

public Optional<ActiveDirectoryNode> getChild(String childRelativeDistinguishedName) {
return Optional.ofNullable(children.get(childRelativeDistinguishedName));
}

private static String getRDN(SearchResult object) {
var distinguishedName = ActiveDirectoryUtils.pickAttribute(object, Attribute.DISTINGUISHED_NAME);
return getRDN(distinguishedName);
}

private static String getRDN(String distinguishedName) {
return distinguishedName.split(",", 2)[0];
}

public List<SearchResult> getDirectChildrenObjects() {
return children.values().stream()
.map(child -> child.object)
.toList();
}

public SearchResult getObject() {
return object;
}

}
Loading

0 comments on commit 0339204

Please sign in to comment.