Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
e01eefe40e
|
@ -52,13 +52,13 @@ Let's look at an example.
|
|||
|
||||
===== Step 1
|
||||
|
||||
Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the `<realm-name>` in your `web.xml` file. For example, if the `web.xml` contains a realm called "xyz" like so:
|
||||
Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the `<realm-name>` in your `web.xml` file. For example, if the `web.xml` contains a realm called "Test JAAS Realm" like so:
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
<login-config>
|
||||
<auth-method>FORM</auth-method>
|
||||
<realm-name>xyz</realm-name>
|
||||
<realm-name>Test JAAS Realm</realm-name>
|
||||
<form-login-config>
|
||||
<form-login-page>/login/login</form-login-page>
|
||||
<form-error-page>/login/error</form-error-page>
|
||||
|
@ -66,7 +66,7 @@ Configure a Jetty `org.eclipse.jetty.jaas.JAASLoginService` to match the `<realm
|
|||
</login-config>
|
||||
----
|
||||
|
||||
Then you need to create a `JAASLoginService` with the matching name of "xyz":
|
||||
then you need to create a `JAASLoginService` with the matching realm name of "Test JAAS Realm":
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
@ -76,9 +76,10 @@ Then you need to create a `JAASLoginService` with the matching name of "xyz":
|
|||
</New>
|
||||
----
|
||||
|
||||
The `LoginModuleName` must match the name of your LoginModule as declared in your login module configuration file (see <<jaas-step-2,Step 2>>).
|
||||
____
|
||||
[CAUTION]
|
||||
The name of the realm-name that you declare in `web.xml` must match exactly the name of your `JAASLoginService`.
|
||||
The name of the realm-name that you declare in `web.xml` must match *exactly* the `Name` field of your `JAASLoginService`.
|
||||
____
|
||||
|
||||
You can declare your `JAASLoginService` in a couple of different ways:
|
||||
|
@ -135,7 +136,7 @@ xyz {
|
|||
|
||||
____
|
||||
[CAUTION]
|
||||
It is imperative that the application name on the first line is exactly the same as the `LoginModuleName` of your `JAASLoginService`.
|
||||
It is imperative that the application name on the first line is *exactly* the same as the `LoginModuleName` of your `JAASLoginService`.
|
||||
____
|
||||
|
||||
You may find it convenient to name this configuration file as `etc/login.conf` because, as we will see below, some of the wiring up for JAAS has been done for you.
|
||||
|
|
|
@ -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,6 +581,9 @@ 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)
|
||||
{
|
||||
|
|
|
@ -40,10 +40,9 @@ public class UserAuthentication extends AbstractUserAuthentication
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void logout()
|
||||
{
|
||||
SecurityHandler security=SecurityHandler.getCurrentSecurityHandler();
|
||||
if (security!=null)
|
||||
security.logout(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,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;
|
||||
|
@ -65,7 +67,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);
|
||||
|
@ -200,6 +201,21 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
|
||||
|
||||
@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)
|
||||
|
@ -537,7 +553,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.
|
||||
*/
|
||||
|
|
|
@ -41,6 +41,8 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
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,22 +99,11 @@ 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;
|
||||
|
@ -1054,6 +1057,174 @@ public class ConstraintTest
|
|||
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
|
||||
|
@ -100,6 +83,53 @@ public interface Authentication
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Authentication Response sent state.
|
||||
* Responses are sent by authenticators either to issue an
|
||||
|
@ -128,6 +158,14 @@ public interface Authentication
|
|||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** 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.
|
||||
* <p>
|
||||
|
|
|
@ -2413,11 +2413,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
|
||||
{
|
||||
|
@ -2429,9 +2431,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