ログ日記

作業ログと日記とメモ

wicket-auth-rolesをカスタマイズする その2

昨日の続き。
権限の一カ所集約はやめて、リンク先ページクラスの権限がないBookmarkablePageLinkに非表示処理を追加する。


AppAnnotationsRoleAuthorizationStrategy.java

public class AppAnnotationsRoleAuthorizationStrategy extends AnnotationsRoleAuthorizationStrategy {
    public AppAnnotationsRoleAuthorizationStrategy(IRoleCheckingStrategy roleCheckingStrategy) {
        super(roleCheckingStrategy);
    }

    @Override
    public boolean isActionAuthorized(Component component, Action action) {
        boolean ret = super.isActionAuthorized(component, action);

        if (!ret)
            return ret;

        if (!(component instanceof BookmarkablePageLink))
            return ret;
        BookmarkablePageLink<?> link = (BookmarkablePageLink<?>) component;
        // ページクラスの表示権限がない場合はそれに対するリンクも表示しない
        Class<?> componentClass = link.getPageClass();
        if (!check(action, componentClass.getAnnotation(AuthorizeAction.class)))
            return false;

        final AuthorizeActions authorizeActionsAnnotation = componentClass.getAnnotation(AuthorizeActions.class);
        if (authorizeActionsAnnotation != null) {
            for (final AuthorizeAction authorizeActionAnnotation : authorizeActionsAnnotation.actions()){
                if (!check(action, authorizeActionAnnotation))
                    return false;
            }
        }

        return true;
    }


    /**
     * Copy from AnnotationsRoleAuthorizationStrategy.
     * @param action
     *            The action to check
     * @param authorizeActionAnnotation
     *            The annotations information
     * @return False if the action is not authorized
     */
    private boolean check(final Action action, final AuthorizeAction authorizeActionAnnotation)
    {
        if (authorizeActionAnnotation != null){
            if (action.getName().equals(authorizeActionAnnotation.action())){
                if (hasAny(new Roles(authorizeActionAnnotation.deny())))
                    return false;

                Roles roles = new Roles(authorizeActionAnnotation.roles());
                if (!(isEmpty(roles) || hasAny(roles)))
                    return false;
            }
        }
        return true;
    }

AppRoleAuthorizationStrategy.java

public class AppRoleAuthorizationStrategy extends CompoundAuthorizationStrategy {
    public AppRoleAuthorizationStrategy(final IRoleCheckingStrategy roleCheckingStrategy)
    {
        add(new AppAnnotationsRoleAuthorizationStrategy(roleCheckingStrategy));
        add(new MetaDataRoleAuthorizationStrategy(roleCheckingStrategy));
    }
}


AppWebApplication.java

    @Override
    protected void init(){
        super.init();

        getSecuritySettings().setAuthorizationStrategy(new AppRoleAuthorizationStrategy(this));


このままでは権限設定があちこちのクラスに散らかって、全部をまとめて見ようとすると困ったことになるんだけど、それはカスタムドックレットで対応することにした。



ちょっとやっつけ感があるがこんな感じ。

    private void addAuthList(List<String> list, String auth){
        auth = auth.trim();

        if (!list.contains(auth))
            list.add(auth);
    }
    private void parseAuthParam(List<String> list, String auths){
        auths = auths.replace("\"", "");
        if (auths.charAt(0) != '{'){
            addAuthList(list, auths);
            return;
        }
        auths = auths.substring(1, auths.length() - 1);
        String[] authArr = auths.split(",");
        for (String auth: authArr){
            addAuthList(list, auth);
        }
    }
    private void parseAnnotationValues(List<String> list, ClassDoc classdoc){
        AnnotationDesc[] annotations = classdoc.annotations();
        for (AnnotationDesc desc: annotations){
            AnnotationTypeDoc type = desc.annotationType();
            if (type.qualifiedName().equals(AUTHORIZE_INSTANTIATION)){
                ElementValuePair[] elements = desc.elementValues();
                for (ElementValuePair val: elements){
                    parseAuthParam(list, val.value().toString());
                }

            }else if (type.qualifiedName().equals(AUTHORIZE_ACTION)){
                ElementValuePair[] elements = desc.elementValues();
                for (ElementValuePair val: elements){
                    if (val.value().toString().equals("\"RENDER\""))
                        continue;
                    parseAuthParam(list, val.value().toString());
                }

            }
        }
        if (list.size() != 0)
            return;

        ClassDoc superClass = classdoc.superclass();
        if (superClass != null)
            parseAnnotationValues(list, superClass);
    }

まだスーパークラスをたどっていく部分は正確ではない。
各クラスごとに指定している権限はORでクラス階層ごとの権限はANDで結合するのが仕様?スーパークラスに複数の権限があってサブクラスにも複数の権限があったらややこしいので、どちらかに統一した方がいいかもしれない。