Skip to content
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 numberDiff line numberDiff line change
Expand Up@@ -40,6 +40,10 @@ public interface AuthenticationConfiguration<AP extends AuthenticationProvider>
@NotNull AP getAuthenticationProvider();
boolean isEnabled();
@NotNull Map<String, Object> getCustomProperties();
default @Nullable String getDomain()
{
return null;
}

/**
* @return Map of all property names and values that are updateable and appropriate for audit logging
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@
import org.labkey.api.cache.CacheManager;
import org.labkey.api.data.CoreSchema;
import org.labkey.api.data.TableSelector;
import org.labkey.api.security.AuthenticationConfiguration.PrimaryAuthenticationConfiguration;
import org.labkey.api.security.AuthenticationProvider.PrimaryAuthenticationProvider;

import java.util.Collection;
Expand All@@ -17,6 +18,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

Expand DownExpand Up@@ -53,6 +55,8 @@ protected Set<AuthenticationConfiguration<?>> createCollection()
}
};

private final Collection<String> _activeDomains;

private AuthenticationConfigurationCollections()
{
boolean acceptOnlyFicamProviders = AuthenticationManager.isAcceptOnlyFicamProviders();
Expand All@@ -71,11 +75,6 @@ private AuthenticationConfigurationCollections()
})
.collect(Collectors.groupingBy(this::getAuthenticationConfigurationFactory));

// Bit of a hack: LdapProvider sets "ldapDomain" to the first configuration's domain. We should add getDomain()
// to AuthenticationConfiguration and collect all email domains, caching them with the collections. This is only
// used for administrative messages, so we'll continue to tolerate this approach for a little while longer.
AuthenticationManager.setLdapDomain(null);

// Add each group of configurations
addConfigurations(configurationMap);

Expand All@@ -85,6 +84,12 @@ private AuthenticationConfigurationCollections()
.collect(Collectors.toMap(p->p, p->Collections.emptyList()));

addConfigurations(permanentMap);

_activeDomains = getActive(PrimaryAuthenticationConfiguration.class).stream()
.map(AuthenticationConfiguration::getDomain)
.filter(Objects::nonNull)
.filter(domain->!AuthenticationManager.ALL_DOMAINS.equals(domain))
.collect(Collectors.toCollection(LinkedHashSet::new));
}

// Little helper method simplifies the stream handling above
Expand DownExpand Up@@ -151,6 +156,11 @@ private void addToMap(SetValuedMap<Class<? extends AuthenticationConfiguration>,

return null != configurations ? configurations : Collections.emptyList();
}

private @NotNull Collection<String> getActiveDomains()
{
return _activeDomains;
}
}

/**
Expand DownExpand Up@@ -209,4 +219,12 @@ public static void clear()
{
CACHE.remove(CACHE_KEY);
}

/**
* Return a collection of all email domains associated with authentication configurations, not including "*" or null
*/
public static @NotNull Collection<String> getActiveDomains()
{
return CACHE.get(CACHE_KEY).getActiveDomains();
}
}
38 changes: 27 additions & 11 deletions api/src/org/labkey/api/security/AuthenticationManager.java
Original file line numberDiff line numberDiff line change
Expand Up@@ -195,22 +195,38 @@ public static void populateSettingsWithStartupProps()
// Populate the general authentication properties (e.g., auto-create accounts, self registration, self-service email changes).
ModuleLoader.getInstance().getConfigProperties(AUTHENTICATION_CATEGORY).stream()
.filter(cp->!cp.getName().equals(PROVIDERS_KEY)) // Ignore "Authentication" -- we don't use this property anymore
.forEach(cp->saveAuthSetting(null, cp.getName(), Boolean.parseBoolean(cp.getValue())));
.forEach(cp->saveAuthSetting(null, cp.getName(), Boolean.parseBoolean(cp.getValue())));
}

public enum Priority { High, Low }

// TODO: Replace this with a generic domain-claiming mechanism
private static String _ldapDomain = null;

public static @Nullable String getLdapDomain()
public static HtmlString getStandardSendVerificationEmailsMessage()
{
return _ldapDomain;
HtmlStringBuilder builder = HtmlStringBuilder.of("Send password verification emails to all new users");
Collection<String> activeDomains = AuthenticationConfigurationCache.getActiveDomains();

if (!activeDomains.isEmpty())
{
// At the moment, only LDAP configurations can be associated with a domain, so we call out LDAP below
builder.append(" except those with email addresses that are configured for LDAP authentication (those ending in ");
builder.append(
activeDomains.stream()
.map(d->"@" + d)
.collect(Collectors.joining(", "))
);

builder.append(")");
}

return builder.getHtmlString();
}

public static void setLdapDomain(String ldapDomain)
// Ignores domain = "*"
public static boolean isLdapEmail(ValidEmail email)
{
_ldapDomain = StringUtils.trimToNull(ldapDomain);
String emailAddress = email.getEmailAddress();
return AuthenticationConfigurationCache.getActiveDomains().stream()
.anyMatch(domain->StringUtils.endsWithIgnoreCase(emailAddress, "@" + domain));
}

public static boolean isRegistrationEnabled()
Expand DownExpand Up@@ -703,15 +719,15 @@ public String getMessage()


/** avoid spamming the audit log **/
private static Cache<String, String> authMessages = CacheManager.getCache(100, TimeUnit.MINUTES.toMillis(10), "Authentication Messages");
private static final Cache<String, String> AUTH_MESSAGES = CacheManager.getCache(100, TimeUnit.MINUTES.toMillis(10), "Authentication Messages");

public static void addAuditEvent(@NotNull User user, HttpServletRequest request, String msg)
{
String key = user.getUserId() + "/" + ((null==request||null==request.getLocalAddr())?"":request.getLocalAddr());
String prevMessage = authMessages.get(key);
String prevMessage = AUTH_MESSAGES.get(key);
if (StringUtils.equals(prevMessage, msg))
return;
authMessages.put(key, msg);
AUTH_MESSAGES.put(key, msg);
if (user.isGuest())
{
UserManager.UserAuditEvent event = new UserManager.UserAuditEvent(ContainerManager.getRoot().getId(), msg, user);
Expand Down
Loading