【问题标题】:Call a secured EJB method on servlet on load(EAP 6.4)在加载时调用 servlet 上的安全 EJB 方法(EAP 6.4)
【发布时间】:2017-08-22 10:26:43
【问题描述】:

我正在尝试在服务器负载上调用安全的 EJB 方法,但出现异常:

09:49:58,011 ERROR [org.jboss.as.ejb3.invocation] (ServerService Thread Pool -- 54) JBAS014134: EJB Invocation failed on component SecuredEJB for method public java.lang.String org.jboss.as.quickstarts.ejb_security.SecuredEJB.getSecurityInfo(): javax.ejb.EJBAccessException: JBAS014502: Invocation on method: public java.lang.String org.jboss.as.quickstarts.ejb_security.SecuredEJB.getSecurityInfo() of bean: SecuredEJB is not allowed
    at org.jboss.as.ejb3.security.AuthorizationInterceptor.processInvocation(AuthorizationInterceptor.java:114) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:86) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50) [jboss-as-ee-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ee.component.TCCLInterceptor.processInvocation(TCCLInterceptor.java:45) [jboss-as-ee-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185) [jboss-as-ee-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:185) [jboss-as-ee-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:73) [jboss-as-ee-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.as.quickstarts.ejb_security.SecuredEJB$$$view1.getSecurityInfo(Unknown Source) [classes:]
    at org.jboss.as.quickstarts.ejb_security.SecuredEJBServlet.init(SecuredEJBServlet.java:55) [classes:]
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1194) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1100) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3593) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:3802) [jbossweb-7.5.7.Final-redhat-1.jar:7.5.7.Final-redhat-1]
    at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:163) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:61) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:96) [jboss-as-web-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [rt.jar:1.7.0_55]
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [rt.jar:1.7.0_55]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_55]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_55]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_55]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.2.Final-redhat-1.jar:2.1.2.Final-redhat-1]

我的项目结构是:

SecuredEJBServlet.java

@SuppressWarnings("serial")
@WebServlet("/SecuredEJBServlet")
@ServletSecurity(@HttpConstraint(rolesAllowed = "quickstarts"))
public class SecuredEJBServlet extends HttpServlet {

    @EJB
    private SecuredEJB securedEJB;

    @Override
public void init(javax.servlet.ServletConfig arg0) throws javax.servlet.ServletException{
    Subject s = CMnJAASLogin.loginMethod();
    runAs(s);
    super.init(arg0);
    System.out.println("Inside init...");
    securedEJB.getName();
    //securedEJB.getSecurityInfo();
}

private void runAs(Subject s){
    Subject.doAs(s, new PrivilegedAction<Object>() {
        @Override
        public Object run() {
            System.out.println("Inside privileged action");
            securedEJB.getSecurityInfo();
            return null;
        }
    });
}

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        securedEJB.getName();
        String principal = securedEJB.getSecurityInfo();
...
}

SecuredEJB.java

@Stateless
@DeclareRoles("java")
@SecurityDomain("custom")
public class SecuredEJB {
    @Resource
    private SessionContext ctx;

    @RolesAllowed({ "java" })
    public String getSecurityInfo() {
        Principal principal = ctx.getCallerPrincipal();
        return principal.toString();
    }

    @PermitAll
    public void getName(){
        System.out.println(principal.getName());
    }
}

CMnAuthenticator.java

public class CMnAuthenticator extends UsernamePasswordLoginModule{
    @Override
    protected String getUsersPassword() throws LoginException {
        return "java";
    }

    @Override
    protected boolean validatePassword(String passwordWant, String passwordHave){
        return true;
    }

    @Override
    protected Group[] getRoleSets() throws LoginException {
        HashMap setsMap = new HashMap();
        String groupName = "Roles";
        Group group = (Group) setsMap.get(groupName);
        if (group == null) {
            group = new SimpleGroup(groupName);
            setsMap.put(groupName, group);
        }
        try {
            Principal p = super.createIdentity("quickstarts");
            group.addMember(p);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        Group[] roleSets = new Group[setsMap.size()];
        setsMap.values().toArray(roleSets);
        return roleSets;
    }
}

CMnEJBAuthenticator.java

public class CMnEJBAuthenticator extends UsernamePasswordLoginModule {
    @Override
    protected String getUsersPassword() throws LoginException {
        return "java";
    }

    @Override
    protected boolean validatePassword(String passwordWant, String passwordHave){
        return true;
    }

    @Override
    protected Group[] getRoleSets() throws LoginException {
        System.out.println("Inside CMnEJBAuthenticator:getRoleSets...");
        HashMap setsMap = new HashMap();
        String groupName = "Roles";
        Group group = (Group) setsMap.get(groupName);
        if (group == null) {
            group = new SimpleGroup(groupName);
            setsMap.put(groupName, group);
        }
        try {
            Principal p = super.createIdentity("java");
            group.addMember(p);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        Group[] roleSets = new Group[setsMap.size()];
        setsMap.values().toArray(roleSets);
        return roleSets;
    }
}

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.jboss.org/schema/jbossas
    http://www.jboss.org/schema/jbossas/jboss-web_7_2.xsd">
    <!-- Configure usage of the security domain "other" -->
    <security-domain>servlet-security-quickstart</security-domain>
    <disable-audit>true</disable-audit>
</jboss-web>

web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   version="3.0">

   <!-- Configure login to be HTTP Basic -->
   <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>RealmUsersRoles</realm-name>
   </login-config>

