[jboss-jira] [JBoss JIRA] (WFLY-13619) Elytron: org.wildfly.security.auth.server.SecurityIdentity not Serializable

Andrej Kolontai (Jira) issues at jboss.org
Thu Jun 25 04:36:05 EDT 2020


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

Andrej Kolontai updated WFLY-13619:
-----------------------------------
    Steps to Reproduce: 
The problem is reproducible with just one server by making the session store persistent.

My production setup is rather complex so I've created a tiny project just to show the effect: [https://github.com/andrejkolontai/jaspic-elytron-distributed-demo]

 

First, get a fresh wildfly distribution (version 20.0.0.Final) and unpack it.

Start it with standalone.sh.

Then, using jboss-cli.sh make the session store persistent:

 
{noformat}
/subsystem=infinispan/cache-container=web/local-cache=passivation/store=file:add(passivation=false,purge=false)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}[standalone at localhost:9990 /] reload
{noformat}
Then create an elytron security domain and connect it to undertow:

 
{noformat}
[standalone at localhost:9990 /] /subsystem=elytron/security-domain=elytronjaspic:add
{"outcome" => "success"}
[standalone at localhost:9990 /] /subsystem=undertow/application-security-domain=elytronjaspic:add(integrated-jaspi=false,security-domain=elytronjaspic)
{"outcome" => "success"}


 
{noformat}
 

The demo project has a servlet, a session scoped cdi bean (counts the requests in a session) an a rather trivial authenticator which uses AutoApplySession.

 

To build it, use the gradle wrapper:

 
{noformat}
./gradlew war{noformat}
 

The repository has three tags to see the difference between old security subsystem and elytron.

First, the old security subsystem to ses how it's used to work:

 
{noformat}
git checkout old-security 
Previous HEAD position was 6dad6c3 Changed security domain to the elytron one
HEAD is now at 547cff7 First Commmit
./gradlew warBUILD SUCCESSFUL in 1s
2 actionable tasks: 1 executed, 1 up-to-date
cp build/libs/jaspic.war ~/devel/wildfly-20.0.0.Final/standalone/deployments/{noformat}
 

 

 Verify that the authentication mechanism kicks in:
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 <html><head><title>Error</title></head><body>Unauthorized</body></html>{noformat}
call with authentication credentials:
{noformat}
curl -w '\n' -c cookies -b cookies -H "secret: shampoo" localhost:8080/jaspic/hallo
 Hallo Welt 0{noformat}
verify that the authentication state is stored in the session (call without secret):
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 Hallo Welt 1{noformat}
reload/restart wildfly

verify the session has survived the reload:
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 Hallo Welt 2{noformat}
Now, switch to elytron by changing the security domain:
{noformat}
git checkout elytron-security{noformat}
build & deploy like above

Now do the same procedure but clear the cookies first:
{noformat}
rm cookies
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
<html><head><title>Error</title></head><body>Unauthorized</body></html>
curl -w '\n' -c cookies -b cookies -H "secret: shampoo" localhost:8080/jaspic/hallo
Hallo Welt 0{noformat}
At this point you should see wildfly throwing exceptions. My demo application seems to work. But my production application would stop working. And the sessions are not actually persisted. One more effect in production: when a server is restarted, it takes a very long time for it to come back again because the running server is struggling to serialize the session data which is not possible while the restarting server is waiting for the cached session data to arrive. After a timeout, the affected applications would just go into .failed.

A possible workaround is to make the application non-distributable:
{noformat}
git checkout non-distributable{noformat}
build & deploy again like above. Repeat the test. Everything just works but, of course, the sessions are not persisted and in production there would be no session failover.

I  could stay with the old security subsystem (like "jaspitest"). But I really like elytron better and words like "dummy" in a production configuration are kind of scary.

That's not much of an issue. But I liked the feeling that I could just redeploy an application or restart a server during normal work hours instead of waiting until midnight or so.

What is also interesting: it only seems to affect jaspic/jsr375 enabled applications. We have one application using form authentication backed by an ldap realm which doesen't seem to have this problem.

  was:
The problem is reproducible with just one server by making the session store persistent.

My production setup is rather complex so I've created a tiny project just to show the effect: [https://github.com/andrejkolontai/jaspic-elytron-distributed-demo]

 

First, get a fresh wildfly distribution (version 20.0.0.Final) and unpack it.

Start it with standalone.sh.

Then, using jboss-cli.sh make the session store persistent:

 
{noformat}
/subsystem=infinispan/cache-container=web/local-cache=passivation/store=file:add(passivation=false,purge=false)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}[standalone at localhost:9990 /] reload
{noformat}
Then create an elytron security domain and connect it to undertow:

 
{noformat}
[standalone at localhost:9990 /] /subsystem=elytron/security-domain=elytronjaspic:add
{"outcome" => "success"}[standalone at localhost:9990 /] /subsystem=undertow/application-security-domain=elytronjaspic:add(integrated-jaspi=false,security-domain=elytronjaspic)
{"outcome" => "success"}


 
{noformat}
 

The demo project has a servlet, a session scoped cdi bean (counts the requests in a session) an a rather trivial authenticator which uses AutoApplySession.

 

To build it, use the gradle wrapper:

 
{noformat}
./gradlew war{noformat}
 

