Skip to content

Commit

Permalink
HttpMethodAuthTest moved to maven + HTTP1.0 client supporting custom …
Browse files Browse the repository at this point in the history
…method

- that was originally implemented by the org.apache.tomcat.task.GTest class
  from Tomcat webserver 3.2 of 2001.

Signed-off-by: David Matějček <david.matejcek@omnifish.ee>
  • Loading branch information
dmatej committed Nov 13, 2023
1 parent 8631cfc commit 995af18
Show file tree
Hide file tree
Showing 11 changed files with 467 additions and 370 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.main.itest.tools;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
* HTTP client using the HTTP 1.0 protocol, allowing to break some standards.
* Useful for testing of server reactions to malformed or obsoleted requests.
* <p>
* Example: Request with nonstandard method, prohibited in later HTTP versions.
*/
public class HttpClient10 {

private final URL url;
private final String user;
private final String password;

/**
* @param url target endpoint.
* @param user
* @param password
*/
public HttpClient10(URL url, String user, String password) {
this.url = url;
this.user = user;
this.password = password;
}


/**
* Sends the HTTP 1.0 request and reads the response.
*
* @param method GET/PUT/... or your custom method.
* @param content the body
* @return {@link HttpResponse}
* @throws Exception
*/
public HttpResponse send(String method, String content) throws Exception {
try (Socket socket = new Socket(url.getHost(), url.getPort())) {
InputStream inputStream = socket.getInputStream();
socket.setSoLinger(true, 1000);
PrintWriter outputWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
outputWriter.println(method + " " + url.getPath() + " HTTP/1.0");
outputWriter.println("Host: " + url.getHost() + ':' + url.getPort());
if (content != null) {
outputWriter.println("Content-Length: " + content.length());
}
if (user != null && password != null) {
String basicAuth = Base64.getEncoder().encodeToString((user + ":" + password).getBytes(UTF_8));
outputWriter.println("Authorization: Basic " + basicAuth);
}
outputWriter.println("");
if (content != null) {
outputWriter.print(content);
}
outputWriter.flush();
return HttpResponse.parse(inputStream);
}
}

/**
* Parsed HTTP response.
*/
public static class HttpResponse {

/**
* Example: <code>HTTP/1.0 403 Forbidden</copde>
*/
public final String responseLine;
/**
* Response headers.
*/
public final Map<String, String> headers;
/**
* Response body
*/
public final String body;


private HttpResponse(String responseLine, Map<String, String> headers, String body) {
this.responseLine = responseLine;
this.headers = headers;
this.body = body;
}


private static HttpResponse parse(InputStream inputStream) throws IOException {
String responseLine = parseResponseLine(inputStream);
Map<String, String> headers = parseHeaders(inputStream);
String body = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8).trim();
return new HttpResponse(responseLine, headers, body);
}


private static Map<String, String> parseHeaders(InputStream is) throws IOException {
Map<String, String> headers = new HashMap<>();
while (true) {
String line = parseResponseLine(is);
if (line == null || line.isEmpty()) {
break;
}
String[] header = parseHeader(line);
headers.put(header[0], header[1]);
}
return headers;
}


private static String[] parseHeader(String line) {
int colon = line.indexOf(':');
if (colon < 0) {
throw new IllegalStateException("Invalid header: " + line);
}
String name = line.substring(0, colon).trim();
String value = line.substring(colon + 1).trim();
return new String[] {name, value};
}


private static String parseResponseLine(InputStream input) throws IOException {
StringBuilder sb = new StringBuilder();
while (true) {
int ch = input.read();
if (ch < 0) {
break;
} else if (ch == '\n') {
break;
}
sb.append((char) ch);
}
// Strip any trailing carriage return
int n = sb.length();
if (n > 0 && sb.charAt(n - 1) == '\r') {
sb.setLength(n - 1);
}
return sb.toString();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -14,35 +15,38 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package com.sun.s1asdev.security.httpMethod;
package org.glassfish.main.test.app.security.http.method;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

public class TestServlet extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
public class HttpMethodTestServlet extends HttpServlet {

private static final long serialVersionUID = 1L;


@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals("FOO")) {
if ("FOO".equals(method)) {
doFoo(req, resp);
} else {
super.service(req, resp);
}
}

public void doFoo(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.println("doFoo with " + req.getUserPrincipal().getName());

public void doFoo(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("doFoo with " + req.getUserPrincipal().getName());
}

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.println("doGet with " + req.getUserPrincipal().getName());

@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("doGet with " + req.getUserPrincipal().getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<!DOCTYPE sun-web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Sun ONE Application Server 7.0 Servlet 2.3//EN' 'http://www.sun.com/software/sunone/appserver/dtds/ sun-web-app_2_3-0.dtd'>
<!--
Copyright (c) 2023 Contributors to the Eclipse Foundation.
Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
Expand All @@ -17,22 +18,21 @@
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->

<sun-web-app>
<security-role-mapping>
<role-name>employee</role-name>
<principal-name>shingwai</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>manager</role-name>
<principal-name>shingwai</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee</role-name>
<principal-name>swchan</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>staff</role-name>
<principal-name>swchan</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee</role-name>
<principal-name>shingwai</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>manager</role-name>
<principal-name>shingwai</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee</role-name>
<principal-name>swchan</principal-name>
</security-role-mapping>
<security-role-mapping>
<role-name>staff</role-name>
<principal-name>swchan</principal-name>
</security-role-mapping>
</sun-web-app>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN' 'http://java.sun.com/j2ee/dtds/web-app_2_2.dtd'>
<!--
Copyright (c) 2023 Contributors to the Eclipse Foundation.
Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->
<web-app>
<display-name>security-httpMethod</display-name>
<distributable></distributable>
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>org.glassfish.main.test.app.security.http.method.HttpMethodTestServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>TestServlet2</servlet-name>
<servlet-class>org.glassfish.main.test.app.security.http.method.HttpMethodTestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>/TestServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>TestServlet2</servlet-name>
<url-pattern>/TestServlet2</url-pattern>
</servlet-mapping>

<security-constraint>
<web-resource-collection>
<web-resource-name>secure1</web-resource-name>
<url-pattern>/TestServlet</url-pattern>
<http-method>FOO</http-method>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>secure2</web-resource-name>
<url-pattern>/TestServlet2</url-pattern>
<http-method>FOO</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>

<login-config>
<auth-method>BASIC</auth-method>
<realm-name>default</realm-name>
</login-config>

<security-role>
<role-name>manager</role-name>
</security-role>
</web-app>

Loading

0 comments on commit 995af18

Please sign in to comment.