    <servlet>
        <servlet-name>bootstrap</servlet-name>
        <servlet-class>org.jboss.as.quickstarts.ejb_security.SecuredEJBServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>bootstrap</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

独立的.xml

<security-domain name="custom" cache-type="default">
                    <authentication>
                        <login-module code="org.jboss.as.quickstarts.ejb_security.others.CMnEJBAuthenticator" flag="required">
                            <module-option name="unauthenticatedIdentity" value="Super"/>
                        </login-module>
                    </authentication>
                </security-domain>
<security-domain name="servlet-security-quickstart" cache-type="default">
                    <authentication>
                        <login-module code="org.jboss.as.quickstarts.ejb_security.others.CMnAuthenticator" flag="required">
                            <module-option name="unauthenticatedIdentity" value="Super"/>
                        </login-module>
                    </authentication>
                </security-domain>

Jaas 身份验证:

package org.jboss.as.quickstarts.ejb_security.others;

import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.LoginContext;
import java.io.IOException;

public class CMnJAASLogin {

    public static Subject loginMethod(){
        LoginContext lc = null;

        CallbackHandler cabHndlr = new CallbackHandler() {
            @Override
            public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                for (int i = 0; i < callbacks.length; i++) {
                    if (callbacks[i] instanceof NameCallback) {
                        NameCallback nc = (NameCallback) callbacks[i];
                        nc.setName("java");
                    } else if (callbacks[i] instanceof PasswordCallback) {
                        PasswordCallback pc = (PasswordCallback) callbacks[i];
                        pc.setPassword("java".toCharArray());
                    } else {
                        throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
                    }
                }
            }
        };
        try {
            lc = new LoginContext("custom", cabHndlr);
            lc.login();
            return lc.getSubject();
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return null;
    }
}

知道我错过了什么吗?

注意:我正在开发 JBoss EAP 6.4 和 java 1.7

向 Servlet 类添加 @RunAs("java") 解决了这个直接的问题。

但如果我需要拒绝其他用户的访问,RunAs 注释将无济于事。

所以,我需要以这种方式解决它(如果没有用户调用方法/ejb/servlet,则使用“java”,否则使用该用户的角色。

【问题讨论】:

  • 添加了 JAAS 身份验证,但看起来 SUbject.doAs 没有按预期工作。相应地编辑了帖子/问题

标签: security ejb jaas jboss-eap-6


【解决方案1】:

我还没有尝试过,但是 servlet 规范的 §15.3.1 说您只需要在 web.xml 中的 servlet 定义中添加一个 run-as 元素:

<servlet>
    <servlet-name>bootstrap</servlet-name>
    <servlet-class>org.jboss.as.quickstarts.ejb_security.SecuredEJBServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <run-as>java</run-as>
</servlet>

但是,对于通常经过身份验证的 servlet 调用,实际经过身份验证的主体是否会传播到 EJB 尚不完全清楚。您将不得不尝试一下。

【讨论】:

  • 嗨史蒂夫,感谢您的评论。我试过了,但没有用。 java 我得到了同样的异常。
  • 是的——它似乎是一个 Servlet 3.1 的东西。考虑在 WildFly 10.1 上对其进行测试,如果这是一个改进,您可能需要迁移到 JBoss EAP 7.x
  • @RunAs("java") to SecuredEJBServlet.java 解决了这个问题。
  • 我将删除此答案,因为我认为它对任何人都没有用
  • 至少它是众多尝试之一。我想,你可以保持原样。
【解决方案2】:

我在 AppConfigurationProperty 中使用 org.jboss.security.ClientLoginModule 后解决了。

最后,JAAS 类看起来像这样:

import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class CMnJAASLogin {

    public static LoginContext loginMethod() {
        LoginContext lc = null;

        CallbackHandler cabHndlr = new CallbackHandler() {
            @Override
            public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                for (int i = 0; i < callbacks.length; i++) {
                    if (callbacks[i] instanceof NameCallback) {
                        NameCallback nc = (NameCallback) callbacks[i];
                        nc.setName("java");
                    } else if (callbacks[i] instanceof PasswordCallback) {
                        PasswordCallback pc = (PasswordCallback) callbacks[i];
                        pc.setPassword("java".toCharArray());
                    } else {
                        throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
                    }
                }
            }
        };
        try {
            String configurationName = "JBoss Test";
            Configuration config = new JBossJaasConfiguration(configurationName);

            lc = new LoginContext(configurationName, new Subject(), cabHndlr, config);
            return lc;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    static class JBossJaasConfiguration extends Configuration {
        private final String configurationName;

        JBossJaasConfiguration(String configurationName) {
            this.configurationName = configurationName;
        }

        @Override
        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
            if (!configurationName.equals(name)) {
                throw new IllegalArgumentException("Unexpected configuration name '" + name + "'");
            }

            return new AppConfigurationEntry[]{

                    createClientLoginModuleConfigEntry(),

            };
        }

        private AppConfigurationEntry createClientLoginModuleConfigEntry() {
            Map<String, String> options = new HashMap<String, String>();
            options.put("multi-threaded", "true");
            options.put("restore-login-identity", "true");

            return new AppConfigurationEntry("org.jboss.security.ClientLoginModule",
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
        }
    }
}

整个项目上传到:https://github.com/shekharswaraj/EJBSecurity

注意:这只是一个包含许多硬编码值的测试项目。整个项目在 EAP6.4 quickstart 的 ejb-security 项目之上进行了修改。

【讨论】:

    猜你喜欢
    • 2017-10-11
    • 2018-05-07
    • 2016-07-19
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    相关资源
    最近更新 更多