You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2017/06/29 05:48:44 UTC

[37/50] kylin git commit: minor, remove refine user cache in spring security

minor, remove refine user cache in spring security


Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/3280172b
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/3280172b
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/3280172b

Branch: refs/heads/master
Commit: 3280172b737f85479eb3432fa12c267b477674fd
Parents: 22d8fae
Author: Hongbin Ma <ma...@apache.org>
Authored: Fri Jun 23 19:08:41 2017 +0800
Committer: liyang-gmt8 <li...@apache.org>
Committed: Fri Jun 23 20:26:46 2017 +0800

----------------------------------------------------------------------
 .../apache/kylin/common/KylinConfigBase.java    | 10 ++-
 .../security/KylinAuthenticationProvider.java   | 91 ++++++++++++--------
 .../apache/kylin/rest/security/ManagedUser.java | 78 ++++++++---------
 .../apache/kylin/rest/service/UserService.java  | 10 +++
 server/src/main/resources/ehcache-test.xml      |  9 +-
 server/src/main/resources/ehcache.xml           |  9 +-
 6 files changed, 111 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
----------------------------------------------------------------------
diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index 2ccf3cf..ecd5261 100644
--- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -502,7 +502,7 @@ abstract public class KylinConfigBase implements Serializable {
     public Integer getSchedulerPollIntervalSecond() {
         return Integer.parseInt(getOptional("kylin.job.scheduler.poll-interval-second", "30"));
     }
-    
+
     public Integer getErrorRecordThreshold() {
         return Integer.parseInt(getOptional("kylin.job.error-record-threshold", "0"));
     }
@@ -1073,6 +1073,14 @@ abstract public class KylinConfigBase implements Serializable {
         return getOptionalIntArray("kylin.server.query-metrics-percentiles-intervals", dft);
     }
 
+    public int getServerUserCacheExpireSeconds() {
+        return Integer.valueOf(this.getOptional("kylin.server.auth-user-cache.expire-seconds", "300"));
+    }
+
+    public int getServerUserCacheMaxEntries() {
+        return Integer.valueOf(this.getOptional("kylin.server.auth-user-cache.max-entries", "100"));
+    }
+
     // ============================================================================
     // WEB
     // ============================================================================

http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/server-base/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java b/server-base/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
index 7322b84..dd9cbad 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/security/KylinAuthenticationProvider.java
@@ -18,7 +18,10 @@
 
 package org.apache.kylin.rest.security;
 
-import org.apache.kylin.common.util.ByteArray;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.rest.service.UserService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,13 +35,12 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.util.Assert;
 
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
 import com.google.common.hash.HashFunction;
 import com.google.common.hash.Hashing;
 
-import net.sf.ehcache.Cache;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Element;
-
 /**
  * A wrapper class for the authentication provider; Will do something more for Kylin.
  */
@@ -46,13 +48,21 @@ public class KylinAuthenticationProvider implements AuthenticationProvider {
 
     private static final Logger logger = LoggerFactory.getLogger(KylinAuthenticationProvider.class);
 
+    private final static com.google.common.cache.Cache<String, Authentication> userCache = CacheBuilder.newBuilder()
+            .maximumSize(KylinConfig.getInstanceFromEnv().getServerUserCacheMaxEntries())
+            .expireAfterWrite(KylinConfig.getInstanceFromEnv().getServerUserCacheExpireSeconds(), TimeUnit.SECONDS)
+            .removalListener(new RemovalListener<String, Authentication>() {
+                @Override
+                public void onRemoval(RemovalNotification<String, Authentication> notification) {
+                    KylinAuthenticationProvider.logger.debug("User cache {} is removed due to {}",
+                            notification.getKey(), notification.getCause());
+                }
+            }).build();
+
     @Autowired
     @Qualifier("userService")
     UserService userService;
 
-    @Autowired
-    private CacheManager cacheManager;
-
     //Embedded authentication provider
     private AuthenticationProvider authenticationProvider;
 
@@ -67,48 +77,53 @@ public class KylinAuthenticationProvider implements AuthenticationProvider {
 
     @Override
     public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-        Authentication authed = null;
-        Cache userCache = cacheManager.getCache("UserCache");
+
         byte[] hashKey = hf.hashString(authentication.getName() + authentication.getCredentials()).asBytes();
-        ByteArray userKey = new ByteArray(hashKey);
+        String userKey = Arrays.toString(hashKey);
+
+        if (userService.isEvictCacheFlag()) {
+            userCache.invalidateAll();
+            userService.setEvictCacheFlag(false);
+        }
+        Authentication authed = userCache.getIfPresent(userKey);
 
-        Element authedUser = userCache.get(userKey);
-        if (null != authedUser) {
-            authed = (Authentication) authedUser.getObjectValue();
+        if (null != authed) {
             SecurityContextHolder.getContext().setAuthentication(authed);
         } else {
             try {
                 authed = authenticationProvider.authenticate(authentication);
-                userCache.put(new Element(userKey, authed));
+
+                ManagedUser user;
+
+                if (authed.getDetails() == null) {
+                    //authed.setAuthenticated(false);
+                    throw new UsernameNotFoundException(
+                            "User not found in LDAP, check whether he/she has been added to the groups.");
+                }
+
+                if (authed.getDetails() instanceof UserDetails) {
+                    UserDetails details = (UserDetails) authed.getDetails();
+                    user = new ManagedUser(details.getUsername(), details.getPassword(), false,
+                            details.getAuthorities());
+                } else {
+                    user = new ManagedUser(authentication.getName(), "skippped-ldap", false, authed.getAuthorities());
+                }
+                Assert.notNull(user, "The UserDetail is null.");
+
+                logger.debug("User {} authorities : {}", user.getUsername(), user.getAuthorities());
+                if (!userService.userExists(user.getUsername())) {
+                    userService.createUser(user);
+                } else {
+                    userService.updateUser(user);
+                }
+
+                userCache.put(userKey, authed);
             } catch (AuthenticationException e) {
                 logger.error("Failed to auth user: " + authentication.getName(), e);
                 throw e;
             }
 
             logger.debug("Authenticated user " + authed.toString());
-
-            ManagedUser user;
-
-            if (authed.getDetails() == null) {
-                //authed.setAuthenticated(false);
-                throw new UsernameNotFoundException(
-                        "User not found in LDAP, check whether he/she has been added to the groups.");
-            }
-
-            if (authed.getDetails() instanceof UserDetails) {
-                UserDetails details = (UserDetails) authed.getDetails();
-                user = new ManagedUser(details.getUsername(), details.getPassword(), false, details.getAuthorities());
-            } else {
-                user = new ManagedUser(authentication.getName(), "skippped-ldap", false, authed.getAuthorities());
-            }
-            Assert.notNull(user, "The UserDetail is null.");
-
-            logger.debug("User authorities :" + user.getAuthorities());
-            if (!userService.userExists(user.getUsername())) {
-                userService.createUser(user);
-            } else {
-                userService.updateUser(user);
-            }
         }
 
         return authed;

http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java b/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java
index 4805d5c..280339e 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java
@@ -22,8 +22,6 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.annotation.Nullable;
-
 import org.apache.kylin.common.persistence.RootPersistentEntity;
 import org.apache.kylin.rest.service.UserGrantedAuthority;
 import org.springframework.security.core.GrantedAuthority;
@@ -31,8 +29,6 @@ import org.springframework.security.core.userdetails.UserDetails;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 
 @SuppressWarnings("serial")
@@ -44,7 +40,7 @@ public class ManagedUser extends RootPersistentEntity implements UserDetails {
     @JsonProperty
     private String password;
     @JsonProperty
-    private List<String> authorities = Lists.newArrayList();
+    private List<UserGrantedAuthority> authorities = Lists.newArrayList();
     @JsonProperty
     private boolean disabled = false;
     @JsonProperty
@@ -56,24 +52,40 @@ public class ManagedUser extends RootPersistentEntity implements UserDetails {
     @JsonProperty
     private int wrongTime = 0;
 
-    private Boolean legacyCatered = false;
     //DISABLED_ROLE is a ancient way to represent disabled user
     //now we no longer support such way, however legacy metadata may still contain it
     private static final String DISABLED_ROLE = "--disabled--";
 
-    //this is computed
-    private List<UserGrantedAuthority> grantedAuthorities = null;
-
     public ManagedUser() {
     }
 
-    public ManagedUser(String username, String password, Boolean defaultPassword, String... authorities) {
+    public ManagedUser(@JsonProperty String username, @JsonProperty String password,
+            @JsonProperty List<UserGrantedAuthority> authorities, @JsonProperty boolean disabled,
+            @JsonProperty boolean defaultPassword, @JsonProperty boolean locked, @JsonProperty long lockedTime,
+            @JsonProperty int wrongTime) {
+        this.username = username;
+        this.password = password;
+        this.authorities = authorities;
+        this.disabled = disabled;
+        this.defaultPassword = defaultPassword;
+        this.locked = locked;
+        this.lockedTime = lockedTime;
+        this.wrongTime = wrongTime;
+
+        caterLegacy();
+    }
+
+    public ManagedUser(String username, String password, Boolean defaultPassword, String... authoritiesStr) {
         this.username = username;
         this.password = password;
         this.setDefaultPassword(defaultPassword);
 
-        this.authorities = Lists.newArrayList(authorities);
-        this.grantedAuthorities = null;
+        this.authorities = Lists.newArrayList();
+        for (String a : authoritiesStr) {
+            authorities.add(new UserGrantedAuthority(a));
+        }
+
+        caterLegacy();
     }
 
     public ManagedUser(String username, String password, Boolean defaultPassword,
@@ -83,6 +95,8 @@ public class ManagedUser extends RootPersistentEntity implements UserDetails {
         this.setDefaultPassword(defaultPassword);
 
         this.setGrantedAuthorities(grantedAuthorities);
+
+        caterLegacy();
     }
 
     public String getUsername() {
@@ -102,45 +116,27 @@ public class ManagedUser extends RootPersistentEntity implements UserDetails {
     }
 
     private void caterLegacy() {
-        if (!legacyCatered) {
-            synchronized (legacyCatered) {
-                Iterator<String> iterator = authorities.iterator();
-                while (iterator.hasNext()) {
-                    if (DISABLED_ROLE.equals(iterator.next())) {
-                        iterator.remove();
-                        this.disabled = true;
-                    }
-                }
-                legacyCatered = true;
+        Iterator<UserGrantedAuthority> iterator = authorities.iterator();
+        while (iterator.hasNext()) {
+            if (DISABLED_ROLE.equals(iterator.next().getAuthority())) {
+                iterator.remove();
+                this.disabled = true;
             }
         }
     }
 
     public List<UserGrantedAuthority> getAuthorities() {
-        caterLegacy();
-        if (grantedAuthorities == null) {
-            grantedAuthorities = Lists.newArrayList();
-            for (String a : authorities) {
-                this.grantedAuthorities.add(new UserGrantedAuthority(a));
-            }
-        }
-        return grantedAuthorities;
+        return this.authorities;
     }
 
     public void setGrantedAuthorities(Collection<? extends GrantedAuthority> grantedAuthorities) {
-        this.authorities = Lists
-                .newArrayList(Collections2.transform(grantedAuthorities, new Function<GrantedAuthority, String>() {
-                    @Nullable
-                    @Override
-                    public String apply(@Nullable GrantedAuthority input) {
-                        return input.getAuthority();
-                    }
-                }));
-        this.grantedAuthorities = null;
+        this.authorities = Lists.newArrayList();
+        for (GrantedAuthority grantedAuthority : grantedAuthorities) {
+            this.authorities.add(new UserGrantedAuthority(grantedAuthority.getAuthority()));
+        }
     }
 
     public boolean isDisabled() {
-        caterLegacy();
         return disabled;
     }
 
@@ -230,6 +226,6 @@ public class ManagedUser extends RootPersistentEntity implements UserDetails {
 
     @Override
     public String toString() {
-        return "KapManagedUser [username=" + username + ", authorities=" + grantedAuthorities + "]";
+        return "ManagedUser [username=" + username + ", authorities=" + authorities + "]";
     }
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java b/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
index 504c035..6682c03 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
@@ -54,6 +54,16 @@ public class UserService implements UserDetailsManager {
     public static final Serializer<ManagedUser> SERIALIZER = new JsonSerializer<>(ManagedUser.class);
 
     protected ResourceStore aclStore;
+    
+    private boolean evictCacheFlag = false;
+
+    public boolean isEvictCacheFlag() {
+        return evictCacheFlag;
+    }
+
+    public void setEvictCacheFlag(boolean evictCacheFlag) {
+        this.evictCacheFlag = evictCacheFlag;
+    }
 
     @PostConstruct
     public void init() throws IOException {

http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/server/src/main/resources/ehcache-test.xml
----------------------------------------------------------------------
diff --git a/server/src/main/resources/ehcache-test.xml b/server/src/main/resources/ehcache-test.xml
index bffe27a..5bd4d13 100644
--- a/server/src/main/resources/ehcache-test.xml
+++ b/server/src/main/resources/ehcache-test.xml
@@ -27,11 +27,4 @@
             >
         <persistence strategy="none"/>
     </cache>
-    <cache name="UserCache"
-           eternal="false"
-           timeToLiveSeconds="10800"
-           memoryStoreEvictionPolicy="LRU"
-            >
-        <persistence strategy="none"/>
-    </cache>
-</ehcache>
\ No newline at end of file
+</ehcache>

http://git-wip-us.apache.org/repos/asf/kylin/blob/3280172b/server/src/main/resources/ehcache.xml
----------------------------------------------------------------------
diff --git a/server/src/main/resources/ehcache.xml b/server/src/main/resources/ehcache.xml
index 1d49ca6..c9efc13 100644
--- a/server/src/main/resources/ehcache.xml
+++ b/server/src/main/resources/ehcache.xml
@@ -27,11 +27,4 @@
             >
         <persistence strategy="none"/>
     </cache>
-    <cache name="UserCache"
-           eternal="false"
-           timeToLiveSeconds="10800"
-           memoryStoreEvictionPolicy="LRU"
-            >
-        <persistence strategy="none"/>
-    </cache>
-</ehcache>
\ No newline at end of file
+</ehcache>