The repository has three tags to see the difference between old security subsystem and elytron.

First, the old security subsystem to ses how it's used to work:

 
{noformat}
git checkout old-security 
Previous HEAD position was 6dad6c3 Changed security domain to the elytron one
HEAD is now at 547cff7 First Commmit
./gradlew warBUILD SUCCESSFUL in 1s
2 actionable tasks: 1 executed, 1 up-to-date
cp build/libs/jaspic.war ~/devel/wildfly-20.0.0.Final/standalone/deployments/{noformat}
 

 

 Verify that the authentication mechanism kicks in:
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 <html><head><title>Error</title></head><body>Unauthorized</body></html>{noformat}
call with authentication credentials:
{noformat}
curl -w '\n' -c cookies -b cookies -H "secret: shampoo" localhost:8080/jaspic/hallo
 Hallo Welt 0{noformat}
verify that the authentication state is stored in the session (call without secret):
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 Hallo Welt 1{noformat}
reload/restart wildfly

verify the session has survived the reload:
{noformat}
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
 Hallo Welt 2{noformat}
Now, switch to elytron by changing the security domain:
{noformat}
git checkout elytron-security{noformat}
build & deploy like above

Now do the same procedure but clear the cookies first:
{noformat}
rm cookies
curl -w '\n' -c cookies -b cookies localhost:8080/jaspic/hallo
<html><head><title>Error</title></head><body>Unauthorized</body></html>
curl -w '\n' -c cookies -b cookies -H "secret: shampoo" localhost:8080/jaspic/hallo
Hallo Welt 0{noformat}
At this point you should see wildfly throwing exceptions. My demo application seems to work. But my production application would stop working. And the sessions are not actually persisted. One more effect in production: when a server is restarted, it takes a very long time for it to come back again because the running server is struggling to serialize the session data which is not possible while the restarting server is waiting for the cached session data to arrive. After a timeout, the affected applications would just go into .failed.

A possible workaround is to make the application non-distributable:
{noformat}
git checkout non-distributable{noformat}
build & deploy again like above. Repeat the test. Everything just works but, of course, the sessions are not persisted and in production there would be no session failover.

I  could stay with the old security subsystem (like "jaspitest"). But I really like elytron better and words like "dummy" in a production configuration are kind of scary.

That's not much of an issue. But I liked the feeling that I could just redeploy an application or restart a server during normal work hours instead of waiting until midnight or so.

What is also interesting: it only seems to affect jaspic/jsr375 enabled applications. We have one application using form authentication backed by an ldap realm which doesen't seem to have this problem.



> Elytron: org.wildfly.security.auth.server.SecurityIdentity not Serializable
> ---------------------------------------------------------------------------
>
>                 Key: WFLY-13619
>                 URL: https://issues.redhat.com/browse/WFLY-13619
>             Project: WildFly
>          Issue Type: Bug
>          Components: Security
>    Affects Versions: 20.0.0.Final
>            Reporter: Andrej Kolontai
>            Assignee: Darran Lofthouse
>            Priority: Minor
>
> Since the old security subsystem has been deprecated for a while I decided to move my applications to elytron which worked just fine up to the point where I tried to migrate an application that is:
>  * distributed
>  * uses Jaspic in form of a JSR375 HttpAuthenticationMechanism which has \{{@AutoApplySession }}
> In the logs I see stacktraces like this:
>  
> {noformat}
> 09:37:22,045 WARN [org.infinispan.PERSISTENCE] (default task-1) ISPN000559: Cannot marshall 'class org.infinispan.marshall.protostream.impl.MarshallableUserObject': java.io.NotSerializableException: org.wildfly.security.auth.server.SecurityIdentity
> at org.jboss.marshalling.river at 2.0.9.Final//org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:272)}}
> at org.jboss.marshalling.river at 2.0.9.Final//org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1141)}}
> at org.jboss.marshalling.river at 2.0.9.Final//org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:1099)}}
> at org.jboss.marshalling.river at 2.0.9.Final//org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:266)}}
> at org.jboss.marshalling at 2.0.9.Final//org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)}}
> at org.jboss.marshalling at 2.0.9.Final//org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)}}
> .....
> Caused by: an exception which occurred:
> in field org.wildfly.elytron.web.undertow.server.servlet.ServletSecurityContextImpl$IdentityContainer.securityIdentity
> in object org.wildfly.elytron.web.undertow.server.servlet.ServletSecurityContextImpl$IdentityContainer at 7bf2af9a
> in object org.wildfly.elytron.web.undertow.server.servlet.ServletSecurityContextImpl$IdentityContainer at 7bf2af9a
> in object java.util.concurrent.ConcurrentHashMap at d02a9ca2
> in object org.wildfly.clustering.marshalling.jboss.SimpleMarshalledValue at d02a9ca2
> {noformat}
>  
>  
> Looks to me like it's trying to serialize the session to replicate it to the other nodes in the cluster and fails because the user identity, which is part of the session because of AutoApplySession, is not serializable. I have checked the source and it is really not serializable.
>  
> I had no problems with the old security subsystem (i.e. jaspitest).



--
This message was sent by Atlassian Jira
(v7.13.8#713008)



More information about the jboss-jira mailing list