Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Building on Mike's response above I have the following solution, because while I much appreciate the general idea (that's why I've copied it ;-) , I see a few problems with it:</p> <ul> <li>Mike's solution will throw a NullPointerException if the JDK requests the authentication via one of the two static request methods in java.net.Authenticator that do not pass the URL (then getRequestingURL() will return null).</li> <li>It requires you to pass in an external regex pattern that deconstructs the URL. This is (very) easy to get wrong, and the URL class in the JDK implements this parsing, so I prefer to use that.</li> <li>It requires that some external class builds the map of PasswordAuthentication objects, and then sets it. It does not implement a registration mechanism that other components in your system can use. I've also turned it into a singleton.</li> <li>More of a style thing: I don't recommend duplicating class names (Authenticator), so I've renamed it DefaultAuthenticator.</li> </ul> <p>Below solution I think solves these issues.</p> <pre><code> /** * Authenticator which keeps credentials to be passed to the requestor based on authority of the requesting URL. The * authority is &lt;pre&gt;user:password@host:port&lt;/pre&gt;, where all parts are optional except the host. * &lt;p&gt; * If the configured credentials are not found, the Authenticator will use the credentials embedded in the URL, if * present. Embedded credentials are in the form of &lt;pre&gt;user:password@host:port&lt;/pre&gt; * * @author Michael Fortin 2011-09-23 */ public final class DefaultAuthenticator extends Authenticator { private static final Logger LOG = Logger.getLogger(DefaultAuthenticator.class.getName()); private static DefaultAuthenticator instance; private Map&lt;String, PasswordAuthentication&gt; authInfo = new HashMap&lt;String, PasswordAuthentication&gt;(); private DefaultAuthenticator() { } public static synchronized DefaultAuthenticator getInstance() { if (instance == null) { instance = new DefaultAuthenticator(); Authenticator.setDefault(instance); } return instance; } // unit testing static void reset() { instance = null; Authenticator.setDefault(null); } @Override protected PasswordAuthentication getPasswordAuthentication() { String requestorInfo = getRequestorInfo(); LOG.info(getRequestorType() + " at \"" + getRequestingPrompt() + "\" is requesting " + getRequestingScheme() + " password authentication for \"" + requestorInfo + "\""); if (authInfo.containsKey(requestorInfo)) { return authInfo.get(requestorInfo); } else { PasswordAuthentication pa = getEmbeddedCredentials(getRequestingURL()); if (pa == null) { LOG.warning("No authentication information"); } return pa; } } /** * Register the authentication information for a given URL. * * @param url - the URL that will request authorization * @param auth - the {@link PasswordAuthentication} for this URL providing the credentials */ public void register(URL url, PasswordAuthentication auth) { String requestorInfo = getRequestorInfo(url.getHost(), url.getPort()); authInfo.put(requestorInfo, auth); } /** * Get the requestor info based on info provided. * * @param host - hostname of requestor * @param port - TCP/IP port * @return requestor info string */ private String getRequestorInfo(String host, int port) { String fullHostname; try { InetAddress addr = InetAddress.getByName(host); fullHostname = addr.getCanonicalHostName(); } catch (UnknownHostException e) { fullHostname = host; } if (port == -1) { return fullHostname; } else { return fullHostname + ":" + port; } } /** * Get the requestor info for the request currently being processed by this Authenticator. * * @return requestor info string for current request */ private String getRequestorInfo() { String host; InetAddress addr = getRequestingSite(); if (addr == null) { host = getRequestingHost(); } else { host = addr.getCanonicalHostName(); } return getRequestorInfo(host, getRequestingPort()); } /** * Get the credentials from the requesting URL. * * @param url - URL to get the credentials from (can be null, method will return null) * @return PasswordAuthentication with credentials from URL or null if URL contains no credentials or if URL is * null itself */ PasswordAuthentication getEmbeddedCredentials(URL url) { if (url == null) { return null; } String userInfo = url.getUserInfo(); int colon = userInfo == null ? -1 : userInfo.indexOf(":"); if (colon == -1) { return null; } else { String userName = userInfo.substring(0, colon); String pass = userInfo.substring(colon + 1); return new PasswordAuthentication(userName, pass.toCharArray()); } } } </code></pre> <p>While I'm at it, let me give you my unit tests (JUnit 4).</p> <pre><code> /** * @author Paul Balm - May 10 2012 */ public class DefaultAuthenticatorTest { private static final Logger LOG = Logger.getLogger(DefaultAuthenticatorTest.class.getName()); @Before public void setUp() throws Exception { DefaultAuthenticator.reset(); DefaultAuthenticator.getInstance(); } @After public void tearDown() { DefaultAuthenticator.reset(); } @Test public void testRequestAuthenticationFromURL() throws MalformedURLException, UnknownHostException { Map&lt;String, String[]&gt; urls = generateURLs(); for (String urlStr : urls.keySet()) { String[] userInfo = urls.get(urlStr); LOG.info("Testing: " + urlStr); URL url = new URL(urlStr); request(userInfo[1], userInfo[2], url, true); } } @Test public void testRequestAuthenticationRegistered() throws UnknownHostException, MalformedURLException { Map&lt;String, String[]&gt; urls = generateURLs(); for (String urlStr : urls.keySet()) { String[] userInfo = urls.get(urlStr); LOG.info("Testing: " + urlStr); URL url = new URL(urlStr); DefaultAuthenticator.reset(); DefaultAuthenticator auth = DefaultAuthenticator.getInstance(); String userName = userInfo[1]; String password = userInfo[2]; if (password != null) { // You can't register a null password auth.register(url, new PasswordAuthentication(userName, password.toCharArray())); } request(userName, password, url, false); } } /** * Generate a bunch of URLs mapped to String array. The String array has the following elements: * - user info part of URL, * - expected user, * - expected password * * Note that the keys of the maps must be strings and not URL objects, because of the way URL.equals is * implemented. This method does not consider the credentials. * * @throws MalformedURLException */ Map&lt;String, String[]&gt; generateURLs() { String[] hosts = new String[]{ "127.0.0.1", "localhost.localdomain"}; List&lt;String[]&gt; userData = new ArrayList&lt;String[]&gt;(); // normal cases userData.add(new String[] { "user:pass@", "user", "pass" }); // results in: http://user:pass@[host] userData.add(new String[] { "", null, null }); // unexpected cases userData.add(new String[] { "@", null, null }); userData.add(new String[] { ":@", "", "" }); userData.add(new String[] { "user:@", "user", "" }); userData.add(new String[] { ":pass@", "", "pass" }); Map&lt;String, String[]&gt; urls = new HashMap&lt;String, String[]&gt;(); for (String[] userInfo : userData) { for (String host : hosts) { String s = "http://" + userInfo[0] + host; urls.put(s, userInfo); } } LOG.info("" + urls.size() + " URLs prepared"); return urls; } private void request(String expectedUser, String expectedPass, URL url, boolean inURL) throws UnknownHostException { String host = url.getHost(); InetAddress addr = InetAddress.getAllByName(host)[0]; int port = url.getPort(); String protocol = url.getProtocol(); String prompt = ""; // prompt for the user when asking for the credentials String scheme = "basic"; // or digest RequestorType reqType = RequestorType.SERVER; PasswordAuthentication credentials = Authenticator.requestPasswordAuthentication(addr, port, protocol, prompt, scheme); // If the credentials are in the URL, you can't find them using this method because we're not passing the URL checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme); // If the credentials are in the URL, you can't find them using this method because we're not passing the URL checkCredentials(url, inURL ? null : expectedUser, inURL ? null : expectedPass, credentials); credentials = Authenticator.requestPasswordAuthentication(host, addr, port, protocol, prompt, scheme, url, reqType); checkCredentials(url, expectedUser, expectedPass, credentials); } private void checkCredentials(URL url, String expectedUser, String expectedPass, PasswordAuthentication credentials) { if (expectedUser == null) { Assert.assertNull(url.toString(), credentials); } else { Assert.assertNotNull(url.toString(), credentials); Assert.assertEquals(url.toString(), expectedUser, credentials.getUserName()); if (expectedPass == null) { Assert.assertNull(url.toString(), credentials.getPassword()); } else { Assert.assertArrayEquals(url.toString(), expectedPass.toCharArray(), credentials.getPassword()); } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload