Jaspic模块没有将主体传播到JBoss 7.4中的本地EJB [英] Jaspic module not propagating principal to local EJB in JBoss 7.4

查看:162
本文介绍了Jaspic模块没有将主体传播到JBoss 7.4中的本地EJB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的JSR-196模块,基本上委托给一个将角色委托给OAuth授予调用的服务。

I have a custom, JSR-196 module, that basically delegates to a service that delegates roles to a OAuth "grants" call.

它可以从一个servlet(request.getUserPrincipal()工作正常)。

It does work from a servlet (request.getUserPrincipal() works fine).

它不会传播到EJB调用,其中SessionContext.getCallerPrincipal()返回一个带有anonymous而不是expect的SimplePrincipal用户名/角色。

It does not propagate to EJB calls, where SessionContext.getCallerPrincipal() returns a SimplePrincipal with "anonymous" instead of expected username / roles.

MycompanyPrincipal是一个简单的类,带有一个简单的getName()和一些自定义属性。

MycompanyPrincipal is a simple class, with a simple getName() and some custom properties.

似乎SubjectInfo.getAuthenticatedSubject()没有委托人。

It seems that SubjectInfo.getAuthenticatedSubject() has no principal.

我设法为此做了一个丑陋的解决方法,请参阅下面的// WORKAROUND。

I managed to make an ugly workaround for that, see "// WORKAROUND" below.

尽管如此,我仍然希望以正确的方式做到这一点(如果可能的话,甚至标准/便携式)。

Still, I'd want to do it the right way (even standard/portable, if possible).

这是我在standalone.xml中定义安全域的地方:

Here is where I define my security domain in standalone.xml:

                <security-domain name="mycompany" cache-type="default">
                    <authentication-jaspi>
                        <login-module-stack name="lm-stack">
                            <login-module code="UsersRoles" flag="required">
                                <module-option name="usersProperties" value="../standalone/configuration/jaspi-users.properties"/>
                                <module-option name="rolesProperties" value="../standalone/configuration/jaspi-roles.properties"/>
                            </login-module>
                        </login-module-stack>
                        <auth-module code="be.mycompany.api.authentication.jaspi.MycompanyAuthModule" flag="required" login-module-stack-ref="lm-stack"/>
                    </authentication-jaspi>
                </security-domain>

这是我的jboss-web.xml:

And here is my jboss-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
    <context-root>api/rules/dev</context-root>
    <security-domain>mycompany</security-domain>
    <valve>
        <class-name>org.jboss.as.web.security.jaspi.WebJASPIAuthenticator</class-name>
    </valve>
</jboss-web>

模块本身是我的应用程序的一部分(我的战争中的一个罐子)。 EJB在其他JAR中定义,也最终在WEB-INF / lib中。

The module itself is part of my application (a jar in my war). The EJBs are defined in other JARs, that also end-up in WEB-INF/lib.

serviceSubject.getPrincipals().add(degroofPrincipal)

这是我的模块(更改了对静态方法调用的ejb调用):

Here is my module (changed ejb calls to static method calls):

package be.mycompany.api.authentication.jaspi;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.message.AuthException;
import javax.security.auth.message.AuthStatus;
import javax.security.auth.message.MessageInfo;
import javax.security.auth.message.MessagePolicy;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.callback.GroupPrincipalCallback;
import javax.security.auth.message.config.ServerAuthContext;
import javax.security.auth.message.module.ServerAuthModule;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;
import org.jboss.security.SecurityContext;
import org.jboss.security.SecurityContextAssociation;
import org.jboss.security.SubjectInfo;

/**
 *
 * @author devyam
 */
public class MycompanyAuthModule implements ServerAuthModule, ServerAuthContext {

    private static final String BEARER_PREFIX = "bearer ";

    private CallbackHandler handler;
    private final Class<?>[] supportedMessageTypes = new Class[]{HttpServletRequest.class, HttpServletResponse.class};

    protected String delegatingLoginContextName = null;
//    private MycompanyAuthenticationService mycompanyAuthenticationService;

    /**
     * <p>
     * Creates an instance of {@code HTTPBasicServerAuthModule}.
     * </p>
     */
    public MycompanyAuthModule() {
//        lookupMycompanyAuthenticationService();
    }

    /**
     * <p>
     * Creates an instance of {@code HTTPBasicServerAuthModule} with the
     * specified delegating login context name.
     * </p>
     *
     * @param delegatingLoginContextName the name of the login context
     * configuration that contains the JAAS modules that are to be called by
     * this module.
     */
    public MycompanyAuthModule(String delegatingLoginContextName) {
        this();
        this.delegatingLoginContextName = delegatingLoginContextName;
    }

    @Override
    public void initialize(MessagePolicy requestPolicy,
            MessagePolicy responsePolicy, CallbackHandler handler,
            @SuppressWarnings("rawtypes") Map options) throws AuthException {

        this.handler = handler;
    }

    /**
     * WebLogic 12c calls this before Servlet is called, Geronimo v3 after,
     * JBoss EAP 6 and GlassFish 3.1.2.2 don't call this at all. WebLogic
     * (seemingly) only continues if SEND_SUCCESS is returned, Geronimo
     * completely ignores return value.
     */
    @Override
    public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException {
        return AuthStatus.SEND_SUCCESS;
    }

    @Override
    public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException {
        HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage();
        HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage();

        String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (authHeader != null && authHeader.startsWith(BEARER_PREFIX)) {
            String token = authHeader.substring(BEARER_PREFIX.length());

            MycompanyPrincipal mycompanyPrincipal = MycompanyAuthenticationService.createPrincipal(token);

            List<String> groups = MycompanyAuthenticationService.getGroups(mycompanyPrincipal);
            String[] groupArray = groups.toArray(new String[0]);

            CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject, mycompanyPrincipal);
            GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject, groupArray);

            try {
                handler.handle(new Callback[]{callerPrincipalCallback, groupPrincipalCallback});
            } catch (IOException | UnsupportedCallbackException exception) {
                throw new RuntimeException(exception);
            }

            //////// WORKAROUND: doesn't work without this in EJBs!
            SecurityContext oldContext = SecurityContextAssociation.getSecurityContext();
            SubjectInfo subjectInfo = oldContext.getSubjectInfo();
            subjectInfo.setAuthenticatedSubject(serviceSubject);
            SecurityContextAssociation.setPrincipal(mycompanyPrincipal);

            serviceSubject.getPrincipals().add(mycompanyPrincipal);
            ////////////// end of workaround

            return AuthStatus.SUCCESS;
        }

        response.setStatus(401);

        return AuthStatus.FAILURE;
    }

    /**
     * A compliant implementation should return HttpServletRequest and
     * HttpServletResponse, so the delegation class {@link ServerAuthContext}
     * can choose the right SAM to delegate to. In this example there is only
     * one SAM and thus the return value actually doesn't matter here.
     */
    @Override
    public Class<?>[] getSupportedMessageTypes() {
        return supportedMessageTypes;
    }

    @Override
    public void cleanSubject(MessageInfo messageInfo, Subject subject)
            throws AuthException {
    }

//    private void lookupMycompanyAuthenticationService() throws RuntimeException {
//        try {
//            BeanManager beanManager = InitialContext.doLookup("java:comp/BeanManager");
//            Bean<?> mycompanyAuthenticationServiceBean = beanManager.getBeans(MycompanyAuthenticationService.class).iterator().next();
//            CreationalContext creationalContext = beanManager.createCreationalContext(mycompanyAuthenticationServiceBean);
//            mycompanyAuthenticationService = (MycompanyAuthenticationService) beanManager.getReference(mycompanyAuthenticationServiceBean, MycompanyAuthenticationService.class, creationalContext);
//        } catch (NamingException exception) {
//            throw new RuntimeException(exception);
//        }
//    }
}


推荐答案

尽管JBoss工程师付出了最大努力,但遗憾的是,将经过身份验证的身份从Servlet传播到EJB是一个永无止境的JBoss故事。

Propagating the authenticated identity from Servlet to EJB is unfortunately a never ending story with JBoss, despite the best efforts of the JBoss engineers.

有大约6个个别错误需要修复,所以你甚至可以达到你现在使用JBoss AS 7.4的程度(我认为是JBoss EAP 6.3),之后会出现一些错误。

There were some 6 individual bugs that had to be fixed so you could even get to the point where you are now in JBoss AS 7.4 (JBoss EAP 6.3 I assume), and there are a couple of bugs after this.

这个特殊的错误是 https://issues.jboss.org/浏览/ SECURITY-745 并在大约2年前提交,但仍然对AS 7 / EAP 6分支开放。这是在 https://issues.jboss.org/browse/SECURITY-744,它被列为开放但我认为它实际上是固定的。

This particular bug is https://issues.jboss.org/browse/SECURITY-745 and was filed almost 2 years ago, but still open for the AS 7/EAP 6 branch. This one came right after https://issues.jboss.org/browse/SECURITY-744, which is listed as open but I think it's actually fixed.

WF 8 / EAP 7分支没有这个错误,但两个分支确实受到影响< a href =https://issues.jboss.org/browse/SECURITY-746\"rel =nofollow> https://issues.jboss.org/browse/SECURITY-746 https://issues.jboss.org/browse/SECURITY-876

The WF 8/EAP 7 branch doesn't have this bug, but both branches do suffer from https://issues.jboss.org/browse/SECURITY-746 and https://issues.jboss.org/browse/SECURITY-876

所以这是JBoss中的已知错误。如果你想解决它,我的建议是联系JBoss。

So it's a known bug in JBoss. If you want to get it solved my advice would be to contact JBoss about it.

我用于AS 7分支的替代解决方法是提供我自己修改的 org.jboss.as.web.security.jaspi.WebJASPIAuthenticator 实现,但是你会马上进入SECURITY-746,所以你需要自定义 be.mycompany.api.authentication.jaspi.MycompanyAuthModule 无论如何都使用过的模块。

An alternative workaround which I used for the AS 7 branch is providing my own modified org.jboss.as.web.security.jaspi.WebJASPIAuthenticator implementation, but then you'll run right away into SECURITY-746, so you need the custom be.mycompany.api.authentication.jaspi.MycompanyAuthModule module that you used anyway.

这篇关于Jaspic模块没有将主体传播到JBoss 7.4中的本地EJB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