From aadf5c19c2052bdfa2bad470c55f4c15c1005d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 27 May 2015 23:50:15 +0200 Subject: [PATCH] Add unit test for DelegateAuthenticator For #197 (missing files) --- .../security/BaseAuthenticatorTest.java | 51 +++++ .../security/DelegatingAuthenticatorTest.java | 192 ++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 agent/jvm/src/test/java/org/jolokia/jvmagent/security/BaseAuthenticatorTest.java create mode 100644 agent/jvm/src/test/java/org/jolokia/jvmagent/security/DelegatingAuthenticatorTest.java diff --git a/agent/jvm/src/test/java/org/jolokia/jvmagent/security/BaseAuthenticatorTest.java b/agent/jvm/src/test/java/org/jolokia/jvmagent/security/BaseAuthenticatorTest.java new file mode 100644 index 000000000..7784a017e --- /dev/null +++ b/agent/jvm/src/test/java/org/jolokia/jvmagent/security/BaseAuthenticatorTest.java @@ -0,0 +1,51 @@ +package org.jolokia.jvmagent.security;/* + * + * Copyright 2014 Roland Huss + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Arrays; + +import javax.security.auth.Subject; + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import org.jolokia.config.ConfigKey; + +import static org.easymock.EasyMock.*; + +/** + * @author roland + * @since 27/05/15 + */ +public class BaseAuthenticatorTest { + protected HttpExchange createExchange(Headers respHeaders, String... reqHeaderValues) { + return createExchange(respHeaders,null,reqHeaderValues); + } + + protected HttpExchange createExchange(Headers respHeaders, Subject subject, String... reqHeaderValues) { + HttpExchange ex = createMock(HttpExchange.class); + Headers reqHeaders = new Headers(); + for (int i = 0; i < reqHeaderValues.length; i+=2) { + reqHeaders.put(reqHeaderValues[i], Arrays.asList(reqHeaderValues[i + 1])); + } + expect(ex.getResponseHeaders()).andStubReturn(respHeaders); + expect(ex.getRequestHeaders()).andStubReturn(reqHeaders); + if (subject != null) { + ex.setAttribute(ConfigKey.JAAS_SUBJECT_REQUEST_ATTRIBUTE, subject); + } + replay(ex); + return ex; + } +} diff --git a/agent/jvm/src/test/java/org/jolokia/jvmagent/security/DelegatingAuthenticatorTest.java b/agent/jvm/src/test/java/org/jolokia/jvmagent/security/DelegatingAuthenticatorTest.java new file mode 100644 index 000000000..f317edb93 --- /dev/null +++ b/agent/jvm/src/test/java/org/jolokia/jvmagent/security/DelegatingAuthenticatorTest.java @@ -0,0 +1,192 @@ +package org.jolokia.jvmagent.security;/* + * + * Copyright 2014 Roland Huss + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Writer; + +import javax.net.ssl.*; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.*; + +import com.sun.net.httpserver.*; +import org.jolokia.test.util.EnvTestUtil; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.servlet.Context; +import org.mortbay.jetty.servlet.ServletHolder; +import org.testng.annotations.*; + +import static org.testng.Assert.*; + +/** + * @author roland + * @since 27/05/15 + */ +public class DelegatingAuthenticatorTest extends BaseAuthenticatorTest { + + private Server jettyServer; + private String url; + + @BeforeClass + public void setup() throws Exception { + int port = EnvTestUtil.getFreePort(); + jettyServer = new Server(port); + Context jettyContext = new Context(jettyServer, "/"); + ServletHolder holder = new ServletHolder(createServlet()); + jettyContext.addServlet(holder, "/test/*"); + + jettyServer.start(); + url = "http://localhost:" + port + "/test"; + } + + private Servlet createServlet() { + return new HttpServlet() { + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String auth = req.getHeader("Authorization"); + if (auth == null || !auth.equals("Bearer blub")) { + resp.setStatus(401); + } else { + resp.setContentType("text/json"); + Writer writer = resp.getWriter(); + if (req.getPathInfo() != null && req.getPathInfo().contains("invalid")) { + writer.append("{\"Invalid JSON\""); + } else { + writer.append("{\"metadata\":{\"name\":\"roland\"},\"array\":[\"eins\",\"zwei\"]}"); + } + } + } + }; + } + + + @Test + public void noAuth() { + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia",url,"json:metadata/name",false); + + Headers respHeader = new Headers(); + HttpExchange ex = createExchange(respHeader); + + Authenticator.Result result = authenticator.authenticate(ex); + assertNotNull(result); + assertTrue(result instanceof Authenticator.Failure); + assertEquals(((Authenticator.Failure) result).getResponseCode(), 401); + } + + @Test + public void withAuth() { + SSLSocketFactory sFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); + HostnameVerifier hVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + try { + String[] data = { + "json:metadata/name", "roland", + "json:array/0", "eins", + "empty:", "", + null, "" + }; + for (int i = 0; i < data.length; i += 2) { + HttpPrincipal principal = executeAuthCheck(data[i]); + assertEquals(principal.getRealm(), "jolokia"); + assertEquals(principal.getUsername(), data[i+1]); + } + } finally { + HttpsURLConnection.setDefaultSSLSocketFactory(sFactory); + HttpsURLConnection.setDefaultHostnameVerifier(hVerifier); + } + } + + private HttpPrincipal executeAuthCheck(String pSpec) { + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia", url, pSpec, true); + + Headers respHeader = new Headers(); + HttpExchange ex = createExchange(respHeader, "Authorization", "Bearer blub"); + + Authenticator.Result result = authenticator.authenticate(ex); + assertNotNull(result); + Authenticator.Success success = (Authenticator.Success) result; + return success.getPrincipal(); + } + + @Test + public void invalidProtocol() { + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia","ftp://ftp.redhat.com",null,false); + + Authenticator.Result result = authenticator.authenticate(createExchange(new Headers())); + Authenticator.Failure failure = (Authenticator.Failure) result; + assertEquals(failure.getResponseCode(),401); + } + + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*blub.*") + public void invalidExtractor() { + new DelegatingAuthenticator("jolokia","http://www.redhat.com","blub:bla",false); + } + + @Test + public void ioException() { + String wrongUrl = "http://0.0.0.2:80"; + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia",wrongUrl,null,false); + HttpExchange exchange = createExchange(new Headers()); + Authenticator.Result result = authenticator.authenticate(exchange); + Authenticator.Failure failure = (Authenticator.Failure) result; + assertEquals(failure.getResponseCode(),503); + String error = exchange.getResponseHeaders().getFirst("X-Error-Details"); + assertTrue(error.contains("http://0.0.0.2:80")); + } + + @Test + public void invalidPath() { + String data[] = new String[] { "json:never/find/me", "never", + "json:metadata/name/yet/deeper", "deeper" }; + for (int i = 0; i < data.length; i +=2) { + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia", url, data[i], false); + HttpExchange exchange = createExchange(new Headers(), "Authorization", "Bearer blub"); + Authenticator.Result result = authenticator.authenticate(exchange); + Authenticator.Failure failure = (Authenticator.Failure) result; + assertEquals(failure.getResponseCode(), 400); + String error = exchange.getResponseHeaders().getFirst("X-Error-Details"); + assertTrue(error.contains(data[i+1])); + } + } + + @Test + public void invalidJson() { + DelegatingAuthenticator authenticator = new DelegatingAuthenticator("jolokia", url + "/invalid","json:metadata/name", false); + HttpExchange exchange = createExchange(new Headers(), "Authorization", "Bearer blub"); + Authenticator.Result result = authenticator.authenticate(exchange); + Authenticator.Failure failure = (Authenticator.Failure) result; + assertEquals(failure.getResponseCode(), 422); + String error = exchange.getResponseHeaders().getFirst("X-Error-Details"); + assertTrue(error.contains("Invalid JSON")); + } + + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*blub.*") + public void malformedUrl() { + new DelegatingAuthenticator("jolokia","blub//://bla",null,false); + } + + @Test + public void emptySpec() { + + HttpPrincipal principal = executeAuthCheck("empty:"); + assertEquals(principal.getRealm(), "jolokia"); + assertEquals(principal.getUsername(), ""); + } + + @AfterClass + public void tearDown() throws Exception { + jettyServer.stop(); + } +}