Package com.rop.security

Source Code of com.rop.security.DefaultSecurityManager

/**
*
* 日    期:12-2-13
*/
package com.rop.security;

import com.rop.*;
import com.rop.annotation.HttpAction;
import com.rop.impl.DefaultServiceAccessController;
import com.rop.impl.SimpleRopRequestContext;
import com.rop.request.UploadFileUtils;
import com.rop.session.SessionManager;
import com.rop.utils.RopUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;

import java.util.*;

/**
* @author 陈雄华
* @version 1.0
*/
public class DefaultSecurityManager implements SecurityManager {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    protected ServiceAccessController serviceAccessController = new DefaultServiceAccessController();

    protected AppSecretManager appSecretManager = new FileBaseAppSecretManager();

    protected SessionManager sessionManager;

    protected InvokeTimesController invokeTimesController;

    protected FileUploadController fileUploadController;

    private static final Map<String, SubErrorType> INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS = new LinkedHashMap<String, SubErrorType>();

    static {
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("typeMismatch", SubErrorType.ISV_PARAMETERS_MISMATCH);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotNull", SubErrorType.ISV_MISSING_PARAMETER);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotEmpty", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Size", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Range", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Pattern", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Min", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Max", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMin", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMax", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Digits", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Past", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Future", SubErrorType.ISV_INVALID_PARAMETE);
        INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("AssertFalse", SubErrorType.ISV_INVALID_PARAMETE);
    }

    @Override
    public MainError validateSystemParameters(RopRequestContext rrc) {
        RopContext ropContext = rrc.getRopContext();
        MainError mainError = null;

        //1.检查appKey
        if (rrc.getAppKey() == null) {
            return MainErrors.getError(MainErrorType.MISSING_APP_KEY, rrc.getLocale());
        }
        if (!appSecretManager.isValidAppKey(rrc.getAppKey())) {
            return MainErrors.getError(MainErrorType.INVALID_APP_KEY, rrc.getLocale());
        }


        //2.检查会话
        mainError = checkSession(rrc);
        if (mainError != null) {
            return mainError;
        }

        //3.检查method参数
        if (rrc.getMethod() == null) {
            return MainErrors.getError(MainErrorType.MISSING_METHOD, rrc.getLocale());
        } else {
            if (!ropContext.isValidMethod(rrc.getMethod())) {
                return MainErrors.getError(MainErrorType.INVALID_METHOD, rrc.getLocale());
            }
        }

        //4.检查v参数
        if (rrc.getVersion() == null) {
            return MainErrors.getError(MainErrorType.MISSING_VERSION, rrc.getLocale());
        } else {
            if (!ropContext.isValidMethodVersion(rrc.getMethod(), rrc.getVersion())) {
                return MainErrors.getError(MainErrorType.UNSUPPORTED_VERSION, rrc.getLocale());
            }
        }

        //5.检查签名正确性
        mainError = checkSign(rrc);
        if (mainError != null) {
            return mainError;
        }

        //6.检查服务方法的版本是否已经过期
        if (rrc.getServiceMethodDefinition().isObsoleted()) {
            return MainErrors.getError(MainErrorType.METHOD_OBSOLETED, rrc.getLocale());
        }

        //7.检查请求HTTP方法的匹配性
        mainError = validateHttpAction(rrc);
        if (mainError != null) {
            return mainError;
        }

        //8.检查 format
        if (!MessageFormat.isValidFormat(rrc.getFormat())) {
            return MainErrors.getError(MainErrorType.INVALID_FORMAT, rrc.getLocale());
        }

        return null;
    }

    @Override
    public MainError validateOther(RopRequestContext rrctx) {

        MainError mainError = null;

        //1.判断应用/用户是否有权访问目标服务
        mainError = checkServiceAccessAllow(rrctx);
        if (mainError != null) {
            return mainError;
        }

        //2.判断应用/会话/用户访问服务的次数或频度是否超限
        mainError = checkInvokeTimesLimit(rrctx);
        if (mainError != null) {
            return mainError;
        }

        //3.如果是上传文件的服务,检查文件类型和大小是否满足要求
        mainError = checkUploadFile(rrctx);
        if (mainError != null) {
            return mainError;
        }

        //4.检查业务参数合法性
        mainError = validateBusinessParams(rrctx);
        if (mainError != null) {
            return mainError;
        }

        return null;
    }

    private MainError checkUploadFile(RopRequestContext rrctx) {
        ServiceMethodHandler serviceMethodHandler = rrctx.getServiceMethodHandler();
        if (serviceMethodHandler != null && serviceMethodHandler.hasUploadFiles()) {
            List<String> fileFieldNames = serviceMethodHandler.getUploadFileFieldNames();
            for (String fileFieldName : fileFieldNames) {
                String paramValue = rrctx.getParamValue(fileFieldName);
                if (paramValue != null) {
                    if (paramValue.indexOf("@") < 0) {
                        return MainErrors.getError(MainErrorType.UPLOAD_FAIL, rrctx.getLocale());
                    } else {
                        String fileType = UploadFileUtils.getFileType(paramValue);
                        if (!fileUploadController.isAllowFileType(fileType)) {
                            return MainErrors.getError(MainErrorType.UPLOAD_FAIL, rrctx.getLocale());
                        }
                        byte[] fileContent = UploadFileUtils.decode(paramValue);
                        if (fileUploadController.isExceedMaxSize(fileContent.length)) {
                            return MainErrors.getError(MainErrorType.UPLOAD_FAIL, rrctx.getLocale());
                        }
                    }
                }
            }
        }
        return null;
    }

    @Override
    public void setInvokeTimesController(InvokeTimesController invokeTimesController) {
        this.invokeTimesController = invokeTimesController;
    }

    @Override
    public void setServiceAccessController(ServiceAccessController serviceAccessController) {
        this.serviceAccessController = serviceAccessController;
    }

    @Override
    public void setAppSecretManager(AppSecretManager appSecretManager) {
        this.appSecretManager = appSecretManager;
    }

    @Override
    public void setSessionManager(SessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    @Override
    public void setFileUploadController(FileUploadController fileUploadController) {
        this.fileUploadController = fileUploadController;
    }

    private MainError checkInvokeTimesLimit(RopRequestContext rrctx) {
        if (invokeTimesController.isAppInvokeFrequencyExceed(rrctx.getAppKey())) {
            return MainErrors.getError(MainErrorType.EXCEED_APP_INVOKE_FREQUENCY_LIMITED, rrctx.getLocale());
        } else if (invokeTimesController.isAppInvokeLimitExceed(rrctx.getAppKey())) {
            return MainErrors.getError(MainErrorType.EXCEED_APP_INVOKE_LIMITED, rrctx.getLocale());
        } else if (invokeTimesController.isSessionInvokeLimitExceed(rrctx.getAppKey(), rrctx.getSessionId())) {
            return MainErrors.getError(MainErrorType.EXCEED_SESSION_INVOKE_LIMITED, rrctx.getLocale());
        } else if (invokeTimesController.isUserInvokeLimitExceed(rrctx.getAppKey(), rrctx.getSession())) {
            return MainErrors.getError(MainErrorType.EXCEED_USER_INVOKE_LIMITED, rrctx.getLocale());
        } else {
            return null;
        }
    }

    /**
     * 校验是否是合法的HTTP动作
     *
     * @param ropRequestContext
     */
    private MainError validateHttpAction(RopRequestContext ropRequestContext) {
        MainError mainError = null;
        HttpAction[] httpActions = ropRequestContext.getServiceMethodDefinition().getHttpAction();
        if (httpActions.length > 0) {
            boolean isValid = false;
            for (HttpAction httpAction : httpActions) {
                if (httpAction == ropRequestContext.getHttpAction()) {
                    isValid = true;
                    break;
                }
            }
            if (!isValid) {
                mainError = MainErrors.getError(MainErrorType.HTTP_ACTION_NOT_ALLOWED, ropRequestContext.getLocale());
            }
        }
        return mainError;
    }

    public ServiceAccessController getServiceAccessController() {
        return serviceAccessController;
    }

    public AppSecretManager getAppSecretManager() {
        return appSecretManager;
    }

    private MainError checkServiceAccessAllow(RopRequestContext smc) {
        if (!getServiceAccessController().isAppGranted(smc.getAppKey(), smc.getMethod(), smc.getVersion())) {
            MainError mainError = SubErrors.getMainError(SubErrorType.ISV_INVALID_PERMISSION, smc.getLocale());
            SubError subError = SubErrors.getSubError(SubErrorType.ISV_INVALID_PERMISSION.value(),
                    SubErrorType.ISV_INVALID_PERMISSION.value(),
                    smc.getLocale());
            mainError.addSubError(subError);
            if (mainError != null && logger.isErrorEnabled()) {
                logger.debug("未向ISV开放该服务的执行权限(" + smc.getMethod() + ")");
            }
            return mainError;
        } else {
            if (!getServiceAccessController().isUserGranted(smc.getSession(), smc.getMethod(), smc.getVersion())) {
                MainError mainError = MainErrors.getError(MainErrorType.INSUFFICIENT_USER_PERMISSIONS, smc.getLocale());
                SubError subError = SubErrors.getSubError(SubErrorType.ISV_INVALID_PERMISSION.value(),
                        SubErrorType.ISV_INVALID_PERMISSION.value(),
                        smc.getLocale());
                mainError.addSubError(subError);
                if (mainError != null && logger.isErrorEnabled()) {
                    logger.debug("未向会话用户开放该服务的执行权限(" + smc.getMethod() + ")");
                }
                return mainError;
            }
            return null;
        }
    }

    private MainError validateBusinessParams(RopRequestContext ropRequestContext) {
        List<ObjectError> errorList =
                (List<ObjectError>) ropRequestContext.getAttribute(SimpleRopRequestContext.SPRING_VALIDATE_ERROR_ATTRNAME);

        //将Bean数据绑定时产生的错误转换为Rop的错误
        if (errorList != null && errorList.size() > 0) {
            return toMainErrorOfSpringValidateErrors(errorList, ropRequestContext.getLocale());
        } else {
            return null;
        }
    }

    /**
     * 检查签名的有效性
     *
     * @param ctx
     * @return
     */
    private MainError checkSign(RopRequestContext ctx) {

        //系统级签名开启,且服务方法需求签名
        if (ctx.isSignEnable()) {
            if (!ctx.getServiceMethodDefinition().isIgnoreSign()) {
                if (ctx.getSign() == null) {
                    return MainErrors.getError(MainErrorType.MISSING_SIGNATURE, ctx.getLocale());
                } else {

                    //获取需要签名的参数
                    List<String> ignoreSignFieldNames = ctx.getServiceMethodHandler().getIgnoreSignFieldNames();
                    HashMap<String, String> needSignParams = new HashMap<String, String>();
                    for (Map.Entry<String, String> entry : ctx.getAllParams().entrySet()) {
                        if (!ignoreSignFieldNames.contains(entry.getKey())) {
                            needSignParams.put(entry.getKey(), entry.getValue());
                        }
                    }

                    //查看密钥是否存在,不存在则说明appKey是非法的
                    String signSecret = getAppSecretManager().getSecret(ctx.getAppKey());
                    if (signSecret == null) {
                        throw new RopException("无法获取" + ctx.getAppKey() + "对应的密钥");
                    }

                    String signValue = RopUtils.sign(needSignParams, signSecret);
                    if (!signValue.equals(ctx.getSign())) {
                        if (logger.isErrorEnabled()) {
                            logger.error(ctx.getAppKey() + "的签名不合法,请检查");
                        }
                        return MainErrors.getError(MainErrorType.INVALID_SIGNATURE, ctx.getLocale());
                    } else {
                        return null;
                    }
                }
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn(ctx.getMethod() + "忽略了签名");
                }
                return null;
            }
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("Rop关闭了签名检查,可通过将配置文件的“needCheckSign”开启。");
            }
            return null;
        }
    }


    /**
     * 是否是合法的会话
     *
     * @param sessionId
     * @return
     */
    private MainError checkSession(RopRequestContext smc) {
        //需要进行session检查
        if (smc.getServiceMethodHandler() != null &&
                smc.getServiceMethodHandler().getServiceMethodDefinition().isNeedInSession()) {
            if (smc.getSessionId() == null) {
                return MainErrors.getError(MainErrorType.MISSING_SESSION, null);
            } else {
                if (!isValidSession(smc)) {
                    return MainErrors.getError(MainErrorType.INVALID_SESSION, null);
                }
            }
        }
        return null;
    }

    private boolean isValidSession(RopRequestContext smc) {
        if (sessionManager.getSession(smc.getSessionId()) == null) {
            if (logger.isDebugEnabled()) {
                logger.debug(smc.getSessionId() + "会话不存在,请检查。");
            }
            return false;
        } else {
            return true;
        }
    }

    /**
     * 将通过JSR 303框架校验的错误转换为Rop的错误体系
     *
     * @param allErrors
     * @param locale
     * @return
     */
    private MainError toMainErrorOfSpringValidateErrors(List<ObjectError> allErrors, Locale locale) {
        if (hastSubErrorType(allErrors, SubErrorType.ISV_MISSING_PARAMETER)) {
            return getBusinessParameterMainError(allErrors, locale, SubErrorType.ISV_MISSING_PARAMETER);
        } else if (hastSubErrorType(allErrors, SubErrorType.ISV_PARAMETERS_MISMATCH)) {
            return getBusinessParameterMainError(allErrors, locale, SubErrorType.ISV_PARAMETERS_MISMATCH);
        } else {
            return getBusinessParameterMainError(allErrors, locale, SubErrorType.ISV_INVALID_PARAMETE);
        }
    }

    /**
     * 判断错误列表中是否包括指定的子错误
     *
     * @param allErrors
     * @param subErrorType1
     * @return
     */
    private boolean hastSubErrorType(List<ObjectError> allErrors, SubErrorType subErrorType1) {
        for (ObjectError objectError : allErrors) {
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                if (INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.containsKey(fieldError.getCode())) {
                    SubErrorType tempSubErrorType = INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.get(fieldError.getCode());
                    if (tempSubErrorType == subErrorType1) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 生成对应子错误的错误类
     *
     * @param allErrors
     * @param locale
     * @param subErrorType
     * @return
     */
    private MainError getBusinessParameterMainError(List<ObjectError> allErrors, Locale locale, SubErrorType subErrorType) {
        MainError mainError = SubErrors.getMainError(subErrorType, locale);
        for (ObjectError objectError : allErrors) {
            if (objectError instanceof FieldError) {
                FieldError fieldError = (FieldError) objectError;
                SubErrorType tempSubErrorType = INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.get(fieldError.getCode());
                if (tempSubErrorType == subErrorType) {

                    String subErrorCode = SubErrors.getSubErrorCode(tempSubErrorType, fieldError.getField(),fieldError.getRejectedValue());

                    SubError subError = SubErrors.getSubError(subErrorCode, tempSubErrorType.value(), locale,
                            fieldError.getField(), fieldError.getRejectedValue());
                    mainError.addSubError(subError);
                }
            }
        }
        return mainError;
    }
}

TOP

Related Classes of com.rop.security.DefaultSecurityManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.