minor, introduce ManagedUser to replace Spring User temp
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/cf2f27a3 Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/cf2f27a3 Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/cf2f27a3 Branch: refs/heads/master Commit: cf2f27a3a8ffc41d5d909ff2b4fd38887305fe9d Parents: 071f3b9 Author: Hongbin Ma <[email protected]> Authored: Thu Jun 22 14:52:28 2017 +0800 Committer: Hongbin Ma <[email protected]> Committed: Thu Jun 22 18:26:32 2017 +0800 ---------------------------------------------------------------------- .../rest/controller2/QueryControllerV2.java | 6 + .../security/KylinAuthenticationProvider.java | 16 +- .../kylin/rest/security/LdapProvider.java | 107 --------- .../apache/kylin/rest/security/ManagedUser.java | 235 +++++++++++++++++++ .../rest/service/AclTableMigrationTool.java | 64 ++--- .../rest/service/UserGrantedAuthority.java | 5 + .../org/apache/kylin/rest/service/UserInfo.java | 82 ------- .../apache/kylin/rest/service/UserService.java | 48 ++-- server/src/main/resources/kylinSecurity.xml | 4 +- .../rest/controller/UserControllerTest.java | 4 +- .../kylin/rest/service/ServiceTestBase.java | 15 +- .../kylin/rest/service/UserServiceTest.java | 8 +- 12 files changed, 318 insertions(+), 276 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java index a641a53..a1b65a0 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java +++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java @@ -23,10 +23,13 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.servlet.http.HttpServletResponse; +import com.google.common.collect.Maps; import org.apache.commons.io.IOUtils; +import org.apache.kylin.common.debug.BackdoorToggles; import org.apache.kylin.metadata.querymeta.SelectedColumnMeta; import org.apache.kylin.rest.controller.BasicController; import org.apache.kylin.rest.exception.InternalErrorException; @@ -84,6 +87,9 @@ public class QueryControllerV2 extends BasicController { "application/vnd.apache.kylin-v2+json" }) @ResponseBody public EnvelopeResponse prepareQueryV2(@RequestBody PrepareSqlRequest sqlRequest) { + Map<String, String> toggles = Maps.newHashMap(); + toggles.put(BackdoorToggles.DEBUG_TOGGLE_PREPARE_ONLY, "true"); + BackdoorToggles.addToggles(toggles); return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, queryService.doQueryWithCache(sqlRequest), ""); } http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/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 dc475c9..7322b84 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,8 +18,6 @@ package org.apache.kylin.rest.security; -import com.google.common.hash.HashFunction; -import com.google.common.hash.Hashing; import org.apache.kylin.common.util.ByteArray; import org.apache.kylin.rest.service.UserService; import org.slf4j.Logger; @@ -30,11 +28,13 @@ import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.util.Assert; +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; @@ -87,17 +87,19 @@ public class KylinAuthenticationProvider implements AuthenticationProvider { logger.debug("Authenticated user " + authed.toString()); - UserDetails user; + 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."); + throw new UsernameNotFoundException( + "User not found in LDAP, check whether he/she has been added to the groups."); } if (authed.getDetails() instanceof UserDetails) { - user = (UserDetails) authed.getDetails(); + UserDetails details = (UserDetails) authed.getDetails(); + user = new ManagedUser(details.getUsername(), details.getPassword(), false, details.getAuthorities()); } else { - user = new User(authentication.getName(), "skippped-ldap", authed.getAuthorities()); + user = new ManagedUser(authentication.getName(), "skippped-ldap", false, authed.getAuthorities()); } Assert.notNull(user, "The UserDetail is null."); http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server-base/src/main/java/org/apache/kylin/rest/security/LdapProvider.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/security/LdapProvider.java b/server-base/src/main/java/org/apache/kylin/rest/security/LdapProvider.java deleted file mode 100644 index c76301b..0000000 --- a/server-base/src/main/java/org/apache/kylin/rest/security/LdapProvider.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.apache.kylin.rest.security; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import org.apache.kylin.rest.service.UserService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; -import org.springframework.security.ldap.authentication.LdapAuthenticator; -import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator; - -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Element; - -/** - * @author xduo - * @deprecated replaced by KylinAuthenticationProvider - * - */ -public class LdapProvider extends LdapAuthenticationProvider { - - private static final Logger logger = LoggerFactory.getLogger(LdapProvider.class); - - @Autowired - @Qualifier("userService") - UserService userService; - - @Autowired - private CacheManager cacheManager; - - MessageDigest md = null; - - /** - * @param authenticator - * @param authoritiesPopulator - */ - public LdapProvider(LdapAuthenticator authenticator, LdapAuthoritiesPopulator authoritiesPopulator) { - super(authenticator, authoritiesPopulator); - - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Failed to init Message Digest ", e); - } - } - - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - Authentication authed = null; - Cache userCache = cacheManager.getCache("UserCache"); - md.reset(); - byte[] hashKey = md.digest((authentication.getName() + authentication.getCredentials()).getBytes()); - String userKey = Arrays.toString(hashKey); - - Element authedUser = userCache.get(userKey); - if (null != authedUser) { - authed = (Authentication) authedUser.getObjectValue(); - SecurityContextHolder.getContext().setAuthentication(authed); - } else { - try { - authed = super.authenticate(authentication); - userCache.put(new Element(userKey, authed)); - } catch (AuthenticationException e) { - logger.error("Failed to auth user: " + authentication.getName(), e); - throw e; - } - - UserDetails user = new User(authentication.getName(), "skippped-ldap", authed.getAuthorities()); - - if (!userService.userExists(authentication.getName())) { - userService.createUser(user); - } else { - userService.updateUser(user); - } - } - - return authed; - } -} http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/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 new file mode 100644 index 0000000..4805d5c --- /dev/null +++ b/server-base/src/main/java/org/apache/kylin/rest/security/ManagedUser.java @@ -0,0 +1,235 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +package org.apache.kylin.rest.security; + +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; +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") +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) +public class ManagedUser extends RootPersistentEntity implements UserDetails { + + @JsonProperty + private String username; + @JsonProperty + private String password; + @JsonProperty + private List<String> authorities = Lists.newArrayList(); + @JsonProperty + private boolean disabled = false; + @JsonProperty + private boolean defaultPassword = false; + @JsonProperty + private boolean locked = false; + @JsonProperty + private long lockedTime = 0L; + @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) { + this.username = username; + this.password = password; + this.setDefaultPassword(defaultPassword); + + this.authorities = Lists.newArrayList(authorities); + this.grantedAuthorities = null; + } + + public ManagedUser(String username, String password, Boolean defaultPassword, + Collection<? extends GrantedAuthority> grantedAuthorities) { + this.username = username; + this.password = password; + this.setDefaultPassword(defaultPassword); + + this.setGrantedAuthorities(grantedAuthorities); + } + + public String getUsername() { + return username; + } + + public void setUsername(String userName) { + this.username = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + 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; + } + } + } + + public List<UserGrantedAuthority> getAuthorities() { + caterLegacy(); + if (grantedAuthorities == null) { + grantedAuthorities = Lists.newArrayList(); + for (String a : authorities) { + this.grantedAuthorities.add(new UserGrantedAuthority(a)); + } + } + return grantedAuthorities; + } + + 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; + } + + public boolean isDisabled() { + caterLegacy(); + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + + public boolean isDefaultPassword() { + return defaultPassword; + } + + public void setDefaultPassword(boolean defaultPassword) { + this.defaultPassword = defaultPassword; + } + + public boolean isLocked() { + return locked; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + public int getWrongTime() { + return wrongTime; + } + + public long getLockedTime() { + return lockedTime; + } + + public void increaseWrongTime() { + int wrongTime = this.getWrongTime(); + if (wrongTime == 2) { + this.setLocked(true); + this.lockedTime = System.currentTimeMillis(); + this.wrongTime = 0; + } else { + this.wrongTime = wrongTime + 1; + } + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return !locked; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return !disabled; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((username == null) ? 0 : username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ManagedUser other = (ManagedUser) obj; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) + return false; + return true; + } + + @Override + public String toString() { + return "KapManagedUser [username=" + username + ", authorities=" + grantedAuthorities + "]"; + } +} http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server-base/src/main/java/org/apache/kylin/rest/service/AclTableMigrationTool.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/AclTableMigrationTool.java b/server-base/src/main/java/org/apache/kylin/rest/service/AclTableMigrationTool.java index fc50410..64bac23 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/AclTableMigrationTool.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/AclTableMigrationTool.java @@ -19,7 +19,6 @@ package org.apache.kylin.rest.service; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -40,6 +39,7 @@ import org.apache.kylin.common.persistence.ResourceStore; import org.apache.kylin.common.persistence.StringEntity; import org.apache.kylin.common.util.Bytes; import org.apache.kylin.rest.security.AclConstant; +import org.apache.kylin.rest.security.ManagedUser; import org.apache.kylin.rest.util.Serializer; import org.apache.kylin.storage.hbase.HBaseConnection; import org.apache.kylin.storage.hbase.HBaseResourceStore; @@ -53,11 +53,13 @@ public class AclTableMigrationTool { private static final Serializer<SidInfo> sidSerializer = new Serializer<SidInfo>(SidInfo.class); - private static final Serializer<DomainObjectInfo> domainObjSerializer = new Serializer<DomainObjectInfo>(DomainObjectInfo.class); + private static final Serializer<DomainObjectInfo> domainObjSerializer = new Serializer<DomainObjectInfo>( + DomainObjectInfo.class); private static final Serializer<AceInfo> aceSerializer = new Serializer<AceInfo>(AceInfo.class); - private static final Serializer<UserGrantedAuthority[]> ugaSerializer = new Serializer<UserGrantedAuthority[]>(UserGrantedAuthority[].class); + private static final Serializer<UserGrantedAuthority[]> ugaSerializer = new Serializer<UserGrantedAuthority[]>( + UserGrantedAuthority[].class); public static final String MIGRATE_OK_PREFIX = "MIGRATE_OK_"; @@ -69,7 +71,8 @@ public class AclTableMigrationTool { return; } else { if (!kylinConfig.getServerMode().equals("all")) { - throw new IllegalStateException("Please make sure that you have config kylin.server.mode=all before migrating data"); + throw new IllegalStateException( + "Please make sure that you have config kylin.server.mode=all before migrating data"); } logger.info("Start to migrate acl table data"); ResourceStore store = ResourceStore.getStore(kylinConfig); @@ -144,11 +147,9 @@ public class AclTableMigrationTool { return; Result result = rs.next(); while (result != null) { - User user = hbaseRowToUser(result); - UserInfo userInfo = convert(user); - store.deleteResource(UserService.getId(userInfo.getUsername())); - store.putResource(UserService.getId(userInfo.getUsername()), userInfo, 0, - UserService.SERIALIZER); + ManagedUser user = hbaseRowToUser(result); + store.deleteResource(UserService.getId(user.getUsername())); + store.putResource(UserService.getId(user.getUsername()), user, 0, UserService.SERIALIZER); result = rs.next(); } } @@ -172,7 +173,8 @@ public class AclTableMigrationTool { return store.exists(MIGRATE_OK_PREFIX + tableName); } - private void convertToResourceStore(KylinConfig kylinConfig, String tableName, ResourceStore store, ResultConverter converter) throws IOException { + private void convertToResourceStore(KylinConfig kylinConfig, String tableName, ResourceStore store, + ResultConverter converter) throws IOException { Table table = null; ResultScanner rs = null; @@ -181,7 +183,8 @@ public class AclTableMigrationTool { table = HBaseConnection.get(kylinConfig.getStorageUrl()).getTable(TableName.valueOf(tableName)); rs = table.getScanner(scan); converter.convertResult(rs, store); - store.putResource(MIGRATE_OK_PREFIX + tableName, new StringEntity(tableName + " migrated"), StringEntity.serializer); + store.putResource(MIGRATE_OK_PREFIX + tableName, new StringEntity(tableName + " migrated"), + StringEntity.serializer); } finally { IOUtils.closeQuietly(rs); IOUtils.closeQuietly(table); @@ -190,7 +193,8 @@ public class AclTableMigrationTool { } private DomainObjectInfo getDomainObjectInfoFromRs(Result result) { - String type = String.valueOf(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_TYPE_COLUMN))); + String type = String.valueOf(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), + Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_TYPE_COLUMN))); String id = new String(result.getRow()); DomainObjectInfo newInfo = new DomainObjectInfo(); newInfo.setId(id); @@ -199,17 +203,20 @@ public class AclTableMigrationTool { } private DomainObjectInfo getParentDomainObjectInfoFromRs(Result result) throws IOException { - DomainObjectInfo parentInfo = domainObjSerializer.deserialize(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_PARENT_COLUMN))); + DomainObjectInfo parentInfo = domainObjSerializer.deserialize(result.getValue( + Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_PARENT_COLUMN))); return parentInfo; } private boolean getInheriting(Result result) { - boolean entriesInheriting = Bytes.toBoolean(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_ENTRY_INHERIT_COLUMN))); + boolean entriesInheriting = Bytes.toBoolean(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), + Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_ENTRY_INHERIT_COLUMN))); return entriesInheriting; } private SidInfo getOwnerSidInfo(Result result) throws IOException { - SidInfo owner = sidSerializer.deserialize(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_OWNER_COLUMN))); + SidInfo owner = sidSerializer.deserialize(result.getValue(Bytes.toBytes(AclConstant.ACL_INFO_FAMILY), + Bytes.toBytes(AclConstant.ACL_INFO_FAMILY_OWNER_COLUMN))); return owner; } @@ -226,27 +233,14 @@ public class AclTableMigrationTool { return allAceInfoMap; } - private UserInfo convert(User user) { - if (user == null) - return null; - UserInfo newInfo = new UserInfo(); - newInfo.setUsername(user.getUserName()); - newInfo.setPassword(user.getPassword()); - List<String> authorities = new ArrayList<>(); - for (String auth : user.getAuthorities()) { - authorities.add(auth); - } - newInfo.setAuthorities(authorities); - return newInfo; - } - - private User hbaseRowToUser(Result result) throws JsonParseException, JsonMappingException, IOException { + private ManagedUser hbaseRowToUser(Result result) throws JsonParseException, JsonMappingException, IOException { if (null == result || result.isEmpty()) return null; String username = Bytes.toString(result.getRow()); - byte[] valueBytes = result.getValue(Bytes.toBytes(AclConstant.USER_AUTHORITY_FAMILY), Bytes.toBytes(AclConstant.USER_AUTHORITY_COLUMN)); + byte[] valueBytes = result.getValue(Bytes.toBytes(AclConstant.USER_AUTHORITY_FAMILY), + Bytes.toBytes(AclConstant.USER_AUTHORITY_COLUMN)); UserGrantedAuthority[] deserialized = ugaSerializer.deserialize(valueBytes); String password = ""; @@ -261,13 +255,7 @@ public class AclTableMigrationTool { authorities = Arrays.asList(deserialized); } } - List<String> authoritiesStr = new ArrayList<>(); - for (UserGrantedAuthority auth : authorities) { - if (auth != null) { - authoritiesStr.add(auth.getAuthority()); - } - } - return new User(username, password, authoritiesStr); + return new ManagedUser(username, password, false, authorities); } interface ResultConverter { http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server-base/src/main/java/org/apache/kylin/rest/service/UserGrantedAuthority.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/UserGrantedAuthority.java b/server-base/src/main/java/org/apache/kylin/rest/service/UserGrantedAuthority.java index 4c2a392..1227177 100644 --- a/server-base/src/main/java/org/apache/kylin/rest/service/UserGrantedAuthority.java +++ b/server-base/src/main/java/org/apache/kylin/rest/service/UserGrantedAuthority.java @@ -20,10 +20,15 @@ package org.apache.kylin.rest.service; import org.springframework.security.core.GrantedAuthority; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonProperty; +@SuppressWarnings("serial") +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE) public class UserGrantedAuthority implements GrantedAuthority { private static final long serialVersionUID = -5128905636841891058L; + @JsonProperty private String authority; public UserGrantedAuthority() { http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server-base/src/main/java/org/apache/kylin/rest/service/UserInfo.java ---------------------------------------------------------------------- diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/UserInfo.java b/server-base/src/main/java/org/apache/kylin/rest/service/UserInfo.java deleted file mode 100644 index 644883d..0000000 --- a/server-base/src/main/java/org/apache/kylin/rest/service/UserInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -package org.apache.kylin.rest.service; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.kylin.common.persistence.RootPersistentEntity; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import com.fasterxml.jackson.annotation.JsonProperty; - - -@SuppressWarnings("serial") -public class UserInfo extends RootPersistentEntity { - - @JsonProperty() - private String username; - @JsonProperty() - private String password; - @JsonProperty() - private List<String> authorities = new ArrayList<>(); - - public UserInfo(String username, String password, List<String> authorities) { - this.username = username; - this.password = password; - this.authorities = authorities; - } - - public UserInfo(UserDetails user) { - this.username = user.getUsername(); - this.password = user.getPassword(); - for (GrantedAuthority a : user.getAuthorities()) { - this.authorities.add(a.getAuthority()); - } - } - - public UserInfo() { - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public List<String> getAuthorities() { - return authorities; - } - - public void setAuthorities(List<String> authorities) { - this.authorities = authorities; - } - -} http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/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 e803040..504c035 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 @@ -31,15 +31,17 @@ import org.apache.kylin.common.persistence.Serializer; import org.apache.kylin.rest.exception.InternalErrorException; import org.apache.kylin.rest.msg.Message; import org.apache.kylin.rest.msg.MsgPicker; +import org.apache.kylin.rest.security.ManagedUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.provisioning.UserDetailsManager; import org.springframework.stereotype.Component; +import com.google.common.base.Preconditions; + /** */ @Component("userService") @@ -49,7 +51,7 @@ public class UserService implements UserDetailsManager { public static final String DIR_PREFIX = "/user/"; - public static final Serializer<UserInfo> SERIALIZER = new JsonSerializer<>(UserInfo.class); + public static final Serializer<ManagedUser> SERIALIZER = new JsonSerializer<>(ManagedUser.class); protected ResourceStore aclStore; @@ -67,11 +69,13 @@ public class UserService implements UserDetailsManager { @Override //@PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN) --- DON'T DO THIS, CAUSES CIRCULAR DEPENDENCY BETWEEN UserService & AclService public void updateUser(UserDetails user) { + Preconditions.checkState(user instanceof ManagedUser, "User {} is not ManagedUser", user); + ManagedUser managedUser = (ManagedUser) user; try { deleteUser(user.getUsername()); String id = getId(user.getUsername()); - aclStore.putResource(id, new UserInfo(user), 0, SERIALIZER); - logger.debug("update user : {}", user.getUsername()); + aclStore.putResource(id, managedUser, 0, SERIALIZER); + logger.trace("update user : {}", user.getUsername()); } catch (IOException e) { throw new InternalErrorException(e); } @@ -82,7 +86,7 @@ public class UserService implements UserDetailsManager { try { String id = getId(userName); aclStore.deleteResource(id); - logger.debug("delete user : {}", userName); + logger.trace("delete user : {}", userName); } catch (IOException e) { throw new InternalErrorException(e); } @@ -96,23 +100,27 @@ public class UserService implements UserDetailsManager { @Override public boolean userExists(String userName) { try { - logger.debug("judge user exist: {}", userName); + logger.trace("judge user exist: {}", userName); return aclStore.exists(getId(userName)); } catch (IOException e) { throw new InternalErrorException(e); } } + /** + * + * @return a ManagedUser + */ @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { Message msg = MsgPicker.getMsg(); try { - UserInfo userInfo = aclStore.getResource(getId(userName), UserInfo.class, SERIALIZER); - if (userInfo == null) { + ManagedUser managedUser = aclStore.getResource(getId(userName), ManagedUser.class, SERIALIZER); + if (managedUser == null) { throw new UsernameNotFoundException(String.format(msg.getUSER_NOT_FOUND(), userName)); } - logger.debug("load user : {}", userName); - return wrap(userInfo); + logger.trace("load user : {}", userName); + return managedUser; } catch (IOException e) { throw new InternalErrorException(e); } @@ -130,28 +138,12 @@ public class UserService implements UserDetailsManager { return all; } - public List<UserDetails> listUsers() throws IOException { - List<UserDetails> all = new ArrayList<UserDetails>(); - List<UserInfo> userInfos = aclStore.getAllResources(DIR_PREFIX, UserInfo.class, SERIALIZER); - for (UserInfo info : userInfos) { - all.add(wrap(info)); - } - return all; + public List<ManagedUser> listUsers() throws IOException { + return aclStore.getAllResources(DIR_PREFIX, ManagedUser.class, SERIALIZER); } public static String getId(String userName) { return DIR_PREFIX + userName; } - protected User wrap(UserInfo userInfo) { - if (userInfo == null) - return null; - List<GrantedAuthority> authorities = new ArrayList<>(); - List<String> auths = userInfo.getAuthorities(); - for (String str : auths) { - authorities.add(new UserGrantedAuthority(str)); - } - return new User(userInfo.getUsername(), userInfo.getPassword(), authorities); - } - } http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server/src/main/resources/kylinSecurity.xml ---------------------------------------------------------------------- diff --git a/server/src/main/resources/kylinSecurity.xml b/server/src/main/resources/kylinSecurity.xml index 039bded..53ed511 100644 --- a/server/src/main/resources/kylinSecurity.xml +++ b/server/src/main/resources/kylinSecurity.xml @@ -246,7 +246,7 @@ <scr:intercept-url pattern="/api/admin*/**" access="hasRole('ROLE_ADMIN')"/> <scr:intercept-url pattern="/api/**" access="isAuthenticated()"/> - <scr:logout invalidate-session="true" delete-cookies="JSESSIONID"/> + <scr:logout invalidate-session="true" delete-cookies="JSESSIONID" logout-url="/j_spring_security_logout" logout-success-url="/." /> <scr:session-management session-fixation-protection="newSession"/> </scr:http> </beans> @@ -288,7 +288,7 @@ <scr:intercept-url pattern="/api/admin*/**" access="hasRole('ROLE_ADMIN')"/> <scr:intercept-url pattern="/api/**" access="isAuthenticated()"/> - <scr:logout invalidate-session="true" delete-cookies="JSESSIONID"/> + <scr:logout invalidate-session="true" delete-cookies="JSESSIONID" logout-url="/j_spring_security_logout" logout-success-url="/." /> <scr:session-management session-fixation-protection="newSession"/> </scr:http> http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server/src/test/java/org/apache/kylin/rest/controller/UserControllerTest.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/kylin/rest/controller/UserControllerTest.java b/server/src/test/java/org/apache/kylin/rest/controller/UserControllerTest.java index 767aaf1..f6b4ae1 100644 --- a/server/src/test/java/org/apache/kylin/rest/controller/UserControllerTest.java +++ b/server/src/test/java/org/apache/kylin/rest/controller/UserControllerTest.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.kylin.rest.constant.Constant; +import org.apache.kylin.rest.security.ManagedUser; import org.apache.kylin.rest.service.ServiceTestBase; import org.junit.Assert; import org.junit.Before; @@ -32,7 +33,6 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; /** @@ -46,7 +46,7 @@ public class UserControllerTest extends ServiceTestBase { public static void setupResource() { staticCreateTestMetadata(); List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); - User user = new User("ADMIN", "ADMIN", authorities); + ManagedUser user = new ManagedUser("ADMIN", "ADMIN", false, authorities); Authentication authentication = new TestingAuthenticationToken(user, "ADMIN", Constant.ROLE_ADMIN); SecurityContextHolder.getContext().setAuthentication(authentication); } http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server/src/test/java/org/apache/kylin/rest/service/ServiceTestBase.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/kylin/rest/service/ServiceTestBase.java b/server/src/test/java/org/apache/kylin/rest/service/ServiceTestBase.java index b45b27b..1d60a53 100644 --- a/server/src/test/java/org/apache/kylin/rest/service/ServiceTestBase.java +++ b/server/src/test/java/org/apache/kylin/rest/service/ServiceTestBase.java @@ -24,6 +24,7 @@ import org.apache.kylin.common.KylinConfig; import org.apache.kylin.common.util.LocalFileMetadataTestCase; import org.apache.kylin.metadata.cachesync.Broadcaster; import org.apache.kylin.rest.constant.Constant; +import org.apache.kylin.rest.security.ManagedUser; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -35,7 +36,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -71,18 +71,19 @@ public class ServiceTestBase extends LocalFileMetadataTestCase { Broadcaster.getInstance(config).notifyClearAll(); if (!userService.userExists("ADMIN")) { - userService.createUser(new User("ADMIN", "KYLIN", Arrays.asList(// - new UserGrantedAuthority(Constant.ROLE_ADMIN), new UserGrantedAuthority(Constant.ROLE_ANALYST), new UserGrantedAuthority(Constant.ROLE_MODELER)))); + userService.createUser(new ManagedUser("ADMIN", "KYLIN", false, Arrays.asList(// + new UserGrantedAuthority(Constant.ROLE_ADMIN), new UserGrantedAuthority(Constant.ROLE_ANALYST), + new UserGrantedAuthority(Constant.ROLE_MODELER)))); } if (!userService.userExists("MODELER")) { - userService.createUser(new User("MODELER", "MODELER", Arrays.asList(// - new UserGrantedAuthority(Constant.ROLE_ANALYST), new UserGrantedAuthority(Constant.ROLE_MODELER)))); + userService.createUser(new ManagedUser("MODELER", "MODELER", false, Arrays.asList(// + new UserGrantedAuthority(Constant.ROLE_ANALYST), new UserGrantedAuthority(Constant.ROLE_MODELER)))); } if (!userService.userExists("ANALYST")) { - userService.createUser(new User("ANALYST", "ANALYST", Arrays.asList(// - new UserGrantedAuthority(Constant.ROLE_ANALYST)))); + userService.createUser(new ManagedUser("ANALYST", "ANALYST", false, Arrays.asList(// + new UserGrantedAuthority(Constant.ROLE_ANALYST)))); } } http://git-wip-us.apache.org/repos/asf/kylin/blob/cf2f27a3/server/src/test/java/org/apache/kylin/rest/service/UserServiceTest.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/kylin/rest/service/UserServiceTest.java b/server/src/test/java/org/apache/kylin/rest/service/UserServiceTest.java index 0d4b580..c49b552 100644 --- a/server/src/test/java/org/apache/kylin/rest/service/UserServiceTest.java +++ b/server/src/test/java/org/apache/kylin/rest/service/UserServiceTest.java @@ -23,13 +23,13 @@ import java.util.ArrayList; import java.util.List; import org.apache.kylin.rest.constant.Constant; +import org.apache.kylin.rest.security.ManagedUser; import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; /** @@ -44,11 +44,12 @@ public class UserServiceTest extends ServiceTestBase { @Test public void testBasics() throws IOException { userService.deleteUser("ADMIN"); + Assert.assertTrue(!userService.userExists("ADMIN")); List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); authorities.add(new SimpleGrantedAuthority(Constant.ROLE_ADMIN)); - User user = new User("ADMIN", "PWD", authorities); + ManagedUser user = new ManagedUser("ADMIN", "PWD", false, authorities); userService.createUser(user); Assert.assertTrue(userService.userExists("ADMIN")); @@ -59,7 +60,8 @@ public class UserServiceTest extends ServiceTestBase { Assert.assertEquals(Constant.ROLE_ADMIN, ud.getAuthorities().iterator().next().getAuthority()); Assert.assertEquals(1, ud.getAuthorities().size()); - Assert.assertTrue(userService.listUserAuthorities().contains(Constant.ROLE_ADMIN)); + List<String> strings = userService.listUserAuthorities(); + Assert.assertTrue(strings.contains(Constant.ROLE_ADMIN)); } }
