improved deferred authentication handling

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@619 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2009-08-03 02:39:33 +00:00
parent e433265fb2
commit 3c71736a7a
18 changed files with 157 additions and 29 deletions

View File

@ -11,6 +11,7 @@ jetty-7.0.0.RC2 29 June 2009
+ 284981 Implement a cross-origin filter
+ Improved handling of overlays and resourceCollections
+ 285006 fix AbstractConnector NPE during shutdown.
+ Improved deferred authentication handling
jetty-7.0.0.RC1 15 June 2009
+ JETTY-1066 283357 400 response for bad URIs

View File

@ -28,5 +28,10 @@
<artifactId>jetty-deploy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -13,8 +13,14 @@
package org.eclipse.jetty.embedded;
import java.lang.management.ManagementFactory;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanServer;
import org.eclipse.jetty.deploy.ContextDeployer;
import org.eclipse.jetty.deploy.WebAppDeployer;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
@ -26,6 +32,7 @@ import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
public class LikeJettyXml
@ -36,7 +43,15 @@ public class LikeJettyXml
System.setProperty("jetty.home",jetty_home);
Server server = new Server();
// Setup JMX
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
server.getContainer().addEventListener(mbContainer);
server.addBean(mbContainer);
mbContainer.addBean(Log.getLog());
// Setup Connectors
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(100);
server.setThreadPool(threadPool);
@ -63,6 +78,9 @@ public class LikeJettyXml
{ contexts, new DefaultHandler(), requestLogHandler });
server.setHandler(handlers);
// Setup deployers
ContextDeployer deployer0 = new ContextDeployer();
deployer0.setContexts(contexts);
deployer0.setConfigurationDir(jetty_home + "/contexts");

View File

@ -32,6 +32,7 @@ import org.eclipse.jetty.security.UserAuthentication;
import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.authentication.DeferredAuthenticator;
import org.eclipse.jetty.security.authentication.DeferredAuthenticator.DeferredAuthentication;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.Authentication.User;
@ -47,6 +48,7 @@ public class JaspiAuthenticator implements Authenticator
private final Subject _serviceSubject;
private final boolean _allowLazyAuthentication;
private final IdentityService _identityService;
private final DeferredAuthentication _deferred;
public JaspiAuthenticator(ServerAuthConfig authConfig, Map authProperties, ServletCallbackHandler callbackHandler,
Subject serviceSubject, boolean allowLazyAuthentication, IdentityService identityService)
@ -62,6 +64,7 @@ public class JaspiAuthenticator implements Authenticator
this._serviceSubject = serviceSubject;
this._allowLazyAuthentication = allowLazyAuthentication;
this._identityService = identityService;
this._deferred=new DeferredAuthentication(this);
}
@ -78,7 +81,7 @@ public class JaspiAuthenticator implements Authenticator
public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
{
if (_allowLazyAuthentication && !mandatory)
return new DeferredAuthenticator.DeferredAuthentication(this,request,response);
return _deferred;
JaspiMessageInfo info = new JaspiMessageInfo(request, response, mandatory);
request.setAttribute("org.eclipse.jetty.security.jaspi.info",info);
@ -104,7 +107,6 @@ public class JaspiAuthenticator implements Authenticator
AuthStatus authStatus = authContext.validateRequest(messageInfo,clientSubject,_serviceSubject);
// String authMethod = (String)messageInfo.getMap().get(JaspiMessageInfo.AUTH_METHOD_KEY);
if (authStatus == AuthStatus.SEND_CONTINUE)
return Authentication.SEND_CONTINUE;
if (authStatus == AuthStatus.SEND_FAILURE)
@ -173,4 +175,10 @@ public class JaspiAuthenticator implements Authenticator
}
}
public boolean isMandatory(ServletRequest request)
{
return false;
}
}

View File

@ -30,7 +30,7 @@
<!-- Add to the Server as a lifecycle -->
<!-- Only do this if you know you will only have a single jetty server -->
<Call name="addLifeCycle">
<Call name="addBean">
<Arg><Ref id="MBeanContainer"/></Arg>
</Call>

View File

