blob: 3d6c7f4a827f442dc6e55ce007efca13376dcb58 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.ambari.server.checks;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ambari.server.controller.PrereqCheckRequest;
import org.apache.ambari.server.controller.internal.URLStreamProvider;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.DesiredConfig;
import org.apache.ambari.server.state.RepositoryType;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.repository.ClusterVersionSummary;
import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.stack.PrereqCheckStatus;
import org.apache.ambari.server.state.stack.PrerequisiteCheck;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.google.inject.Provider;
/**
* Unit tests for RangerPasswordCheck
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(RangerPasswordCheck.class)
public class RangerPasswordCheckTest {
private static final String RANGER_URL = "http://foo:6080/";
private static final String GOOD_LOGIN_RESPONSE = "{\"count\": 0 }";
private static final String BAD_LOGIN_RESPONSE = "<html>Ranger redirects to login HTML</html>";
private static final String GOOD_USER_RESPONSE =
"{\"queryTimeMS\": 1446758948823," +
"\"vXUsers\": [" +
" {" +
" \"name\": \"r_admin\"" +
" }" +
"]}";
private static final String NO_USER_RESPONSE =
"{\"queryTimeMS\": 1446758948823," +
"\"vXUsers\": [" +
"]}";
private Clusters m_clusters = EasyMock.createMock(Clusters.class);
private Map<String, String> m_configMap = new HashMap<>();
private RangerPasswordCheck m_rpc = null;
private URLStreamProvider m_streamProvider = EasyMock.createMock(URLStreamProvider.class);
@Mock
private ClusterVersionSummary m_clusterVersionSummary;
@Mock
private VersionDefinitionXml m_vdfXml;
@Mock
private RepositoryVersionEntity m_repositoryVersion;
final Map<String, Service> m_services = new HashMap<>();
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
m_configMap.put("policymgr_external_url", RANGER_URL);
m_configMap.put("admin_username", "admin");
m_configMap.put("admin_password", "pass");
m_configMap.put("ranger_admin_username", "r_admin");
m_configMap.put("ranger_admin_password", "r_pass");
Cluster cluster = EasyMock.createMock(Cluster.class);
Config config = EasyMock.createMock(Config.class);
final Map<String, Service> services = new HashMap<>();
final Service service = EasyMock.createMock(Service.class);
services.put("RANGER", service);
Map<String, DesiredConfig> desiredMap = new HashMap<>();
DesiredConfig dc = EasyMock.createMock(DesiredConfig.class);
desiredMap.put("admin-properties", dc);
desiredMap.put("ranger-env", dc);
expect(dc.getTag()).andReturn("").anyTimes();
expect(config.getProperties()).andReturn(m_configMap).anyTimes();
expect(cluster.getServices()).andReturn(services).anyTimes();
expect(cluster.getService("RANGER")).andReturn(service).anyTimes();
expect(cluster.getDesiredConfigs()).andReturn(desiredMap).anyTimes();
expect(cluster.getDesiredConfigByType((String) anyObject())).andReturn(config).anyTimes();
expect(cluster.getConfig((String) anyObject(), (String) anyObject())).andReturn(config).anyTimes();
expect(m_clusters.getCluster((String) anyObject())).andReturn(cluster).anyTimes();
replay(m_clusters, cluster, dc, config);
m_rpc = new RangerPasswordCheck();
m_rpc.clustersProvider = new Provider<Clusters>() {
@Override
public Clusters get() {
// TODO Auto-generated method stub
return m_clusters;
}
};
EasyMock.reset(m_streamProvider);
PowerMockito.whenNew(URLStreamProvider.class).withAnyArguments().thenReturn(m_streamProvider);
m_services.clear();
Mockito.when(m_repositoryVersion.getType()).thenReturn(RepositoryType.STANDARD);
Mockito.when(m_repositoryVersion.getRepositoryXml()).thenReturn(m_vdfXml);
Mockito.when(m_vdfXml.getClusterSummary(Mockito.any(Cluster.class))).thenReturn(m_clusterVersionSummary);
Mockito.when(m_clusterVersionSummary.getAvailableServiceNames()).thenReturn(m_services.keySet());
}
@Test
public void testApplicable() throws Exception {
final Service service = EasyMock.createMock(Service.class);
m_services.put("RANGER", service);
Cluster cluster = m_clusters.getCluster("cluster");
EasyMock.reset(cluster);
expect(cluster.getServices()).andReturn(m_services).anyTimes();
expect(cluster.getCurrentStackVersion()).andReturn(new StackId("HDP-2.3")).anyTimes();
replay(cluster);
PrereqCheckRequest request = new PrereqCheckRequest("cluster");
request.setTargetRepositoryVersion(m_repositoryVersion);
assertTrue(m_rpc.isApplicable(request));
}
@SuppressWarnings("unchecked")
@Test
public void testMissingProps() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
m_configMap.clear();
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not check credentials. Missing property admin-properties/policymgr_external_url", check.getFailReason());
m_configMap.put("policymgr_external_url", RANGER_URL);
check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not check credentials. Missing property ranger-env/admin_username", check.getFailReason());
m_configMap.put("admin_username", "admin");
check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not check credentials. Missing property ranger-env/admin_password", check.getFailReason());
m_configMap.put("admin_password", "pass");
check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not check credentials. Missing property ranger-env/ranger_admin_username", check.getFailReason());
m_configMap.put("ranger_admin_username", "r_admin");
check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not check credentials. Missing property ranger-env/ranger_admin_password", check.getFailReason());
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes()));
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes()));
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes()));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
m_configMap.put("ranger_admin_password", "r_pass");
check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.PASS, check.getStatus());
}
@SuppressWarnings("unchecked")
@Test
public void testNormal() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.PASS, check.getStatus());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testNoUser() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(NO_USER_RESPONSE.getBytes())).once();
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.PASS, check.getStatus());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testBadUserParsing() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(
"some really bad non-json".getBytes()));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
String error = "The response from Ranger was malformed. ";
error += "com.google.gson.stream.MalformedJsonException: Expected EOF at line 1 column 6. ";
error += "Request: " + RANGER_URL + "service/xusers/users?name=r_admin";
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals(error, check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testJsonCasting() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes()));
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(
"{ \"data\": \"bad\", \"vXUsers\": \"xyz\" }".getBytes()));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
String error = "The response from Ranger was malformed. ";
error += "java.lang.String cannot be cast to java.util.List. ";
error += "Request: " + RANGER_URL + "service/xusers/users?name=r_admin";
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals(error, check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testAdminUnauthorized() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(401);
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.SERVICES_RANGER_PASSWORD_VERIFY, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
assertEquals("Credentials for user 'admin' in Ambari do not match Ranger.", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testAdminUnauthorizedByRedirect() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(BAD_LOGIN_RESPONSE.getBytes()));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.SERVICES_RANGER_PASSWORD_VERIFY, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
assertEquals("Credentials for user 'admin' in Ambari do not match Ranger.", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testAdminIOException() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andThrow(new IOException("whoops"));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.SERVICES_RANGER_PASSWORD_VERIFY, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not access Ranger to verify user 'admin' against " + RANGER_URL + "service/public/api/repository/count. whoops", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testAdminBadResponse() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(404);
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.SERVICES_RANGER_PASSWORD_VERIFY, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not verify credentials for user 'admin'. Response code 404 received from " + RANGER_URL + "service/public/api/repository/count", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testUserUnauthorized() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(401);
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
assertEquals("Credentials for user 'r_admin' in Ambari do not match Ranger.", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testUserUnauthorizedByRedirect() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(BAD_LOGIN_RESPONSE.getBytes())).once();
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.FAIL, check.getStatus());
assertEquals("Credentials for user 'r_admin' in Ambari do not match Ranger.", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testUserIOException() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andThrow(new IOException("again!"));
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not access Ranger to verify user 'r_admin' against " + RANGER_URL + "service/public/api/repository/count. again!", check.getFailReason());
verify(conn, m_streamProvider);
}
@SuppressWarnings("unchecked")
@Test
public void testUserBadResponse() throws Exception {
HttpURLConnection conn = EasyMock.createMock(HttpURLConnection.class);
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_LOGIN_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(200);
expect(conn.getInputStream()).andReturn(new ByteArrayInputStream(GOOD_USER_RESPONSE.getBytes())).once();
expect(conn.getResponseCode()).andReturn(500);
expect(m_streamProvider.processURL((String) anyObject(), (String) anyObject(),
(InputStream) anyObject(), (Map<String, List<String>>) anyObject())).andReturn(
conn).anyTimes();
replay(conn, m_streamProvider);
PrerequisiteCheck check = new PrerequisiteCheck(null, null);
m_rpc.perform(check, new PrereqCheckRequest("cluster"));
assertEquals(PrereqCheckStatus.WARNING, check.getStatus());
assertEquals("Could not verify credentials for user 'r_admin'. Response code 500 received from " + RANGER_URL + "service/public/api/repository/count", check.getFailReason());
verify(conn, m_streamProvider);
}
}