diff --git a/src/zutil/net/http/HttpHeader.java b/src/zutil/net/http/HttpHeader.java index fe59e96..af856b7 100755 --- a/src/zutil/net/http/HttpHeader.java +++ b/src/zutil/net/http/HttpHeader.java @@ -45,7 +45,7 @@ public class HttpHeader { private HashMap cookies; - protected HttpHeader(){ + public HttpHeader(){ urlAttributes = new HashMap(); headers = new HashMap(); cookies = new HashMap(); diff --git a/src/zutil/net/http/HttpHeaderParser.java b/src/zutil/net/http/HttpHeaderParser.java index 00bd7c9..982dac9 100755 --- a/src/zutil/net/http/HttpHeaderParser.java +++ b/src/zutil/net/http/HttpHeaderParser.java @@ -31,6 +31,7 @@ import zutil.parser.URLDecoder; import java.io.IOException; import java.io.InputStream; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -106,7 +107,7 @@ public class HttpHeaderParser { if( statusLine.startsWith("HTTP/") ){ header.setIsRequest(false); header.setHTTPVersion( Float.parseFloat( statusLine.substring( 5 , 8))); - header.setHTTPCode( Integer.parseInt( statusLine.substring( 9, 12 ))); + header.setHTTPCode( Integer.parseInt( statusLine.substring( 9, statusLine.indexOf(' ', 9) ))); } // Client Request else if(statusLine.contains("HTTP/")){ @@ -163,12 +164,12 @@ public class HttpHeaderParser { */ public static void parseHeaderValues(Map map, String headerValue, String delimiter){ if(headerValue != null && !headerValue.isEmpty()){ - String[] tmp = headerValue.split(delimiter); - for(String cookie : tmp){ - String[] tmp2 = PATTERN_EQUAL.split(cookie, 2); + String[] tmpArr = headerValue.split(delimiter); + for(String cookie : tmpArr){ + String[] tmpStr = PATTERN_EQUAL.split(cookie, 2); map.put( - tmp2[0].trim(), // Key - StringUtil.trim((tmp2.length>1 ? tmp2[1] : "").trim(), '\"')); //Value + tmpStr[0].trim(), // Key + StringUtil.trim((tmpStr.length>1 ? tmpStr[1] : "").trim(), '\"')); //Value } } } diff --git a/src/zutil/net/http/HttpPrintStream.java b/src/zutil/net/http/HttpPrintStream.java index 6f4b178..80d3024 100755 --- a/src/zutil/net/http/HttpPrintStream.java +++ b/src/zutil/net/http/HttpPrintStream.java @@ -86,7 +86,7 @@ public class HttpPrintStream extends OutputStream{ this.out = new PrintStream(out); this.httpVersion = "1.1"; this.message_type = type; - this.res_status_code = 0; + this.res_status_code = 200; this.headers = new HashMap(); this.cookies = new HashMap(); this.buffer = new StringBuffer(); diff --git a/src/zutil/net/http/page/HttpDigestAuthPage.java b/src/zutil/net/http/page/HttpDigestAuthPage.java new file mode 100755 index 0000000..dd20c21 --- /dev/null +++ b/src/zutil/net/http/page/HttpDigestAuthPage.java @@ -0,0 +1,63 @@ +package zutil.net.http.page; + +import zutil.net.http.HttpHeader; +import zutil.net.http.HttpPage; +import zutil.net.http.HttpPrintStream; + +import java.io.IOException; +import java.util.Map; + +/** + * A abstract page that requires HTTP Digest authentication + * to access the subclass HttpPage. + * + * @see rfc2617 + * @author Ziver + */ +public abstract class HttpDigestAuthPage implements HttpPage{ + private static final String HTTP_AUTH_HEADER = "WWW-Authenticate"; + private static final String AUTH_TYPE = "Digest"; + + private static final String AUTH_REALM = "realm"; + private static final String AUTH_QUALITY_OF_PROTECTION = "qop"; + private static final String AUTH_NONCE = "nonce"; + private static final String AUTH_OPAQUE = "opaque"; + + private static final String AUTH_USERNAME = "username"; + private static final String AUTH_URI = "uri"; + private static final String AUTH_CNONCE = "cnonce"; + private static final String AUTH_RESPONSE = "response"; + + + private String realm; + + + @Override + public final void respond(HttpPrintStream out, + HttpHeader headers, + Map session, + Map cookie, + Map request) throws IOException { + + out.setStatusCode(401); + out.setHeader(HTTP_AUTH_HEADER, generateAuthHeader()); + } + + private String generateAuthHeader(){ + StringBuilder str = new StringBuilder(); + str.append(AUTH_TYPE).append(' '); + str.append(AUTH_REALM).append("=\"").append("ll").append("\", "); + str.append(AUTH_QUALITY_OF_PROTECTION).append("=\"").append("ll").append("\", "); + str.append(AUTH_NONCE).append("=\"").append("ll").append("\", "); + str.append(AUTH_OPAQUE).append("=\"").append("ll").append("\""); + return str.toString(); + } + + + + public abstract void authRespond(HttpPrintStream out, + HttpHeader headers, + Map session, + Map cookie, + Map request) throws IOException; +} diff --git a/test/zutil/net/http/page/HttpDigestAuthPageTest.java b/test/zutil/net/http/page/HttpDigestAuthPageTest.java new file mode 100755 index 0000000..e490223 --- /dev/null +++ b/test/zutil/net/http/page/HttpDigestAuthPageTest.java @@ -0,0 +1,73 @@ +package zutil.net.http.page; + +import org.junit.Test; +import zutil.io.StringOutputStream; +import zutil.net.http.HttpHeader; +import zutil.net.http.HttpHeaderParser; +import zutil.net.http.HttpPrintStream; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * @author Ziver on 2016-10-26. + */ +public class HttpDigestAuthPageTest { + private static final String PAGE_CONTENT = "Hello World!"; + + @Test + public void cleanRequest() throws IOException { + HttpHeader header = new HttpHeader(); + HttpHeader output = makeRequest(header); + + assertEquals(401, output.getHTTPCode()); + assertTrue(output.getHeader("WWW-Authenticate") != null); + assertEquals("Digest", parseAuthType(output)); + Map authHeader = parseAuthHeader(output); + assertTrue(authHeader.containsKey("realm")); + assertTrue(authHeader.containsKey("qop")); + assertTrue(authHeader.containsKey("nonce")); + assertTrue(authHeader.containsKey("opaque")); + } + + + + + + public static HttpHeader makeRequest(HttpHeader headers) throws IOException { + StringOutputStream buff = new StringOutputStream(); + HttpPrintStream out = new HttpPrintStream(buff); + new HttpDigestTestPage().respond( + out, headers, new HashMap(), new HashMap(), new HashMap()); + out.flush(); + HttpHeaderParser parser = new HttpHeaderParser(buff.toString()); + return parser.read(); + } + + public static String parseAuthType(HttpHeader headers){ + String tmp = headers.getHeader("WWW-Authenticate"); + return tmp.substring(0, tmp.indexOf(' ')); + } + public static HashMap parseAuthHeader(HttpHeader headers){ + HashMap authHeaders = new HashMap<>(); + String tmp = headers.getHeader("WWW-Authenticate"); + HttpHeaderParser.parseHeaderValues(authHeaders, + tmp.substring(tmp.indexOf(' ')+1), + ","); + return authHeaders; + } + + private static class HttpDigestTestPage extends HttpDigestAuthPage{ + @Override + public void authRespond(HttpPrintStream out, + HttpHeader headers, + Map session, + Map cookie, + Map request) throws IOException { + out.print(PAGE_CONTENT); + } + } +} \ No newline at end of file