@ -0,0 +1,2 @@
AbstractHandler: Jetty Handler.
dump(): dump the handler structure as a string

View File

@ -62,6 +62,15 @@ public interface Authenticator
*/
Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException;
/* ------------------------------------------------------------ */
/** Ask Authenticator if authentication is mandatory for a specific request.
* This allows authenticators like FORM authentication to be called for specific requests like j_security_check,
* even if there is not constraint.
*
* @param request
* @return
*/
boolean isMandatory(ServletRequest request);
/* ------------------------------------------------------------ */
/**

View File

@ -340,4 +340,17 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
}
return false;
}
/* ------------------------------------------------------------ */
protected void dump(StringBuilder b,String indent)
{
super.dump(b,indent);
b.append(indent).append(" +=roles=").append(_roles).append('\n');
for (Object path : _constraintMap.keySet())
{
Object constraint = _constraintMap.get(path);
b.append(indent).append(" +=").append(path).append('=').append(constraint).append('\n');
}
}
}

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.security;
import java.io.IOException;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -43,6 +44,12 @@ import org.eclipse.jetty.util.log.Log;
* The Authenticator may either be directly set on the handler
* or will be create during {@link #start()} with a call to
* either the default or set AuthenticatorFactory.
* <p>
* SecurityHandler has a set of initparameters that are used by the
* Authentication.Configuration. At startup, any context init parameters
* that start with "org.eclipse.jetty.security." that do not have
* values in the SecurityHandler init parameters, are copied.
*
*/
public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.Configuration
{
@ -284,6 +291,20 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
protected void doStart()
throws Exception
{
// copy security init parameters
ContextHandler.Context context =ContextHandler.getCurrentContext();
if (context!=null)
{
Enumeration<String> names=context.getInitParameterNames();
while (names!=null && names.hasMoreElements())
{
String name =names.nextElement();
if (name.startsWith("org.eclipse.jetty.security.") &&
getInitParameter(name)==null)
setInitParameter(name,context.getInitParameter(name));
}
}
// complicated resolution of login and identity service to handle
// many different ways these can be constructed and injected.
@ -404,14 +425,17 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
return;
}
final Authenticator authenticator = _authenticator;
// is Auth mandatory?
boolean isAuthMandatory = isAuthMandatory(baseRequest, base_response, constraintInfo);
boolean isAuthMandatory =
isAuthMandatory(baseRequest, base_response, constraintInfo) ||
authenticator.isMandatory(request);
// check authentication
Object previousIdentity = null;
try
{
final Authenticator authenticator = _authenticator;
Authentication authentication = baseRequest.getAuthentication();
if (authentication==null || authentication==Authentication.NOT_CHECKED)
authentication=authenticator.validateRequest(request, response, isAuthMandatory);
@ -469,7 +493,6 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
}
else
authenticator.secureResponse(request, response, isAuthMandatory, null);
//TODO fish previousIdentity out of something.
}
else
{

View File

@ -44,10 +44,13 @@ import org.eclipse.jetty.util.log.Log;
*/
public class DeferredAuthenticator extends DelegateAuthenticator
{
private final DeferredAuthentication _deferred;
/* ------------------------------------------------------------ */
public DeferredAuthenticator(Authenticator delegate)
{
super(delegate);
_deferred=new DeferredAuthentication(delegate);
}
/* ------------------------------------------------------------ */
@ -57,10 +60,9 @@ public class DeferredAuthenticator extends DelegateAuthenticator
*/
public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
{
if (!mandatory)
{
return new DeferredAuthentication(_delegate,request,response);
}
if (!(mandatory || _delegate.isMandatory(request)))
return _deferred;
return _delegate.validateRequest(request,response,mandatory);
}
@ -70,19 +72,15 @@ public class DeferredAuthenticator extends DelegateAuthenticator
public static class DeferredAuthentication implements Authentication.Deferred
{
protected final Authenticator _authenticator;
protected final ServletRequest _request;
protected final ServletResponse _response;
private IdentityService _identityService;
private Object _previousAssociation;
public DeferredAuthentication(Authenticator authenticator, ServletRequest request, ServletResponse response)
public DeferredAuthentication(Authenticator authenticator)
{
if (authenticator == null)
throw new NullPointerException("No Authenticator");
this._authenticator = authenticator;
this._request = request;
this._response = response;
}
/* ------------------------------------------------------------ */
@ -107,11 +105,11 @@ public class DeferredAuthenticator extends DelegateAuthenticator
/**
* @see org.eclipse.jetty.server.Authentication.Deferred#authenticate()
*/
public Authentication authenticate()
public Authentication authenticate(ServletRequest request)
{
try
{
Authentication authentication = _authenticator.validateRequest(_request,__nullResponse,false);
Authentication authentication = _authenticator.validateRequest(request,__nullResponse,false);
if (authentication!=null && (authentication instanceof Authentication.User) && !(authentication instanceof Authentication.ResponseSent))
{
@ -135,7 +133,7 @@ public class DeferredAuthenticator extends DelegateAuthenticator
{
try
{
Authentication authentication = _authenticator.validateRequest(_request,response,true);
Authentication authentication = _authenticator.validateRequest(request,response,true);
if (authentication instanceof Authentication.User && _identityService!=null)
_previousAssociation=_identityService.associate(((Authentication.User)authentication).getUserIdentity());
return authentication;
@ -328,4 +326,5 @@ public class DeferredAuthenticator extends DelegateAuthenticator
{
}
};
}

View File

@ -55,4 +55,8 @@ public class DelegateAuthenticator implements Authenticator
return _delegate.secureResponse(req,res, mandatory, validatedUser);
}
public boolean isMandatory(ServletRequest request)
{
return _delegate.isMandatory(request);
}
}

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.security.UserAuthentication;
import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.Authentication.Deferred;
import org.eclipse.jetty.server.Authentication.User;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
@ -48,8 +49,9 @@ import org.eclipse.jetty.util.log.Log;
* to be used together with the {@link SessionCachingAuthenticator} so that the
* auth results may be associated with the session.
*
* This authenticator implements form authentication using dispatchers unless
* the {@link #__FORM_DISPATCH} init parameters is set to false.
* This authenticator implements form authentication will use dispatchers to
* the login page if the {@link #__FORM_DISPATCH} init parameter is set to true.
* Otherwise it will redirect.
*
*/
public class FormAuthenticator extends LoginAuthenticator
@ -75,6 +77,7 @@ public class FormAuthenticator extends LoginAuthenticator
/* ------------------------------------------------------------ */
public FormAuthenticator(String login,String error)
{
this();
if (login!=null)
setLoginPage(login);
if (error!=null)
@ -96,7 +99,7 @@ public class FormAuthenticator extends LoginAuthenticator
if (error!=null)
setErrorPage(error);
String dispatch=configuration.getInitParameter(FormAuthenticator.__FORM_DISPATCH);
_dispatch=dispatch==null || Boolean.getBoolean(dispatch);
_dispatch=dispatch!=null && Boolean.getBoolean(dispatch);
}
/* ------------------------------------------------------------ */
@ -258,6 +261,12 @@ public class FormAuthenticator extends LoginAuthenticator
return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
}
/* ------------------------------------------------------------ */
public boolean isMandatory(ServletRequest request)
{
return ((HttpServletRequest)request).getRequestURI().endsWith(__J_SECURITY_CHECK);
}
/* ------------------------------------------------------------ */
public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
{

View File

@ -13,6 +13,8 @@
package org.eclipse.jetty.security.authentication;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
@ -41,4 +43,8 @@ public abstract class LoginAuthenticator implements Authenticator
return _loginService;
}
public boolean isMandatory(ServletRequest request)
{
return false;
}
}

View File

@ -12,7 +12,7 @@
# format, either plain text or OBF:.
#
jetty: MD5:164c88b302622e17050af52c89945d44,user
admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq,user
plain: plain,user
user: password,user

View File

@ -65,7 +65,7 @@ public interface Authentication
* non-manditory authentication.
* @return The new Authentication state.
*/
Authentication authenticate();
Authentication authenticate(ServletRequest request);
/* ------------------------------------------------------------ */
/** Authenticate and possibly send a challenge.

View File

@ -354,7 +354,7 @@ public class Request implements HttpServletRequest
public String getAuthType()
{
if (_authentication instanceof Authentication.Deferred)
_authentication = ((Authentication.Deferred)_authentication).authenticate();
_authentication = ((Authentication.Deferred)_authentication).authenticate(this);
if (_authentication instanceof Authentication.User)
return ((Authentication.User)_authentication).getAuthMethod();
@ -1174,7 +1174,7 @@ public class Request implements HttpServletRequest
public UserIdentity getUserIdentity()
{
if (_authentication instanceof Authentication.Deferred)
_authentication = ((Authentication.Deferred)_authentication).authenticate();
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
if (_authentication instanceof Authentication.User)
return ((Authentication.User)_authentication).getUserIdentity();
@ -1194,7 +1194,7 @@ public class Request implements HttpServletRequest
public Principal getUserPrincipal()
{
if (_authentication instanceof Authentication.Deferred)
_authentication = ((Authentication.Deferred)_authentication).authenticate();
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
if (_authentication instanceof Authentication.User)
{
@ -1278,7 +1278,7 @@ public class Request implements HttpServletRequest
public boolean isUserInRole(String role)
{
if (_authentication instanceof Authentication.Deferred)
_authentication = ((Authentication.Deferred)_authentication).authenticate();
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this));
if (_authentication instanceof Authentication.User)
return ((Authentication.User)_authentication).isUserInRole(_scope,role);
@ -1296,7 +1296,7 @@ public class Request implements HttpServletRequest
/* ------------------------------------------------------------ */
protected void recycle()
{
_authentication=Authentication.NOT_CHECKED;
setAuthentication(Authentication.NOT_CHECKED);
_async.recycle();
_asyncSupported=true;
_handled=false;

View File

@ -0,0 +1,29 @@
<HTML>
<HEAD>
<TITLE>Powered By Jetty - Auth Links</TITLE>
<META http-equiv="Pragma" content="no-cache">
<META http-equiv="Cache-Control" content="no-cache,no-store">
</HEAD>
<BODY>
<A HREF="http://jetty.eclipse.org"><IMG SRC="jetty_banner.gif"></A>
<h1>Jetty 7 Authentication Links</h1>
<p>
This page contains several links to test the authentication constraints:
<ul>
<li><a href="auth/file.txt">auth/file.txt</a> - Forbidden</li>
<li><a href="auth/relax.txt">auth/relax.txt</a> - Allowed</li>
<li><a href="dump/auth/noaccess/info">dump/auth/noaccess/*</a> - Forbidden</li>
<li><a href="dump/auth/relax/info">dump/auth/relax/*</a> - Allowed</li>
<li><a href="dump/auth/info">dump/auth/*</a> - Authenticated any user</li>
<li><a href="dump/auth/admin/info">dump/auth/admin/*</a> - Authenticated admin role (<a href="session/?Action=Invalidate">click</a> to invalidate session)</li>
<li><a href="dump/ssl/info">dump/ssl/*</a> - Confidential</li>
</ul>
<p/>
<p>
Usernames/Passwords are jetty/jetty admin/admin & user/password
</p>
<p>
Return to <a href=".">main menu</a>.
</p>
</BODY>
</HTML>

View File

@ -31,10 +31,11 @@ This is a test context that serves:
<li>a <a href="dispatch">Dispatcher Servlet</a></li>
<li>a <a href="jetty/">Transparent Proxy</a> (to jetty.mortbay.org)</li>
<li>a <a href="cgi-bin/hello.sh">CGI script</a> (unix only)</li>
<li>a <a href="auth.html">Authentication</a></li>
</ul>
<p/>
<!--
<p>
Other demonstration contexts, some of which may need manual deployment
(check the README.txt file for details):
@ -48,6 +49,7 @@ Other demonstration contexts, some of which may need manual deployment
<li> a demo of the <a href="/test-jaas">JAAS features</a></li>
</ul>
<p/>
-->
This webapp is deployed in $JETTY_HOME/webapp/test and configured by $JETTY_HOME/contexts/test.xml