# HG changeset patch # User Severin Gehwolf # Date 1503489069 -7200 # Node ID cc16bcb56e6049b8cead8eaf173000691b76d881 # Parent 7815245e79153f4f77b202a7aab1a80d8951cb2a Use BASIC authentication as fallback. Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024650.html diff -r 7815245e7915 -r cc16bcb56e60 agent/core/src/main/java/com/redhat/thermostat/agent/http/HttpRequestService.java --- a/agent/core/src/main/java/com/redhat/thermostat/agent/http/HttpRequestService.java Wed Aug 23 11:14:49 2017 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/http/HttpRequestService.java Wed Aug 23 13:51:09 2017 +0200 @@ -52,6 +52,7 @@ import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; @@ -63,6 +64,8 @@ import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.shared.config.CommonPaths; import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.storage.config.FileStorageCredentials; +import com.redhat.thermostat.storage.core.StorageCredentials; @Component @Service(value = HttpRequestService.class) @@ -70,28 +73,32 @@ private static final Logger logger = LoggingUtils.getLogger(HttpRequestService.class); + private static final String UNKNOWN_CREDS = "UNKNOWN:UNKNOWN"; private static final String KEYCLOAK_TOKEN_SERVICE = "/auth/realms/__REALM__/protocol/openid-connect/token"; private static final String KEYCLOAK_CONTENT_TYPE = "application/x-www-form-urlencoded"; + private final CredentialsCreator credsCreator; // Used for BASIC auth private final HttpClientCreator httpClientCreator; private final ConfigCreator configCreator; private Gson gson = new GsonBuilder().create(); private HttpClientFacade client; private AgentStartupConfiguration agentStartupConfiguration; - + private StorageCredentials creds; // Used for BASIC auth private KeycloakAccessToken keycloakAccessToken; + @Reference private SSLConfiguration sslConfig; @Reference private CommonPaths commonPaths; public HttpRequestService() { - this(new HttpClientCreator(), new ConfigCreator()); + this(new HttpClientCreator(), new ConfigCreator(), new CredentialsCreator()); } - HttpRequestService(HttpClientCreator clientCreator, ConfigCreator configCreator) { + HttpRequestService(HttpClientCreator clientCreator, ConfigCreator configCreator, CredentialsCreator credsCreator) { this.httpClientCreator = clientCreator; this.configCreator = configCreator; + this.credsCreator = credsCreator; } @Activate @@ -99,6 +106,7 @@ try { agentStartupConfiguration = configCreator.create(commonPaths); client = httpClientCreator.create(sslConfig); + creds = credsCreator.create(commonPaths); client.start(); logger.log(Level.FINE, "HttpRequestService activated"); } catch (Exception e) { @@ -124,7 +132,10 @@ try { if (agentStartupConfiguration.isKeycloakEnabled()) { - request.header("Authorization", "Bearer " + getAccessToken()); + request.header(HttpHeader.AUTHORIZATION.asString(), "Bearer " + getAccessToken()); + } else { + request.header(HttpHeader.AUTHORIZATION.asString(), + getBasicAuthHeaderValue()); } ContentResponse response = request.send(); int status = response.getStatus(); @@ -210,9 +221,27 @@ return "grant_type=refresh_token&client_id=" + agentStartupConfiguration.getKeycloakClient() + "&refresh_token=" + keycloakAccessToken.getRefreshToken(); } + + String getBasicAuthHeaderValue() { + String username = creds.getUsername(); + char[] pwdChar = creds.getPassword(); + String userpassword; + if (username == null || username.isEmpty() || pwdChar == null) { + logger.warning("No credentials specified in " + commonPaths.getUserAgentAuthConfigFile() + ". The connection will fail."); + userpassword = UNKNOWN_CREDS; + } else { + String pwd = new String(pwdChar); + userpassword = username + ":" + pwd; + } + + @SuppressWarnings("restriction") + String encodedAuthorization = new sun.misc.BASE64Encoder() + .encode(userpassword.getBytes()); + return "Basic " + encodedAuthorization; + } // Package-private for testing - void setConfiguration(AgentStartupConfiguration configuration) { + void setConfiguration(AgentStartupConfiguration configuration) { this.agentStartupConfiguration = configuration; } @@ -232,6 +261,12 @@ } } + static class CredentialsCreator { + StorageCredentials create(CommonPaths paths) { + return new FileStorageCredentials(paths.getUserAgentAuthConfigFile()); + } + } + @SuppressWarnings("serial") public static class RequestFailedException extends Exception { diff -r 7815245e7915 -r cc16bcb56e60 agent/core/src/test/java/com/redhat/thermostat/agent/http/HttpRequestServiceTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/agent/http/HttpRequestServiceTest.java Wed Aug 23 11:14:49 2017 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/http/HttpRequestServiceTest.java Wed Aug 23 13:51:09 2017 +0200 @@ -38,6 +38,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -64,10 +65,14 @@ import com.redhat.thermostat.agent.config.AgentStartupConfiguration; import com.redhat.thermostat.agent.http.HttpRequestService.ConfigCreator; +import com.redhat.thermostat.agent.http.HttpRequestService.CredentialsCreator; import com.redhat.thermostat.agent.http.HttpRequestService.HttpClientCreator; import com.redhat.thermostat.agent.http.HttpRequestService.RequestFailedException; import com.redhat.thermostat.shared.config.CommonPaths; import com.redhat.thermostat.shared.config.SSLConfiguration; +import com.redhat.thermostat.storage.core.StorageCredentials; + +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; public class HttpRequestServiceTest { @@ -75,9 +80,12 @@ private static final URI GET_URI = GATEWAY_URI.resolve("?q=foo&l=3"); private static final String payload = "{}"; private static final String keycloakUrl = "http://127.0.0.1:31000/keycloak"; + private static final char[] BASIC_PASSWORD = new char[] { 'p', 'a', 's', 's' }; + private static final String BASIC_USERNAME = "testing"; private HttpClientCreator clientCreator; private ConfigCreator configCreator; + private CredentialsCreator credsCreator; private HttpClientFacade client; private Request httpRequest; @@ -92,6 +100,11 @@ clientCreator = mock(HttpClientCreator.class); when(clientCreator.create(any(SSLConfiguration.class))).thenReturn(client); configCreator = mock(ConfigCreator.class); + credsCreator = mock(CredentialsCreator.class); + StorageCredentials creds = mock(StorageCredentials.class); + when(creds.getPassword()).thenReturn(BASIC_PASSWORD); + when(creds.getUsername()).thenReturn(BASIC_USERNAME); + when(credsCreator.create(any(CommonPaths.class))).thenReturn(creds); } @Test @@ -179,9 +192,38 @@ verify(httpRequest).send(); } + @Test + public void verifyNoKeycloakDefaultsToAuthBasic() throws Exception { + AgentStartupConfiguration configuration = createNoKeycloakConfig(); + + HttpRequestService service = createAndActivateRequestService(configuration); + + service.sendHttpRequest(null, GATEWAY_URI, com.redhat.thermostat.agent.http.HttpRequestService.Method.GET); + + verify(client).newRequest(GATEWAY_URI); + verify(configuration).isKeycloakEnabled(); + + ArgumentCaptor authValueCaptor = ArgumentCaptor.forClass(String.class); + verify(httpRequest).header(eq(HttpHeader.AUTHORIZATION.asString()), authValueCaptor.capture()); + String authValueEncoded = authValueCaptor.getValue(); + assertTrue(authValueEncoded.startsWith("Basic ")); + String userPassEncoded = authValueEncoded.substring("Basic ".length()); + String decodedUserPass = getDecodedUserPass(userPassEncoded); + String expectedCreds = BASIC_USERNAME + ":" + new String(BASIC_PASSWORD); + assertEquals(expectedCreds, decodedUserPass); + verify(httpRequest).method(eq(HttpMethod.GET)); + verify(httpRequest).send(); + } + + private String getDecodedUserPass(String userPassEncoded) throws IOException { + @SuppressWarnings("restriction") + byte[] decodedBytes = new sun.misc.BASE64Decoder().decodeBuffer(userPassEncoded); + return new String(decodedBytes); + } + private HttpRequestService createAndActivateRequestService(AgentStartupConfiguration configuration) throws Exception { when(configCreator.create(any(CommonPaths.class))).thenReturn(configuration); - HttpRequestService service = new HttpRequestService(clientCreator, configCreator); + HttpRequestService service = new HttpRequestService(clientCreator, configCreator, credsCreator); service.activate(); verify(client).start(); return service; @@ -196,7 +238,7 @@ AgentStartupConfiguration configuration = createNoKeycloakConfig(); ConfigCreator configCreator = mock(ConfigCreator.class); when(configCreator.create(any(CommonPaths.class))).thenReturn(configuration); - HttpRequestService service = new HttpRequestService(creator, configCreator); + HttpRequestService service = new HttpRequestService(creator, configCreator, credsCreator); service.activate(); String content = service.sendHttpRequest(null, GET_URI, com.redhat.thermostat.agent.http.HttpRequestService.Method.GET); verify(getClient).newRequest(GET_URI); @@ -212,7 +254,7 @@ AgentStartupConfiguration configuration = createNoKeycloakConfig(); ConfigCreator configCreator = mock(ConfigCreator.class); when(configCreator.create(any(CommonPaths.class))).thenReturn(configuration); - HttpRequestService service = new HttpRequestService(creator, configCreator); + HttpRequestService service = new HttpRequestService(creator, configCreator, credsCreator); service.activate(); // Add extra slashes to URI