/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.test.integration.web.formauth; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.container.test.api.OperateOnDeployment; import org.jboss.arquillian.container.test.api.RunAsClient; import org.jboss.arquillian.junit.Arquillian; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.as.arquillian.container.ManagementClient; import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.test.integration.management.ManagementOperations; import org.jboss.as.test.shared.util.AssumeTestGroupUtil; import org.jboss.dmr.ModelNode; import org.jboss.logging.Logger; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Test; import org.junit.runner.RunWith; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Tests of form authentication * * @author Scott.Stark@jboss.org * @author lbarreiro@redhat.com */ @RunWith(Arquillian.class) @RunAsClient public class FormAuthUnitTestCase { private static Logger log = Logger.getLogger(FormAuthUnitTestCase.class); @ArquillianResource private URL baseURLNoAuth; @ArquillianResource private ManagementClient managementClient; private static final String USERNAME = "user2"; private static final String PASSWORD = "password2"; DefaultHttpClient httpclient = new DefaultHttpClient(); @Deployment(name="form-auth.war", testable = false) public static WebArchive deployment() { ClassLoader tccl = Thread.currentThread().getContextClassLoader(); String resourcesLocation = "org/jboss/as/test/integration/web/formauth/resources/"; WebArchive war = ShrinkWrap.create(WebArchive.class, "form-auth.war"); war.setWebXML(tccl.getResource(resourcesLocation + "web.xml")); war.addAsWebInfResource(tccl.getResource(resourcesLocation + "jboss-web.xml"), "jboss-web.xml"); war.addClass(SecureServlet.class); war.addClass(SecuredPostServlet.class); war.addClass(LogoutServlet.class); war.addAsWebResource(tccl.getResource(resourcesLocation + "index.html"), "index.html"); war.addAsWebResource(tccl.getResource(resourcesLocation + "unsecure_form.html"), "unsecure_form.html"); war.addAsWebResource(tccl.getResource(resourcesLocation + "restricted/errors.jsp"), "restricted/errors.jsp"); war.addAsWebResource(tccl.getResource(resourcesLocation + "restricted/error.html"), "restricted/error.html"); war.addAsWebResource(tccl.getResource(resourcesLocation + "restricted/login.html"), "restricted/login.html"); return war; } /** * Test form authentication of a secured servlet * * @throws Exception */ @Test @OperateOnDeployment("form-auth.war") public void testFormAuth() throws Exception { log.trace("+++ testFormAuth"); doSecureGetWithLogin("restricted/SecuredServlet"); /* * Access the resource without attempting a login to validate that the * session is valid and that any caching on the server is working as * expected. */ doSecureGet("restricted/SecuredServlet"); } /** * Test that a bad login is redirected to the errors.jsp and that the * session j_exception is not null. */ @Test @OperateOnDeployment("form-auth.war") public void testFormAuthException() throws Exception { log.trace("+++ testFormAuthException"); URL url = new URL(baseURLNoAuth + "restricted/SecuredServlet"); HttpGet httpget = new HttpGet(url.toURI()); log.trace("Executing request " + httpget.getRequestLine()); HttpResponse response = httpclient.execute(httpget); int statusCode = response.getStatusLine().getStatusCode(); Header[] errorHeaders = response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); HttpEntity entity = response.getEntity(); if ((entity != null) && (entity.getContentLength() > 0)) { String body = EntityUtils.toString(entity); assertTrue("Redirected to login page", body.indexOf("j_security_check") > 0); } else { fail("Empty body in response"); } String sessionID = null; for (Cookie k : httpclient.getCookieStore().getCookies()) { if (k.getName().equalsIgnoreCase("JSESSIONID")) sessionID = k.getValue(); } log.trace("Saw JSESSIONID=" + sessionID); // Submit the login form HttpPost formPost = new HttpPost(baseURLNoAuth + "j_security_check"); formPost.addHeader("Referer", baseURLNoAuth + "restricted/login.html"); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("j_username", "baduser")); formparams.add(new BasicNameValuePair("j_password", "badpass")); formPost.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8")); log.trace("Executing request " + formPost.getRequestLine()); HttpResponse postResponse = httpclient.execute(formPost); statusCode = postResponse.getStatusLine().getStatusCode(); errorHeaders = postResponse.getHeaders("X-NoJException"); assertTrue("Should see HTTP_OK. Got " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is not null", errorHeaders.length != 0); log.debug("Saw X-JException, " + Arrays.toString(errorHeaders)); } /** * Test form authentication of a secured servlet and validate that there is * a SecurityAssociation setting Subject. */ @Test @OperateOnDeployment("form-auth.war") public void testFormAuthSubject() throws Exception { log.trace("+++ testFormAuthSubject"); doSecureGetWithLogin("restricted/SecuredServlet"); } /** * Test that a post from an unsecured form to a secured servlet does not * loose its data during the redirect to the form login. */ @Test @OperateOnDeployment("form-auth.war") public void testPostDataFormAuth() throws Exception { log.trace("+++ testPostDataFormAuth"); URL url = new URL(baseURLNoAuth + "unsecure_form.html"); HttpGet httpget = new HttpGet(url.toURI()); log.trace("Executing request " + httpget.getRequestLine()); HttpResponse response = httpclient.execute(httpget); int statusCode = response.getStatusLine().getStatusCode(); Header[] errorHeaders = response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); EntityUtils.consume(response.getEntity()); // Submit the form to /restricted/SecuredPostServlet HttpPost restrictedPost = new HttpPost(baseURLNoAuth + "restricted/SecuredPostServlet"); List<NameValuePair> restrictedParams = new ArrayList<NameValuePair>(); restrictedParams.add(new BasicNameValuePair("checkParam", "123456")); restrictedPost.setEntity(new UrlEncodedFormEntity(restrictedParams, "UTF-8")); log.trace("Executing request " + restrictedPost.getRequestLine()); HttpResponse restrictedResponse = httpclient.execute(restrictedPost); statusCode = restrictedResponse.getStatusLine().getStatusCode(); errorHeaders = restrictedResponse.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); HttpEntity entity = restrictedResponse.getEntity(); if ((entity != null) && (entity.getContentLength() > 0)) { String body = EntityUtils.toString(entity); assertTrue("Redirected to login page", body.indexOf("j_security_check") > 0); } else { fail("Empty body in response"); } String sessionID = null; for (Cookie k : httpclient.getCookieStore().getCookies()) { if (k.getName().equalsIgnoreCase("JSESSIONID")) sessionID = k.getValue(); } log.trace("Saw JSESSIONID=" + sessionID); // Submit the login form HttpPost formPost = new HttpPost(baseURLNoAuth + "j_security_check"); formPost.addHeader("Referer", baseURLNoAuth + "restricted/login.html"); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("j_username", "user1")); formparams.add(new BasicNameValuePair("j_password", "password1")); formPost.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8")); log.trace("Executing request " + formPost.getRequestLine()); HttpResponse postResponse = httpclient.execute(formPost); statusCode = postResponse.getStatusLine().getStatusCode(); errorHeaders = postResponse.getHeaders("X-NoJException"); assertTrue("Should see HTTP_MOVED_TEMP. Got " + statusCode, statusCode == HttpURLConnection.HTTP_MOVED_TEMP); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); EntityUtils.consume(postResponse.getEntity()); // Follow the redirect to the SecureServlet Header location = postResponse.getFirstHeader("Location"); URL indexURI = new URL(location.getValue()); HttpGet war1Index = new HttpGet(indexURI.toURI()); log.trace("Executing request " + war1Index.getRequestLine()); HttpResponse war1Response = httpclient.execute(war1Index); statusCode = war1Response.getStatusLine().getStatusCode(); errorHeaders = war1Response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); HttpEntity war1Entity = war1Response.getEntity(); if ((war1Entity != null) && (entity.getContentLength() > 0)) { String body = EntityUtils.toString(war1Entity); if (body.indexOf("j_security_check") > 0) fail("Get of " + indexURI + " redirected to login page"); } else { fail("Empty body in response"); } } /** * Test that the war which uses <security-domain * flushOnSessionInvalidation="true"> in the jboss-web.xml does not have any * jaas security domain cache entries after the web session has been * invalidated. */ @Test public void testFlushOnSessionInvalidation() throws Exception { AssumeTestGroupUtil.assumeElytronProfileTestsEnabled(); log.trace("+++ testFlushOnSessionInvalidation"); final ModelNode addr = new ModelNode(); addr.add(ModelDescriptionConstants.SUBSYSTEM, "security"); addr.add("security-domain", "other"); addr.protect(); final ModelNode listCachedPrincipalsOperation = new ModelNode(); listCachedPrincipalsOperation.get(ModelDescriptionConstants.OP_ADDR).set(addr); listCachedPrincipalsOperation.get(ModelDescriptionConstants.OP).set("list-cached-principals"); // Access a secured servlet to create a session and jaas cache entry doSecureGetWithLogin("restricted/SecuredServlet"); // Validate that the jaas cache has our principal final ModelNode node = ManagementOperations.executeOperation(managementClient.getControllerClient(), listCachedPrincipalsOperation); assertNotNull(node); final Set<String> cachedPrincipals = createSetOfPrincipals(node); assertTrue(USERNAME + " should be cached now.", cachedPrincipals.contains(USERNAME)); // Logout to clear the cache doSecureGet("Logout"); final ModelNode node2 = ManagementOperations.executeOperation(managementClient.getControllerClient(), listCachedPrincipalsOperation); assertNotNull(node2); final Set<String> cachedPrincipals2 = createSetOfPrincipals(node2); assertFalse(USERNAME + " should no longer be cached.", cachedPrincipals2.contains(USERNAME)); } private Set<String> createSetOfPrincipals(final ModelNode list) { Set<String> set = new HashSet<>(); for (ModelNode node : list.asList()) { set.add(node.asString()); } return set; } public HttpPost doSecureGetWithLogin(String path) throws Exception { return doSecureGetWithLogin(path, USERNAME, PASSWORD); } public HttpPost doSecureGetWithLogin(String path, String username, String password) throws Exception { log.trace("+++ doSecureGetWithLogin : " + path); URL url = new URL(baseURLNoAuth + path); HttpGet httpget = new HttpGet(url.toURI()); log.trace("Executing request " + httpget.getRequestLine()); HttpResponse response = httpclient.execute(httpget); int statusCode = response.getStatusLine().getStatusCode(); Header[] errorHeaders = response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); HttpEntity entity = response.getEntity(); if ((entity != null) && (entity.getContentLength() > 0)) { String body = EntityUtils.toString(entity); assertTrue("Redirected to login page", body.indexOf("j_security_check") > 0); } else { fail("Empty body in response"); } String sessionID = null; for (Cookie k : httpclient.getCookieStore().getCookies()) { if (k.getName().equalsIgnoreCase("JSESSIONID")) sessionID = k.getValue(); } log.trace("Saw JSESSIONID=" + sessionID); // Submit the login form HttpPost formPost = new HttpPost(baseURLNoAuth + "j_security_check"); formPost.addHeader("Referer", baseURLNoAuth + "restricted/login.html"); List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("j_username", username)); formparams.add(new BasicNameValuePair("j_password", password)); formPost.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8")); log.trace("Executing request " + formPost.getRequestLine()); HttpResponse postResponse = httpclient.execute(formPost); statusCode = postResponse.getStatusLine().getStatusCode(); errorHeaders = postResponse.getHeaders("X-NoJException"); assertTrue("Should see HTTP_MOVED_TEMP. Got " + statusCode, statusCode == HttpURLConnection.HTTP_MOVED_TEMP); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); EntityUtils.consume(postResponse.getEntity()); // Follow the redirect to the SecureServlet Header location = postResponse.getFirstHeader("Location"); URL indexURI = new URL(location.getValue()); HttpGet war1Index = new HttpGet(url.toURI()); log.trace("Executing request " + war1Index.getRequestLine()); HttpResponse war1Response = httpclient.execute(war1Index); statusCode = war1Response.getStatusLine().getStatusCode(); errorHeaders = war1Response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); HttpEntity war1Entity = war1Response.getEntity(); if ((war1Entity != null) && (entity.getContentLength() > 0)) { String body = EntityUtils.toString(war1Entity); if (body.indexOf("j_security_check") > 0) fail("Get of " + indexURI + " redirected to login page"); } else { fail("Empty body in response"); } return formPost; } public void doSecureGet(String path) throws Exception { log.trace("+++ doSecureGet : " + path); String sessionID = null; for (Cookie k : httpclient.getCookieStore().getCookies()) { if (k.getName().equalsIgnoreCase("JSESSIONID")) sessionID = k.getValue(); } log.trace("Saw JSESSIONID=" + sessionID); URL url = new URL(baseURLNoAuth + path); HttpGet httpget = new HttpGet(url.toURI()); log.trace("Executing request" + httpget.getRequestLine()); HttpResponse response = httpclient.execute(httpget); int statusCode = response.getStatusLine().getStatusCode(); Header[] errorHeaders = response.getHeaders("X-NoJException"); assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); } }