[jboss-jira] [JBoss JIRA] (WFLY-9251) Security context is not thread safe

charles ghislain (JIRA) issues at jboss.org
Thu Aug 24 03:36:00 EDT 2017


     [ https://issues.jboss.org/browse/WFLY-9251?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

charles ghislain updated WFLY-9251:
-----------------------------------
    Steps to Reproduce: 
Please see the attached POC for reproduction:
- Build the maven project
- Place the authmodule jar in a wildfly module, along with a module descriptor:

{noformat}
<module xmlns="urn:jboss:module:1.3" name="be.test.testauthmodule">

    <dependencies>
        <!-- Needed for javax.security.auth -->
        <module name="javax.api" export="false"/>
        <module name="org.apache.logging.log4j"/>
     </dependencies>

    <resources>
        <resource-root path="authmodule-1.0-SNAPSHOT.jar"/>
    </resources>
</module>
{noformat}

- Make sure it is loaded eagerly:
{noformat}
 <subsystem xmlns="urn:jboss:domain:ee:4.0">
            <global-modules>
                     <module name="be.test.testauthmodule"/>
{noformat}
- Specify the realm and login module in the standalone config:
{noformat}
 <security-domain name="TestSecurityDomain" cache-type="default">
                    <authentication>
                        <login-module code="be.test.TestLoginModule" flag="required"/>
                        <login-module code="org.jboss.security.ClientLoginModule" flag="optional"/>
                    </authentication>
                </security-domain>
{noformat}
{noformat}
<security-realm name="TestRealm">
                <authentication>
                    <jaas name="TestSecurityDomain"/>
                </authentication>
            </security-realm>
{noformat}

- Deploy the war to your wildfly instance
- Make sure you have several worker threads. In the IO subsystem, I use 8 IO threads and 64 task threads.
- Launch a bunch of requests simultaneously. Requests must authenticate themeselves using a Basic Authorization header with a login starting by 'test-' to pass authorization. You could paste the following snippet in the browser js console opened from a page serving your wildfly content (to avoid cors):

{noformat}
var count = 500;
var failures = [];
var responseCount = 0;

let url = 'http://localhost:8080/ws-1.0-SNAPSHOT/test';

function onReqLoad(index, event, xhr) {
    if (xhr.readyState === 4) {
        responseCount++;
        console.log(index + ' ' + xhr.status);
        if (xhr.status >= 400) {
            failures.push(index);
        }
    }
}

function doit() {
    var i = 0;
    while (i < count) {
        let xhr = new XMLHttpRequest();
        let index = i;
        xhr.addEventListener('load', function (event) {
                onReqLoad(index, event, xhr)
            }
        );
        xhr.open('GET', url);
        xhr.setRequestHeader('Authorization', 'Basic dGVzdC1hZXJhOnRlc3Rlc3Rlc3Q=');
        xhr.withCredentials = true;
        xhr.send();
        i++
    }

}

function logStatus() {
    console.log('totlal: ' + responseCount + ' ; failures:');
    console.log(failures);
}
doit();
window.setTimeout(function(){logStatus();}, 30000);
{noformat}


You should notice some requests getting a 401 response, while most of them get the expected 200.

I you modify your wildfly config to use only a single worker thread and a single task thread, then you should notice that all requests pass, although it takes much longer for the server to process them.

  was:
Please see the attached POC for reproduction:
- Build the maven project
- Place the authmodule jar in a wildfly module, along with a module descriptor:

{noformat}
<module xmlns="urn:jboss:module:1.3" name="be.test.testauthmodule">

    <dependencies>
        <!-- Needed for javax.security.auth -->
        <module name="javax.api" export="false"/>
        <module name="org.apache.logging.log4j"/>
     </dependencies>

    <resources>
        <resource-root path="authmodule-1.0-SNAPSHOT.jar"/>
    </resources>
</module>
{noformat}

- Make sure it is loaded eagerly:
{noformat}
 <subsystem xmlns="urn:jboss:domain:ee:4.0">
            <global-modules>
                     <module name="be.test.testauthmodule"/>
{noformat}
- Specify the realm and login module in the standalone config:
{noformat}
 <security-domain name="TestSecurityDomain" cache-type="default">
                    <authentication>
                        <login-module code="be.test.TestLoginModule" flag="required"/>
                        <login-module code="org.jboss.security.ClientLoginModule" flag="optional"/>
                    </authentication>
                </security-domain>
{noformat}
{noformat}
<security-realm name="TestRealm">
                <authentication>
                    <jaas name="TestSecurityDomain"/>
                </authentication>
            </security-realm>
{noformat}

- Deploy the war to your wildfly instance
- Make sure you have several worker threads. In the IO subsystem, I use 8 IO threads and 64 task threads.
- Launch a bunch of requests simultaneously. Requests must authenticate themeselves using a Basic Authorization header with a login starting by 'test-' to pass authorization. You could paste the following snippet in the browser js console opened from a page serving your wildfly content (to avoid cors):

{noformat}
var count = 500;
var failures = [];
var responseCount = 0;

let url = 'http://localhost:8080/ws-1.0-SNAPSHOT/test';

function onReqLoad(index, event, xhr) {
    if (xhr.readyState === 4) {
        responseCount++;
        console.log(index + ' ' + xhr.status);
        if (xhr.status >= 400) {
            failures.push(index);
        }
    }
}

function doit() {
    var i = 0;
    while (i < count) {
        let xhr = new XMLHttpRequest();
        let index = i;
        xhr.addEventListener('load', function (event) {
                onReqLoad(index, event, xhr)
            }
        );
        xhr.open('GET', url);
        xhr.setRequestHeader('Authorization', 'Basic dGVzdC1hZXJhOnRlc3Rlc3Rlc3Q=');
        xhr.withCredentials = true;
        xhr.send();
        i++
    }

}

function logStatus() {
    console.log('totlal: ' + responseCount + ' ; failures:');
    console.log(failures);
}
doit();
{noformat}


You should notice some requests getting a 401 response, while most of them get the expected 200.

I you modify your wildfly config to use only a single worker thread and a single task thread, then you should notice that all requests pass, although it takes much longer for the server to process them.



> Security context is not thread safe
> -----------------------------------
>
>                 Key: WFLY-9251
>                 URL: https://issues.jboss.org/browse/WFLY-9251
>             Project: WildFly
>          Issue Type: Bug
>          Components: Security
>    Affects Versions: 10.1.0.Final
>         Environment: Windows, LInux
>            Reporter: charles ghislain
>            Assignee: Darran Lofthouse
>              Labels: jaas, security, security-context, thread-safety, threads
>         Attachments: wildflytestauthcontext-2.zip, wildflytestauthcontext.zip
>
>
> Using a custom JAAS login module, we sometimes fail to obtain the authenticated subject from the 'javax.security.auth.Subject.container' policy context. This appear to be related to the worker threads. 
> See the reproduction steps below. When a wildfly instance attempts to authenticate 500 requests coming simultaneously, a bunch of them fail. If you configure wildfly to only use a single worker thread and a single task thread, this issue disappears.
> The issue is as follow:
> I login using HttpServletRequest#login.
> Right after that, login.getUserPrincipal return the correct principal.
> However, sometimes, PolicyContext.getContext("javax.security.auth.Subject.container") returns null. Right after the login.
> In our production app, PolicyContext.getContext("javax.security.auth.Subject.container") returns null during some EJB call, throwing random exceptions from various parts of the application. 



--
This message was sent by Atlassian JIRA
(v7.2.3#72005)


More information about the jboss-jira mailing list