Loading cadcTomcat/build.xml +1 −1 Original line number Original line Diff line number Diff line Loading @@ -136,7 +136,7 @@ </classpath> </classpath> <test name="ca.nrc.cadc.tomcat.CadcBasicAuthenticatorTest"/> <test name="ca.nrc.cadc.tomcat.CadcBasicAuthenticatorTest"/> <test name="ca.nrc.cadc.tomcat.RealmRegistryClientTest"/> <test name="ca.nrc.cadc.tomcat.AuthenticationLookupTest"/> <formatter type="plain" usefile="false"/> <formatter type="plain" usefile="false"/> </junit> </junit> </target> </target> Loading cadcTomcat/src/ca/nrc/cadc/tomcat/RealmRegistryClient.java→cadcTomcat/src/ca/nrc/cadc/tomcat/AuthenticationLookup.java +26 −147 Original line number Original line Diff line number Diff line Loading @@ -69,21 +69,13 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URL; import java.net.UnknownHostException; import java.net.UnknownHostException; import java.util.List; import org.apache.log4j.Logger; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.ListIterator; /** /** * A very simple caching IVOA Registry client. All the lookups done by this client use a properties * A very simple caching IVOA Registry client. All the lookups done by this client use a properties Loading @@ -102,52 +94,26 @@ import java.util.ListIterator; * <pre> * <pre> * ca.nrc.cadc.reg.client.RegistryClient.host=www.example.com * ca.nrc.cadc.reg.client.RegistryClient.host=www.example.com * </pre> * </pre> * * <p> * This class is a forked and trimmed version of ca.nrc.cadc.reg.client.RegistryClient. It was forked * This class is a forked and trimmed version of ca.nrc.cadc.reg.client.RegistryClient. It was forked * to allow the realm implementation to be deployed without library dependencies. * to allow the realm implementation to be deployed without library dependencies. * * * @author pdowler * @author pdowler */ */ public class RealmRegistryClient public class AuthenticationLookup { { private static Logger log = Logger.getLogger(RealmRegistryClient.class); private static Logger log = Logger.getLogger(AuthenticationLookup.class); private static final String CACHE_FILENAME = "RegistryClient.properties"; private static final String LOCAL_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.local"; private static final String LOCAL_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.local"; private static final String HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.host"; private static final String HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.host"; private static final String SHORT_HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.shortHostname"; private static final String SHORT_HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.shortHostname"; private URL url; private RealmMultiValuedProperties mvp; private String hostname; private String hostname; private String shortHostname; private String shortHostname; /** * Constructor. Uses a properties file called RegistryClient.properties found in the classpath. */ public RealmRegistryClient() { try { File conf = new File(System.getProperty("user.home") + "/config", CACHE_FILENAME); URL furl; if (conf.exists()) furl = new URL("file://" + conf.getAbsolutePath()); else furl = RealmRegistryClient.class.getResource("/"+CACHE_FILENAME); init(furl, false); private void init() } catch(Exception ex) { throw new RuntimeException("failed to find URL to " + CACHE_FILENAME, ex); } } private void init(URL url, boolean unused) { { this.url = url; try try { { String localP = System.getProperty(LOCAL_PROPERTY); String localP = System.getProperty(LOCAL_PROPERTY); Loading @@ -159,8 +125,10 @@ public class RealmRegistryClient log.debug("shortHost: " + shortHostP); log.debug("shortHost: " + shortHostP); if ("true".equals(localP)) if ("true".equals(localP)) { { log.debug(LOCAL_PROPERTY + " is set, assuming localhost runs the service"); log.debug(LOCAL_PROPERTY this.hostname = InetAddress.getLocalHost().getCanonicalHostName(); + " is set, assuming localhost runs the service"); this.hostname = InetAddress.getLocalHost() .getCanonicalHostName(); } } if (shortHostP != null) if (shortHostP != null) Loading @@ -176,66 +144,36 @@ public class RealmRegistryClient { { hostP = hostP.trim(); hostP = hostP.trim(); if (hostP.length() > 0) if (hostP.length() > 0) { this.hostname = hostP; this.hostname = hostP; } } } } } catch (UnknownHostException ex) catch (UnknownHostException ex) { { log.warn("failed to find localhost name via name resolution (" + ex.toString() + "): using localhost"); log.warn("failed to find localhost name via name resolution (" + ex.toString() + "): using localhost"); this.hostname = "localhost"; this.hostname = "localhost"; } } } } public URL getServiceURL(URI serviceID, String protocol, String path) public URL configureAuthenticationServiceURL(URL serviceURL) throws MalformedURLException throws MalformedURLException { { init(); init(); log.debug("getServiceURL: " + serviceID + "," + protocol + "," + path); log.debug("configureAuthenticationServiceURL: " + serviceURL + "," + serviceURL.getProtocol() + "," + serviceURL.getPath()); //List<URL> urls = lookup.get(serviceID); List<String> strs = mvp.getProperty(serviceID.toString()); if (strs == null || strs.isEmpty() ) { return null; // no matching serviceURI } List<Service> srvs = new ArrayList<Service>(strs.size()); for (String s : strs) { srvs.add(new Service(s)); } String testproto = protocol + "://"; ListIterator<Service> iter = srvs.listIterator(); while ( iter.hasNext() ) { Service srv = iter.next(); boolean noMatch = false; if (protocol != null && !srv.url.startsWith(testproto)) noMatch = true; // wrong protocol if (noMatch) { iter.remove(); log.debug("getServiceURL: constraints not matched: " + srv + " vs " + protocol); } else log.debug("getServiceURL: found match: " + srv + " vs " + protocol); } if (srvs.isEmpty()) return null; Service srv = srvs.get(0); // first match StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder(); if (hostname != null || shortHostname != null) if (hostname != null || shortHostname != null) { { URL ret = new URL(srv.url); sb.append(serviceURL.getProtocol()); sb.append(ret.getProtocol()); sb.append("://"); sb.append("://"); if (shortHostname != null) if (shortHostname != null) { { String hname = shortHostname; String hname = shortHostname; String fqhn = ret.getHost(); String fqhn = serviceURL.getHost(); int i = fqhn.indexOf('.'); int i = fqhn.indexOf('.'); if (i > 0) if (i > 0) { { Loading @@ -248,78 +186,19 @@ public class RealmRegistryClient { { sb.append(hostname); sb.append(hostname); } } int p = ret.getPort(); int p = serviceURL.getPort(); if (p > 0 && p != ret.getDefaultPort()) if (p > 0 && p != serviceURL.getDefaultPort()) { { sb.append(":"); sb.append(":"); sb.append(p); sb.append(p); } } sb.append(ret.getPath()); sb.append(serviceURL.getPath()); } } else else sb.append(srv.url); if (path != null) sb.append(path); return new URL(sb.toString()); } private class Service { String str; String url; public String toString() { return str; } Service(String s) { { this.str = s; sb.append(serviceURL); String[] parts = s.split(" "); this.url = parts[0]; } } } private void init() { if (mvp != null) return; InputStream istream = null; try { // find the cache resource from the url if (url == null) throw new RuntimeException("failed to find cache resource."); // read the properties log.debug("init: reading config from " + url); istream = url.openStream(); this.mvp = new RealmMultiValuedProperties(); mvp.load(istream); if (log.isDebugEnabled()) return new URL(sb.toString()); { for (String k : mvp.keySet()) { List<String> values = mvp.getProperty(k); for (String v : values) { log.debug(k + " = " + v); } } } } catch(IOException ex) { throw new RuntimeException("failed to load resource: " + CACHE_FILENAME, ex); } finally { if (istream != null) try { istream.close(); } catch(Throwable t) { log.warn("failed to close " + url, t); } } } } } } cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java +40 −25 Original line number Original line Diff line number Diff line Loading @@ -71,11 +71,9 @@ package ca.nrc.cadc.tomcat; import java.io.IOException; import java.io.IOException; import java.net.HttpURLConnection; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URL; import java.security.Principal; import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.List; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.realm.GenericPrincipal; Loading @@ -83,11 +81,12 @@ import org.apache.catalina.realm.RealmBase; import org.apache.log4j.Level; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.Logger; /** /** * Custom class for Tomcat realm authentication. * Custom class for Tomcat realm authentication. * * <p> * This class was written against the Apache Tomcat 7 (7.0.33.0) API * This class was written against the Apache Tomcat 7 (7.0.33.0) API * * <p> * Authentication checks are performed as REST calls to servers * Authentication checks are performed as REST calls to servers * implementing the cadcAccessControl-Server code. * implementing the cadcAccessControl-Server code. * * Loading @@ -97,7 +96,9 @@ public class CadcBasicAuthenticator extends RealmBase { { private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class); private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class); private static final String AC_URI = "ivo://ivoa.net/std/UMS#login-0.1"; private String loginURL; static static { { Loading @@ -105,6 +106,17 @@ public class CadcBasicAuthenticator extends RealmBase Logger.getLogger("ca.nrc.cadc.tomcat").setLevel(Level.INFO); Logger.getLogger("ca.nrc.cadc.tomcat").setLevel(Level.INFO); } } /** * Set the login URL for the current host. Used by the realm configuration. * * @param loginURL The String login URL. */ public void setLoginURL(final String loginURL) { this.loginURL = loginURL; } @Override @Override protected String getName() protected String getName() { { Loading Loading @@ -139,7 +151,7 @@ public class CadcBasicAuthenticator extends RealmBase if (valid) if (valid) { { // authentication ok, add public role // authentication ok, add public role List<String> roles = Arrays.asList("public"); List<String> roles = Collections.singletonList("public"); // Don't want to return the password here in the principal // Don't want to return the password here in the principal // in case it makes it into the servlet somehow // in case it makes it into the servlet somehow Loading @@ -151,7 +163,8 @@ public class CadcBasicAuthenticator extends RealmBase catch (Throwable t) catch (Throwable t) { { success = false; success = false; String message = "Could not do http basic authentication: " + t.getMessage(); String message = "Could not do http basic authentication: " + t.getMessage(); log.error(message, t); log.error(message, t); throw new IllegalStateException(message, t); throw new IllegalStateException(message, t); } } Loading @@ -159,28 +172,30 @@ public class CadcBasicAuthenticator extends RealmBase { { long duration = System.currentTimeMillis() - start; long duration = System.currentTimeMillis() - start; StringBuilder json = new StringBuilder(); // Converted from StringBuilder as it was unnecessary. json.append("{"); // jenkinsd 2016.08.09 json.append("\"method\":\"AUTH\","); String json = "{" + json.append("\"user\":\"" + username + "\","); "\"method\":\"AUTH\"," + json.append("\"success\":" + success + ","); "\"user\":\"" + username + "\"," + json.append("\"time\":" + duration); "\"success\":" + success + "," + json.append("}"); "\"time\":" + duration + "}"; log.info(json.toString()); log.info(json); } } } } boolean login(String username, String credentials) boolean login(String username, String credentials) throws URISyntaxException, IOException throws IOException { { RealmRegistryClient registryClient = new RealmRegistryClient(); AuthenticationLookup registryClient = new AuthenticationLookup(); URL loginURL = registryClient.getServiceURL( URL authServiceURL = new URI(AC_URI + "#login"), "http", ""); registryClient.configureAuthenticationServiceURL( new URL(loginURL)); String post = "username=" + username + "&password=" + credentials; String post = "username=" + username + "&password=" + credentials; HttpURLConnection conn = (HttpURLConnection) loginURL.openConnection(); HttpURLConnection conn = (HttpURLConnection) authServiceURL.openConnection(); conn.setRequestMethod("POST"); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoOutput(true); Loading @@ -199,7 +214,8 @@ public class CadcBasicAuthenticator extends RealmBase { { // not an unauthorized, so log the // not an unauthorized, so log the // possible server side error // possible server side error String errorMessage = "Error calling /ac/login, error code: " + responseCode; String errorMessage = "Error calling /ac/login, error code: " + responseCode; throw new IllegalStateException(errorMessage); throw new IllegalStateException(errorMessage); } } Loading @@ -211,5 +227,4 @@ public class CadcBasicAuthenticator extends RealmBase } } } } cadcTomcat/test/src/ca/nrc/cadc/tomcat/RealmRegistryClientTest.java→cadcTomcat/test/src/ca/nrc/cadc/tomcat/AuthenticationLookupTest.java +48 −100 Original line number Original line Diff line number Diff line Loading @@ -70,6 +70,7 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.net.InetAddress; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URI; import java.net.URI; import java.net.URL; import java.net.URL; Loading @@ -84,12 +85,12 @@ import org.junit.Test; /** /** * * @author pdowler * @author pdowler */ */ public class RealmRegistryClientTest public class AuthenticationLookupTest { { private static Logger log = Logger.getLogger(RealmRegistryClientTest.class); private static Logger log = Logger .getLogger(AuthenticationLookupTest.class); static static { { Loading Loading @@ -130,110 +131,47 @@ public class RealmRegistryClientTest { { } } static String DUMMY_URI = "ivo://example.com/srv"; static URL DUMMY_URL; static String DUMMY_URL = "http://www.example.com/current/path/to/my/service"; static String DUMMY_CERT_URL = "https://www.example.com/current/path/to/my/service"; static String DUMMY_PASSWORD_URL = "http://www.example.com/current/path/to/my/auth-service"; static String DUMMY_TOKEN_URL = DUMMY_URL; static String DUMMY_COOKIE_URL = DUMMY_URL; @Test static public void testNotFound() throws Exception { { try try { { RealmRegistryClient rc = new RealmRegistryClient(); DUMMY_URL = new URL( "http://www.example.com/current/path/to/my/service"); URL url = rc.getServiceURL(new URI("ivo://foo/bar"), null, null); Assert.assertNull(url); } } catch(Exception unexpected) catch (MalformedURLException e) { { log.error("unexpected exception", unexpected); // Will never happen. Assert.fail("unexpected exception: " + unexpected); } } } } @Test public void testFound() throws Exception { try { RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL(DUMMY_URL); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); Assert.assertEquals(expected, url); } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } } @Test @Test public void testFoundViaConfigFile() throws Exception public void testFound() throws Exception { String home = System.getProperty("user.home"); try { { String fakeHome = System.getProperty("user.dir") + "/test"; AuthenticationLookup authLookup = new AuthenticationLookup(); log.debug("setting user.home = " + fakeHome); System.setProperty("user.home", fakeHome); RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL("http://alt.example.com/current/path/to/my/service"); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); URL url = rc.getServiceURL(new URI("ivo://example.com/srv"), "http", null); Assert.assertEquals(DUMMY_URL, url); Assert.assertEquals(expected, url); } } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } finally { // reset System.setProperty("user.home", home); } } @Test public void testFoundWithProtocol() throws Exception { try { RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL(DUMMY_URL); URL url = rc.getServiceURL(new URI(DUMMY_URI), "http", null); Assert.assertEquals(expected, url); expected = new URL(DUMMY_CERT_URL); url = rc.getServiceURL(new URI(DUMMY_URI), "https", null); Assert.assertEquals(expected, url); } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } } @Test @Test public void testFoundLocal() throws Exception public void testFoundLocal() throws Exception { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "true"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", RealmRegistryClient rc = new RealmRegistryClient(); "true"); AuthenticationLookup authLookup = new AuthenticationLookup(); String localhost = InetAddress.getLocalHost().getCanonicalHostName(); String localhost = InetAddress.getLocalHost() URL expected = new URL("http://" + localhost + "/current/path/to/my/service"); .getCanonicalHostName(); URL expected = new URL("http://" + localhost + "/current/path/to/my/service"); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals(expected, url); Assert.assertEquals(expected, url); } } catch (Exception unexpected) catch (Exception unexpected) Loading @@ -243,7 +181,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "false"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "false"); } } } } Loading @@ -252,14 +191,17 @@ public class RealmRegistryClientTest { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", "foo.bar.com"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", RealmRegistryClient rc = new RealmRegistryClient(); "foo.bar.com"); AuthenticationLookup authLookup = new AuthenticationLookup(); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); url = rc.getServiceURL(new URI(DUMMY_URI), null, null); url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); } } catch (Exception unexpected) catch (Exception unexpected) { { Loading @@ -268,7 +210,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", ""); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", ""); } } } } Loading @@ -277,11 +220,15 @@ public class RealmRegistryClientTest { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.shortHostname", "foo"); System.setProperty( RealmRegistryClient rc = new RealmRegistryClient(); "ca.nrc.cadc.reg.client.RegistryClient.shortHostname", "foo"); AuthenticationLookup authLookup = new AuthenticationLookup(); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.example.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals( "http://foo.example.com/current/path/to/my/service", url.toExternalForm()); } } catch (Exception unexpected) catch (Exception unexpected) Loading @@ -291,7 +238,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.shortHostname", ""); System.setProperty( "ca.nrc.cadc.reg.client.RegistryClient.shortHostname", ""); } } } } } } cadcTomcat/test/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticatorTest.java +8 −6 Original line number Original line Diff line number Diff line Loading @@ -71,7 +71,6 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.io.IOException; import java.io.IOException; import java.net.URISyntaxException; import junit.framework.Assert; import junit.framework.Assert; Loading @@ -80,10 +79,12 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.Logger; import org.junit.Test; import org.junit.Test; public class CadcBasicAuthenticatorTest public class CadcBasicAuthenticatorTest { { private static Logger log = Logger.getLogger(CadcBasicAuthenticatorTest.class); private static Logger log = Logger.getLogger(CadcBasicAuthenticatorTest.class); static static { { Loading @@ -97,7 +98,8 @@ public class CadcBasicAuthenticatorTest try try { { TestAuthenticator auth = new TestAuthenticator(true); TestAuthenticator auth = new TestAuthenticator(true); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); Assert.assertNotNull(p); Assert.assertNotNull(p); Assert.assertEquals("wrong num roles", 1, p.getRoles().length); Assert.assertEquals("wrong num roles", 1, p.getRoles().length); Loading @@ -117,7 +119,8 @@ public class CadcBasicAuthenticatorTest try try { { TestAuthenticator auth = new TestAuthenticator(false); TestAuthenticator auth = new TestAuthenticator(false); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); Assert.assertNull(p); Assert.assertNull(p); } } Loading @@ -138,8 +141,7 @@ public class CadcBasicAuthenticatorTest } } @Override @Override boolean login(String username, String credentials) boolean login(String username, String credentials) throws IOException throws URISyntaxException, IOException { { return authenticate; return authenticate; } } Loading Loading
cadcTomcat/build.xml +1 −1 Original line number Original line Diff line number Diff line Loading @@ -136,7 +136,7 @@ </classpath> </classpath> <test name="ca.nrc.cadc.tomcat.CadcBasicAuthenticatorTest"/> <test name="ca.nrc.cadc.tomcat.CadcBasicAuthenticatorTest"/> <test name="ca.nrc.cadc.tomcat.RealmRegistryClientTest"/> <test name="ca.nrc.cadc.tomcat.AuthenticationLookupTest"/> <formatter type="plain" usefile="false"/> <formatter type="plain" usefile="false"/> </junit> </junit> </target> </target> Loading
cadcTomcat/src/ca/nrc/cadc/tomcat/RealmRegistryClient.java→cadcTomcat/src/ca/nrc/cadc/tomcat/AuthenticationLookup.java +26 −147 Original line number Original line Diff line number Diff line Loading @@ -69,21 +69,13 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URL; import java.net.UnknownHostException; import java.net.UnknownHostException; import java.util.List; import org.apache.log4j.Logger; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.ListIterator; /** /** * A very simple caching IVOA Registry client. All the lookups done by this client use a properties * A very simple caching IVOA Registry client. All the lookups done by this client use a properties Loading @@ -102,52 +94,26 @@ import java.util.ListIterator; * <pre> * <pre> * ca.nrc.cadc.reg.client.RegistryClient.host=www.example.com * ca.nrc.cadc.reg.client.RegistryClient.host=www.example.com * </pre> * </pre> * * <p> * This class is a forked and trimmed version of ca.nrc.cadc.reg.client.RegistryClient. It was forked * This class is a forked and trimmed version of ca.nrc.cadc.reg.client.RegistryClient. It was forked * to allow the realm implementation to be deployed without library dependencies. * to allow the realm implementation to be deployed without library dependencies. * * * @author pdowler * @author pdowler */ */ public class RealmRegistryClient public class AuthenticationLookup { { private static Logger log = Logger.getLogger(RealmRegistryClient.class); private static Logger log = Logger.getLogger(AuthenticationLookup.class); private static final String CACHE_FILENAME = "RegistryClient.properties"; private static final String LOCAL_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.local"; private static final String LOCAL_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.local"; private static final String HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.host"; private static final String HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.host"; private static final String SHORT_HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.shortHostname"; private static final String SHORT_HOST_PROPERTY = "ca.nrc.cadc.reg.client.RegistryClient.shortHostname"; private URL url; private RealmMultiValuedProperties mvp; private String hostname; private String hostname; private String shortHostname; private String shortHostname; /** * Constructor. Uses a properties file called RegistryClient.properties found in the classpath. */ public RealmRegistryClient() { try { File conf = new File(System.getProperty("user.home") + "/config", CACHE_FILENAME); URL furl; if (conf.exists()) furl = new URL("file://" + conf.getAbsolutePath()); else furl = RealmRegistryClient.class.getResource("/"+CACHE_FILENAME); init(furl, false); private void init() } catch(Exception ex) { throw new RuntimeException("failed to find URL to " + CACHE_FILENAME, ex); } } private void init(URL url, boolean unused) { { this.url = url; try try { { String localP = System.getProperty(LOCAL_PROPERTY); String localP = System.getProperty(LOCAL_PROPERTY); Loading @@ -159,8 +125,10 @@ public class RealmRegistryClient log.debug("shortHost: " + shortHostP); log.debug("shortHost: " + shortHostP); if ("true".equals(localP)) if ("true".equals(localP)) { { log.debug(LOCAL_PROPERTY + " is set, assuming localhost runs the service"); log.debug(LOCAL_PROPERTY this.hostname = InetAddress.getLocalHost().getCanonicalHostName(); + " is set, assuming localhost runs the service"); this.hostname = InetAddress.getLocalHost() .getCanonicalHostName(); } } if (shortHostP != null) if (shortHostP != null) Loading @@ -176,66 +144,36 @@ public class RealmRegistryClient { { hostP = hostP.trim(); hostP = hostP.trim(); if (hostP.length() > 0) if (hostP.length() > 0) { this.hostname = hostP; this.hostname = hostP; } } } } } catch (UnknownHostException ex) catch (UnknownHostException ex) { { log.warn("failed to find localhost name via name resolution (" + ex.toString() + "): using localhost"); log.warn("failed to find localhost name via name resolution (" + ex.toString() + "): using localhost"); this.hostname = "localhost"; this.hostname = "localhost"; } } } } public URL getServiceURL(URI serviceID, String protocol, String path) public URL configureAuthenticationServiceURL(URL serviceURL) throws MalformedURLException throws MalformedURLException { { init(); init(); log.debug("getServiceURL: " + serviceID + "," + protocol + "," + path); log.debug("configureAuthenticationServiceURL: " + serviceURL + "," + serviceURL.getProtocol() + "," + serviceURL.getPath()); //List<URL> urls = lookup.get(serviceID); List<String> strs = mvp.getProperty(serviceID.toString()); if (strs == null || strs.isEmpty() ) { return null; // no matching serviceURI } List<Service> srvs = new ArrayList<Service>(strs.size()); for (String s : strs) { srvs.add(new Service(s)); } String testproto = protocol + "://"; ListIterator<Service> iter = srvs.listIterator(); while ( iter.hasNext() ) { Service srv = iter.next(); boolean noMatch = false; if (protocol != null && !srv.url.startsWith(testproto)) noMatch = true; // wrong protocol if (noMatch) { iter.remove(); log.debug("getServiceURL: constraints not matched: " + srv + " vs " + protocol); } else log.debug("getServiceURL: found match: " + srv + " vs " + protocol); } if (srvs.isEmpty()) return null; Service srv = srvs.get(0); // first match StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder(); if (hostname != null || shortHostname != null) if (hostname != null || shortHostname != null) { { URL ret = new URL(srv.url); sb.append(serviceURL.getProtocol()); sb.append(ret.getProtocol()); sb.append("://"); sb.append("://"); if (shortHostname != null) if (shortHostname != null) { { String hname = shortHostname; String hname = shortHostname; String fqhn = ret.getHost(); String fqhn = serviceURL.getHost(); int i = fqhn.indexOf('.'); int i = fqhn.indexOf('.'); if (i > 0) if (i > 0) { { Loading @@ -248,78 +186,19 @@ public class RealmRegistryClient { { sb.append(hostname); sb.append(hostname); } } int p = ret.getPort(); int p = serviceURL.getPort(); if (p > 0 && p != ret.getDefaultPort()) if (p > 0 && p != serviceURL.getDefaultPort()) { { sb.append(":"); sb.append(":"); sb.append(p); sb.append(p); } } sb.append(ret.getPath()); sb.append(serviceURL.getPath()); } } else else sb.append(srv.url); if (path != null) sb.append(path); return new URL(sb.toString()); } private class Service { String str; String url; public String toString() { return str; } Service(String s) { { this.str = s; sb.append(serviceURL); String[] parts = s.split(" "); this.url = parts[0]; } } } private void init() { if (mvp != null) return; InputStream istream = null; try { // find the cache resource from the url if (url == null) throw new RuntimeException("failed to find cache resource."); // read the properties log.debug("init: reading config from " + url); istream = url.openStream(); this.mvp = new RealmMultiValuedProperties(); mvp.load(istream); if (log.isDebugEnabled()) return new URL(sb.toString()); { for (String k : mvp.keySet()) { List<String> values = mvp.getProperty(k); for (String v : values) { log.debug(k + " = " + v); } } } } catch(IOException ex) { throw new RuntimeException("failed to load resource: " + CACHE_FILENAME, ex); } finally { if (istream != null) try { istream.close(); } catch(Throwable t) { log.warn("failed to close " + url, t); } } } } } }
cadcTomcat/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticator.java +40 −25 Original line number Original line Diff line number Diff line Loading @@ -71,11 +71,9 @@ package ca.nrc.cadc.tomcat; import java.io.IOException; import java.io.IOException; import java.net.HttpURLConnection; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URL; import java.security.Principal; import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.List; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.realm.GenericPrincipal; Loading @@ -83,11 +81,12 @@ import org.apache.catalina.realm.RealmBase; import org.apache.log4j.Level; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.Logger; /** /** * Custom class for Tomcat realm authentication. * Custom class for Tomcat realm authentication. * * <p> * This class was written against the Apache Tomcat 7 (7.0.33.0) API * This class was written against the Apache Tomcat 7 (7.0.33.0) API * * <p> * Authentication checks are performed as REST calls to servers * Authentication checks are performed as REST calls to servers * implementing the cadcAccessControl-Server code. * implementing the cadcAccessControl-Server code. * * Loading @@ -97,7 +96,9 @@ public class CadcBasicAuthenticator extends RealmBase { { private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class); private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class); private static final String AC_URI = "ivo://ivoa.net/std/UMS#login-0.1"; private String loginURL; static static { { Loading @@ -105,6 +106,17 @@ public class CadcBasicAuthenticator extends RealmBase Logger.getLogger("ca.nrc.cadc.tomcat").setLevel(Level.INFO); Logger.getLogger("ca.nrc.cadc.tomcat").setLevel(Level.INFO); } } /** * Set the login URL for the current host. Used by the realm configuration. * * @param loginURL The String login URL. */ public void setLoginURL(final String loginURL) { this.loginURL = loginURL; } @Override @Override protected String getName() protected String getName() { { Loading Loading @@ -139,7 +151,7 @@ public class CadcBasicAuthenticator extends RealmBase if (valid) if (valid) { { // authentication ok, add public role // authentication ok, add public role List<String> roles = Arrays.asList("public"); List<String> roles = Collections.singletonList("public"); // Don't want to return the password here in the principal // Don't want to return the password here in the principal // in case it makes it into the servlet somehow // in case it makes it into the servlet somehow Loading @@ -151,7 +163,8 @@ public class CadcBasicAuthenticator extends RealmBase catch (Throwable t) catch (Throwable t) { { success = false; success = false; String message = "Could not do http basic authentication: " + t.getMessage(); String message = "Could not do http basic authentication: " + t.getMessage(); log.error(message, t); log.error(message, t); throw new IllegalStateException(message, t); throw new IllegalStateException(message, t); } } Loading @@ -159,28 +172,30 @@ public class CadcBasicAuthenticator extends RealmBase { { long duration = System.currentTimeMillis() - start; long duration = System.currentTimeMillis() - start; StringBuilder json = new StringBuilder(); // Converted from StringBuilder as it was unnecessary. json.append("{"); // jenkinsd 2016.08.09 json.append("\"method\":\"AUTH\","); String json = "{" + json.append("\"user\":\"" + username + "\","); "\"method\":\"AUTH\"," + json.append("\"success\":" + success + ","); "\"user\":\"" + username + "\"," + json.append("\"time\":" + duration); "\"success\":" + success + "," + json.append("}"); "\"time\":" + duration + "}"; log.info(json.toString()); log.info(json); } } } } boolean login(String username, String credentials) boolean login(String username, String credentials) throws URISyntaxException, IOException throws IOException { { RealmRegistryClient registryClient = new RealmRegistryClient(); AuthenticationLookup registryClient = new AuthenticationLookup(); URL loginURL = registryClient.getServiceURL( URL authServiceURL = new URI(AC_URI + "#login"), "http", ""); registryClient.configureAuthenticationServiceURL( new URL(loginURL)); String post = "username=" + username + "&password=" + credentials; String post = "username=" + username + "&password=" + credentials; HttpURLConnection conn = (HttpURLConnection) loginURL.openConnection(); HttpURLConnection conn = (HttpURLConnection) authServiceURL.openConnection(); conn.setRequestMethod("POST"); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoOutput(true); Loading @@ -199,7 +214,8 @@ public class CadcBasicAuthenticator extends RealmBase { { // not an unauthorized, so log the // not an unauthorized, so log the // possible server side error // possible server side error String errorMessage = "Error calling /ac/login, error code: " + responseCode; String errorMessage = "Error calling /ac/login, error code: " + responseCode; throw new IllegalStateException(errorMessage); throw new IllegalStateException(errorMessage); } } Loading @@ -211,5 +227,4 @@ public class CadcBasicAuthenticator extends RealmBase } } } }
cadcTomcat/test/src/ca/nrc/cadc/tomcat/RealmRegistryClientTest.java→cadcTomcat/test/src/ca/nrc/cadc/tomcat/AuthenticationLookupTest.java +48 −100 Original line number Original line Diff line number Diff line Loading @@ -70,6 +70,7 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.net.InetAddress; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URI; import java.net.URI; import java.net.URL; import java.net.URL; Loading @@ -84,12 +85,12 @@ import org.junit.Test; /** /** * * @author pdowler * @author pdowler */ */ public class RealmRegistryClientTest public class AuthenticationLookupTest { { private static Logger log = Logger.getLogger(RealmRegistryClientTest.class); private static Logger log = Logger .getLogger(AuthenticationLookupTest.class); static static { { Loading Loading @@ -130,110 +131,47 @@ public class RealmRegistryClientTest { { } } static String DUMMY_URI = "ivo://example.com/srv"; static URL DUMMY_URL; static String DUMMY_URL = "http://www.example.com/current/path/to/my/service"; static String DUMMY_CERT_URL = "https://www.example.com/current/path/to/my/service"; static String DUMMY_PASSWORD_URL = "http://www.example.com/current/path/to/my/auth-service"; static String DUMMY_TOKEN_URL = DUMMY_URL; static String DUMMY_COOKIE_URL = DUMMY_URL; @Test static public void testNotFound() throws Exception { { try try { { RealmRegistryClient rc = new RealmRegistryClient(); DUMMY_URL = new URL( "http://www.example.com/current/path/to/my/service"); URL url = rc.getServiceURL(new URI("ivo://foo/bar"), null, null); Assert.assertNull(url); } } catch(Exception unexpected) catch (MalformedURLException e) { { log.error("unexpected exception", unexpected); // Will never happen. Assert.fail("unexpected exception: " + unexpected); } } } } @Test public void testFound() throws Exception { try { RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL(DUMMY_URL); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); Assert.assertEquals(expected, url); } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } } @Test @Test public void testFoundViaConfigFile() throws Exception public void testFound() throws Exception { String home = System.getProperty("user.home"); try { { String fakeHome = System.getProperty("user.dir") + "/test"; AuthenticationLookup authLookup = new AuthenticationLookup(); log.debug("setting user.home = " + fakeHome); System.setProperty("user.home", fakeHome); RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL("http://alt.example.com/current/path/to/my/service"); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); URL url = rc.getServiceURL(new URI("ivo://example.com/srv"), "http", null); Assert.assertEquals(DUMMY_URL, url); Assert.assertEquals(expected, url); } } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } finally { // reset System.setProperty("user.home", home); } } @Test public void testFoundWithProtocol() throws Exception { try { RealmRegistryClient rc = new RealmRegistryClient(); URL expected = new URL(DUMMY_URL); URL url = rc.getServiceURL(new URI(DUMMY_URI), "http", null); Assert.assertEquals(expected, url); expected = new URL(DUMMY_CERT_URL); url = rc.getServiceURL(new URI(DUMMY_URI), "https", null); Assert.assertEquals(expected, url); } catch(Exception unexpected) { log.error("unexpected exception", unexpected); Assert.fail("unexpected exception: " + unexpected); } } @Test @Test public void testFoundLocal() throws Exception public void testFoundLocal() throws Exception { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "true"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", RealmRegistryClient rc = new RealmRegistryClient(); "true"); AuthenticationLookup authLookup = new AuthenticationLookup(); String localhost = InetAddress.getLocalHost().getCanonicalHostName(); String localhost = InetAddress.getLocalHost() URL expected = new URL("http://" + localhost + "/current/path/to/my/service"); .getCanonicalHostName(); URL expected = new URL("http://" + localhost + "/current/path/to/my/service"); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals(expected, url); Assert.assertEquals(expected, url); } } catch (Exception unexpected) catch (Exception unexpected) Loading @@ -243,7 +181,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "false"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.local", "false"); } } } } Loading @@ -252,14 +191,17 @@ public class RealmRegistryClientTest { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", "foo.bar.com"); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", RealmRegistryClient rc = new RealmRegistryClient(); "foo.bar.com"); AuthenticationLookup authLookup = new AuthenticationLookup(); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); url = rc.getServiceURL(new URI(DUMMY_URI), null, null); url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals("http://foo.bar.com/current/path/to/my/service", url.toExternalForm()); } } catch (Exception unexpected) catch (Exception unexpected) { { Loading @@ -268,7 +210,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", ""); System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.host", ""); } } } } Loading @@ -277,11 +220,15 @@ public class RealmRegistryClientTest { { try try { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.shortHostname", "foo"); System.setProperty( RealmRegistryClient rc = new RealmRegistryClient(); "ca.nrc.cadc.reg.client.RegistryClient.shortHostname", "foo"); AuthenticationLookup authLookup = new AuthenticationLookup(); URL url = rc.getServiceURL(new URI(DUMMY_URI), null, null); URL url = authLookup.configureAuthenticationServiceURL(DUMMY_URL); Assert.assertEquals("http://foo.example.com/current/path/to/my/service", url.toExternalForm()); Assert.assertEquals( "http://foo.example.com/current/path/to/my/service", url.toExternalForm()); } } catch (Exception unexpected) catch (Exception unexpected) Loading @@ -291,7 +238,8 @@ public class RealmRegistryClientTest } } finally finally { { System.setProperty("ca.nrc.cadc.reg.client.RegistryClient.shortHostname", ""); System.setProperty( "ca.nrc.cadc.reg.client.RegistryClient.shortHostname", ""); } } } } } }
cadcTomcat/test/src/ca/nrc/cadc/tomcat/CadcBasicAuthenticatorTest.java +8 −6 Original line number Original line Diff line number Diff line Loading @@ -71,7 +71,6 @@ package ca.nrc.cadc.tomcat; package ca.nrc.cadc.tomcat; import java.io.IOException; import java.io.IOException; import java.net.URISyntaxException; import junit.framework.Assert; import junit.framework.Assert; Loading @@ -80,10 +79,12 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.Logger; import org.junit.Test; import org.junit.Test; public class CadcBasicAuthenticatorTest public class CadcBasicAuthenticatorTest { { private static Logger log = Logger.getLogger(CadcBasicAuthenticatorTest.class); private static Logger log = Logger.getLogger(CadcBasicAuthenticatorTest.class); static static { { Loading @@ -97,7 +98,8 @@ public class CadcBasicAuthenticatorTest try try { { TestAuthenticator auth = new TestAuthenticator(true); TestAuthenticator auth = new TestAuthenticator(true); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); Assert.assertNotNull(p); Assert.assertNotNull(p); Assert.assertEquals("wrong num roles", 1, p.getRoles().length); Assert.assertEquals("wrong num roles", 1, p.getRoles().length); Loading @@ -117,7 +119,8 @@ public class CadcBasicAuthenticatorTest try try { { TestAuthenticator auth = new TestAuthenticator(false); TestAuthenticator auth = new TestAuthenticator(false); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); GenericPrincipal p = (GenericPrincipal) auth.authenticate("user", "pass"); Assert.assertNull(p); Assert.assertNull(p); } } Loading @@ -138,8 +141,7 @@ public class CadcBasicAuthenticatorTest } } @Override @Override boolean login(String username, String credentials) boolean login(String username, String credentials) throws IOException throws URISyntaxException, IOException { { return authenticate; return authenticate; } } Loading