Jetty 9.4.x 3456 programmatic authentication (#3472)
* Issue #3456 Allow multiple programmatic login/logout in same request. Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
441280c9fc
commit
432fc41a32
|
@ -21,6 +21,11 @@ package org.eclipse.jetty.security;
|
|||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.Authentication.User;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.UserIdentity.Scope;
|
||||
|
@ -95,4 +100,23 @@ public abstract class AbstractUserAuthentication implements User, Serializable
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication logout (ServletRequest request)
|
||||
{
|
||||
SecurityHandler security=SecurityHandler.getCurrentSecurityHandler();
|
||||
if (security!=null)
|
||||
{
|
||||
security.logout(this);
|
||||
Authenticator authenticator = security.getAuthenticator();
|
||||
if (authenticator instanceof LoginAuthenticator)
|
||||
{
|
||||
((LoginAuthenticator)authenticator).logout(request);
|
||||
return new LoggedOutAuthentication((LoginAuthenticator)authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public interface Authenticator
|
|||
* @param mandatory True if authentication is mandatory.
|
||||
* @return An Authentication. If Authentication is successful, this will be a {@link org.eclipse.jetty.server.Authentication.User}. If a response has
|
||||
* been sent by the Authenticator (which can be done for both successful and unsuccessful authentications), then the result will
|
||||
* implement {@link org.eclipse.jetty.server.Authentication.ResponseSent}. If Authentication is not manditory, then a
|
||||
* implement {@link org.eclipse.jetty.server.Authentication.ResponseSent}. If Authentication is not mandatory, then a
|
||||
* {@link org.eclipse.jetty.server.Authentication.Deferred} may be returned.
|
||||
*
|
||||
* @throws ServerAuthException if unable to validate request
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.security;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
|
||||
/**
|
||||
* LoggedOutAuthentication
|
||||
*
|
||||
* An Authentication indicating that a user has been previously, but is not currently logged in,
|
||||
* but may be capable of logging in after a call to Request.login(String,String)
|
||||
*/
|
||||
public class LoggedOutAuthentication implements Authentication.NonAuthenticated
|
||||
{
|
||||
private LoginAuthenticator _authenticator;
|
||||
|
||||
public LoggedOutAuthentication (LoginAuthenticator authenticator)
|
||||
{
|
||||
_authenticator = authenticator;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Authentication login(String username, Object password, ServletRequest request)
|
||||
{
|
||||
if (username == null)
|
||||
return null;
|
||||
|
||||
UserIdentity identity = _authenticator.login(username, password, request);
|
||||
if (identity != null)
|
||||
{
|
||||
IdentityService identity_service = _authenticator.getLoginService().getIdentityService();
|
||||
UserAuthentication authentication = new UserAuthentication("API",identity);
|
||||
if (identity_service != null)
|
||||
identity_service.associate(identity);
|
||||
return authentication;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -581,8 +581,11 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
public void logout(Authentication.User user)
|
||||
{
|
||||
LOG.debug("logout {}",user);
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
LoginService login_service=getLoginService();
|
||||
if (login_service!=null)
|
||||
if (login_service != null)
|
||||
{
|
||||
login_service.logout(user.getUserIdentity());
|
||||
}
|
||||
|
|
|
@ -40,10 +40,9 @@ public class UserAuthentication extends AbstractUserAuthentication
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void logout()
|
||||
{
|
||||
SecurityHandler security=SecurityHandler.getCurrentSecurityHandler();
|
||||
if (security!=null)
|
||||
security.logout(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.security.LoggedOutAuthentication;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
|
@ -66,7 +68,6 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
try
|
||||
{
|
||||
Authentication authentication = _authenticator.validateRequest(request,__deferredResponse,true);
|
||||
|
||||
if (authentication!=null && (authentication instanceof Authentication.User) && !(authentication instanceof Authentication.ResponseSent))
|
||||
{
|
||||
LoginService login_service= _authenticator.getLoginService();
|
||||
|
@ -131,6 +132,25 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Authentication logout (ServletRequest request)
|
||||
{
|
||||
SecurityHandler security=SecurityHandler.getCurrentSecurityHandler();
|
||||
if (security!=null)
|
||||
{
|
||||
security.logout(null);
|
||||
if (_authenticator instanceof LoginAuthenticator)
|
||||
{
|
||||
((LoginAuthenticator)_authenticator).logout(request);
|
||||
return new LoggedOutAuthentication((LoginAuthenticator)_authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Object getPreviousAssociation()
|
||||
|
|
|
@ -192,6 +192,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
UserIdentity user = super.login(username,password,request);
|
||||
if (user!=null)
|
||||
{
|
||||
|
||||
HttpSession session = ((HttpServletRequest)request).getSession(true);
|
||||
Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
|
||||
|
@ -199,7 +200,22 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
return user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void logout(ServletRequest request)
|
||||
{
|
||||
super.logout(request);
|
||||
HttpServletRequest httpRequest = (HttpServletRequest)request;
|
||||
HttpSession session = httpRequest.getSession(false);
|
||||
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
//clean up session
|
||||
session.removeAttribute(SessionAuthentication.__J_AUTHENTICATED);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void prepareRequest(ServletRequest request)
|
||||
|
@ -536,7 +552,8 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** This Authentication represents a just completed Form authentication.
|
||||
/**
|
||||
* This Authentication represents a just completed Form authentication.
|
||||
* Subsequent requests from the same user are authenticated by the presents
|
||||
* of a {@link SessionAuthentication} instance in their session.
|
||||
*/
|
||||
|
|
|
@ -40,6 +40,8 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
protected LoginService _loginService;
|
||||
protected IdentityService _identityService;
|
||||
private boolean _renewSession;
|
||||
|
||||
|
||||
|
||||
protected LoginAuthenticator()
|
||||
{
|
||||
|
@ -63,6 +65,19 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void logout (ServletRequest request)
|
||||
{
|
||||
HttpServletRequest httpRequest = (HttpServletRequest)request;
|
||||
HttpSession session = httpRequest.getSession(false);
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
session.removeAttribute(Session.SESSION_CREATED_SECURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void setConfiguration(AuthConfiguration configuration)
|
||||
{
|
||||
|
|
|
@ -33,18 +33,25 @@ import org.eclipse.jetty.security.AbstractUserAuthentication;
|
|||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.session.Session;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class SessionAuthentication extends AbstractUserAuthentication implements Serializable, HttpSessionActivationListener, HttpSessionBindingListener
|
||||
|
||||
/**
|
||||
* SessionAuthentication
|
||||
*
|
||||
* When a user has been successfully authenticated with some types
|
||||
* of Authenticator, the Authenticator stashes a SessionAuthentication
|
||||
* into a HttpSession to remember that the user is authenticated.
|
||||
*
|
||||
*/
|
||||
public class SessionAuthentication extends AbstractUserAuthentication
|
||||
implements Serializable, HttpSessionActivationListener, HttpSessionBindingListener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(SessionAuthentication.class);
|
||||
|
||||
private static final long serialVersionUID = -4643200685888258706L;
|
||||
|
||||
|
||||
|
||||
public final static String __J_AUTHENTICATED="org.eclipse.jetty.security.UserIdentity";
|
||||
|
||||
private final String _name;
|
||||
|
@ -92,23 +99,12 @@ public class SessionAuthentication extends AbstractUserAuthentication implements
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void logout()
|
||||
{
|
||||
if (_session!=null && _session.getAttribute(__J_AUTHENTICATED)!=null)
|
||||
_session.removeAttribute(__J_AUTHENTICATED);
|
||||
|
||||
doLogout();
|
||||
}
|
||||
|
||||
private void doLogout()
|
||||
{
|
||||
SecurityHandler security=SecurityHandler.getCurrentSecurityHandler();
|
||||
if (security!=null)
|
||||
security.logout(this);
|
||||
if (_session!=null)
|
||||
_session.removeAttribute(Session.SESSION_CREATED_SECURE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -118,7 +114,6 @@ public class SessionAuthentication extends AbstractUserAuthentication implements
|
|||
@Override
|
||||
public void sessionWillPassivate(HttpSessionEvent se)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -131,18 +126,15 @@ public class SessionAuthentication extends AbstractUserAuthentication implements
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void valueBound(HttpSessionBindingEvent event)
|
||||
{
|
||||
if (_session==null)
|
||||
{
|
||||
_session=event.getSession();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void valueUnbound(HttpSessionBindingEvent event)
|
||||
{
|
||||
doLogout();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import java.util.function.Consumer;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.HttpConstraintElement;
|
||||
import javax.servlet.HttpMethodConstraintElement;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -61,6 +63,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
|
@ -1053,6 +1056,174 @@ public class ConstraintTest
|
|||
assertThat(response, startsWith("HTTP/1.1 403"));
|
||||
assertThat(response, containsString("!role"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test Request.login() Request.logout() with FORM authenticator
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testFormProgrammaticLoginLogout() throws Exception
|
||||
{
|
||||
//Test programmatic login/logout within same request:
|
||||
// login - perform programmatic login that should succeed, next request should be also logged in
|
||||
// loginfail - perform programmatic login that should fail, next request should not be logged in
|
||||
// loginfaillogin - perform programmatic login that should fail then another that succeeds, next request should be logged in
|
||||
// loginlogin - perform successful login then try another that should fail, next request should be logged in
|
||||
// loginlogout - perform successful login then logout, next request should not be logged in
|
||||
// loginlogoutlogin - perform successful login then logout then login successfully again, next request should be logged in
|
||||
_security.setHandler(new ProgrammaticLoginRequestHandler());
|
||||
_security.setAuthenticator(new FormAuthenticator("/testLoginPage","/testErrorPage",false));
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
|
||||
//login
|
||||
response = _connector.getResponse("GET /ctx/prog?action=login HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response, containsString("user=admin"));
|
||||
_server.stop();
|
||||
|
||||
//loginfail
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/prog?action=loginfail HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
if (response.contains("JSESSIONID"))
|
||||
{
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
}
|
||||
else
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n\r\n");
|
||||
|
||||
assertThat(response, not(containsString("user=admin")));
|
||||
_server.stop();
|
||||
|
||||
//loginfaillogin
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/prog?action=loginfail HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
response = _connector.getResponse("GET /ctx/prog?action=login HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response, containsString("user=admin"));
|
||||
_server.stop();
|
||||
|
||||
//loginlogin
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/prog?action=loginlogin HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response, containsString("user=admin"));
|
||||
_server.stop();
|
||||
|
||||
//loginlogout
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/prog?action=loginlogout HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response, containsString("user=null"));
|
||||
_server.stop();
|
||||
|
||||
//loginlogoutlogin
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/prog?action=loginlogoutlogin HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(response, containsString("user=user0"));
|
||||
_server.stop();
|
||||
|
||||
|
||||
//Test constraint-based login with programmatic login/logout:
|
||||
// constraintlogin - perform constraint login, followed by programmatic login which should fail (already logged in)
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, containsString(" 302 Found"));
|
||||
assertThat(response, containsString("/ctx/testLoginPage"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/testLoginPage HTTP/1.0\r\n"+
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + session)));
|
||||
response = _connector.getResponse("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password");
|
||||
assertThat(response, startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response, containsString("Location"));
|
||||
assertThat(response, containsString("/ctx/auth/info"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + session)));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?action=constraintlogin HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
_server.stop();
|
||||
|
||||
// logout - perform constraint login, followed by programmatic logout, which should succeed
|
||||
_server.start();
|
||||
response = _connector.getResponse("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, containsString(" 302 Found"));
|
||||
assertThat(response, containsString("/ctx/testLoginPage"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/testLoginPage HTTP/1.0\r\n"+
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + session)));
|
||||
response = _connector.getResponse("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password");
|
||||
assertThat(response, startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response, containsString("Location"));
|
||||
assertThat(response, containsString("/ctx/auth/info"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + session)));
|
||||
session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||
response = _connector.getResponse("GET /ctx/prog?action=logout HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
response = _connector.getResponse("GET /ctx/prog?x=y HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + session + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
assertThat(response, containsString("user=null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrictBasic() throws Exception
|
||||
|
@ -1512,6 +1683,72 @@ public class ConstraintTest
|
|||
}
|
||||
}
|
||||
|
||||
private class ProgrammaticLoginRequestHandler extends AbstractHandler
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
String action = request.getParameter("action");
|
||||
if (StringUtil.isBlank(action))
|
||||
{
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
response.getWriter().println("user="+request.getRemoteUser());
|
||||
return;
|
||||
}
|
||||
else if ("login".equals(action))
|
||||
{
|
||||
request.login("admin", "password");
|
||||
return;
|
||||
}
|
||||
else if ("loginfail".equals(action))
|
||||
{
|
||||
request.login("admin", "fail");
|
||||
return;
|
||||
}
|
||||
else if ("loginfaillogin".equals(action))
|
||||
{
|
||||
try
|
||||
{
|
||||
request.login("admin", "fail");
|
||||
}
|
||||
catch (ServletException se)
|
||||
{
|
||||
request.login("admin", "password");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ("loginlogin".equals(action))
|
||||
{
|
||||
request.login("admin", "password");
|
||||
request.login("foo", "bar");
|
||||
}
|
||||
else if ("loginlogout".equals(action))
|
||||
{
|
||||
request.login("admin", "password");
|
||||
request.logout();
|
||||
}
|
||||
else if ("loginlogoutlogin".equals(action))
|
||||
{
|
||||
request.login("admin", "password");
|
||||
request.logout();
|
||||
request.login("user0", "password");
|
||||
}
|
||||
else if ("constraintlogin".equals(action))
|
||||
{
|
||||
String user = request.getRemoteUser();
|
||||
request.login("admin", "password");
|
||||
}
|
||||
else if ("logout".equals(action))
|
||||
{
|
||||
request.logout();
|
||||
}
|
||||
else
|
||||
response.sendError(500);
|
||||
}
|
||||
}
|
||||
private class RoleRefHandler extends HandlerWrapper
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -45,11 +45,12 @@ public interface Authentication
|
|||
/* ------------------------------------------------------------ */
|
||||
/** A successful Authentication with User information.
|
||||
*/
|
||||
public interface User extends Authentication
|
||||
public interface User extends LogoutAuthentication
|
||||
{
|
||||
String getAuthMethod();
|
||||
UserIdentity getUserIdentity();
|
||||
boolean isUserInRole(UserIdentity.Scope scope,String role);
|
||||
@Deprecated
|
||||
void logout();
|
||||
}
|
||||
|
||||
|
@ -63,31 +64,13 @@ public interface Authentication
|
|||
HttpServletResponse getHttpServletResponse();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A deferred authentication with methods to progress
|
||||
* the authentication process.
|
||||
/**
|
||||
* An authentication that is capable of performing a programmatic login
|
||||
* operation.
|
||||
*
|
||||
*/
|
||||
public interface Deferred extends Authentication
|
||||
public interface LoginAuthentication extends Authentication
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Authenticate if possible without sending a challenge.
|
||||
* This is used to check credentials that have been sent for
|
||||
* non-manditory authentication.
|
||||
* @param request the request
|
||||
* @return The new Authentication state.
|
||||
*/
|
||||
Authentication authenticate(ServletRequest request);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Authenticate and possibly send a challenge.
|
||||
* This is used to initiate authentication for previously
|
||||
* non-manditory authentication.
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @return The new Authentication state.
|
||||
*/
|
||||
Authentication authenticate(ServletRequest request,ServletResponse response);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Login with the LOGIN authenticator
|
||||
|
@ -98,6 +81,53 @@ public interface Authentication
|
|||
*/
|
||||
Authentication login(String username,Object password,ServletRequest request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An authentication that is capable of performing a programmatic
|
||||
* logout operation.
|
||||
*
|
||||
*/
|
||||
public interface LogoutAuthentication extends Authentication
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Remove any user information that may be present in the request
|
||||
* such that a call to getUserPrincipal/getRemoteUser will return null.
|
||||
*
|
||||
* @param request the request
|
||||
* @return NoAuthentication if we successfully logged out
|
||||
*/
|
||||
Authentication logout (ServletRequest request);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A deferred authentication with methods to progress
|
||||
* the authentication process.
|
||||
*/
|
||||
public interface Deferred extends LoginAuthentication, LogoutAuthentication
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Authenticate if possible without sending a challenge.
|
||||
* This is used to check credentials that have been sent for
|
||||
* non-mandatory authentication.
|
||||
* @param request the request
|
||||
* @return The new Authentication state.
|
||||
*/
|
||||
Authentication authenticate(ServletRequest request);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Authenticate and possibly send a challenge.
|
||||
* This is used to initiate authentication for previously
|
||||
* non-mandatory authentication.
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @return The new Authentication state.
|
||||
*/
|
||||
Authentication authenticate(ServletRequest request,ServletResponse response);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -127,6 +157,14 @@ public interface Authentication
|
|||
public interface SendSuccess extends ResponseSent
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** After a logout, the authentication reverts to a state
|
||||
* where it is possible to programmatically log in again.
|
||||
*/
|
||||
public interface NonAuthenticated extends LoginAuthentication
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Unauthenticated state.
|
||||
|
|
|
@ -2432,11 +2432,13 @@ public class Request implements HttpServletRequest
|
|||
@Override
|
||||
public void login(String username, String password) throws ServletException
|
||||
{
|
||||
if (_authentication instanceof Authentication.Deferred)
|
||||
if (_authentication instanceof Authentication.LoginAuthentication)
|
||||
{
|
||||
_authentication=((Authentication.Deferred)_authentication).login(username,password,this);
|
||||
if (_authentication == null)
|
||||
Authentication auth = ((Authentication.LoginAuthentication)_authentication).login(username,password,this);
|
||||
if (auth == null)
|
||||
throw new Authentication.Failed("Authentication failed for username '"+username+"'");
|
||||
else
|
||||
_authentication = auth;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2448,9 +2450,8 @@ public class Request implements HttpServletRequest
|
|||
@Override
|
||||
public void logout() throws ServletException
|
||||
{
|
||||
if (_authentication instanceof Authentication.User)
|
||||
((Authentication.User)_authentication).logout();
|
||||
_authentication=Authentication.UNAUTHENTICATED;
|
||||
if (_authentication instanceof Authentication.LogoutAuthentication)
|
||||
_authentication = ((Authentication.LogoutAuthentication)_authentication).logout(this);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
Loading…
Reference in New Issue