Digest is now listening to correct headers
This commit is contained in:
parent
c4efab0609
commit
2c7a9a6eff
5 changed files with 107 additions and 29 deletions
|
|
@ -195,7 +195,7 @@ public class StringUtil {
|
|||
}
|
||||
|
||||
|
||||
private static ArrayList<String> SPACES = new ArrayList<String>();
|
||||
private static ArrayList<String> SPACES = new ArrayList<>();
|
||||
/**
|
||||
* @return A string containing a specific amount of spaces
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -148,19 +148,22 @@ public class HttpHeader {
|
|||
}
|
||||
|
||||
|
||||
protected void setIsRequest(boolean request) { this.request = request; }
|
||||
protected void setRequestType(String type){
|
||||
public void setIsRequest(boolean request) { this.request = request; }
|
||||
public void setRequestType(String type){
|
||||
this.type = type;
|
||||
}
|
||||
protected void setHTTPVersion(float version){
|
||||
public void setHTTPVersion(float version){
|
||||
this.version = version;
|
||||
}
|
||||
protected void setHTTPCode(int code){
|
||||
public void setHTTPCode(int code){
|
||||
this.httpCode = code;
|
||||
}
|
||||
protected void setRequestURL(String url){
|
||||
public void setRequestURL(String url){
|
||||
this.url = url.trim().replaceAll("//", "/");
|
||||
}
|
||||
public void setHeader(String key, String value){
|
||||
this.headers.put(key.toUpperCase(), value);
|
||||
}
|
||||
protected void setInputStream(InputStream in){
|
||||
this.in = in;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ public class HttpHeaderParser {
|
|||
* stores them in a HashMap. If a pair only contain a key the the value
|
||||
* will be set as a empty string.
|
||||
*
|
||||
* TODO: method is not quote aware
|
||||
* @param map the Map where key and values will be stored.
|
||||
* @param headerValue the raw header value String that will be parsed.
|
||||
* @param delimiter the delimiter that separates key and value pairs (e.g. ';' for Cookies or ',' for Cache-Control)
|
||||
|
|
@ -168,8 +169,8 @@ public class HttpHeaderParser {
|
|||
for(String cookie : tmpArr){
|
||||
String[] tmpStr = PATTERN_EQUAL.split(cookie, 2);
|
||||
map.put(
|
||||
tmpStr[0].trim(), // Key
|
||||
StringUtil.trim((tmpStr.length>1 ? tmpStr[1] : "").trim(), '\"')); //Value
|
||||
tmpStr[0].trim(), // Key
|
||||
StringUtil.trim((tmpStr.length>1 ? tmpStr[1] : "").trim(), '\"')); //Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,45 @@
|
|||
package zutil.net.http.page;
|
||||
|
||||
import zutil.Encrypter;
|
||||
import zutil.Hasher;
|
||||
import zutil.net.http.HttpHeader;
|
||||
import zutil.net.http.HttpPage;
|
||||
import zutil.net.http.HttpPrintStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A abstract page that requires HTTP Digest authentication
|
||||
* to access the subclass HttpPage.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2617">rfc2617</a>
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2069">rfc2069</a>
|
||||
* @author Ziver
|
||||
*/
|
||||
public abstract class HttpDigestAuthPage implements HttpPage{
|
||||
private static final String DEAFULT_REALM = "Login";
|
||||
private static final String HTTP_AUTH_HEADER = "WWW-Authenticate";
|
||||
private static final String HTTP_CLIENT_HEADER = "Authorization";
|
||||
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_OPAQUE = "opaque"; // OPTIONAL can be used as session data
|
||||
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;
|
||||
private String realm = DEAFULT_REALM;
|
||||
private SecureRandom secRandom = new SecureRandom();
|
||||
|
||||
|
||||
|
||||
public void setRealm(String realm){
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
|
|
@ -39,20 +49,61 @@ public abstract class HttpDigestAuthPage implements HttpPage{
|
|||
Map<String, String> cookie,
|
||||
Map<String, String> request) throws IOException {
|
||||
|
||||
out.setStatusCode(401);
|
||||
out.setHeader(HTTP_AUTH_HEADER, generateAuthHeader());
|
||||
if (headers.getHeader(HTTP_CLIENT_HEADER) == null) {
|
||||
session.put(AUTH_NONCE, generateNonce());
|
||||
out.setStatusCode(401);
|
||||
out.setHeader(HTTP_AUTH_HEADER, generateAuthHeader((String) session.get(AUTH_NONCE)));
|
||||
}
|
||||
else{
|
||||
authRespond(out, headers, session, cookie, request);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateAuthHeader(){
|
||||
|
||||
private String generateAuthHeader(String nonce){
|
||||
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("\"");
|
||||
str.append(AUTH_REALM).append("=\"").append(realm).append("\", ");
|
||||
str.append(AUTH_NONCE).append("=\"").append(nonce).append("\", ");
|
||||
//str.append(AUTH_OPAQUE).append("=\"").append("ll").append("\"");
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private String generateNonce(){
|
||||
byte[] buff = new byte[128/8];
|
||||
secRandom.nextBytes(buff);
|
||||
return Hasher.SHA1(buff);
|
||||
}
|
||||
|
||||
private static String generateH1(String username, String password, String realm) {
|
||||
String ha1 = null;
|
||||
// If the algorithm directive's value is "MD5" or unspecified, then HA1 is
|
||||
// HA1=MD5(username:realm:password)
|
||||
ha1 = Hasher.MD5(username +":"+ realm +":"+ password);
|
||||
// If the algorithm directive's value is "MD5-sess", then HA1 is
|
||||
// HA1=MD5(MD5(username:realm:password):nonce:cnonce)
|
||||
return ha1;
|
||||
}
|
||||
|
||||
private static String generateH2(String uri) {
|
||||
String ha2;
|
||||
// If the qop directive's value is "auth" or is unspecified, then HA2 is
|
||||
// HA2=MD5(method:digestURI)
|
||||
ha2 = Hasher.MD5("MD5:"+ uri);
|
||||
// If the qop directive's value is "auth-int", then HA2 is
|
||||
// HA2=MD5(method:digestURI:MD5(entityBody))
|
||||
return ha2;
|
||||
}
|
||||
|
||||
private static String generateResponseHash(String ha1, String ha2, String nonce){
|
||||
String response;
|
||||
// If the qop directive's value is "auth" or "auth-int", then compute the response as follows:
|
||||
// response=MD5(HA1:nonce:nonceCount:cnonce:qop:HA2)
|
||||
// If the qop directive is unspecified, then compute the response as follows:
|
||||
// response=MD5(HA1:nonce:HA2)
|
||||
response = Hasher.MD5(ha1 +":"+ nonce +":"+ ha2);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
public abstract void authRespond(HttpPrintStream out,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue