Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 359329

Summary: JASPI won't runs on Jetty
Product: [RT] Jetty Reporter: guofeng zhang <guofeng>
Component: serverAssignee: Jan Bartel <janb>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: guofeng, janb, jetty-inbox
Version: 8.0.1   
Target Milestone: 7.5.x   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
The attached is the fix for Jetty 8.0.1.v20110908
none
Tar file of small test webapp maven project for jaspi testing
none
the test web app for JASPI fix
none
my test web app none

Description guofeng zhang CLA 2011-09-28 23:01:56 EDT
Build Identifier: jetty-8.0.1.v20110908

When I configured Jetty 8 to use JASPI, it does not works. I tried to fix it. The fix is attached.

Reproducible: Always

Steps to Reproduce:
Following the steps to setup a web app to use JASPI for container-managed security, then access the protected resourcs in the web app, the problem could be reproduced.
1.       Creating a JASPI configuration XML file for your auth module:
<?xml version="1.0" encoding="UTF-8"?>
<jaspi xmlns="http://geronimo.apache.org/xml/ns/geronimo-jaspi">
 
    <configProvider>
        <messageLayer>HTTP</messageLayer>
        <appContext>/ui</appContext>
        <description>description</description>
        <serverAuthConfig>
            <authenticationContextID>authenticationContextID2</authenticationContextID>
            <protected>true</protected>
            <serverAuthContext>
                <serverAuthModule>
                    <className>org.eclipse.jetty.security.jaspi.modules.FormAuthModule</className>
                    <options>
                       org.eclipse.jetty.security.jaspi.modules.LoginPage=/secure/jaaslogin
                       org.eclipse.jetty.security.jaspi.modules.ErrorPage=/secure/jaaserror
                    </options>
                </serverAuthModule>
            </serverAuthContext>
        </serverAuthConfig>
        <persistent>true</persistent>
    </configProvider>
</jaspi>
   The above using the Jetty built-in FormAuthModule, if you want to use the built-in Basic or Digest auth module, the <serverAuthModule> part should be:
                <serverAuthModule>
                    <className>org.eclipse.jetty.security.jaspi.modules.DigestAuthModule</className>
                    <options>
                       org.eclipse.jetty.security.jaspi.modules.RealmName=JAASRealm
                    </options>
                </serverAuthModule>
Or
                <serverAuthModule>
                    <className>org.eclipse.jetty.security.jaspi.modules.BasicAuthModule</className>
                    <options>
                       org.eclipse.jetty.security.jaspi.modules.RealmName=JAASRealm
                    </options>
                </serverAuthModule>
 
Here I use the implementation of JASPI of geronimo-jaspi 2.0-SNAPSHOT from geronimo-jaspi (https://github.com/apache/geronimo-jaspi). you could use geronimo-jaspi 1.1.1 release, but you might need to implements javax.security.auth.message.config.AuthConfigProvider (and not javax.security.auth.message.module.ServerAuthModule) and configure it in the above XML file.
 
2.       Configuring your AppContext to use JaspiAuthenticatorFactory. I configured it in jetty-web.xml file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Set name="securityHandler">
      <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
         <Set name="loginService">
            <New class="org.eclipse.jetty.plus.jaas.JAASLoginService">
              <Set name="name">JAASRealm</Set>
              <Set name="loginModuleName">jaas</Set>
            </New>
         </Set>
 
         <Set name="authenticatorFactory">
             <New class="org.eclipse.jetty.security.jaspi.JaspiAuthenticatorFactory" />
         </Set>
      </New>
  </Set>
</Configure>
 
3.       When launching Jetty, using -Dorg.apache.geronimo.jaspic.configurationFile to tell geronimo-jaspi where to find the JASPI configuration file. The following is the jetty-maven-plugin configuration (my JASPI configuration file is form-test-jaspi-2.xml):
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>${jetty.version}</version>
       <configuration>
           <scanIntervalSeconds>10</scanIntervalSeconds>
           <webAppConfig>
              <contextPath>/ui</contextPath>
              <parentLoaderPriority>true</parentLoaderPriority>
          </webAppConfig>
 
          <systemProperties>
             <systemProperty>
               <name>java.security.auth.login.config</name>
               <value>./conf/jetty/jaas.conf</value>
            </systemProperty>
            <systemProperty>
              <name>org.apache.geronimo.jaspic.configurationFile</name>
              <value>./conf/jaspi/form-test-jaspi-2.xml</value>
            </systemProperty>
        </configuration>
        <dependencies>
           <dependency>
              <groupId>org.eclipse.jetty</groupId>
              <artifactId>jetty-jaspi</artifactId>
              <version>${jetty.version}</version>
           </dependency>
           <dependency>
              <groupId>org.apache.geronimo.components</groupId>
              <artifactId>geronimo-jaspi</artifactId>
              <version>2.0-SNAPSHOT</version>
           </dependency>
         </dependencies>
      </plugin>
In my test, I use my own JAAS login module, which configured in jaas.conf. you could use Jetty built-in login module as described in http://wiki.eclipse.org/Jetty/Feature/JAAS.
Comment 1 guofeng zhang CLA 2011-09-28 23:05:35 EDT
Created attachment 204240 [details]
The attached is the fix for Jetty 8.0.1.v20110908
Comment 2 Jan Bartel CLA 2011-09-29 01:15:42 EDT
More info via email from Guofeng:

One thing I want to mention it here because I wonder if it will affect the stability of Jetty when it is deployed on the product environment. You please pay attention on it.

 

In the process of debugging my fix, sometime when an exception (like NullPointerException or ServerAuthException) thrown, the Jetty print on Dos Console the following:

11:49:27.583 [qtp21447570-16] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-20] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-18] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-15] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-17] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-16] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-19] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

11:49:27.583 [qtp21447570-20] DEBUG o.e.jetty.server.AsyncHttpConnection - async request

 

It flood the console and causes the CPU 100% usage. Jetty is very slow to response the request. When the fix works well. This does not occur again.

 

To reproduce it, try to change secureResponse() in JaspiAuthenticator like the following to throw an exception (this occurs before my fix in that info in req is null):

    public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException

    {

        JaspiMessageInfo info = (JaspiMessageInfo)req.getAttribute("org.eclipse.jetty.security.jaspi.info");

        //if (info==null)

        throw new NullPointerException("MeesageInfo from request missing: " + req);

        //return secureResponse(info,validatedUser);

    }

 

I do not know whether it is a bug or because it is in the debug phrase, so I mention it here.
Comment 3 Jan Bartel CLA 2011-09-29 02:55:11 EDT
Hi Guofeng,

I seem to have a problem with the geronimo-jaspi jars. I checked out git://github.com/apache/geronimo-jaspi.git  and built the geronimo-jaspi module, however the geronimo-jaspi jar that was produced does not contain any of the org/apache/geronimo/components/jaspi/impl/ classes, so when I run jetty I get:

