Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw error if user leader is missing when accepting requests #256

Merged
merged 6 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,37 +43,37 @@ public ActiveDirectorySearcher objectClasses(List<ActiveDirectoryObjectClass> ob
}

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

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

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

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

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

public ActiveDirectorySearcher excludeDistinguishedName(String distinguishedName) {
var value = String.format("(!(distinguishedName=%s))", distinguishedName);
var value = String.format("(!(distinguishedName=%s))", escapeSpecialCharacters(distinguishedName));
filter.append(value);
return this;
}
Expand All @@ -89,6 +89,11 @@ public ActiveDirectorySearcher isDisabled(){
return this;
}

// Based on https://learn.microsoft.com/en-us/archive/technet-wiki/5392.active-directory-ldap-syntax-filters#Special_Characters
private String escapeSpecialCharacters(String query) {
return query.replaceAll("\\\\", "\\\\5C");
}

public List<SearchResult> search() {
var controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package info.fingo.urlopia.request;

import info.fingo.urlopia.api.v2.BaseCustomException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(code = HttpStatus.PRECONDITION_FAILED, reason = "LEADER_NOT_FOUND")
public class LeaderNotFoundException extends BaseCustomException {
private static final String ERROR_MSG = "Leader has not been found";

public LeaderNotFoundException() {
super(ERROR_MSG);
}

@Override
public HttpStatus getHttpStatus() {
return HttpStatus.PRECONDITION_FAILED;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ public Request create(Long userId, BaseRequestInput requestInput) {
log.info("New normal request with id: %d has been created".formatted(request.getId()));

var leader = userService.getAcceptanceLeaderForUser(user);
if (leader != null) {
this.acceptanceService.create(request, leader);
} else {
this.accept(request);
if (leader == null) {
throw new LeaderNotFoundException();
}

this.acceptanceService.create(request, leader);

return requestRepository
.findById(request.getId())
.orElseThrow(NoSuchElementException::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,34 @@ private User getUserLeaderUnsafe(User user) throws NamingException {
var userDN = userSearch.stream().findFirst().map(NameClassPair::getNameInNamespace).orElse("");
var organizationalUnits = extractOrganizationalUnitsDNs(userDN);

LOGGER.info("Starting search of the '{}' manager", userDN);

// Step 2: Find first existing and valid OU manager.
for (var ouDn : organizationalUnits) {
LOGGER.info("Looking for a manager in the '{}' group", ouDn);
var controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

var ouSearch = activeDirectory.newSearch().distinguishedName(ouDn).search(controls);
if (ouSearch.isEmpty()) {
LOGGER.warn("No search results for '{}' OU", ouDn);
}

for (var result : ouSearch) {
var attributes = result.getAttributes();
var managedBy = attributes.get(Attribute.MANAGED_BY.getKey());
var managedByDN = managedBy != null ? (String) managedBy.get() : "";
if (!managedByDN.isBlank() && !managedByDN.equals(userDN)) {
var managedBy = result.getAttributes().get(Attribute.MANAGED_BY.getKey());
if (managedBy == null) {
LOGGER.warn("Missing managedBy attribute for '{}' OU", ouDn);
continue;
}

var managedByDN = (String) managedBy.get();
if (!managedByDN.equals(userDN)) {
var manager = getManagerDetails(managedByDN);
if (manager.isPresent()) {
LOGGER.info("Manager of '{}' OU found: '{}'", ouDn, managedByDN);
return manager.get();
} else {
LOGGER.warn("Manager of '{}' OU has not been found", ouDn);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CREATE UNIQUE INDEX users_mail_index ON users (mail);
CREATE UNIQUE INDEX users_mail_key ON users (mail);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_mail_key;
DROP INDEX IF EXISTS users_mail_key;
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class NormalRequestServiceSpec extends Specification{
getTeams() >> Set.of(team)
}
userRepository.findById(userId) >> Optional.of(user)
userService.getAcceptanceLeaderForUser(user) >> team.getLeader()

and: "request mock with repo with endDate before startDate"
def request = Mock(Request){
Expand Down
1 change: 1 addition & 0 deletions view.react/src/helpers/errors/ErrorCodeMappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const loginErrorCodeMappings = {
const requestsErrorCodeMappings = {
"END_DATE_IS_BEFORE_START_DATE": "Data końcowa nie powinna być przed datą początkową",
"NOT_ENOUGH_DAYS": "Nie posiadasz wystarczającej liczby dni urlopowych",
"LEADER_NOT_FOUND": "Nie została znaleziona osoba wymagana do akceptacji wniosku",
"REQUEST_OVERLAPPING": "Wybrany termin pokrywa się z terminem jednej z wcześniej utworzonych okoliczności",
}

Expand Down
Loading