JETTY-1192 Fixed Digested POST
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1383 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
fa37afd7fe
commit
0207f90d5b
|
@ -0,0 +1,329 @@
|
|||
package org.eclipse.jetty.test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.security.Password;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.DefaultIdentityService;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
public class DigestPostTest extends TestCase
|
||||
{
|
||||
private static final String NC = "00000001";
|
||||
|
||||
public final static String __message =
|
||||
"0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 0123456789 \n"+
|
||||
"9876543210 9876543210 9876543210 9876543210 9876543210 9876543210 9876543210 9876543210 \n"+
|
||||
"1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 \n"+
|
||||
"0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 0987654321 \n"+
|
||||
"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz \n"+
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ \n"+
|
||||
"Now is the time for all good men to come to the aid of the party.\n"+
|
||||
"How now brown cow.\n"+
|
||||
"The quick brown fox jumped over the lazy dog.\n";
|
||||
|
||||
public volatile static String _received = null;
|
||||
private Server _server;
|
||||
|
||||
public void setUp()
|
||||
{
|
||||
try
|
||||
{
|
||||
_server = new Server();
|
||||
_server.setConnectors(new Connector[]
|
||||
{ new SelectChannelConnector() });
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SECURITY);
|
||||
context.setContextPath("/test");
|
||||
context.addServlet(PostServlet.class,"/");
|
||||
|
||||
HashLoginService realm = new HashLoginService("test");
|
||||
realm.putUser("testuser",new Password("password"),new String[]{"test"});
|
||||
_server.addBean(realm);
|
||||
|
||||
ConstraintSecurityHandler security=(ConstraintSecurityHandler)context.getSecurityHandler();
|
||||
security.setAuthenticator(new DigestAuthenticator());
|
||||
security.setLoginService(realm);
|
||||
|
||||
Constraint constraint = new Constraint("SecureTest","test");
|
||||
constraint.setAuthenticate(true);
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setConstraint(constraint);
|
||||
mapping.setPathSpec("/*");
|
||||
|
||||
security.setConstraintMappings(new ConstraintMapping[]{mapping});
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[]
|
||||
{ context, new DefaultHandler() });
|
||||
_server.setHandler(handlers);
|
||||
|
||||
_server.start();
|
||||
}
|
||||
catch (final Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see junit.framework.TestCase#tearDown()
|
||||
*/
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
|
||||
public void testServerDirectlyHTTP10() throws Exception
|
||||
{
|
||||
Socket socket = new Socket("127.0.0.1",_server.getConnectors()[0].getLocalPort());
|
||||
byte[] bytes = __message.getBytes("UTF-8");
|
||||
|
||||
_received=null;
|
||||
socket.getOutputStream().write(
|
||||
("POST /test/ HTTP/1.0\r\n"+
|
||||
"Host: 127.0.0.1:"+_server.getConnectors()[0].getLocalPort()+"\r\n"+
|
||||
"Content-Length: "+bytes.length+"\r\n"+
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
socket.getOutputStream().write(bytes);
|
||||
socket.getOutputStream().flush();
|
||||
|
||||
String result = IO.toString(socket.getInputStream());
|
||||
|
||||
assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertEquals(null,_received);
|
||||
|
||||
int n=result.indexOf("nonce=");
|
||||
String nonce=result.substring(n+7,result.indexOf('"',n+7));
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] b= md.digest(String.valueOf(System.currentTimeMillis()).getBytes(org.eclipse.jetty.util.StringUtil.__ISO_8859_1));
|
||||
String cnonce=encode(b);
|
||||
String digest="Digest username=\"testuser\" realm=\"test\" nonce=\""+nonce+"\" uri=\"/test/\" algorithm=MD5 response=\""+
|
||||
newResponse("POST","/test/",cnonce,"testuser","test","password",nonce,"auth")+
|
||||
"\" qop=auth nc="+NC+" cnonce=\""+cnonce+"\"";
|
||||
|
||||
|
||||
socket = new Socket("127.0.0.1",_server.getConnectors()[0].getLocalPort());
|
||||
|
||||
_received=null;
|
||||
socket.getOutputStream().write(
|
||||
("POST /test/ HTTP/1.0\r\n"+
|
||||
"Host: 127.0.0.1:"+_server.getConnectors()[0].getLocalPort()+"\r\n"+
|
||||
"Content-Length: "+bytes.length+"\r\n"+
|
||||
"Authorization: "+digest+"\r\n"+
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
socket.getOutputStream().write(bytes);
|
||||
socket.getOutputStream().flush();
|
||||
|
||||
result = IO.toString(socket.getInputStream());
|
||||
|
||||
assertTrue(result.startsWith("HTTP/1.1 200 OK"));
|
||||
assertEquals(__message,_received);
|
||||
}
|
||||
|
||||
public void testServerDirectlyHTTP11() throws Exception
|
||||
{
|
||||
Socket socket = new Socket("127.0.0.1",_server.getConnectors()[0].getLocalPort());
|
||||
byte[] bytes = __message.getBytes("UTF-8");
|
||||
|
||||
_received=null;
|
||||
socket.getOutputStream().write(
|
||||
("POST /test/ HTTP/1.1\r\n"+
|
||||
"Host: 127.0.0.1:"+_server.getConnectors()[0].getLocalPort()+"\r\n"+
|
||||
"Content-Length: "+bytes.length+"\r\n"+
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
socket.getOutputStream().write(bytes);
|
||||
socket.getOutputStream().flush();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
byte[] buf=new byte[4096];
|
||||
int len=socket.getInputStream().read(buf);
|
||||
String result=new String(buf,0,len,"UTF-8");
|
||||
|
||||
assertTrue(result.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertEquals(null,_received);
|
||||
|
||||
int n=result.indexOf("nonce=");
|
||||
String nonce=result.substring(n+7,result.indexOf('"',n+7));
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] b= md.digest(String.valueOf(System.currentTimeMillis()).getBytes(StringUtil.__ISO_8859_1));
|
||||
String cnonce=encode(b);
|
||||
String digest="Digest username=\"testuser\" realm=\"test\" nonce=\""+nonce+"\" uri=\"/test/\" algorithm=MD5 response=\""+
|
||||
newResponse("POST","/test/",cnonce,"testuser","test","password",nonce,"auth")+
|
||||
"\" qop=auth nc="+NC+" cnonce=\""+cnonce+"\"";
|
||||
|
||||
_received=null;
|
||||
socket.getOutputStream().write(
|
||||
("POST /test/ HTTP/1.0\r\n"+
|
||||
"Host: 127.0.0.1:"+_server.getConnectors()[0].getLocalPort()+"\r\n"+
|
||||
"Content-Length: "+bytes.length+"\r\n"+
|
||||
"Authorization: "+digest+"\r\n"+
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
socket.getOutputStream().write(bytes);
|
||||
socket.getOutputStream().flush();
|
||||
|
||||
result = IO.toString(socket.getInputStream());
|
||||
|
||||
assertTrue(result.startsWith("HTTP/1.1 200 OK"));
|
||||
assertEquals(__message,_received);
|
||||
}
|
||||
|
||||
public void testServerWithHttpClientStringContent() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setRealmResolver(new SimpleRealmResolver(new TestRealm()));
|
||||
client.start();
|
||||
|
||||
String srvUrl = "http://127.0.0.1:" + _server.getConnectors()[0].getLocalPort() + "/test/";
|
||||
|
||||
ContentExchange ex = new ContentExchange();
|
||||
ex.setMethod(HttpMethods.POST);
|
||||
ex.setURL(srvUrl);
|
||||
ex.setRequestContent(new ByteArrayBuffer(__message,"UTF-8"));
|
||||
|
||||
_received=null;
|
||||
client.send(ex);
|
||||
ex.waitForDone();
|
||||
|
||||
assertEquals(__message,_received);
|
||||
assertEquals(200,ex.getResponseStatus());
|
||||
}
|
||||
|
||||
|
||||
public void testServerWithHttpClientStreamContent() throws Exception
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
client.setRealmResolver(new SimpleRealmResolver(new TestRealm()));
|
||||
client.start();
|
||||
|
||||
String srvUrl = "http://127.0.0.1:" + _server.getConnectors()[0].getLocalPort() + "/test/";
|
||||
|
||||
ContentExchange ex = new ContentExchange();
|
||||
ex.setMethod(HttpMethods.POST);
|
||||
ex.setURL(srvUrl);
|
||||
ex.setRequestContentSource(new BufferedInputStream(new FileInputStream("src/test/resources/message.txt")));
|
||||
|
||||
_received=null;
|
||||
client.send(ex);
|
||||
ex.waitForDone();
|
||||
|
||||
String sent = IO.toString(new FileInputStream("src/test/resources/message.txt"));
|
||||
assertEquals(sent,_received);
|
||||
|
||||
assertEquals(200,ex.getResponseStatus());
|
||||
}
|
||||
|
||||
public static class TestRealm implements Realm
|
||||
{
|
||||
public String getPrincipal()
|
||||
{
|
||||
return "testuser";
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return "test";
|
||||
}
|
||||
|
||||
public String getCredentials()
|
||||
{
|
||||
return "password";
|
||||
}
|
||||
}
|
||||
|
||||
public static class PostServlet extends HttpServlet
|
||||
{
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException
|
||||
{
|
||||
String received = IO.toString(request.getInputStream());
|
||||
_received = received;
|
||||
|
||||
response.setStatus(200);
|
||||
response.getWriter().println("Received "+received.length()+" bytes");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected String newResponse(String method, String uri, String cnonce, String principal, String realm, String credentials, String nonce, String qop)
|
||||
throws Exception
|
||||
{
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
|
||||
// calc A1 digest
|
||||
md.update(principal.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(realm.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(credentials.getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] ha1 = md.digest();
|
||||
// calc A2 digest
|
||||
md.reset();
|
||||
md.update(method.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(uri.getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] ha2=md.digest();
|
||||
|
||||
md.update(TypeUtil.toString(ha1,16).getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(nonce.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(NC.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(cnonce.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(qop.getBytes(StringUtil.__ISO_8859_1));
|
||||
md.update((byte)':');
|
||||
md.update(TypeUtil.toString(ha2,16).getBytes(StringUtil.__ISO_8859_1));
|
||||
byte[] digest=md.digest();
|
||||
|
||||
// check digest
|
||||
return encode(digest);
|
||||
}
|
||||
|
||||
private static String encode(byte[] data)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
for (int i=0; i<data.length; i++)
|
||||
{
|
||||
buffer.append(Integer.toHexString((data[i] & 0xf0) >>> 4));
|
||||
buffer.append(Integer.toHexString(data[i] & 0x0f));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc.
|
||||
Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque
|
||||
habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
|
||||
Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam
|
||||
at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate
|
||||
velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum.
|
||||
Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum
|
||||
eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa
|
||||
sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam
|
||||
consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque.
|
||||
Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse
|
||||
et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.
|
Loading…
Reference in New Issue