2011-09-29 16:38:53.315:INFO:oejs.Server:jetty-7.5.2-SNAPSHOT
2011-09-29 16:38:53.603:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
2011-09-29 16:38:53.771:WARN:oejuc.AbstractLifeCycle:FAILED org.eclipse.jetty.security.ConstraintSecurityHandler@50f8ae79#FAILED: java.lang.NoClassDefFoundError: org/apache/geronimo/components/jaspi/impl/ConfigProviderImpl
java.lang.NoClassDefFoundError: org/apache/geronimo/components/jaspi/impl/ConfigProviderImpl
        at org.apache.geronimo.components.jaspi.AuthConfigFactoryImpl.initialize(AuthConfigFactoryImpl.java:279)
        at org.apache.geronimo.components.jaspi.AuthConfigFactoryImpl.loadConfig(AuthConfigFactoryImpl.java:271)
        at org.apache.geronimo.components.jaspi.AuthConfigFactoryImpl.<init>(AuthConfigFactoryImpl.java:75)
        at org.apache.geronimo.components.jaspi.AuthConfigFactoryImpl.<init>(AuthConfigFactoryImpl.java:79)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
        at java.lang.Class.newInstance0(Class.java:355)
        at java.lang.Class.newInstance(Class.java:308)
        at javax.security.auth.message.config.AuthConfigFactory$3.run(AuthConfigFactory.java:66)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.message.config.AuthConfigFactory.getFactory(AuthConfigFactory.java:62)
        at org.eclipse.jetty.security.jaspi.JaspiAuthenticatorFactory.getAuthenticator(JaspiAuthenticatorFactory.java:91)
        at org.eclipse.jetty.security.SecurityHandler.doStart(SecurityHandler.java:323)
        at org.eclipse.jetty.security.ConstraintSecurityHandler.doStart(ConstraintSecurityHandler.java:228)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
        at org.eclipse.jetty.server.handler.ScopedHandler.doStart(ScopedHandler.java:97)
        at org.eclipse.jetty.server.session.SessionHandler.doStart(SessionHandler.java:116)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
        at org.eclipse.jetty.server.handler.ScopedHandler.doStart(ScopedHandler.java:97)
        at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:632)
        at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:233)
        at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1213)
        at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:589)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:454)
        at org.mortbay.jetty.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:248)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:224)
        at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:167)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:224)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
        at org.eclipse.jetty.server.Server.doStart(Server.java:261)
        at org.mortbay.jetty.plugin.JettyServer.doStart(JettyServer.java:65)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
        at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:481)
        at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:334)
        at org.mortbay.jetty.plugin.JettyRunMojo.execute(JettyRunMojo.java:513)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)



Can you attach to this issue a version of the geronimo-jaspi jars that work? Or tell me how to generate jaspi jars that will work?

thanks
Jan
Comment 4 guofeng zhang CLA 2011-09-29 03:13:43 EDT
add the following line to maven-bundle-plugin in geronimo-jaspi/pom.xml
                        <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>, which will like:

                    <instructions>
                        ....
                        <Private-Package>org.apache.geronimo.osgi.locator</Private-Package>
                        <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>
                        <Bundle-Activator>org.apache.geronimo.osgi.locator.Activator</Bundle-Activator>
                    </instructions>


When lauching jetty, if you met NoClassDefFoundError for ProviderLocator class, you need to add the following dependency for jetty-maven-plugin:
           <dependency>
              <groupId>org.apache.geronimo.specs</groupId>
              <artifactId>geronimo-osgi-locator</artifactId>
              <version>1.0</version>
            </dependency>
Comment 5 Jan Bartel CLA 2011-09-29 04:15:26 EDT
Thanks, I seem to have overcome those problems now.

Can you confirm if the error you saw before your fixes was this:

java.lang.NullPointerException: MeesageInfo from request missing: [GET /foo/]@116134643 org.eclipse.jetty.server.Request@6ec12f3
	at org.eclipse.jetty.security.jaspi.JaspiAuthenticator.secureResponse(JaspiAuthenticator.java:94)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:500)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:227)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:940)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:409)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:186)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:874)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
	at org.eclipse.jetty.server.Server.handle(Server.java:349)
	at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:441)
	at org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:914)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:565)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:217)
	at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:52)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:555)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:43)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
	at java.lang.Thread.run(Thread.java:662)

?

thanks
Jan



