/*
* 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.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.kylin.common.KylinConfig;
import org.apache.kylin.common.persistence.ResourceStore;
import org.apache.kylin.common.persistence.Serializer;
import org.apache.kylin.common.util.JsonUtil;
import org.apache.kylin.rest.constant.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
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;
/**
*/
@Component("userService")
public class UserService implements UserDetailsManager {
private Logger logger = LoggerFactory.getLogger(UserService.class);
public static final String DIR_PREFIX = "/user/";
protected ResourceStore aclStore;
@PostConstruct
public void init() throws IOException {
aclStore = ResourceStore.getStore(KylinConfig.getInstanceFromEnv());
logger.debug("UserService init");
}
@Override
@PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
public void createUser(UserDetails user) {
updateUser(user);
}
@Override
@PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN)
public void updateUser(UserDetails user) {
try {
deleteUser(user.getUsername());
String id = getId(user.getUsername());
aclStore.putResource(id, new UserInfo(user), 0, UserInfoSerializer.getInstance());
logger.debug("update user : {}", user.getUsername());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void deleteUser(String userName) {
try {
String id = getId(userName);
aclStore.deleteResource(id);
logger.debug("delete user : {}", userName);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void changePassword(String oldPassword, String newPasswor) {
throw new UnsupportedOperationException();
}
@Override
public boolean userExists(String userName) {
try {
logger.debug("judge user exist: {}", userName);
return aclStore.exists(getId(userName));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
try {
UserInfo userInfo = aclStore.getResource(getId(userName), UserInfo.class, UserInfoSerializer.getInstance());
if (userInfo == null) {
throw new UsernameNotFoundException("User:" + userName + " Not found");
}
logger.debug("load user : {}", userName);
return wrap(userInfo);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<String> listUserAuthorities() {
List<String> all = new ArrayList<String>();
for (UserDetails user : listUsers()) {
for (GrantedAuthority auth : user.getAuthorities()) {
if (!all.contains(auth.getAuthority())) {
all.add(auth.getAuthority());
}
}
}
return all;
}
public List<UserDetails> listUsers() {
List<UserDetails> all = new ArrayList<UserDetails>();
try {
List<UserInfo> userInfos = aclStore.getAllResources(DIR_PREFIX, UserInfo.class, UserInfoSerializer.getInstance());
for (UserInfo info : userInfos) {
all.add(wrap(info));
}
} catch (IOException e) {
throw new RuntimeException("Failed to list users", e);
}
return all;
}
public static String getId(String userName) {
return DIR_PREFIX + userName;
}
private 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);
}
public static class UserInfoSerializer implements Serializer<UserInfo> {
private static final UserInfoSerializer serializer = new UserInfoSerializer();
private UserInfoSerializer() {
}
public static UserInfoSerializer getInstance() {
return serializer;
}
@Override
public void serialize(UserInfo userInfo, DataOutputStream out) throws IOException {
String json = JsonUtil.writeValueAsString(userInfo);
out.writeUTF(json);
}
@Override
public UserInfo deserialize(DataInputStream in) throws IOException {
String json = in.readUTF();
return JsonUtil.readValue(json, UserInfo.class);
}
}
}