/*
* Copyright (c) 2008-2016 Computer Network Information Center (CNIC), Chinese Academy of Sciences.
*
* This file is part of Duckling project.
*
* Licensed 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 cn.vlabs.umt.services.account;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import org.apache.log4j.Logger;
import tebie.applib.api.APIContext;
import tebie.applib.api.IClient;
import cn.vlabs.duckling.api.umt.rmi.userv7.SearchField;
import cn.vlabs.umt.common.datasource.CoreMailDBException;
import cn.vlabs.umt.common.util.CommonUtils;
import cn.vlabs.umt.common.util.Config;
import cn.vlabs.umt.services.user.bean.CoreMailUserInfo;
import cn.vlabs.umt.services.user.bean.User;
/**
* 用户远程调用API的Client
*
* @author lvly
* @since 2013-1-10
*/
public class CoreMailUseableClient extends ICoreMailClient{
/**
* API信息,得去CoreMail那里用管理员账号,开通,并配置到umt.properties
* */
private Config umtConfig;
private ICoreMailDBDAO coremailDAO;
/**
* 获得配置文件,umt.properties
* */
public Config getUmtConfig(){
return this.umtConfig;
}
/**
* 构造方法
* @param config 配置文件实体类
* */
public CoreMailUseableClient(Config config,ICoreMailDBDAO coremailDAO) {
this.umtConfig = config;
this.coremailDAO=coremailDAO;
}
public static final String BEAN_ID="coreMailClient";
private static final Logger LOG = Logger.getLogger(CoreMailUseableClient.class);
private static final String KEY_API_IP = "umt.coremail.api.ip";
private static final String KEY_API_PORT = "umt.coremail.api.port";
private static final String KEY_DEFAULT_API_IP = "127.0.0.1";
private static final int KEY_DEFAULT_API_PORT = 8080;
private static final String KEY_PROVIDER_ID="umt.coremail.api.providerId";
private static final String KEY_ORG_ID="umt.coremail.api.orgId";
private static final String KEY_EMAIL_DOMAIN="umt.coremail.api.email.domain";
private static final String KEY_API_USER_STATUS="umt.coremail.api.user.status";
private static final String KEY_API_USER_COS_ID="umt.coremail.api.user.cosId";
private static final String KEY_API_USER_QUO_DELTA="umt.coremail.api.user.quotaDelta";
/**
* 获得于CoreMail的通讯客户端
* */
private IClient getCoreMailClient() throws IOException {
return getCoreMailClient(1000);
}
private IClient getCoreMailClient(int timeout)throws IOException {
Socket socket = new Socket(umtConfig.getStringProp(KEY_API_IP, KEY_DEFAULT_API_IP), umtConfig.getInt(
KEY_API_PORT, KEY_DEFAULT_API_PORT));
socket.setSoTimeout(timeout);
return APIContext.getClient(socket);
}
/**
* 邮件系统验证用户是否存在
* @param usreName 用户邮箱
* */
public boolean isUserExt(String userName) {
IClient client = null;
APIContext context = null;
if(isBlack(formatEmail(userName))){
return false;
}
try {
client = getCoreMailClient();
context=client.userExist(formatEmail(userName));
switch (context.getRetCode()) {
case APIContext.RC_NORMAL:
return true;
default:
return false;
}
} catch (IOException e) {
LOG.error(e.getMessage());
LOG.debug(e.getMessage(),e);
return false;
}finally{
closeClient(client);
}
}
/**
* 更改用户的对应密码,注意,请先用authenticate验证,就密码是否相同
*
* @param userName
* 用户账户
* @param newPassword
* ,明文密码
* @return 是否更改成功
* */
public boolean changePassword(String userName, String newPassword) {
IClient client = null;
APIContext context = null;
try {
client = getCoreMailClient();
context = client.changeAttrs(userName, "password=" + URLEncoder.encode(newPassword,"UTF-8"));
switch (context.getRetCode()) {
case APIContext.RC_USER_NOT_FOUND:
LOG.info("Not Found User :" + userName);
return false;
case APIContext.RC_NORMAL:
LOG.info("passWordChange Success:" + userName);
return true;
default:
return false;
}
} catch (IOException e) {
LOG.error(e.getMessage());
LOG.debug(e.getMessage(),e);
return false;
} finally {
closeClient(client);
}
}
/**
* 每次操作务必调用此方法,关闭连接
*
* @param client
* API要求每个线程都有独立的client,并且执行完成以后,释放掉
* */
private void closeClient(IClient client) {
if (client != null) {
try {
client.close();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
}
/**
* 验证邮箱用户名密码,是否正确
*
* @param userName
* 用户名
* @param passWord
* 用户密码
* */
public CoreMailAuthenticateResult authenticate(String userName, String passWord) {
IClient client = null;
APIContext context = null;
if(isBlack(userName)){
return new CoreMailAuthenticateResult(false, false);
}
if(umtConfig.getBooleanProp("use.coremail.db", false)){
try {
long start=System.currentTimeMillis();
CoreMailUserInfo userInfo=coremailDAO.authticate(formatEmail(userName), passWord);
/*if(userInfo==null){
LOG.info("db:password Error:"+userName);
return new CoreMailAuthenticateResult(false, false);
}*/
if(userInfo!=null){
return validateCanAccessFromUserInfo(start,userInfo,true);
}
} catch (CoreMailDBException e) {
if(CoreMailDBException.WHY_DB_ERROR.equals(e.getWhy())){
LOG.error(e.getWhy(),e);
}else if(CoreMailDBException.WHY_PWD_ERROR.equals(e.getWhy())){
LOG.info("user "+userName+" encType strange!!!");
}
}
}
try {
client = getCoreMailClient();
context = client.authenticate(formatEmail(userName), passWord);
switch (context.getRetCode()) {
case APIContext.RC_USER_NOT_FOUND:
LOG.info("Not Found User :" + userName);
return new CoreMailAuthenticateResult(false, false);
case APIContext.RC_PASSWORD_ERR:
LOG.info("passWordError in User:" + userName);
return new CoreMailAuthenticateResult(false, true);
case APIContext.RC_NORMAL:{
long start=System.currentTimeMillis();
CoreMailUserInfo coreMailUserInfo=getCoreMailUserInfo(formatEmail(userName));
return validateCanAccessFromUserInfo(start,coreMailUserInfo,false);
}default:{
LOG.info("unkown code :" + context.getRetCode());
return new CoreMailAuthenticateResult(false, false);
}
}
} catch (IOException e) {
LOG.error(e.getMessage());
LOG.debug(e.getMessage(),e);
return new CoreMailAuthenticateResult(false, false);
} finally {
closeClient(client);
}
}
private CoreMailAuthenticateResult validateCanAccessFromUserInfo(long start,CoreMailUserInfo userInfo,boolean db){
if(userInfo==null){
LOG.info("why userinfo is null?");
return new CoreMailAuthenticateResult(false, false);
}
if(!CoreMailUserInfo.STATUS_NORMAL.equals(userInfo.getStatus())){
LOG.info("user's info is null! cause user's status is unnormal");
return new CoreMailAuthenticateResult(true, true,userInfo);
}else if(userInfo.isExpired()){
LOG.info("user is expired! ");
return new CoreMailAuthenticateResult(true, true,userInfo);
}
LOG.info("validate["+userInfo.getEmail()+"] password use "+(db?"db":"api")+" "+(System.currentTimeMillis()-start)+"ms");
return new CoreMailAuthenticateResult(true, true,userInfo);
}
/**
* 用户登录
*
* @param userName
* 用户名
* @param passWord
* 密码
* @return 返回操作是否成功
* */
public boolean login(String userName, String passWord) {
if (authenticate(userName, passWord).isSuccess()) {
IClient client = null;
APIContext context = null;
if(isBlack(userName)){
return false;
}
try {
client = getCoreMailClient();
context = client.userLoginEx(userName, "type=API");
switch (context.getRetCode()) {
case APIContext.RC_NORMAL: {
return true;
}
case APIContext.RC_USER_NOT_FOUND: {
LOG.error("userNotFound");
break;
}
case APIContext.RC_SES_ERROR: {
LOG.error("SessionError");
break;
}
default: {
LOG.error("unkown error,error code:" + context.getRetCode());
break;
}
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}finally{
closeClient(client);
}
}
return false;
}
/**
* 从URL规则的字符串里面提取值,如
* getParameter("&userName=zs&password=123","userName"),即会返回zs
*
* @param encoded
* 已经encode过的字符串
* @param key
* 需要提取的key
* @return value
* */
private String getParameter(String encoded, String key) throws UnsupportedEncodingException {
int start;
if (encoded.startsWith(key + '=')) {
start = key.length() + 1;
} else {
int i = encoded.indexOf('&' + key + '=');
if (i == -1) {
return null;
}
start = i + key.length() + 2;
}
int end = encoded.indexOf('&', start);
String value = (end == -1) ? encoded.substring(start) : encoded.substring(start, end);
return URLDecoder.decode(value, "UTF-8");
}
/**
* 获得用户信息,请调用这个方法前,用authenticate(userName,passWord)验证改用户是否有效
*
* @param userName
* @return 用户信息
* */
public CoreMailUserInfo getCoreMailUserInfo(String userName) {
IClient client = null;
APIContext context = null;
if(isBlack(userName)){
return null;
}
try {
client = getCoreMailClient();
context = client.getAttrsEx(userName, "true_name=&user_id=&user_status=&user_expiry_date=");
if (APIContext.RC_NORMAL == context.getRetCode()) {
String result = context.getResult();
String expireTime=getParameter(result, "user_expiry_date");
String trueName = getParameter(result, "true_name");
String status=getParameter(result, "user_status");
CoreMailUserInfo userInfo=new CoreMailUserInfo();
userInfo.setEmail(userName.toLowerCase());
userInfo.setTrueName(CommonUtils.isNull(trueName)?userName:trueName);
userInfo.setExpireTime(expireTime);
userInfo.setStatus(status);
return userInfo;
}
} catch (IOException e) {
LOG.error(e.getMessage());
LOG.debug(e.getMessage(),e);
}finally{
closeClient(client);
}
return null;
}
private Attributes abstractSearch(String orgIds,String[] userAttributes, Attributes[] filters,String[] orders,int offset,int size){
try {
APIContext obj = getCoreMailClient().listUsersJNDI(orgIds, null, true, true, userAttributes, filters, orders, offset, size);
return (Attributes)(obj.getResultEx());
} catch (IOException e) {
LOG.error(e.getMessage(),e);
} catch (NamingException e) {
LOG.error(e.getMessage(),e);
}
return null;
}
private Attributes getFilter(SearchField field,String keyword){
Attributes filter = new BasicAttributes();
filter.put("op", 6); // LIKE
filter.put("val", "%"+keyword+"%");
switch(field){
case TRUE_NAME:{
filter.put("name","true_name");
break;
}
case DOMAIN:{
filter.put("name","domain_name");
break;
}
case CSTNET_ID:{
filter.put("name","user_id");
break;
}
default:throw new RuntimeException("the CoreMail Field Unkown");
}
return filter;
}
private String getOrderBy(SearchField field){
switch(field){
case TRUE_NAME:{
return "true_name";
}
case DOMAIN:{
return "domain_name";
}
case CSTNET_ID:{
return "user_id";
}
default:throw new RuntimeException("the CoreMail Field can't be ALL");
}
}
/**
* 获取次关键字有多少结果
* @param keyword
* */
public int getSize(String domain,String keyword,SearchField field){
Attributes filter=getFilter(field,keyword);
int total=0;
for(String orgId:getOrgId(domain)){
try {
Attributes result=abstractSearch(orgId,new String[]{}, new Attributes[]{filter}, null,0,-1);
total+=(int)result.get("total").get();
} catch (NamingException e) {
LOG.error(e.getMessage(),e);
}
}
return total;
}
private String[] getOrgId(String domain) {
APIContext context;
try {
if("all".equals(domain)){
return new String[]{null};
}
else if(!CommonUtils.isNull(domain)&&domainExist(domain)){
context = getCoreMailClient().getOrgListByDomain(domain);
return context.getResult().split(",");
}
return new String[]{};
} catch (IOException e) {
LOG.error(e.getMessage(),e);
return new String[]{};
}
}
/**
* 根据关键字搜索
* @param keyword 关键字
* @param field 搜索字段
* @param offset 偏移
* @param size -1为无限制
* @return
*/
public List<User> searchByKeyword(String keyword,String domain,SearchField field,int offset,int size){
String[] userAttributes = {"user_id","domain_name", "true_name"};
// 定义一个域名查询条件查询条件
Attributes filter =getFilter(field,keyword);
List<User> list=new ArrayList<User>();
for(String orgId:getOrgId(domain)){
Attributes result=abstractSearch(orgId,userAttributes, new Attributes[]{filter}, new String[]{getOrderBy(field)},offset,size);
if(result!=null){
Attribute u=result.get("u");
addUserToList(u, list);
}
}
return list;
}
public void addUserToList(Attribute u,List<User> list){
for(int i=0;i<u.size();i++){
try {
Attributes userInfo=(Attributes)u.get(i);
User user=new User();
user.setCstnetId(userInfo.get("user_id").get()+"@"+userInfo.get("domain_name").get());
Object trueName=userInfo.get("true_name").get();
user.getTrueName();
user.setTrueName(trueName==null?null:trueName.toString());
user.setType(User.USER_TYPE_CORE_MAIL);
list.add(user);
} catch (NamingException e) {
LOG.error(e.getMessage(),e);
}
}
}
/**
* 检查CoreMail域名是否已存在
* */
public boolean domainExist(String domainName){
if(isBlack("example@"+domainName)){
return false;
}
try {
String domain=CommonUtils.trim(domainName);
if(umtConfig.getBooleanProp("use.coremail.db", false)){
try{
return coremailDAO.isDomainExits(domain);
}catch(CoreMailDBException e){
LOG.error(e.getMessage(),e);
}
}
APIContext context=getCoreMailClient().domainExist(domain);
return !CommonUtils.isNull(context.getResult())&&context.getRetCode()==APIContext.RC_NORMAL;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 创建用户
* @param username
* @param password
*/
public boolean createUser(String username,String trueName, String password) {
IClient client = null;
APIContext context = null;
try {
client = getCoreMailClient(5000);
String param="password="+password+
"&domain_name="+umtConfig.getStringProp(KEY_EMAIL_DOMAIN, "")+
"&user_status="+umtConfig.getStringProp(KEY_API_USER_STATUS, "")+
"&cos_id="+umtConfig.getStringProp(KEY_API_USER_COS_ID, "")+
""a_delta="+umtConfig.getStringProp(KEY_API_USER_QUO_DELTA, "")+
"&true_name="+trueName;
context = client.createUser(
umtConfig.getStringProp(KEY_PROVIDER_ID, ""),
umtConfig.getStringProp(KEY_ORG_ID, ""),
getUserName(username), param
);
if(context.getRetCode()==APIContext.RC_NORMAL){
return true;
}else{
LOG.error(context.getErrorInfo()+"["+param+"]");
return false;
}
} catch (IOException e) {
LOG.error(e.getMessage());
LOG.debug(e.getMessage(),e);
return false;
}finally{
closeClient(client);
}
}
public void print(APIContext context,String oper){
System.out.println("The Result of Operation["+oper+"]:");
System.out.println("{");
System.out.println("\tError Info:"+context.getErrorInfo());
System.out.println("\tResult:"+context.getResult());
System.out.println("\tReturn Code:"+context.getRetCode());
System.out.println("\tResult Ex:"+context.getResultEx());
System.out.println("}\n\n");
}
}