(In reply to comment #4)
> add the following line to maven-bundle-plugin in geronimo-jaspi/pom.xml
>                        
> <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>,
> which will like:
> 
>                     <instructions>
>                         ....
>                        
> <Private-Package>org.apache.geronimo.osgi.locator</Private-Package>
>                        
> <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>
>                        
> <Bundle-Activator>org.apache.geronimo.osgi.locator.Activator</Bundle-Activator>
>                     </instructions>
> 
> 
> When lauching jetty, if you met NoClassDefFoundError for ProviderLocator class,
> you need to add the following dependency for jetty-maven-plugin:
>            <dependency>
>               <groupId>org.apache.geronimo.specs</groupId>
>               <artifactId>geronimo-osgi-locator</artifactId>
>               <version>1.0</version>
>             </dependency>
Comment 6 guofeng zhang CLA 2011-09-29 04:21:52 EDT
Yes.

(In reply to comment #5)
> Thanks, I seem to have overcome those problems now.
> Can you confirm if the error you saw before your fixes was this:
> java.lang.NullPointerException: MeesageInfo from request missing: [GET
> /foo/]@116134643 org.eclipse.jetty.server.Request@6ec12f3
>     at
> org.eclipse.jetty.security.jaspi.JaspiAuthenticator.secureResponse(JaspiAuthenticator.java:94)
>     at
> org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:500)
>     at
> org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:227)
>     at
> org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:940)
>     at
> org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:409)
>     at
> org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:186)
>     at
> org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:874)
>     at
> org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
>     at
> org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
>     at
> org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
>     at
> org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
>     at org.eclipse.jetty.server.Server.handle(Server.java:349)
>     at
> org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:441)
>     at
> org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:914)
>     at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:565)
>     at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:217)
>     at
> org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:52)
>     at
> org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:555)
>     at
> org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:43)
>     at
> org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
>     at
> org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
>     at java.lang.Thread.run(Thread.java:662)
> ?
> thanks
> Jan
> (In reply to comment #4)
> > add the following line to maven-bundle-plugin in geronimo-jaspi/pom.xml
> >                        
> > <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>,
> > which will like:
> > 
> >                     <instructions>
> >                         ....
> >                        
> > <Private-Package>org.apache.geronimo.osgi.locator</Private-Package>
> >                        
> > <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>
> >                        
> > <Bundle-Activator>org.apache.geronimo.osgi.locator.Activator</Bundle-Activator>
> >                     </instructions>
> > 
> > 
> > When lauching jetty, if you met NoClassDefFoundError for ProviderLocator class,
> > you need to add the following dependency for jetty-maven-plugin:
> >            <dependency>
> >               <groupId>org.apache.geronimo.specs</groupId>
> >               <artifactId>geronimo-osgi-locator</artifactId>
> >               <version>1.0</version>
> >             </dependency>
Comment 7 guofeng zhang CLA 2011-09-29 04:26:11 EDT
Yes. but it is not the root of the issue. I do not make any changes to JaspiAuthenticator.secureResponse(). By fixing other part, it works well.
 
(In reply to comment #6)
> Yes.
> (In reply to comment #5)
> > Thanks, I seem to have overcome those problems now.
> > Can you confirm if the error you saw before your fixes was this:
> > java.lang.NullPointerException: MeesageInfo from request missing: [GET
> > /foo/]@116134643 org.eclipse.jetty.server.Request@6ec12f3
> >     at
> > org.eclipse.jetty.security.jaspi.JaspiAuthenticator.secureResponse(JaspiAuthenticator.java:94)
> >     at
> > org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:500)
> >     at
> > org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:227)
> >     at
> > org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:940)
> >     at
> > org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:409)
> >     at
> > org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:186)
> >     at
> > org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:874)
> >     at
> > org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
> >     at
> > org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
> >     at
> > org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
> >     at
> > org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
> >     at org.eclipse.jetty.server.Server.handle(Server.java:349)
> >     at
> > org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:441)
> >     at
> > org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:914)
> >     at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:565)
> >     at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:217)
> >     at
> > org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:52)
> >     at
> > org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:555)
> >     at
> > org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:43)
> >     at
> > org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
> >     at
> > org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
> >     at java.lang.Thread.run(Thread.java:662)
> > ?
> > thanks
> > Jan
> > (In reply to comment #4)
> > > add the following line to maven-bundle-plugin in geronimo-jaspi/pom.xml
> > >                        
> > > <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>,
> > > which will like:
> > > 
> > >                     <instructions>
> > >                         ....
> > >                        
> > > <Private-Package>org.apache.geronimo.osgi.locator</Private-Package>
> > >                        
> > > <Private-Package>org.apache.geronimo.components.jaspi.impl.*</Private-Package>
> > >                        
> > > <Bundle-Activator>org.apache.geronimo.osgi.locator.Activator</Bundle-Activator>
> > >                     </instructions>
> > > 
> > > 
> > > When lauching jetty, if you met NoClassDefFoundError for ProviderLocator class,
> > > you need to add the following dependency for jetty-maven-plugin:
> > >            <dependency>
> > >               <groupId>org.apache.geronimo.specs</groupId>
> > >               <artifactId>geronimo-osgi-locator</artifactId>
> > >               <version>1.0</version>
> > >             </dependency>
Comment 8 Jan Bartel CLA 2011-10-03 02:40:41 EDT
Hi Guofeng,

I think there is an error in the geronimo-jaspi implementation in the ServerAuthContextImpl class, line 73:


if (result == AuthStatus.SEND_SUCCESS || result == AuthStatus.SEND_CONTINUE || result == AuthStatus.FAILURE) {
                return result;
}
throw new AuthException("Invalid AuthStatus " + result + " from server auth module validateRequest: " + serverAuthModule);


According to the final release of the Jaspi Specification, the javadocs for ServerAuth interface, p. 88, the following are the only allowable results for the validateRequest(MessageInfo,Subject,Subject):

• AuthStatus.SUCCESS when the application request message was successfully validated. The validated request message is available by calling getRequestMessage on messageInfo.

• AuthStatus.SEND_SUCCESS to indicate that validation/processing of the request message successfully produced the secured application response message (in messageInfo). The secured response message is available by calling getResponseMessage on messageInfo.

• AuthStatus.SEND_CONTINUE to indicate that message validation is incomplete, and that a preliminary response was returned as the response message in messageInfo. When this status value is returned to challenge an application request message, the challenged request must be saved by the authentication module such that it can be recovered when the module’s validateRequest message is called to process the request returned for the challenge.

• AuthStatus.SEND_FAILURE to indicate that message validation failed and that an appropriate failure response message is available by calling getResponseMessage on messageInfo.

The FormAuthModule is returning AuthStatus.SEND_FAILURE (eg to indicate that the user's password was not authenticated), but the ServerAuthContextImpl class is expecting AuthStatus.FAILURE instead.

cheers
Jan
Comment 9 Jan Bartel CLA 2011-10-03 23:40:06 EDT
Guofeng,

I've made a branch called "bug-359329" which you can check out from the jetty git repo at http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git 

I've made a few modifications so that jaspi appears to now be working, at least with FORM authentication. I haven't tried it with BASIC auth yet.

There's a lot of debug left in the code for now, as I'd like David Jencks to have a look at it, as I think there's a lot of scope for cleaning up and rationalising the jaspi impl - I think it got left behind as the jetty codebase changed around it.

If you would like to checkout and build the branch and test it against your set up, that would be very helpful.

thanks,
Jan
Comment 10 guofeng zhang CLA 2011-10-10 05:38:06 EDT
(In reply to comment #9)

I tested your branch using FormAuthModule, but it does not works well.
Steps
1. browse "http://localhost:8080/ui/jasssecured/index", where jasssecured/* is container-protected resources. 
2. the FORM login page configured in web.xml is displayed. (correct)
The error is the saved juri is incorrect:
Redirecting to login page /secure/jaaslogin and remembering juri=http://localhos
t:8080/ui/ajax_request/liftAjax.js

the remembering juri should be "localhost:8080/ui/jasssecured/index", not "http://localhost:8080/ui/ajax_request/liftAjax.js".

3. type correct user name and password, liftAjax.js is displayed, instead of index.html.

I met this case in my fix, I did it as the following:
            //** Don't auth the Deferred authentication.
            Authentication authentication = ((org.eclipse.jetty.server.Request)request).getAuthentication() ;
            if (authentication instanceof Authentication.Deferred )
                return AuthStatus.SEND_SUCCESS;

before:
            session.setAttribute(__J_URI, buf.toString());
in FormAuthModule.validateRequest(JaspiMessageInfo messageInfo)

In JaspiAuthenticator.validateRequest(ServletRequest request, ServletResponse response, boolean mandatory), I removed the following:
   if (_allowLazyAuthentication && !mandatory)
       return _deferred;

and added in JaspiAuthenticator.validateRequest(JaspiMessageInfo messageInfo) the following:
           if (authStatus == AuthStatus.SUCCESS)
            {
            	if ( !isMandatory( messageInfo ) )
            		return _deferred ;

In my mail, I said I do not know if I did the above change to JaspiAuthenticator correctly. Does the change make FormAuthModule to deal with Authentication.Deferred in the above if statement?
Comment 11 Jan Bartel CLA 2011-10-10 23:59:38 EDT
Guofeng,

What is referencing the ajax_request/liftAjax.js? Is it the form login page?
Do you have static resources that are referenced by a protected url, but that
are not themselves protected? Or are the static resources also behind a
protected url?

thanks
Jan







(In reply to comment #10)
> (In reply to comment #9)
> 
> I tested your branch using FormAuthModule, but it does not works well.
> Steps
> 1. browse "http://localhost:8080/ui/jasssecured/index", where jasssecured/* is
> container-protected resources. 
> 2. the FORM login page configured in web.xml is displayed. (correct)
> The error is the saved juri is incorrect:
> Redirecting to login page /secure/jaaslogin and remembering
> juri=http://localhos
> t:8080/ui/ajax_request/liftAjax.js
> 
> the remembering juri should be "localhost:8080/ui/jasssecured/index", not
> "http://localhost:8080/ui/ajax_request/liftAjax.js".
> 
> 3. type correct user name and password, liftAjax.js is displayed, instead of
> index.html.
> 
> I met this case in my fix, I did it as the following:
>             //** Don't auth the Deferred authentication.
>             Authentication authentication =
> ((org.eclipse.jetty.server.Request)request).getAuthentication() ;
>             if (authentication instanceof Authentication.Deferred )
>                 return AuthStatus.SEND_SUCCESS;
> 
> before:
>             session.setAttribute(__J_URI, buf.toString());
> in FormAuthModule.validateRequest(JaspiMessageInfo messageInfo)
> 
> In JaspiAuthenticator.validateRequest(ServletRequest request, ServletResponse
> response, boolean mandatory), I removed the following:
>    if (_allowLazyAuthentication && !mandatory)
>        return _deferred;
> 
> and added in JaspiAuthenticator.validateRequest(JaspiMessageInfo messageInfo)
> the following:
>            if (authStatus == AuthStatus.SUCCESS)
>             {
>                 if ( !isMandatory( messageInfo ) )
>                     return _deferred ;
> 
> In my mail, I said I do not know if I did the above change to
> JaspiAuthenticator correctly. Does the change make FormAuthModule to deal with
> Authentication.Deferred in the above if statement?
Comment 12 Jan Bartel CLA 2011-10-11 00:02:11 EDT
And also, I made some changes to the uri that was saved before doing the re-direct, so can you check that your branch is up-to-date?

thanks
Jan


(In reply to comment #11)
> Guofeng,
> 
> What is referencing the ajax_request/liftAjax.js? Is it the form login page?
> Do you have static resources that are referenced by a protected url, but that
> are not themselves protected? Or are the static resources also behind a
> protected url?
> 
> thanks
> Jan
> 
> 
> 
> 
> 
> 
> 
> (In reply to comment #10)
> > (In reply to comment #9)
> > 
> > I tested your branch using FormAuthModule, but it does not works well.
> > Steps
> > 1. browse "http://localhost:8080/ui/jasssecured/index", where jasssecured/* is
> > container-protected resources. 
> > 2. the FORM login page configured in web.xml is displayed. (correct)
> > The error is the saved juri is incorrect:
> > Redirecting to login page /secure/jaaslogin and remembering
> > juri=http://localhos
> > t:8080/ui/ajax_request/liftAjax.js
> > 
> > the remembering juri should be "localhost:8080/ui/jasssecured/index", not
> > "http://localhost:8080/ui/ajax_request/liftAjax.js".
> > 
> > 3. type correct user name and password, liftAjax.js is displayed, instead of
> > index.html.
> > 
> > I met this case in my fix, I did it as the following:
> >             //** Don't auth the Deferred authentication.
> >             Authentication authentication =
> > ((org.eclipse.jetty.server.Request)request).getAuthentication() ;
> >             if (authentication instanceof Authentication.Deferred )
> >                 return AuthStatus.SEND_SUCCESS;
> > 
> > before:
> >             session.setAttribute(__J_URI, buf.toString());
> > in FormAuthModule.validateRequest(JaspiMessageInfo messageInfo)
> > 
> > In JaspiAuthenticator.validateRequest(ServletRequest request, ServletResponse
> > response, boolean mandatory), I removed the following:
> >    if (_allowLazyAuthentication && !mandatory)
> >        return _deferred;
> > 
> > and added in JaspiAuthenticator.validateRequest(JaspiMessageInfo messageInfo)
> > the following:
> >            if (authStatus == AuthStatus.SUCCESS)
> >             {
> >                 if ( !isMandatory( messageInfo ) )
> >                     return _deferred ;
> > 
> > In my mail, I said I do not know if I did the above change to
> > JaspiAuthenticator correctly. Does the change make FormAuthModule to deal with
> > Authentication.Deferred in the above if statement?
Comment 13 guofeng zhang CLA 2011-10-11 06:22:26 EDT
(In reply to comment #8)
Yes. You are right. for my fix, I let FormAuthModule return SEND_CONTINUE. but this is just temporary for me.
Comment 14 guofeng zhang CLA 2011-10-11 06:44:36 EDT
(In reply to comment #12)

liftAjax.js is refereneced in the form login page. it is not protected by Jetty. The form login page and all resources referenced in the form login page are not protected.

I tested the last change in the branch. case 1 passed, but others failed.

case 1: (1) let the browser point to the protected page: http://localhost:8080/ui/jasssecured/index
        (2) the login page displayed correctly, type the correct user name and password, the index page is displayed.
     this test case passed.

case 2:
    (1) let the browser point to the protected page: http://localhost:8080/ui/jasssecured/index
    (2) the login page displayed correctly, type the wrong user name and/or password to force the login failure. 
    (3) login error page displayed correctly. there is a link on the error page to go to the login page again.
    (4) on the login page, type correct user name and password, the console output indicate that the login module works well. but the browser still display the login page. type http://localhost:8080/ui/jasssecured/index directly in the address bar, the index page displayed correctly.
    in step 3, if i donot click the link on the error page to go to the form login page directly, but type http://localhost:8080/ui/jasssecured/index in the address bar, the form login page displayed correctly. Type correct user name and password, the bahavior is the same as (4).
    
case 3: open the form login page directly: http://localhost:8080/ui/secure/jaaslogin. type correct user name and password. the browser still display the login page. then type http://localhost:8080/ui/jasssecured/index, the index page displayed directly.
Comment 15 Jan Bartel CLA 2011-10-11 20:57:42 EDT
Created attachment 204981 [details]
Tar file of small test webapp maven project for jaspi testing

Small test webapp for doing jaspi testing.
Comment 16 Jan Bartel CLA 2011-10-11 20:59:56 EDT
Guofeng,

I have not been able to reproduce the problems you reported. Did you check that your browser caches had been emptied before doing the tests?

I've also attached a small test webapp that I'm using. After unpacking it, do:
  mvn jetty:run

Then hit the url http://localhost:8080/foo/auth.html. Click on the link that says "jaspi/index.html - Authenticated Any User" to hit a protected url that will force you to the login form.

cheers
Jan
Comment 17 guofeng zhang CLA 2011-10-12 02:40:24 EDT
Created attachment 204993 [details]
the test web app for JASPI fix
Comment 18 guofeng zhang CLA 2011-10-12 05:08:18 EDT
Created attachment 205006 [details]
my test web app

This attachment can reproduce the failure described in comment 14.
Comment 19 guofeng zhang CLA 2011-10-12 05:30:09 EDT
(In reply to comment #18)
> Created attachment 205006 [details]
> my test web app
> 
> This attachment can reproduce the failure described in comment 14.

Using your test web app, I cannot reproduce the failure described in comment 14. but using my web app, it can be reproduced. I use the same browser: Google Chrome 16.0.899.0.

The attached is a simplified version of my web app. but It can be used to reproduce the errors.

I think the issue might relate to the session setting after the successful authentication.

In org.planner.ui.bootstrap.Boot.scala, I have the following code:


    LiftRules.earlyInStateful.append(
    ignoredReq => {
         Authentication.tryToStoreCurrentUserAndRolesInSession()
      }
    )
/*

    // Check Login -  if not login, directory to /secure/login
    LiftRules.dispatch.prepend(NamedPF("Login Validation") {
      case Req( page, "", _)
      if !MUser.loggedIn_? && page.head != "secure" && page.head != "static" =>
      {
       _log.debug( "MUser.loggedIn_?:"+MUser.loggedIn_? + " page:" + page);
        () => Full(RedirectResponse("/secure/jaaslogin"))
      }
    })

*/

I comment the last part so that the form login page is not affected by this part.

If I comment out:
    LiftRules.earlyInStateful.append(
    ignoredReq => {
         Authentication.tryToStoreCurrentUserAndRolesInSession()
      }
    )
Your fix works well using the test cases in comment 14. but if I enable it (i.e, uncomment it), the errors described in comment 14 reproduced. The above code only store the  user object in the session.

In my attachment, there are myfixlog and yourfixlog. you can compare the difference. Main part as the following:
Yours:
16:57:09.598 [qtp6435687-18 - /ui/secure/j_security_check] DEBUG org.eclipse.jetty.server.Server - REQUEST /ui/secure/j_security_check on org.eclipse.jetty.server.nio.SelectChannelConnector$SelectChannelHttpConnection@dc5434@127.0.0.1:8080<->127.0.0.1:1233
.......
16:57:09.645 [qtp6435687-18 - /ui/secure/j_security_check] DEBUG org.eclipse.jetty.server.Server - RESPONSE /ui/secure/j_security_check  302
...
==>16:57:09.645 [qtp6435687-19 - /ui/secure/jaaslogin] DEBUG org.eclipse.jetty.server.Server - REQUEST /ui/secure/jaaslogin on org.eclipse.jetty.server.nio.SelectChannelConnector$SelectChannelHttpConnection@dc5434@127.0.0.1:8080<->127.0.0.1:1233

My:
17:00:20.695 [qtp6847200-18 - /ui/secure/j_security_check] DEBUG org.eclipse.jetty.server.Server - REQUEST /ui/secure/j_security_check on org.eclipse.jetty.server.nio.SelectChannelConnector$SelectChannelHttpConnection@6e18b0@127.0.0.1:8080<->127.0.0.1:1261
...
17:00:20.758 [qtp6847200-18 - /ui/secure/j_security_check] DEBUG org.eclipse.jetty.server.Server - RESPONSE /ui/secure/j_security_check  302
==>17:00:20.758 [qtp6847200-20 - /ui/jasssecured/index] DEBUG org.eclipse.jetty.server.Server - REQUEST /ui/jasssecured/index on org.eclipse.jetty.server.nio.SelectChannelConnector$SelectChannelHttpConnection@6e18b0@127.0.0.1:8080<->127.0.0.1:1261

Another: I find that your fix will invoke the login module when the user has been authenticated and the protected resource is re-accessed. I think it should not invoke the login module if the user has been authenticated (the authentication might take time and deal with it in the login module is not an easy task).

There are two subdirectories in my attachmeht. first you could build security module (containing the login module). then using mvn jetty:run in the ui module to run jetty. 

NOTE THAT the user name and password is hard coded as "admin" and "password" in the login module.

you can access the protected resource using: 
  localhost:8080/ui/jasssecured/index
it should display the form login page. input "admin/password" to log in or test the failure cases.
Comment 20 guofeng zhang CLA 2011-10-12 05:40:27 EDT
(In reply to comment #19)

you please first change the jetty.version property to 7.5.2-SNAPSHOT of pom.xml in the root directory. In the attachment it is set as the following:
  <properties>
   ....
    <jetty.version>8.0.3.v20111011</jetty.version>
    <!--jetty.version>7.5.2-SNAPSHOT</jetty.version-->
    ...
  </properties>
Comment 21 Jan Bartel CLA 2011-10-13 01:46:55 EDT
Hi Guofeng,

> Another: I find that your fix will invoke the login module when the user has
> been authenticated and the protected resource is re-accessed. I think it should
> not invoke the login module if the user has been authenticated (the
> authentication might take time and deal with it in the login module is not an
> easy task).

The FormAuthModule validateRequest will always be called, but unless J_SECURITY_CHECK is on the request url (ie its the form login module POST), then the JAAS login module should not be called.

I'm still trying to work out why calling request.getRemoteUser() should cause the problem shown by your test webapp. Will post later when I have more info.

cheers
Jan
Comment 22 guofeng zhang CLA 2011-10-13 03:21:47 EDT
(In reply to comment #21)
> 
> The FormAuthModule validateRequest will always be called, but unless
> J_SECURITY_CHECK is on the request url (ie its the form login module POST),
> then the JAAS login module should not be called.
> 

FormAuthModule.validateRequest() will invoke the login module using the following code:
            if (form_cred != null)
            {
                boolean success = tryLogin(messageInfo, clientSubject, response, session, form_cred._jUserName, new Password(new String(form_cred._jPassword)));
                if (success) { return AuthStatus.SUCCESS; }
            }
I think the session has been authenticated when form_cred is not null, so I change it to:
            if (form_cred != null)
            {
            	clientSubject.getPrivateCredentials().addAll( form_cred._subject.getPrivateCredentials( UserIdentity.class) ) ;
                return AuthStatus.SUCCESS;
            }

For this, I add Subject field in FormCredential class:
    private static class FormCredential implements Serializable, HttpSessionBindingListener
    {
        ....
        transient Subject _subject ;

        private FormCredential(String _jUserName, char[] _jPassword, Principal _userPrincipal, Subject subject)
        {
            .......
            this._subject = subject ;
        }
and in tryLogin() method, if the user is authenticated successfully:
            if (!loginCallbacks.isEmpty())
            {
                LoginCallbackImpl loginCallback = loginCallbacks.iterator().next();
                FormCredential form_cred = new FormCredential(username, pwdChars, loginCallback.getUserPrincipal(), loginCallback.getSubject() );

                session.setAttribute(__J_AUTHENTICATED, form_cred);
            }
In this way, if the session has been authenticated, the login module won't be invoked again.
Comment 23 Jan Bartel CLA 2011-10-14 00:44:41 EDT
Hi Guofeng,

I fixed the FormAuthModule so that your test webapp worked. Changes checked into the branch. It was a silly error with checking if the inbound request matched the login page. So you should be good to update your branch and try again (Note that the jetty version has changed to 7.5.4-SNAPSHOT as I've merged HEAD into the branch).

As for trying to avoid invoking the LoginModule for a request for protected resource AFTER authentication has already taken place, that is a bit more problematic.

I see with your workaround you are trying to use the information in the Subject to achieve it, however I don't think we're 100% there with that solution.

I think we somehow need to invoke the LoginService.validate(UserIdentity) method, which is what the other non-jaspi jetty authentication code does (eg see FormAuthenticator line 240). The difficulty is that the FormAuthModule does not know about the LoginService, so that is going to be difficult to arrange.

I will think about this one over the weekend.

cheers
Jan



(In reply to comment #22)
> (In reply to comment #21)
> > 
> > The FormAuthModule validateRequest will always be called, but unless
> > J_SECURITY_CHECK is on the request url (ie its the form login module POST),
> > then the JAAS login module should not be called.
> > 
> 
> FormAuthModule.validateRequest() will invoke the login module using the
> following code:
>             if (form_cred != null)
>             {
>                 boolean success = tryLogin(messageInfo, clientSubject,
> response, session, form_cred._jUserName, new Password(new
> String(form_cred._jPassword)));
>                 if (success) { return AuthStatus.SUCCESS; }
>             }
> I think the session has been authenticated when form_cred is not null, so I
> change it to:
>             if (form_cred != null)
>             {
>                 clientSubject.getPrivateCredentials().addAll(
> form_cred._subject.getPrivateCredentials( UserIdentity.class) ) ;
>                 return AuthStatus.SUCCESS;
>             }
> 
> For this, I add Subject field in FormCredential class:
>     private static class FormCredential implements Serializable,
> HttpSessionBindingListener
>     {
>         ....
>         transient Subject _subject ;
> 
>         private FormCredential(String _jUserName, char[] _jPassword, Principal
> _userPrincipal, Subject subject)
>         {
>             .......
>             this._subject = subject ;
>         }
> and in tryLogin() method, if the user is authenticated successfully:
>             if (!loginCallbacks.isEmpty())
>             {
>                 LoginCallbackImpl loginCallback =
> loginCallbacks.iterator().next();
>                 FormCredential form_cred = new FormCredential(username,
> pwdChars, loginCallback.getUserPrincipal(), loginCallback.getSubject() );
> 
>                 session.setAttribute(__J_AUTHENTICATED, form_cred);
>             }
> In this way, if the session has been authenticated, the login module won't be
> invoked again.
Comment 24 guofeng zhang CLA 2011-10-14 11:06:56 EDT
(In reply to comment #23)

Hi Jan,

Hi, Jan,

Could you deploy 7.5.4_SNAPSHOT to https://oss.sonatype.org/content/groups/jetty/, especially jetty-maven-plugin:7.5.4_SNAPSHOT. I do not know how to launch 7.5.4_SNAPSHOT jetty server using the plugin.


> 
> I think we somehow need to invoke the LoginService.validate(UserIdentity)
> method, which is what the other non-jaspi jetty authentication code does (eg
> see FormAuthenticator line 240). The difficulty is that the FormAuthModule does
> not know about the LoginService, so that is going to be difficult to arrange.

I do not have the bird-view of Jetty's identity/authentication service. By browsing ServletCallbackHandler class in jetty-jaspi module, I have made that workarround, so I do not know if I did it well. You please make your decision. But I think avoid invoking the login module is a useful requirement.

I forget mentioning the following in my comment 22. I also made changes to ServletCallbackHandler.handle(), I added:
            else if (callback instanceof CredentialValidationCallback)
            {
               ...
                if (user!=null)
                {
                    .....
credentialValidationCallback.getSubject().getPrivateCredentials().add( loginCallback ) ;
                }
            }
loginService is called here. loginServer should reference to JAASLoginServer, the login method of JAASLoginService has no side-effect, but return a identity service instance which wrapping the subject. So I think it might be not problematic not to call loginService.login() when the session has been authenticated. 

Thanks!
Comment 25 guofeng zhang CLA 2011-10-16 23:46:25 EDT
(In reply to comment #24)
> (In reply to comment #23)
> 
> Hi Jan,

> Could you deploy 7.5.4_SNAPSHOT to
> https://oss.sonatype.org/content/groups/jetty/, especially
> jetty-maven-plugin:7.5.4_SNAPSHOT. I do not know how to launch 7.5.4_SNAPSHOT
> jetty server using the plugin.
> 
I tested 7.5.4-SNAPSHOT using my test app. The following cases passed:

(1) accss http://localhost:8080/ui/jasssecured/index, the login page displayed, type correct user name and password, the index.html page is displayed (passed)
(2) accss http://localhost:8080/ui/secure/jaaslogin, that is, directly open the form login page, type correctly user name and password, the root index page (/) displayed. (passed)

But if I input incorrect username or password for the above two cases, the result is not expected:
(1) accss http://localhost:8080/ui/jasssecured/index, the login page displayed, type incorrect user name or password, the form error page is displayed. On this page, there is a link to the form login page, click it to go to the login page again, then type correct user name and password, the displayed page is still the login page. the expected result should be the index page is displayed. (not passed)
(2) accss http://localhost:8080/ui/secure/jaaslogin, that is, directly open the form login page, type incorrect user name and password, the form error page is displayed. Click the link on the page to go to the login page again. Type correct user name and password, the displayed page is still the login page. the expected result should be the root index page (that is, /) is displayed. (not passed)
Comment 26 Jan Bartel CLA 2011-10-17 04:30:40 EDT
(In reply to comment #25)

Hi Guofeng,

There's a couple of things that are stopping cases 2 and 3 working as expected. Firstly, the jaspi module has been configured with the login and error pages as /secure/jaaslogin and /secure/jaaserror, but the link on the jaaserror page links to /secure/jaaslogin.html. The FormAuthModule has no way of knowing that /secure/jaaslogin and /secure/jaaslogin.html are the same thing because of the framework you're using. Changing the link to /secure/jaaslogin removes this problem.

After fixing the link, and after incorrectly entering the login name/pwd,then following the link, and then correctly entering the login name/pwd, the contents of the /ui/ajax_request/liftAjax.js are displayed. The reason for this is:

1. the incoming request for the /ui/ajax_request/liftAjax.js - which is not behind a protected url - is handled by the SecurityHandler/jaspi as a Deferred authentication.

2. the same incoming request then passes through to the servlet, which passes it to the Authentication.tryToStoreCurrentUserAndRolesInSession method, which triggers the Deferred authentication to authenticate the user, which redirects to the login page (because no login has succeeded yet), and remembers the page that was being requested that triggered the authentication.

So, because of the Authentication.tryToStoreCurrentUserAndRolesInSession JaspiAuthenticator.validateRequest() will be called for every request, even on urls that are not protected. For urls that are protected, JaspiAuthenticator.validateRequest() will sometimes be called twice: once by the SecurityHandler looking after the protected url, and then once by the Authentication.tryToStoreCurrentUserAndRolesInSession.



cheers
Jan
Comment 27 Jan Bartel CLA 2011-10-17 19:46:52 EDT
Guofeng,

OK, I've added support for calling Request.getRemoteUser() on a DeferredAuthentication. When this happens, the FormAuthModule cannot really process the authentication, because it cannot send a challenge to direct the user to the form and thus capture the username/password. So in this edge case, the FormAuthModule really has to return AuthStatus.SUCCESS (same as it does if the auth isn't mandatory).

So I think all of your test cases are now working - but please do let me know if not.

thanks
Jan
Comment 28 guofeng zhang CLA 2011-10-18 06:11:55 EDT
(In reply to comment #27)
Hi jan,

My tests passed. Thanks!
Comment 29 Jan Bartel CLA 2012-01-08 22:26:56 EST
Released in 7.6.0.RC3.
Comment 30 guofeng zhang CLA 2012-01-11 00:32:56 EST
(In reply to comment #29)
> Released in 7.6.0.RC3.

When will it be merged to 8.x? we know that it not works in 8.x either.
Comment 31 Jan Bartel CLA 2012-01-11 01:15:56 EST
Hi Guofeng,

it was merged into jetty-8 in time for a RC3 release but we don't seem to have done that release. In any case, it is all ready to go next time we do a release of jetty-8.

cheers
Jan
Comment 32 guofeng zhang CLA 2012-01-15 23:30:37 EST
Jan,

I tried 8.1.0.RC4. I found that you have merged what I mentioned in Comment 22 and Comment 24 about not invoking login module again when the user has been authenticated. I wonder if you forget the following change in FormAuthModule.validateRequest:
                //TODO: we would like the form auth module to be able to invoke the loginservice.validate() method to check the previously authed user
                //
                //boolean success = tryLogin(messageInfo, clientSubject, response, session, form_cred._jUserName, new Password(new String(form_cred._jPassword)));
                //if (success) { return AuthStatus.SUCCESS; }
                //** Change to:
            	clientSubject.getPrivateCredentials().addAll( form_cred._subject.getPrivateCredentials( UserIdentity.class) ) ;
                return AuthStatus.SUCCESS;

If the above change is not merged, the login module will be always called even if the user has logged in successfully.

Hope I understand the RC4 code correctly.

Guofeng
Comment 33 Jan Bartel CLA 2012-01-17 02:50:29 EST
Hi Guofeng,

I can't quite remember exactly, but I thought we avoided calling the LoginModule again because when we go into FormAuthModule.validateRequest, it is not mandatory?

Can you go back to using the bug-359329 branch, as it has debug output in it, and send me the log that shows that we call the LoginModule even if the user has already been authenticated???

thanks,
Jan

(In reply to comment #32)
> Jan,
> 
> I tried 8.1.0.RC4. I found that you have merged what I mentioned in Comment 22
> and Comment 24 about not invoking login module again when the user has been
> authenticated. I wonder if you forget the following change in
> FormAuthModule.validateRequest:
>                 //TODO: we would like the form auth module to be able to invoke
> the loginservice.validate() method to check the previously authed user
>                 //
>                 //boolean success = tryLogin(messageInfo, clientSubject,
> response, session, form_cred._jUserName, new Password(new
> String(form_cred._jPassword)));
>                 //if (success) { return AuthStatus.SUCCESS; }
>                 //** Change to:
>                 clientSubject.getPrivateCredentials().addAll(
> form_cred._subject.getPrivateCredentials( UserIdentity.class) ) ;
>                 return AuthStatus.SUCCESS;
> 
> If the above change is not merged, the login module will be always called even
> if the user has logged in successfully.
> 
> Hope I understand the RC4 code correctly.
> 
> Guofeng
Comment 34 guofeng zhang CLA 2012-01-17 04:05:35 EST
(In reply to comment #33)
> Hi Guofeng,
> 
> I can't quite remember exactly, but I thought we avoided calling the
> LoginModule again because when we go into FormAuthModule.validateRequest, it is
> not mandatory?
> 
> Can you go back to using the bug-359329 branch, as it has debug output in it,
> and send me the log that shows that we call the LoginModule even if the user
> has already been authenticated???
> 
> thanks,
> Jan

This test is done against my attached test web app.

jasssecured/* is protected by web security in web.xml.

(1) when I typed http://localhost:8080/ui/jasssecured/index. the login page display, and I did the log in:
.....
ISLOGINORERRORPAGE? /jasssecured/index error: /secure/jaaserror login:/secure/jaaslogin
Form cred: form.username=admin form.pwd=password
user name: admin <----------My Login Module's output
LoginCallbackImpls.isEmpty=false

(2)then I typed http://localhost:8080/ui/jasssecured/first.
ISLOGINORERRORPAGE? /jasssecured/first error: /secure/jaaserror login:/secure/jaaslogin
Form cred: form.username=admin form.pwd=password
user name: admin <----------My Login Module's output

The following is the output. I removed the stacktrace.

ISLOGINORERRORPAGE? / error: /secure/jaaserror login:/secure/jaaslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/ mandato
ry=true isLoginOrError=false
ISLOGINORERRORPAGE? / error: /secure/jaaserror login:/secure/jaaslogin
JaspiAuthenticator.validateRequest returning UNAUTHENTICATED
16:47:09.114 [qtp5177132-15] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/ returned 302, took 500 Milliseconds
Securityhandler calling secureResponse, for Authentication.User
JaspiAuthenticator.secureResponse uri=/ui/

JaspiAuthenticator.validateRequest, uri=/ui/secure/jaaslogin lazy=true mandatory
=false
...............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /secure/jaaslogin error: /secure/jaaserror login:/secure/jaa
slogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/secure/j
aaslogin mandatory=false isLoginOrError=true
JaspiAuthenticator.validateRequest returning org.eclipse.jetty.security.authenti
cation.DeferredAuthentication@135236e
uri=/ui/secure/jaaslogin Auth is deferred

JaspiAuthenticator.validateRequest, uri=/ui/secure/jaaslogin lazy=true mandatory
=true
..............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /secure/jaaslogin error: /secure/jaaserror login:/secure/jaa
slogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/secure/j
aaslogin mandatory=true isLoginOrError=true
ISLOGINORERRORPAGE? /secure/jaaslogin error: /secure/jaaserror login:/secure/jaa
slogin
JaspiAuthenticator.validateRequest returning UNAUTHENTICATED
16:47:09.567 [qtp5177132-15] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/secure/jaaslogin returned 200, took 438 Milliseconds
Securityhandler calling secureResponse, for Authentication.User
JaspiAuthenticator.secureResponse uri=/ui/secure/jaaslogin

JaspiAuthenticator.validateRequest, uri=/ui/jasssecured/index lazy=true mandator
y=true
.............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /jasssecured/index error: /secure/jaaserror login:/secure/ja
aslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/jasssecu
red/index mandatory=true isLoginOrError=false
ISLOGINORERRORPAGE? /jasssecured/index error: /secure/jaaserror login:/secure/ja
aslogin
Redirecting to login page /secure/jaaslogin and remembering juri=http://localhos
t:8080/ui/jasssecured/index
JaspiAuthenticator.validateRequest returning CHALLENGE

JaspiAuthenticator.validateRequest, uri=/ui/secure/j_security_check lazy=true ma
ndatory=false
..................
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /secure/j_security_check error: /secure/jaaserror login:/sec
ure/jaaslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/secure/j
_security_check mandatory=true isLoginOrError=false
ISLOGINORERRORPAGE? /secure/j_security_check error: /secure/jaaserror login:/sec
ure/jaaslogin
Try login username=admin password=password
user name: admin
LoginCallbackImpls.isEmpty=false
FormAuthModule, LoginCallbackImpl.isEmpty=false
FormAuthModule succesful login, sending redirect to http://localhost:8080/ui/jas
ssecured/index
JaspiAuthenticator.validateRequest returning CHALLENGE

JaspiAuthenticator.validateRequest, uri=/ui/jasssecured/index lazy=true mandator
y=true
...............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /jasssecured/index error: /secure/jaaserror login:/secure/ja
aslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/jasssecu
red/index mandatory=true isLoginOrError=false
ISLOGINORERRORPAGE? /jasssecured/index error: /secure/jaaserror login:/secure/jaaslogin
Form cred: form.username=admin form.pwd=password
user name: admin
LoginCallbackImpls.isEmpty=false
FormAuthModule, LoginCallbackImpl.isEmpty=false
JaspiAuthenticator.validateRequest returning {User,JASPI,DefaultUserIdentity('ad
min')}
16:47:27.504 [qtp5177132-20] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/jasssecured/index returned 200, took 250 Milliseconds
JaspiAuthenticator.secureResponse uri=/ui/jasssecured/index

JaspiAuthenticator.validateRequest, uri=/ui/ajax_request/liftAjax.js lazy=true m
andatory=false
..............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /ajax_request/liftAjax.js error: /secure/jaaserror login:/se
cure/jaaslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/ajax_req
uest/liftAjax.js mandatory=false isLoginOrError=false
JaspiAuthenticator.validateRequest returning org.eclipse.jetty.security.authenti
cation.DeferredAuthentication@135236e
uri=/ui/ajax_request/liftAjax.js Auth is deferred

JaspiAuthenticator.validateRequest, uri=/ui/ajax_request/liftAjax.js lazy=true m
andatory=true
...............
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /ajax_request/liftAjax.js error: /secure/jaaserror login:/se
cure/jaaslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/ajax_req
uest/liftAjax.js mandatory=true isLoginOrError=false
ISLOGINORERRORPAGE? /ajax_request/liftAjax.js error: /secure/jaaserror login:/se
cure/jaaslogin
Form cred: form.username=admin form.pwd=password
user name: admin
LoginCallbackImpls.isEmpty=false
FormAuthModule, LoginCallbackImpl.isEmpty=false
JaspiAuthenticator.validateRequest returning {User,JASPI,DefaultUserIdentity('ad
min')}
16:47:27.692 [qtp5177132-16] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/ajax_request/liftAjax.js returned 200, took 157 Milliseconds
Securityhandler calling secureResponse, for Authentication.User
JaspiAuthenticator.secureResponse uri=/ui/ajax_request/liftAjax.js

JaspiAuthenticator.validateRequest, uri=/ui/jasssecured/first lazy=true mandator
y=true
.....................
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /jasssecured/first error: /secure/jaaserror login:/secure/ja
aslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/jasssecu
red/first mandatory=true isLoginOrError=false
ISLOGINORERRORPAGE? /jasssecured/first error: /secure/jaaserror login:/secure/jaaslogin
Form cred: form.username=admin form.pwd=password
user name: admin
LoginCallbackImpls.isEmpty=false
FormAuthModule, LoginCallbackImpl.isEmpty=false
JaspiAuthenticator.validateRequest returning {User,JASPI,DefaultUserIdentity('ad
min')}
16:47:33.020 [qtp5177132-18] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/jasssecured/first returned 200, took 47 Milliseconds
JaspiAuthenticator.secureResponse uri=/ui/jasssecured/first

JaspiAuthenticator.validateRequest, uri=/ui/ajax_request/liftAjax.js lazy=true m
andatory=false
......................
jaspAuthenticator.validateRequest(info)
ISLOGINORERRORPAGE? /ajax_request/liftAjax.js error: /secure/jaaserror login:/se
cure/jaaslogin
FormAuthModule.validateRequest(info,subject,serviceSubject) for uri=/ui/ajax_req
uest/liftAjax.js mandatory=false isLoginOrError=false
JaspiAuthenticator.validateRequest returning {User,JASPI,DefaultUserIdentity('ad
min')}
16:47:33.098 [qtp5177132-20] INFO  net.liftweb.util.TimeHelpers - Service reques
t (GET) /ui/ajax_request/liftAjax.js returned 200, took 0 Milliseconds
JaspiAuthenticator.secureResponse uri=/ui/ajax_request/liftAjax.js
Comment 35 Jan Bartel CLA 2012-01-19 02:32:01 EST
Hi Guofeng,

I'd really rather find some way that the FormAuthModule could invoke the LoginService.validate method, but I just haven't been able to think of one!

So failing that, I implemented your suggestion of copying the private credentials from the subject stored in the form_cred. I've committed that change to the branch - can you retest on your system? It seems to work for me, and doesn't seem to have broken anything else.

thanks
Jan
Comment 36 Jan Bartel CLA 2012-01-19 02:32:36 EST
Reopening for the enhancement to avoid reinvoking LoginModule.login when already authenticated.
Comment 37 guofeng zhang CLA 2012-01-19 04:39:28 EST
(In reply to comment #36)
> Reopening for the enhancement to avoid reinvoking LoginModule.login when
> already authenticated.

It works OK now. Thanks!
Comment 38 Jan Bartel CLA 2012-01-24 01:31:53 EST
Fixed for RC5.