[jboss-cvs] JBossAS SVN: r67525 - in trunk: testsuite/imports/sections and 7 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Tue Nov 27 18:51:57 EST 2007
Author: sguilhen at redhat.com
Date: 2007-11-27 18:51:56 -0500 (Tue, 27 Nov 2007)
New Revision: 67525
Added:
trunk/testsuite/src/resources/web/programmatic/error.html
trunk/testsuite/src/resources/web/programmatic/login.html
trunk/testsuite/src/resources/web/programmatic/restricted/
trunk/testsuite/src/resources/web/programmatic/restricted/restricted.html
Modified:
trunk/testsuite/build.xml
trunk/testsuite/imports/sections/web.xml
trunk/testsuite/src/main/org/jboss/test/web/servlets/ProgrammaticLoginTestServlet.java
trunk/testsuite/src/main/org/jboss/test/web/test/WebProgrammaticLoginTestCase.java
trunk/testsuite/src/resources/web/programmatic/WEB-INF/jbosstest-web.xml
trunk/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java
trunk/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java
Log:
JBAS-4424: Merge from Branch_4_2.
Modified: trunk/testsuite/build.xml
===================================================================
--- trunk/testsuite/build.xml 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/testsuite/build.xml 2007-11-27 23:51:56 UTC (rev 67525)
@@ -722,9 +722,11 @@
<!-- Tests needing non-clustered tomcat SSO -->
<patternset id="tc-sso.includes">
<include name="org/jboss/test/web/test/SingleSignOnUnitTestCase.class"/>
+ <include name="org/jboss/test/web/test/WebProgrammaticLoginTestCase.class"/>
</patternset>
<patternset id="tc-sso.excludes">
<exclude name="org/jboss/test/web/test/SingleSignOnUnitTestCase.class"/>
+ <exclude name="org/jboss/test/web/test/WebProgrammaticLoginTestCase.class"/>
</patternset>
<!-- Tests needing clustered tomcat SSO -->
<patternset id="tc-sso-clustered.includes">
Modified: trunk/testsuite/imports/sections/web.xml
===================================================================
--- trunk/testsuite/imports/sections/web.xml 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/testsuite/imports/sections/web.xml 2007-11-27 23:51:56 UTC (rev 67525)
@@ -649,6 +649,10 @@
<classes dir="${build.classes}">
<include name="org/jboss/test/web/servlets/Programm*Servlet.class"/>
</classes>
+ <fileset dir="${build.resources}/web/programmatic">
+ <include name="restricted/*.html"/>
+ <include name="*.html"/>
+ </fileset>
</war>
<zip destfile="${build.lib}/programmaticweblogin.ear">
<zipfileset dir="${build.resources}/web/programmatic" prefix="META-INF">
Modified: trunk/testsuite/src/main/org/jboss/test/web/servlets/ProgrammaticLoginTestServlet.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/web/servlets/ProgrammaticLoginTestServlet.java 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/testsuite/src/main/org/jboss/test/web/servlets/ProgrammaticLoginTestServlet.java 2007-11-27 23:51:56 UTC (rev 67525)
@@ -44,28 +44,41 @@
{
private static final long serialVersionUID = 1L;
- protected void service(HttpServletRequest request, HttpServletResponse response)
+ protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
- {
+ {
+ String operation = request.getParameter("operation");
String username = request.getParameter("username");
String pass = request.getParameter("pass");
-
+
+ if("login".equals(operation))
+ this.login(request, username, pass);
+ else if("logout".equals(operation))
+ this.logout(request);
+ else
+ throw new ServletException("Unrecognized operation: " + operation);
+ }
+
+ private void login(HttpServletRequest request, String username, String pass)
+ throws ServletException
+ {
if(username == null || pass == null)
- throw new RuntimeException("username or password is null");
- WebAuthentication pwl = new WebAuthentication();
- pwl.login(username, pass);
-
- //Only when there is web login, does the principal be visible
- log("User Principal="+request.getUserPrincipal());
- log("isUserInRole(Authorized User)="+request.isUserInRole("AuthorizedUser"));
+ throw new RuntimeException("username or password is null");
+ WebAuthentication pwl = new WebAuthentication();
+ pwl.login(username, pass);
+
+ //Only when there is web login, does the principal become visible
+ log("User Principal=" + request.getUserPrincipal());
+ log("isUserInRole(Authorized User)=" + request.isUserInRole("AuthorizedUser"));
if(request.getUserPrincipal() == null || !request.isUserInRole("AuthorizedUser"))
throw new ServletException("User is not authenticated or the isUserInRole check failed");
-
-
+ }
+
+ private void logout(HttpServletRequest request) throws ServletException
+ {
//Log the user out
- pwl.logout();
-
+ new WebAuthentication().logout();
if(request.getUserPrincipal() != null || request.isUserInRole("AuthorizedUser"))
- throw new ServletException("User is still authenticated or pass: isUserInRole(Authorized User)");
- }
+ throw new ServletException("User is still authenticated or pass: isUserInRole(Authorized User)");
+ }
}
Modified: trunk/testsuite/src/main/org/jboss/test/web/test/WebProgrammaticLoginTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/web/test/WebProgrammaticLoginTestCase.java 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/testsuite/src/main/org/jboss/test/web/test/WebProgrammaticLoginTestCase.java 2007-11-27 23:51:56 UTC (rev 67525)
@@ -61,15 +61,18 @@
{
String baseURLNoAuth = "http://" + getServerHost()
+ ":" + Integer.getInteger("web.port", 8080) + "/";
- String path1 = "war1/TestServlet";
+ String path = "war1/TestServlet";
// try to perform programmatic auth without supplying login information.
HttpMethod indexGet = null;
try
{
- indexGet = new GetMethod(baseURLNoAuth+path1);
+ indexGet = new GetMethod(baseURLNoAuth + path + "?operation=login");
int responseCode = httpConn.executeMethod(indexGet);
- assertTrue("Get Error("+responseCode+")",
+ assertTrue("Get Error(" + responseCode + ")",
responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR);
+ // assert access to the restricted area of the first application is denied.
+ SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth +
+ "war1/restricted/restricted.html");
// assert access to the second application is not granted, as no successful login
// was performed (and therefore no ssoid has been set).
SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth + "war2/index.html");
@@ -80,13 +83,16 @@
indexGet.releaseConnection();
}
// try to perform programmatic auth with no valid username/password.
- path1 = path1 + "?username=dummy&pass=dummy";
+ path = path + "?operation=login&username=dummy&pass=dummy";
try
{
- indexGet = new GetMethod(baseURLNoAuth+path1);
+ indexGet = new GetMethod(baseURLNoAuth + path);
int responseCode = httpConn.executeMethod(indexGet);
- assertTrue("Get Error("+responseCode+")",
+ assertTrue("Get Error(" + responseCode + ")",
responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR);
+ // assert access to the restricted applications remains denied.
+ SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth +
+ "war1/restricted/restricted.html");
SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth + "war2/index.html");
}
finally
@@ -104,22 +110,36 @@
{
String baseURLNoAuth = "http://" + getServerHost()
+ ":" + Integer.getInteger("web.port", 8080) + "/";
- String path1 = "war1/TestServlet?username=jduke&pass=theduke";
+ String path1 = "war1/TestServlet?operation=login&username=jduke&pass=theduke";
HttpMethod indexGet = null;
+ HttpMethod indexGet2 = null;
try
{
- indexGet = new GetMethod(baseURLNoAuth+path1);
+ indexGet = new GetMethod(baseURLNoAuth + path1);
int responseCode = httpConn.executeMethod(indexGet);
- assertTrue("Get OK("+responseCode+")", responseCode == HttpURLConnection.HTTP_OK);
- // check the sso cookie has been created
+ assertTrue("Get OK(" + responseCode + ")", responseCode == HttpURLConnection.HTTP_OK);
+ // assert access to the restricted are of the first application is now allowed.
+ SSOBaseCase.checkAccessAllowed(this.httpConn, baseURLNoAuth +
+ "war1/restricted/restricted.html");
+ // assert the sso cookie has been created.
SSOBaseCase.processSSOCookie(this.httpConn.getState(), baseURLNoAuth, baseURLNoAuth);
- // check that access to the second application is allowed
+ // assert access to the second application is allowed.
SSOBaseCase.checkAccessAllowed(this.httpConn, baseURLNoAuth + "war2/index.html");
+
+ // perform a programmatic logout and assert access is not allowed anymore.
+ indexGet2 = new GetMethod(baseURLNoAuth + "war1/TestServlet?operation=logout");
+ responseCode = httpConn.executeMethod(indexGet2);
+ assertTrue("Get OK("+responseCode+")", responseCode == HttpURLConnection.HTTP_OK);
+ SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth +
+ "war1/restricted/restricted.html");
+ SSOBaseCase.checkAccessDenied(this.httpConn, baseURLNoAuth + "war2/index.html");
}
finally
{
if(indexGet != null)
indexGet.releaseConnection();
+ if(indexGet2 != null)
+ indexGet2.releaseConnection();
}
}
}
Modified: trunk/testsuite/src/resources/web/programmatic/WEB-INF/jbosstest-web.xml
===================================================================
--- trunk/testsuite/src/resources/web/programmatic/WEB-INF/jbosstest-web.xml 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/testsuite/src/resources/web/programmatic/WEB-INF/jbosstest-web.xml 2007-11-27 23:51:56 UTC (rev 67525)
@@ -20,9 +20,24 @@
<url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Restricted</web-resource-name>
+ <description>Restricted Area</description>
+ <url-pattern>/restricted/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <description>Only authenticated users can access secure content</description>
+ <role-name>AuthorizedUser</role-name>
+ </auth-constraint>
+ </security-constraint>
+
<login-config>
- <auth-method>BASIC</auth-method>
- <realm-name>JBossTest Servlets</realm-name>
+ <auth-method>FORM</auth-method>
+ <form-login-config>
+ <form-login-page>/login.html</form-login-page>
+ <form-error-page>/error.html</form-error-page>
+ </form-login-config>
</login-config>
<security-role>
Added: trunk/testsuite/src/resources/web/programmatic/error.html
===================================================================
--- trunk/testsuite/src/resources/web/programmatic/error.html (rev 0)
+++ trunk/testsuite/src/resources/web/programmatic/error.html 2007-11-27 23:51:56 UTC (rev 67525)
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Error Page For Examples</title>
+</head>
+
+ <body bgcolor="white">
+ Invalid username and/or password, please try again
+ </body>
+</html>
+
Added: trunk/testsuite/src/resources/web/programmatic/login.html
===================================================================
--- trunk/testsuite/src/resources/web/programmatic/login.html (rev 0)
+++ trunk/testsuite/src/resources/web/programmatic/login.html 2007-11-27 23:51:56 UTC (rev 67525)
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Login Page for Examples</title>
+</head>
+
+ <body bgcolor="white">
+ <form method="POST" action="j_security_check">
+ <table border="0" cellspacing="5">
+ <tr>
+ <th align="right">Username:</th>
+ <td align="left"><input type="text" name="j_username"></td>
+ </tr>
+ <tr>
+ <th align="right">Password:</th>
+ <td align="left"><input type="password" name="j_password"></td>
+ </tr>
+ <tr>
+ <td align="right"><input type="submit" value="Log In"></td>
+ <td align="left"><input type="reset"></td>
+ </tr>
+ </table>
+ </form>
+ </body>
+</html>
+
Added: trunk/testsuite/src/resources/web/programmatic/restricted/restricted.html
===================================================================
--- trunk/testsuite/src/resources/web/programmatic/restricted/restricted.html (rev 0)
+++ trunk/testsuite/src/resources/web/programmatic/restricted/restricted.html 2007-11-27 23:51:56 UTC (rev 67525)
@@ -0,0 +1,10 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <title>Programmatic Login Secure Page</title>
+</head>
+
+<body>
+<h1>Programmatic Login Secure Page</h1>
+</body>
+</html>
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/security/SecurityAssociationValve.java 2007-11-27 23:51:56 UTC (rev 67525)
@@ -60,7 +60,9 @@
public static ThreadLocal<JBossWebMetaData> activeWebMetaData = new ThreadLocal<JBossWebMetaData>();
/** Maintain the Catalina Request for programmatic web login */
public static ThreadLocal<Request> activeRequest = new ThreadLocal<Request>();
-
+ /** Maintain the Catalina Response for programmatic web login */
+ public static ThreadLocal activeResponse = new ThreadLocal();
+
/** The web app metadata */
private JBossWebMetaData metaData;
/** The name in the session under which the Subject is stored */
@@ -103,8 +105,9 @@
log.trace("Begin invoke, caller"+caller);
// Set the active meta data
activeWebMetaData.set(metaData);
- //Set the active request
+ //Set the active request and response objects
activeRequest.set(request);
+ activeResponse.set(response);
try
{
@@ -223,6 +226,7 @@
activeWebMetaData.set(null);
userPrincipal.set(null);
activeRequest.set(null);
+ activeResponse.set(null);
}
}
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java 2007-11-27 23:11:08 UTC (rev 67524)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/security/login/WebAuthentication.java 2007-11-27 23:51:56 UTC (rev 67525)
@@ -20,15 +20,25 @@
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.web.tomcat.security.login;
-
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.cert.X509Certificate;
+import java.util.Random;
+import java.util.UUID;
import javax.naming.NamingException;
+import javax.servlet.http.Cookie;
+import org.apache.catalina.Container;
+import org.apache.catalina.Pipeline;
import org.apache.catalina.Session;
+import org.apache.catalina.Valve;
import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.SingleSignOn;
import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
import org.jboss.web.tomcat.security.SecurityAssociationValve;
//$Id$
@@ -40,12 +50,13 @@
* @version $Revision$
*/
public class WebAuthentication
-{
+{
private static final String AUTH_TYPE = "PROGRAMMATIC_WEB_LOGIN";
+
public WebAuthentication()
- {
+ {
}
-
+
/**
* Login an user via the CLIENT-CERT method
* @param certs X509 certificates
@@ -55,16 +66,16 @@
{
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
- if(request == null)
+ if (request == null)
throw new IllegalStateException("request is null");
Principal p = request.getContext().getRealm().authenticate(certs);
- if(p != null)
+ if (p != null)
{
- register(request,p, null, null);
+ register(request, p, null, null);
}
- return p!= null;
+ return p != null;
}
-
+
/**
* Login an user via the BASIC, FORM, DIGEST methods
* @param username
@@ -72,29 +83,29 @@
* @return
* @throws NamingException
*/
- public boolean login(String username, Object credential)
- {
+ public boolean login(String username, Object credential)
+ {
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
- if(request == null)
+ if (request == null)
throw new IllegalStateException("request is null");
-
+
Principal p = null;
- if(credential instanceof String)
+ if (credential instanceof String)
{
- p = request.getContext().getRealm().authenticate(username, (String)credential);
- }
+ p = request.getContext().getRealm().authenticate(username, (String) credential);
+ }
else if (credential instanceof byte[])
{
- p = request.getContext().getRealm().authenticate(username, (byte[])credential);
- }
- if(p != null)
+ p = request.getContext().getRealm().authenticate(username, (byte[]) credential);
+ }
+ if (p != null)
{
- register(request,p, username, credential);
+ register(request, p, username, credential);
}
return p != null;
- }
-
+ }
+
/**
* Log the user out
*
@@ -103,11 +114,11 @@
{
//Get the active request
Request request = (Request) SecurityAssociationValve.activeRequest.get();
- if(request == null)
+ if (request == null)
throw new IllegalStateException("request is null");
unregister(request);
}
-
+
/**
* Register the principal with the request, session etc just the way AuthenticatorBase does
* @param request Catalina Request
@@ -118,25 +129,75 @@
protected void register(Request request, Principal principal, String username, Object password)
{
request.setAuthType(AUTH_TYPE);
- request.setUserPrincipal(principal);
-
+ request.setUserPrincipal(principal);
+
//Cache the authentication principal in the session
Session session = request.getSessionInternal(false);
- if(session != null)
+ if (session != null)
{
session.setAuthType(AUTH_TYPE);
session.setPrincipal(principal);
if (username != null)
- session.setNote(Constants.SESS_USERNAME_NOTE, username);
+ session.setNote(Constants.SESS_USERNAME_NOTE, username);
else
- session.removeNote(Constants.SESS_USERNAME_NOTE);
+ session.removeNote(Constants.SESS_USERNAME_NOTE);
if (password != null)
- session.setNote(Constants.SESS_PASSWORD_NOTE, getPasswordAsString(password));
+ session.setNote(Constants.SESS_PASSWORD_NOTE, getPasswordAsString(password));
else
- session.removeNote(Constants.SESS_PASSWORD_NOTE);
+ session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
+
+ // JBAS-4424: Programmatic web authentication with SSO
+ SingleSignOn sso = this.getSingleSignOn(request);
+ if (sso == null)
+ return;
+
+ // Only create a new SSO entry if the SSO did not already set a note
+ // for an existing entry (as it would do with subsequent requests
+ // for DIGEST and SSL authenticated contexts)
+ String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+ if (ssoId == null)
+ {
+ // Construct a cookie to be returned to the client
+ ssoId = generateSessionId();
+ Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
+ cookie.setMaxAge(-1);
+ cookie.setPath("/");
+
+ // Bugzilla 41217
+ cookie.setSecure(request.isSecure());
+
+ // Bugzilla 34724
+ String ssoDomain = sso.getCookieDomain();
+ if (ssoDomain != null)
+ {
+ cookie.setDomain(ssoDomain);
+ }
+
+ Response response = (Response) SecurityAssociationValve.activeResponse.get();
+ response.addCookie(cookie);
+
+ // Register this principal with our SSO valve
+ sso.register(ssoId, principal, AUTH_TYPE, username, this.getPasswordAsString(password));
+ request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
+
+ }
+ else
+ {
+ // Update the SSO session with the latest authentication data
+ // sso.update(ssoId, principal, AUTH_TYPE, username, this.getPasswordAsString(password));
+ }
+
+ // Always associate a session with a new SSO reqistration.
+ // SSO entries are only removed from the SSO registry map when
+ // associated sessions are destroyed; if a new SSO entry is created
+ // above for this request and the user never revisits the context, the
+ // SSO entry will never be cleared if we don't associate the session
+ if (session == null)
+ session = request.getSessionInternal(true);
+ sso.associate(ssoId, session);
}
-
+
/**
* Log the user out
* @param request
@@ -144,31 +205,88 @@
protected void unregister(Request request)
{
request.setAuthType(null);
- request.setUserPrincipal(null);
-
- //Cache the authentication principal in the session
+ request.setUserPrincipal(null);
+
+ // Cache the authentication principal in the session.
Session session = request.getSessionInternal(false);
- if(session != null)
+ if (session != null)
{
session.setAuthType(null);
session.setPrincipal(null);
session.removeNote(Constants.SESS_USERNAME_NOTE);
session.removeNote(Constants.SESS_PASSWORD_NOTE);
}
+ // Unregister the SSOID.
+ SingleSignOn sso = this.getSingleSignOn(request);
+ if(sso != null) {
+ String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+ sso.deregister(ssoId);
+ }
}
-
+
private String getPasswordAsString(Object cred)
{
String p = null;
-
- if(cred instanceof String)
+
+ if (cred instanceof String)
{
- p = (String)cred;
+ p = (String) cred;
}
- else if(cred instanceof byte[])
+ else if (cred instanceof byte[])
{
- p = new String((byte[])cred);
+ p = new String((byte[]) cred);
}
return p;
}
+
+ /**
+ * <p>
+ * Generate and return a new session identifier for the cookie that identifies an SSO principal.
+ * </p>
+ *
+ * @return a <code>String</code> representing the generated identifier.
+ */
+ private String generateSessionId()
+ {
+ UUID uid = UUID.randomUUID();
+ String higherBits = Long.toHexString(uid.getMostSignificantBits());
+ String lowerBits = Long.toHexString(uid.getLeastSignificantBits());
+
+ return (higherBits + lowerBits).toUpperCase();
+ }
+
+ /**
+ * <p>
+ * Obtain a reference to the <code>SingleSignOn</code> valve, if one was configured.
+ * </p>
+ *
+ * @param request the <code>Request</code> object used to look up the SSO valve.
+ * @return a reference to the <code>SingleSignOn</code> valve, or <code>null</code> if no SSO valve
+ * has been configured.
+ */
+ private SingleSignOn getSingleSignOn(Request request)
+ {
+ SingleSignOn sso = null;
+ Container parent = request.getContext().getParent();
+ while ((sso == null) && (parent != null))
+ {
+ if (!(parent instanceof Pipeline))
+ {
+ parent = parent.getParent();
+ continue;
+ }
+ Valve valves[] = ((Pipeline) parent).getValves();
+ for (int i = 0; i < valves.length; i++)
+ {
+ if (valves[i] instanceof SingleSignOn)
+ {
+ sso = (SingleSignOn) valves[i];
+ break;
+ }
+ }
+ if (sso == null)
+ parent = parent.getParent();
+ }
+ return sso;
+ }
}
More information about the jboss-cvs-commits
mailing list