This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 6efba98  Logs the users login attempt status and its roles if required
     new 1becadb  This closes #1218
6efba98 is described below

commit 6efba9878343a62c5aa5abaf419f227d3afa21c2
Author: Juan Cabrerizo <j...@cloudsoft.io>
AuthorDate: Fri Aug 6 17:50:36 2021 +0100

    Logs the users login attempt status and its roles if required
---
 .../apache/brooklyn/rest/BrooklynWebConfig.java    | 11 +++++
 .../security/provider/LdapSecurityProvider.java    | 54 ++++++++++++++++++++--
 2 files changed, 62 insertions(+), 3 deletions(-)

diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynWebConfig.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynWebConfig.java
index 5fa4c7e..f78ccdd 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynWebConfig.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/BrooklynWebConfig.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.core.config.ConfigPredicates;
 import org.apache.brooklyn.rest.security.provider.DelegatingSecurityProvider;
 import 
org.apache.brooklyn.rest.security.provider.ExplicitUsersSecurityProvider;
 import org.apache.brooklyn.rest.security.provider.SecurityProvider;
+import org.apache.brooklyn.util.text.Strings;
 
 public class BrooklynWebConfig {
 
@@ -88,6 +89,16 @@ public class BrooklynWebConfig {
             "Whether user groups should be fetched from the LDAP server",
             false);
 
+    public final static ConfigKey<Boolean> LDAP_LOGIN_INFO_LOG = 
ConfigKeys.newBooleanConfigKey(
+            BASE_NAME_SECURITY+".ldap.login_info_log",
+            "Whether the users attempt to login and its groups are print on 
the `info` log",
+            false);
+
+    public final static ConfigKey<String> GROUP_CONFIG_KEY_NAME = 
ConfigKeys.newStringConfigKey(
+            BASE_NAME_SECURITY+".ldap.group_config_key",
+            "Config key name for defining groups-role relationship",
+            Strings.EMPTY);
+
     public final static ConfigKey<Boolean> HTTPS_REQUIRED = 
ConfigKeys.newBooleanConfigKey(
             BASE_NAME+".security.https.required",
             "Whether HTTPS is required; false here can be overridden by CLI 
option", false); 
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/LdapSecurityProvider.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/LdapSecurityProvider.java
index 4360623..00c9bf2 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/LdapSecurityProvider.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/LdapSecurityProvider.java
@@ -26,17 +26,22 @@ import com.google.common.collect.Lists;
 import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import javax.naming.Context;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.directory.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
+
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.StringConfigMap;
+import org.apache.brooklyn.core.config.ConfigPredicates;
 import org.apache.brooklyn.rest.BrooklynWebConfig;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
@@ -49,6 +54,14 @@ import static 
org.apache.brooklyn.core.mgmt.entitlement.WebEntitlementContext.US
 /**
  * A {@link SecurityProvider} implementation that relies on LDAP to 
authenticate.
  *
+ * CONFIG EXAMPLE
+ * brooklyn.webconsole.security.ldap.url=ldap://<server>:<port>/
+ * brooklyn.webconsole.security.ldap.realm=<,>realm>
+ * brooklyn.webconsole.security.ldap.ou=<ou>.<parent_ou>
+ * brooklyn.webconsole.security.ldap.fetch_user_group=true
+ * 
brooklyn.webconsole.security.ldap.group_config_key=<role_resolver_config_key>
+ * brooklyn.webconsole.security.ldap.login_info_log=true
+ *
  * @author Peter Veentjer.
  */
 public class LdapSecurityProvider extends AbstractSecurityProvider implements 
SecurityProvider {
@@ -59,13 +72,22 @@ public class LdapSecurityProvider extends 
AbstractSecurityProvider implements Se
     private final String ldapUrl;
     private final String defaultLdapRealm;
     private final String organizationUnit;
+    private boolean logUserLoginAttempt;
     private boolean fetchUserGroups = false;
+    private List<String> validGroups;
 
     public LdapSecurityProvider(ManagementContext mgmt) {
         StringConfigMap properties = mgmt.getConfig();
         ldapUrl = properties.getConfig(BrooklynWebConfig.LDAP_URL);
         Strings.checkNonEmpty(ldapUrl, "LDAP security provider configuration 
missing required property " + BrooklynWebConfig.LDAP_URL);
         fetchUserGroups = 
properties.getConfig(BrooklynWebConfig.LDAP_FETCH_USER_GROUPS);
+        logUserLoginAttempt = 
properties.getConfig(BrooklynWebConfig.LDAP_LOGIN_INFO_LOG);
+        String prefix = 
properties.getConfig(BrooklynWebConfig.GROUP_CONFIG_KEY_NAME);
+        if (fetchUserGroups && Strings.isNonBlank(prefix)) {
+            validGroups = getConfiguredGroups(properties, prefix);
+        } else {
+            validGroups = ImmutableList.of();
+        }
 
         String realmConfig = 
properties.getConfig(BrooklynWebConfig.LDAP_REALM);
         if (Strings.isNonBlank(realmConfig)) {
@@ -98,7 +120,7 @@ public class LdapSecurityProvider extends 
AbstractSecurityProvider implements Se
             // InitialDirContext doesn't do authentication if no password is 
supplied!
             return false;
         }
-
+        addToInfoLog("Login attempt with " + user);
         try {
             Hashtable env = new Hashtable();
             env.put(Context.INITIAL_CONTEXT_FACTORY, 
"com.sun.jndi.ldap.LdapCtxFactory");
@@ -111,17 +133,38 @@ public class LdapSecurityProvider extends 
AbstractSecurityProvider implements Se
             if (fetchUserGroups) {
                 List<String> userGroups = getUserGroups(user, ctx);
                 if (userGroups.isEmpty()) {
+                    addToInfoLog("Unsuccessful for " + user);
+                    LOG.trace("User {} is not member of any group", user);
                     return false;
                 }
                 // adds user groups to the session
                 sessionSupplierOnSuccess.get().setAttribute(USER_GROUPS, 
userGroups);
+                addToInfoLog("Successful for " + user + " member of " + 
userGroups);
+            } else {
+                addToInfoLog("Successful for " + user);
             }
             return allow(sessionSupplierOnSuccess.get(), user);
         } catch (NamingException e) {
+            addToInfoLog("Unsuccessful for " + user);
             return false;
         }
     }
 
+    private List<String> getConfiguredGroups(StringConfigMap properties, 
String prefix) {
+        ImmutableList.Builder<String> configuredGroupsBuilder = 
ImmutableList.builder();
+        StringConfigMap roles = 
properties.submap(ConfigPredicates.nameStartsWith(prefix + "."));
+        for (Map.Entry<ConfigKey<?>, ?> entry : 
roles.getAllConfigLocalRaw().entrySet()) {
+            
configuredGroupsBuilder.add(Strings.removeFromStart(entry.getKey().getName(), 
prefix + "."));
+        }
+        return configuredGroupsBuilder.build();
+    }
+
+    private void addToInfoLog(String s) {
+        if (logUserLoginAttempt) {
+            LOG.info(s);
+        }
+    }
+
     private List<String> getUserGroups(String user, DirContext ctx) throws 
NamingException {
         ImmutableList.Builder<String> groupsListBuilder = 
ImmutableList.builder();
 
@@ -135,14 +178,19 @@ public class LdapSecurityProvider extends 
AbstractSecurityProvider implements Se
             Attributes attrs = rslt.getAttributes();
 
             Attribute memberOf = attrs.get("memberOf");
-            if(memberOf != null){
+            if (memberOf != null) {
                 NamingEnumeration<?> groups = memberOf.getAll();
                 while (groups.hasMore()) {
                     
groupsListBuilder.add(getGroupName(groups.next().toString()));
                 }
             }
         }
-        return groupsListBuilder.build();
+        ImmutableList<String> ldapGroups = groupsListBuilder.build();
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("LDAP groups for {}: {}", user, ldapGroups);
+        }
+        // only store return the LDAP groups with a matching role in the 
configuration file
+        return ldapGroups.stream().filter(ldapGroup -> 
validGroups.contains(ldapGroup)).collect(Collectors.toList());
     }
 
     private String buildUserContainer() {

Reply via email to