--- /dev/null
+// AuthFilter.java\r
+// $Id: AuthFilter.java,v 1.1 2010/06/15 12:27:25 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.www.protocol.http.auth;\r
+\r
+import java.awt.Button;\r
+import java.awt.Component;\r
+import java.awt.Container;\r
+import java.awt.Event;\r
+import java.awt.Frame;\r
+import java.awt.GridBagConstraints;\r
+import java.awt.GridBagLayout;\r
+import java.awt.Label;\r
+import java.awt.Panel;\r
+import java.awt.TextComponent;\r
+import java.awt.TextField;\r
+import java.awt.Window;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import java.util.Hashtable;\r
+\r
+import org.w3c.tools.codec.Base64Encoder;\r
+\r
+import org.w3c.www.protocol.http.HttpException;\r
+import org.w3c.www.protocol.http.HttpManager;\r
+import org.w3c.www.protocol.http.PropRequestFilter;\r
+import org.w3c.www.protocol.http.Reply;\r
+import org.w3c.www.protocol.http.Request;\r
+\r
+import org.w3c.www.http.HTTP;\r
+import org.w3c.www.http.HttpChallenge;\r
+import org.w3c.www.http.HttpCredential;\r
+import org.w3c.www.http.HttpFactory;\r
+import org.w3c.www.http.HttpReplyMessage;\r
+import org.w3c.www.http.HttpRequestMessage;\r
+\r
+class UserField extends TextField {\r
+ PasswordPrompter prompter = null;\r
+\r
+ public boolean keyDown(Event evt, int key) {\r
+ if ( key == '\t' ) {\r
+ prompter.focusPassword();\r
+ return true;\r
+ }\r
+ return super.keyDown(evt, key);\r
+ }\r
+\r
+ UserField(PasswordPrompter prompter, String txt, int len) {\r
+ super(txt, len);\r
+ this.prompter = prompter;\r
+ }\r
+\r
+}\r
+\r
+class PasswordField extends TextField {\r
+ PasswordPrompter prompter = null;\r
+\r
+ public boolean keyDown(Event evt, int key) {\r
+ if ((key == '\n') || (key == '\r')) {\r
+ prompter.done(PasswordPrompter.EVT_OK);\r
+ return true;\r
+ }\r
+ return super.keyDown(evt, key);\r
+ }\r
+\r
+ PasswordField(PasswordPrompter prompter, String txt, int len) {\r
+ super(txt, len);\r
+ setEchoCharacter('*');\r
+ this.prompter = prompter;\r
+ }\r
+}\r
+\r
+class PasswordPrompter extends Panel {\r
+ TextField txtUser = null;\r
+ TextField txtPassword = null;\r
+ Button butOk = null;\r
+ Button butCancel = null;\r
+\r
+ String user = null;\r
+ String password = null;\r
+\r
+ static final int EVT_OK = 1;\r
+ static final int EVT_CANCEL = 2;\r
+ int evt = -1;\r
+\r
+ protected synchronized boolean waitForCompletion() {\r
+ while ( true ) {\r
+ // Wait for next event:\r
+ while ( evt < 0 ) {\r
+ try {\r
+ wait();\r
+ } catch (InterruptedException ex) {\r
+ }\r
+ }\r
+ // Handle the event:\r
+ switch(evt) {\r
+ case EVT_OK:\r
+ return true;\r
+ case EVT_CANCEL:\r
+ return false;\r
+ }\r
+ }\r
+ }\r
+\r
+ protected synchronized void done(int evt) {\r
+ this.evt = evt;\r
+ notifyAll();\r
+ }\r
+\r
+ protected void focusPassword() {\r
+ txtPassword.requestFocus();\r
+ }\r
+\r
+ public boolean action(Event evt, Object what) {\r
+ int e = -1;\r
+ if ( evt.target == butOk ) {\r
+ e = EVT_OK;\r
+ } else if ( evt.target == butCancel ) {\r
+ e = EVT_CANCEL;\r
+ } else {\r
+ return super.action(evt, what);\r
+ }\r
+ // We are done with this dialog:\r
+ done(e);\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Get the entered user name.\r
+ * @return The user name as a String.\r
+ */\r
+\r
+ public String getUser() {\r
+ return user;\r
+ }\r
+\r
+ /**\r
+ * Get the entered password.\r
+ * @return The password as a String.\r
+ */\r
+\r
+ public String getPassword() {\r
+ return password;\r
+ }\r
+\r
+ /**\r
+ * Run the dialog, as if modal.\r
+ * @return A boolean <strong>false</strong> if interaction was canceled,\r
+ * <strong>true</strong> otherwise.\r
+ */\r
+\r
+ public boolean prompt() {\r
+ Frame toplevel = new Frame("Authentication Required");\r
+ toplevel.add("Center", this);\r
+ toplevel.pack();\r
+ toplevel.show();\r
+ // Set focus to the user name:\r
+ txtUser.requestFocus();\r
+ // Wait for completion, pack up the result, and delete GUI:\r
+ boolean result = waitForCompletion();\r
+ this.user = txtUser.getText();\r
+ this.password = txtPassword.getText();\r
+ toplevel.hide();\r
+ toplevel.dispose();\r
+ return result;\r
+ }\r
+\r
+ PasswordPrompter(Request request, Reply reply) {\r
+ // Setup the layout:\r
+ super();\r
+ GridBagLayout gb = new GridBagLayout();\r
+ setLayout(gb);\r
+ // Create the title label:\r
+ HttpChallenge challenge = (request.hasProxy()\r
+ ? reply.getProxyAuthenticate()\r
+ : reply.getWWWAuthenticate());\r
+ Label label = new Label(challenge.getScheme()\r
+ + " authentication for "\r
+ + challenge.getAuthParameter("realm"));\r
+ GridBagConstraints row = new GridBagConstraints();\r
+ row.gridwidth = GridBagConstraints.REMAINDER;\r
+ row.anchor = GridBagConstraints.WEST;\r
+ gb.setConstraints(label, row);\r
+ add(label);\r
+ // Create the entries:\r
+ GridBagConstraints ct = new GridBagConstraints();\r
+ ct.gridx = GridBagConstraints.RELATIVE ;\r
+ ct.anchor = GridBagConstraints.EAST ;\r
+ ct.weighty = 1.0 ;\r
+ GridBagConstraints cv = new GridBagConstraints() ;\r
+ cv.gridx = GridBagConstraints.RELATIVE ;\r
+ cv.gridwidth = GridBagConstraints.REMAINDER ;\r
+ cv.fill = GridBagConstraints.HORIZONTAL ;\r
+ cv.anchor = GridBagConstraints.WEST ;\r
+ cv.weightx = 1.0 ;\r
+ cv.weighty = 1.0 ;\r
+ // Create user entry:\r
+ label = new Label("User:", Label.LEFT);\r
+ gb.setConstraints(label, ct);\r
+ add(label);\r
+ txtUser = new UserField(this, "", 32);\r
+ gb.setConstraints(txtUser, cv);\r
+ add(txtUser);\r
+ // Create password entry:\r
+ label = new Label("Password:", Label.LEFT);\r
+ gb.setConstraints(label, ct);\r
+ add(label);\r
+ txtPassword = new PasswordField(this, "", 32);\r
+ gb.setConstraints(txtPassword, cv);\r
+ add(txtPassword);\r
+ // Add the row of buttons:\r
+ butOk = new Button("Ok");\r
+ row.anchor = GridBagConstraints.EAST;\r
+ row.weightx = 1.0;\r
+ row.gridwidth = GridBagConstraints.RELATIVE;\r
+ gb.setConstraints(butOk, row);\r
+ add(butOk);\r
+ butCancel = new Button("Cancel");\r
+ row.anchor = GridBagConstraints.WEST;\r
+ row.gridwidth = GridBagConstraints.REMAINDER;\r
+ gb.setConstraints(butCancel, row);\r
+ add(butCancel);\r
+ }\r
+}\r
+\r
+class CachedRealm {\r
+ public String realm = null;\r
+ public HttpCredential credentials = null;\r
+\r
+ CachedRealm(String realm, HttpCredential credentials) {\r
+ this.realm = realm;\r
+ this.credentials = credentials;\r
+ }\r
+}\r
+\r
+public class AuthFilter implements PropRequestFilter {\r
+ /**\r
+ * The per-server realms we know about.\r
+ */\r
+ protected static Hashtable realms = new Hashtable(13);\r
+ /**\r
+ * the HttpManager that installed us.\r
+ */\r
+ protected HttpManager manager = null;\r
+\r
+ protected static void registerRealm(Request request\r
+ , Reply reply\r
+ , HttpCredential credentials) {\r
+ // Do we already know about that realm ?\r
+ if ( lookupRealm(request, reply) != null )\r
+ return;\r
+ // Register the realm:\r
+ String srvkey = request.getManager().getServerKey(request);\r
+ String realm = ((request.hasProxy()\r
+ ? reply.getProxyAuthenticate()\r
+ : reply.getWWWAuthenticate())\r
+ .getAuthParameter("realm"));\r
+ CachedRealm cache[] = (CachedRealm[]) realms.get(srvkey);\r
+ if ( cache == null ) {\r
+ cache = new CachedRealm[1];\r
+ cache[0] = new CachedRealm(realm, credentials);\r
+ } else {\r
+ CachedRealm nc[] = new CachedRealm[cache.length+1];\r
+ System.arraycopy(cache, 0, nc, 0, cache.length);\r
+ nc[cache.length] = new CachedRealm(realm, credentials);\r
+ cache = nc;\r
+ }\r
+ realms.put(srvkey, cache);\r
+ }\r
+\r
+ protected static HttpCredential lookupRealm(Request request\r
+ , Reply reply) {\r
+ // Lookup known realms on target server:\r
+ String srvkey = request.getManager().getServerKey(request);\r
+ CachedRealm cache[] = (CachedRealm[]) realms.get(srvkey);\r
+ if ( cache == null )\r
+ return null;\r
+ // Found something, check:\r
+ HttpChallenge challenge = (request.hasProxy()\r
+ ? reply.getProxyAuthenticate()\r
+ : reply.getWWWAuthenticate());\r
+ String realm = challenge.getAuthParameter("realm");\r
+ for (int i = 0 ; i < cache.length ; i++) {\r
+ if ( cache[i].realm.equalsIgnoreCase(realm) )\r
+ return cache[i].credentials;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * PropRequestFilter implementation - Initialize the filter.\r
+ * Time to register ourself to the HttpManager.\r
+ * @param manager The HTTP manager that is initializing ourself.\r
+ */\r
+\r
+ public void initialize(HttpManager manager) {\r
+ this.manager = manager;\r
+ // We install ourself as a global filter, we are cool !\r
+ manager.setFilter(this);\r
+ manager.setAllowUserInteraction(true);\r
+ }\r
+\r
+ /**\r
+ * This filter doesn't handle exceptions.\r
+ * @param request The request that triggered the exception.\r
+ * @param ex The triggered exception.\r
+ * @return Always <strong>false</strong>.\r
+ */\r
+\r
+ public boolean exceptionFilter(Request request, HttpException ex) {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * On the way out, we let the request fly through.\r
+ * @param request The request about to be emitted.\r
+ */\r
+\r
+ public Reply ingoingFilter(Request request) {\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Catch any authentication requirement, and fullfill it with user's help.\r
+ * This method trap all request for authentication, and pops up a\r
+ * dialog prompting for the user's name and password.\r
+ * <p>It then retries the request with the provided authentication\r
+ * informations.\r
+ * @param request The request that requires authentication.\r
+ * @param reply The original reply.\r
+ * @exception HttpException If some HTTP error occurs.\r
+ */\r
+\r
+ public Reply outgoingFilter(Request request, Reply reply) \r
+ throws HttpException\r
+ {\r
+ // Is this really for us to catch ?\r
+ if ((reply.getStatus() != HTTP.UNAUTHORIZED)\r
+ && (reply.getStatus() != HTTP.PROXY_AUTH_REQUIRED))\r
+ return null;\r
+ // Do we know about this realm ?\r
+ HttpCredential credentials = null;\r
+ if ((credentials = lookupRealm(request, reply)) == null) {\r
+ // If we can't interact, we can't help:\r
+ if ( ! request.getAllowUserInteraction() ) \r
+ return null;\r
+ // Great ! Now we can indeed help:\r
+ PasswordPrompter prompter = new PasswordPrompter(request, reply);\r
+ if ( ! prompter.prompt() )\r
+ return null;\r
+ String user = prompter.getUser();\r
+ String password = prompter.getPassword();\r
+ // Compute credentials:\r
+ credentials = HttpFactory.makeCredential("Basic");\r
+ Base64Encoder encoder = new Base64Encoder(user+":"+password);\r
+ credentials.setAuthParameter("cookie", encoder.processString());\r
+ }\r
+ // Now restart the request we the right auth infos:\r
+ if ( request.hasProxy() )\r
+ request.setProxyAuthorization(credentials);\r
+ else\r
+ request.setAuthorization(credentials);\r
+ Reply retry = request.getManager().runRequest(request);\r
+ if ( retry.getStatus() / 100 != 4 ) {\r
+ // We did succeed, register server/realm infos:\r
+ registerRealm(request, reply, credentials);\r
+ // Create the local auth filter:\r
+ if ( request.hasProxy() ) {\r
+ LocalAuthFilter.installProxyAuth(manager, credentials);\r
+ } else {\r
+ LocalAuthFilter.installLocalAuth(manager\r
+ , request.getURL()\r
+ , credentials);\r
+ }\r
+ // Swallow input stream of original reply:\r
+ try {\r
+ InputStream in = reply.getInputStream();\r
+ if ( in != null )\r
+ in.close();\r
+ } catch (IOException ex) {\r
+ }\r
+ // Return the right reply:\r
+ return retry;\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * We don't maintain cached informations.\r
+ */\r
+\r
+ public void sync() {\r
+ }\r
+\r
+}\r