Fork me on GitHub

Secure Page Tutorial

This tutorial looks at configuring a page to only be accessed via a secure channel (HTTPS).

The below example for this tutorial will implement a simple page to capture card details.

Tutorial Source

Secure Page

To configure the page to always be accessed via a secure channel, the following REST YAML path configuration is used:

secure: true

Setting secure: true in the path-level YAML file ensures any HTTP request to card is automatically redirected (307) to HTTPS before the handler runs.

To ease development, WoOF by default runs with a generic security key that is self signed. Typically for development and testing this will require trusting the key within the browser to access the page. This default setup should only be used for development/testing to avoid manual key setup.

For production, a trusted third-party signed security key is recommended to be configured.

Please also see the HttpServerLocation for details on configuring the web application's location for generation of the link URLs.

Template

The page template content is as follows:

<!DOCTYPE html>
<html>
<body>
    <h1>Enter card details</h1>
    <form action="/card" method="POST">
        Card number: <input type="text" name="number" th:value="${model.number}" size="19" /> <br />
        Expiry date: <input type="text" name="month" th:value="${model.month}" size="2" /> /
                    <input type="text" name="year" th:value="${model.year}" size="4" />
        CSC: <input type="text" name="csc" th:value="${model.csc}" size="3" /> <br />
        <input type="submit" value="save" />
    </form>
    <a href="/main">Back to main page</a>
</body>
</html>

This is similar HTML to previous tutorials.

Logic Class

The logic for the page is the following:

public class CardLogic {

	@Data
	@HttpParameters
	public static class CardDetails implements Serializable {
		private static final long serialVersionUID = 1L;

		private String number;

		private String month;

		private String year;

		private String csc;
	}

	public CardDetails getTemplateData(CardDetails cardDetails, ServerHttpConnection connection) {

		// Confirm a secure connection (not needed but included for tutorial)
		if (!connection.isSecure()) {
			throw new IllegalStateException();
		}

		// Return the card details for rendering
		return cardDetails;
	}

	public void save(CardDetails cardDetails, ServerHttpConnection connection) {

		// Confirm a secure connection (not needed but included for tutorial)
		if (!connection.isSecure()) {
			throw new IllegalStateException();
		}

		// Logic for processing the card details
	}

}

Again this is similar to previous tutorials. The isSecure() check confirms that the connection is always HTTPS when the handler runs (due to the secure: true configuration).

Remaining Code

The main page is included for completeness of the tutorial code.

<!DOCTYPE html>
<html>
<body>
    <h1>Main Page</h1>
    <a href="/card">Enter card details</a>
</body>
</html>

Unit Test

The unit test requests the page via HTTP and confirms the redirect to HTTPS returns the page successfully. The exception within the page logic ensures rendering the response only occurs over a secure channel (HTTPS).

@ExtendWith(OfficeFloorExtension.class)
public class SecurePageTest {

	@RegisterExtension
	public final HttpClientExtension client = new HttpClientExtension(true);

	@Test
	public void testSecurePage() throws Exception {

		// Ensure redirect to secure access to page
		this.assertHttpRequest("http://localhost:7878/card");
	}

	private void assertHttpRequest(String url) throws IOException {
		HttpResponse response = this.client.execute(new HttpGet(url));
		assertEquals(200, response.getStatusLine().getStatusCode(), "Should be successful (after possible redirect)");
		String entity = EntityUtils.toString(response.getEntity());
		assertTrue(entity.contains("<h1>Enter card details</h1>"),
				"Should be rendering page as secure (and not exception)");
	}

}

Next

The next tutorial looks at securing a specific link.