How to authorize browsers with my own Java https server?
843790Aug 8 2006 — edited Aug 9 2006Hi, Java developers!
I have modified the server.java program in the book "Java Example in a nutshell"
to be a tiny SSL web server. When it gets a request, no matter what it is,
it opens the "index.html" file and ship it.
It works most time. Sometimes it needs the browser to refresh to get it.
I do not know why. Netscape and Firebox works better. IE 6 worse. IE 7 absolutely not working.
If some one could help, that will be great. But my problem is not this.
I want to add the client authentication to this program.
I have created the keystore and truststore files as usual. If the client
is a java program, I know to put a -Djavax.net.sll.trustStore=... -Djavax.net. sll.trustStorePass=... into client's JVM.
Now the client is the browsers such a IE and Netscape and Firebox. I know these browsers only accept .pk12 files or X509 certificates. I think these files must be created by openssl. I have searched for several days. I cannot find any instruction to create certificates
for browsers in order for the browser to communicate with a Java program with SSL capable.
I attached 3 programs in the following. The first one is a DOS batch program to create the keystore files and start the java program.
The second one is a DOS batch program to generate random characters so that I can create passwords.
The third program is a the java program to serve https requrests and throw back an "index.html" file to the requester.
To make this tiny https server more useful, I need client authentication.
That means I do not want every body visit this site. I only permit those
permitted to visit this site. I will email certificate to those who are
allowed to visit this site.
So I need to setNeedClientAuth to be true:
listen_socket.setNeedClientAuth(true);
What else I need to be done in order to make those browsers to work with my https server?
On the browser side, I can follow Tomcat and Apache web server to make certificate file to be imported into the browsers. But on the Java program side, I really do not know how to do it in order for the browsers to communicate with my Java program.
This is my program to create the keystore files.
rem @echo off
if exist server.keystore goto there
call ran.bat
set pass=%string%
call ran.bat
set pass=%pass%%string%
set password=%pass%%1%RANDOM%%2%RANDOM%
call ran.bat
set CN=%string%%random%
call ran.bat
set OU=%string%%random%
call ran.bat
set O=%string%%random%
call ran.bat
set L=%string%%random%
call ran.bat
set S=%string%%random%
keytool -genkey -v -alias server -keyalg RSA -keystore server.keystore
-keypass %password% -storepass %password% -dname "CN=%CN%%OU%, OU=%OU%,
O=%O%, L=%L%, S=%S%, C=US"
keytool -genkey -v -alias browser -keyalg RSA -keystore browser.keystore
-keypass %password% -storepass %password% -dname "CN=%OU%%CN%, OU=%OU%,
O=%O%, L=%L%, S=%S%, C=US"
keytool -export -rfc -keystore server.keystore -keypass %password% -storepass
%password% -alias server -file server.public-key
keytool -export -rfc -keystore browser.keystore -keypass %password% -storepass
%password% -alias browser -file browser.public-key
keytool -import -alias browser -keystore server.keystore -keypass %password%
-storepass %password% -file browser.public-key -noprompt
keytool -import -alias server -keystore browser.keystore -keypass %password%
-storepass %password% -file server.public-key -noprompt
:there
java -jar -Djavax.net.ssl.keyStore=server.keystore -Djavax.net.ssl.keyStorePassword=%
password% httpServer.jar httpServer$httpd 443
echo on
This is my ran.bat file to generate random characters.
@echo off
set string=
set ch=
:loop
set string=%string%%ch%
set ran=%ranDOM%
set ch=0
if %ran% GTR 528 set ch=1
if %ran% GTR 1056 set ch=2
if %ran% GTR 1584 set ch=3
if %ran% GTR 2112 set ch=4
if %ran% GTR 2640 set ch=5
if %ran% GTR 3168 set ch=6
if %ran% GTR 3696 set ch=7
if %ran% GTR 4224 set ch=8
if %ran% GTR 4752 set ch=9
if %ran% GTR 5280 set ch=A
if %ran% GTR 5808 set ch=B
if %ran% GTR 6336 set ch=C
if %ran% GTR 6864 set ch=D
if %ran% GTR 7392 set ch=E
if %ran% GTR 7920 set ch=F
if %ran% GTR 8448 set ch=G
if %ran% GTR 8976 set ch=H
if %ran% GTR 9504 set ch=I
if %ran% GTR 10032 set ch=J
if %ran% GTR 10560 set ch=K
if %ran% GTR 11088 set ch=L
if %ran% GTR 11616 set ch=M
if %ran% GTR 12144 set ch=N
if %ran% GTR 12672 set ch=O
if %ran% GTR 13200 set ch=P
if %ran% GTR 13728 set ch=Q
if %ran% GTR 14256 set ch=R
if %ran% GTR 14784 set ch=S
if %ran% GTR 15312 set ch=T
if %ran% GTR 15840 set ch=U
if %ran% GTR 16368 set ch=V
if %ran% GTR 16896 set ch=W
if %ran% GTR 17424 set ch=X
if %ran% GTR 17952 set ch=Y
if %ran% GTR 18480 set ch=Z
if %ran% GTR 19008 set ch=a
if %ran% GTR 19536 set ch=b
if %ran% GTR 20064 set ch=c
if %ran% GTR 20592 set ch=d
if %ran% GTR 21120 set ch=e
if %ran% GTR 21648 set ch=f
if %ran% GTR 22176 set ch=g
if %ran% GTR 22704 set ch=h
if %ran% GTR 23232 set ch=i
if %ran% GTR 23760 set ch=j
if %ran% GTR 24288 set ch=k
if %ran% GTR 24816 set ch=l
if %ran% GTR 25344 set ch=m
if %ran% GTR 25872 set ch=n
if %ran% GTR 26400 set ch=o
if %ran% GTR 26928 set ch=p
if %ran% GTR 27456 set ch=q
if %ran% GTR 27984 set ch=r
if %ran% GTR 28512 set ch=s
if %ran% GTR 29040 set ch=t
if %ran% GTR 29568 set ch=u
if %ran% GTR 30096 set ch=v
if %ran% GTR 30624 set ch=w
if %ran% GTR 31152 set ch=x
if %ran% GTR 31680 set ch=y
if %ran% GTR 32208 set ch=z
if %ran% GTR 16000 goto end
goto loop
:end
This is my Java program. It is a SSL web server!
/*usage: java httpServer httpServer$httpd 443 */
import javax.net.ssl.*;
import java.security.*;
import javax.net.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class httpServer {
public static void main(String[] args) {
httpServer s = new httpServer(System.out, 300);
int port = 443;
int i = 0;
String serviceName = args[i++];
try {
Class serviceClass = Class.forName(serviceName);
Service service = (Service)serviceClass.newInstance();
s.addService(service, port);
} catch (Exception e) {
e.printStackTrace();
}
}
ConnectionManager connectionManager;
Hashtable<Integer,Listener> services;
ThreadGroup threadGroup;
PrintWriter logStream;
public httpServer(OutputStream logStream, int maxConnections) {
setLogStream(logStream);
log("Starting httpServer");
threadGroup = new ThreadGroup("httpServer");
connectionManager = new ConnectionManager(threadGroup, maxConnections);
connectionManager.start();
services = new Hashtable<Integer,Listener>();
}
public void setLogStream(OutputStream out) {
if (out != null) logStream = new PrintWriter(new OutputStreamWriter(out))
;
else logStream = null;
}
protected synchronized void log(String s) {
if (logStream != null) {
logStream.println("[" + new Date() + "] " + s);
logStream.flush();
}
}
protected void log(Object o) { log(o.toString()); }
public void addService(Service service, int port) throws IOException {
Integer key = new Integer(port);
if (services.get(key) != null)
throw new IllegalArgumentException("Port " + port + " already in use.")
;
Listener listener = new Listener(threadGroup, port, service);
services.put(key, listener);
log("Starting service " + service.getClass().getName() + " on port "
+ port);
listener.start();
}
public class Listener extends Thread {
public ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault(
);
ServerSocket listen_socket;
int port;
Service service;
boolean stop = false;
public Listener(ThreadGroup group, int port, Service service)
throws IOException {
super(group, "Listener:" + port);
listen_socket = serverSocketFactory.createServerSocket(port);
listen_socket.setSoTimeout(600000);
this.port = port;
this.service = service;
}
public void run() {
while(!stop) {
try {
Socket client = listen_socket.accept();
connectionManager.addConnection(client, service);
}
catch (InterruptedIOException e) {}
catch (IOException e) {log(e);}
}
}
}
public class ConnectionManager extends Thread {
int maxConnections;
Vector<Connection> connections;
public ConnectionManager(ThreadGroup group, int maxConnections) {
super(group, "ConnectionManager");
this.setDaemon(true);
this.maxConnections = maxConnections;
connections = new Vector<Connection>(maxConnections);
log("Starting connection manager. Max connections: " + maxConnections)
;
}
synchronized void addConnection(Socket s, Service service) {
if (connections.size() >= maxConnections) {
try {
PrintWriter out = new PrintWriter(s.getOutputStream());
out.println("Connection refused; " +
"httpServer has reached maximum number of clients.");
out.flush();
s.close();
log("Connection refused to " + s.getInetAddress().getHostAddress()
+
":" + s.getPort() + ": max connections reached.");
} catch (IOException e) {log(e);}
}
else {
Connection c = new Connection(s, service);
connections.addElement(c);
log("Connected to " + s.getInetAddress().getHostAddress() +":" +
s.getPort() + " on port " + s.getLocalPort() );
c.start();
}
}
public synchronized void endConnection() { this.notify(); }
public synchronized void setMaxConnections(int max) { maxConnections=max;
}
public void run() {
while(true) {
for(int i = 0; i < connections.size(); i++) {
Connection c = (Connection)connections.elementAt(i);
if (!c.isAlive()) {
connections.removeElementAt(i);
}
}
try { synchronized(this) { this.wait(); } }
catch(InterruptedException e) {}
}
}
}
public class Connection extends Thread {
Socket client;
Service service;
public Connection(Socket client, Service service) {
super("httpServer.Connection:" + client.getInetAddress().getHostAddress(
) +
":" + client.getPort());
this.client = client;
this.service = service;
}
public void run() {
try {
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
service.serve(in, out);
}
catch (IOException e) {log(e);}
finally { connectionManager.endConnection(); }
}
}
public interface Service {
public void serve(InputStream in, OutputStream out) throws IOException;
}
public static class httpd implements Service {
final static String CRLF = "\r\n";
public void serve(InputStream i, OutputStream o) throws IOException
{
FileReader f = null;
String line = null;
BufferedReader buff = null;
InputStream web = null;
boolean fileExists = true ;
try{
URL url = new URL("http://www.ddint.org");
web=url.openStream();
}
catch ( Exception e )
{
fileExists = false ;
System.out.println(e);
}
Random random = new Random();
int r = random.nextInt(64);
r+=1024;
String statusLine = "HTTP/1.1 200 OK" + CRLF ;
String serverLine = "Server: Apache/2.2";
String hconnection = "Connection = Close" + CRLF;
String pragma = "Pragma = no-cache" + CRLF;
String contentTypeLine = "Content-type:text/html " + CRLF ;
String contentLengthLine = "Content-Length: " + r + CRLF;
o.write(statusLine.getBytes());
o.write(hconnection.getBytes());
o.write(pragma.getBytes());
o.write(serverLine.getBytes());
o.write(contentTypeLine.getBytes());
o.write(contentLengthLine.getBytes());
o.write(CRLF.getBytes());
try {
if (fileExists)
{
sendBytes(web, o) ;
web.close();
o.close();
i.close();
}
} catch (Exception e){System.out.println(e.toString());}
}
private static void sendBytes(InputStream is, OutputStream os) throws
Exception {
byte[] buffer = new byte[1024] ;
int bytes = 0 ;
while ((bytes = is.read(buffer)) != -1 )
{
os.write(buffer, 0, bytes);
}
}
}
}