/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service;
import static org.hamcrest.core.AnyOf.anyOf;
import static org.hamcrest.core.Is.is;
import java.net.URI;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.core.NewCookie;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.model.auth.ACLEntry;
import com.emc.storageos.model.auth.AuthnCreateParam;
import com.emc.storageos.model.auth.AuthnProviderRestRep;
import com.emc.storageos.model.auth.RoleAssignmentEntry;
import com.emc.storageos.model.errorhandling.ServiceErrorRestRep;
import com.emc.storageos.model.password.PasswordResetParam;
import com.emc.storageos.model.tenant.TenantResponse;
import com.emc.storageos.model.tenant.TenantUpdateParam;
import com.emc.storageos.model.tenant.UserMappingAttributeParam;
import com.emc.storageos.model.tenant.UserMappingChanges;
import com.emc.storageos.model.tenant.UserMappingParam;
import com.emc.storageos.model.varray.NetworkRestRep;
import com.emc.storageos.model.vpool.BlockVirtualPoolRestRep;
import com.emc.storageos.model.vpool.FileVirtualPoolRestRep;
import com.emc.storageos.security.authentication.NoAuthHeaderUserFilter;
import com.emc.storageos.security.authorization.PermissionsKey;
import com.emc.storageos.services.util.EnvConfig;
import com.emc.storageos.svcs.errorhandling.resources.ServiceCode;
import com.emc.vipr.model.sys.licensing.License;
import com.emc.vipr.model.sys.licensing.LicenseFeature;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.ClientFilter;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.api.client.filter.LoggingFilter;
/**
*
* Base class for jersey client type tests which includes all the necessary
* http/https client setups and AD configuration.
*
*/
public class ApiTestBase {
public static final String AD_SERVER1_IP = EnvConfig.get("sanity", "ad1.ip");
public static final String AD_SERVER1_HOST = EnvConfig.get("sanity", "ad1.hostname");
public static final String AD_SERVER2_IP = EnvConfig.get("sanity", "ad2.ip");
public static final String LDAP_SERVER1_IP = EnvConfig.get("sanity", "ldap1.ip");
// Constants for all local and AD based users and groups, using the .165 AD server.
protected static final String ROOTTENANT_ATTR = "sanity";
protected static final String ROOTTENANT_NAME = "Root Provider Tenant";
protected static final String SYSADMIN = "root";
protected static final String SYSADMIN_PASS_WORD = "ChangeMe";
protected static final String SYSMONITOR = "sysmonitor";
protected static final String SYSMONITOR_PASS_WORD = "ChangeMe1!";
protected static final String SVCUSER = "svcuser";
protected static final String SVCUSER_PASS_WORD = "ChangeMe1!";
protected static final String PROXY_USER = "proxyuser";
protected static final String PROXY_USER_PWD = "ChangeMe1!";
protected static final String TENANTADMIN = "sanity_tenant_admin@sanity.local";
protected static final String ZONEADMIN = "zadmin@sanity.local";
protected static final String SUPERUSER = "super_sanity@sanity.local";
protected static final String ROOTTENANTADMIN = "rtadmin@Sanity.Local";
protected static final String ROOTTENANTADMIN_FORASSIGNMENT = "RTAdmin@sanity.local";
protected static final String ROOTUSER = "Sanity_User@Sanity.Local";
protected static final String ROOTUSER2 = "sanity_user2@sanity.local";
protected static final String ZONEADMINS_GROUP = "ZoneAdmins@sanity.local";
protected static final String TENANT_ADMINS_GROUP = "RootTenantAdmins@sanity.local";
// Subtenant1 configuration
protected static final String SUBTENANT1_ATTR = "SUBTENANT1";
protected static final String SUBTENANT1_ADMIN = "sTadmin1@sanity.local";
protected static final String SUBTENANT1_ADMIN2 = "st1admin2@Sanity.Local";
protected static final String SUBTENANT1_USER = "st1user@sanity.local";
protected static final String SUBTENANT1_READER = "st1reader@sanity.local";
// use funky case for these groups to test that role assignments are case-insensitive
protected static final String SUBTENANT1_ADMINS_GROUP = "sUbTeNaNt1aDmInS@sanity.local";
protected static final String SUBTENANT1_USERS_GROUP = "subtenant1USERS@sanity.local";
// Subtenant2 configuration
protected static final String SUBTENANT2_ATTR = "subtenant2";
protected static final String SUBTENANT2_ADMIN = "stadmin2@sanity.local";
protected static final String SUBTENANT2_ADMIN2 = "st2admin2@sanity.local";
protected static final String SUBTENANT2_ADMINS_GROUP = "Subtenant2Admins@sanity.local";
protected static final String SUBTENANT2_USER = "st2user@sanity.local";
protected static final String SUBTENANT13_USER = "st12user@sanity.local";
// Subtenant3 Configuration
protected static final String SUBTENANT3_ATTR = "Test Group";
protected static final String SUBTENANT3_ADMIN = "testuser@sanity.local";
// Subtenant cross tenant configuration
protected static final String CROSS_TENANT_USER = "cross1@sanity.local";
protected static final String ASUBSETOFUSERS_GROUP = "ASubSetOfUsers@sanity.local";
// LDAPS Configuration
protected static final String LDAPS_USER = "user1@secureldap.com";
protected static final String LDAPS_PASS_WORD = "password";
protected static final Logger _log = LoggerFactory.getLogger(ApiTest.class);
protected static final String AD_PASS_WORD = EnvConfig.get("sanity", "ad.manager.password");
protected static final String LICENSE_FILE = "INCREMENT ViPR_Controller EMCLM 2.0 permanent uncounted " +
"VENDOR_STRING=CAPACITY=1024;CAPACITY_UNIT=TB;SWID=PXTYD1DZK59Y4C;PLC=VIPR; " +
"HOSTID=ANY dist_info=\"ACTIVATED TO 49ers Inn\" ISSUER=EMC " +
"ISSUED=10-Jan-2014 NOTICE=\"ACTIVATED TO License Site Number: " +
"PTA06JUN20131086059\" SN=2162734 SIGN=\"00EC 6B99 FB75 280D B932 75DD 21D1 EC00 5634 5848 462F 7ACD 0032 5081 2923\"" +
"\nINCREMENT ViPR_HDFS EMCLM 2.0 permanent uncounted " +
"VENDOR_STRING=SWID=PXTYD1DZK59Y4C;PLC=VIPR; HOSTID=ANY " +
"dist_info=\"ACTIVATED TO 49ers Inn\" ISSUER=EMC " +
"ISSUED=10-Jan-2014 NOTICE=\"ACTIVATED TO License Site Number: " +
"PTA06JUN20131086059\" SN=2162734 SIGN=\"0073 059F D54D 7CC9 4ADA 0B13 6160 9100 688E 8167 37DA E911 28F2 CC96 798A\"" +
"\nINCREMENT ViPR_Object EMCLM 2.0 permanent uncounted " +
"VENDOR_STRING=SWID=PXTYD1DZK59Y4C;PLC=VIPR; HOSTID=ANY " +
"dist_info=\"ACTIVATED TO 49ers Inn\" ISSUER=EMC " +
"ISSUED=10-Jan-2014 NOTICE=\"ACTIVATED TO License Site Number: " +
"PTA06JUN20131086059\" SN=2162734 SIGN=\"000E BA65 2065 4DBD 8888 CAEB 94EE F800 BAF0 FF51 A3F0 1E81 E731 4ECB FACC\"" +
"\nINCREMENT ViPR_Unstructured EMCLM 2.0 permanent uncounted " +
"VENDOR_STRING=CAPACITY=1024;CAPACITY_UNIT=TB;SWID=PXTYD1DZK59Y4C;PLC=VIPR; " +
"HOSTID=ANY dist_info=\"ACTIVATED TO 49ers Inn\" ISSUER=EMC " +
"ISSUED=10-Jan-2014 NOTICE=\"ACTIVATED TO License Site Number: " +
"PTA06JUN20131086059\" SN=2162734 SIGN=\"00CF 2080 FDCA D7E1 CA22 5DE7 DA9A 0000 1938 D26C 4AB5 76CB AA43 2662 0FCD\"" +
"\nINCREMENT ViPR_CAS EMCLM 2.0 permanent uncounted " +
"VENDOR_STRING=SWID=PXTYD1DZK59Y4C;PLC=VIPR; HOSTID=ANY " +
"dist_info=\"ACTIVATED TO 49ers Inn\" ISSUER=EMC " +
"ISSUED=10-Jan-2014 NOTICE=\"ACTIVATED TO License Site Number: " +
"PTA06JUN20131086059\" SN=2162734 SIGN=\"009E 6082 66B8 3D16 69AC 9C84 8FDD DB00 C762 3EBB 52FC 04C8 72A2 A5A9 4CC8\"";
protected BalancedWebResource rSys, rMon, rZAdmin, rZAdminGr, rTAdmin, rTAdminGr,
rSTAdmin1, rSTAdminGr1, rSTAdmin2, rSTAdminGr2,
rProjRead, rProjUserGr, rUnAuth, rRootUser2, rSTAdmin3, rProxyUser, rLdaps,
rST13User, rSTCross, rST2User;
protected Map<String, List<ProjectEntry>> expectedProjListResults = new HashMap<String, List<ProjectEntry>>();
protected URI rootTenantId, subtenant1Id, subtenant2Id, subtenant3Id;
protected URI _nh, _testProject, _fs, _volume, _group;
protected FileVirtualPoolRestRep _cosFile;
protected BlockVirtualPoolRestRep _cosBlock;
protected NetworkRestRep _iptzone;
protected NetworkRestRep _fctzone;
protected String _projectsUrlFormat = "/tenants/%s/projects";
protected String _projectUrl = "/projects/%s";
protected String _projectUrlDelete = "/projects/%s/deactivate";
protected String _projectAclUrl = _projectUrl + "/acl";
protected String _blockCosAclUrl = "/block/vpools/%s/acl";
protected String _fileCosAclUrl = "/file/vpools/%s/acl";
protected static volatile List<String> baseUrls;
/**
* Class to encapsulate a list of WebResources
*/
public class BalancedWebResource {
private int index = 0;
private final List<WebResource> _hosts;
public BalancedWebResource() {
index = 0;
_hosts = new LinkedList<WebResource>();
}
public void addWebResource(WebResource w) {
_hosts.add(w);
}
public WebResource getNextHost() {
if (index == _hosts.size() - 1) {
index = 0;
return _hosts.get(_hosts.size() - 1);
} else {
return _hosts.get(index++);
}
}
public WebResource path(String p) {
return getNextHost().path(p);
}
}
/**
* initialize the list of hosts based on the APP_HOST_NAMES env. variable
*
* @param isHttps: true for https urls, false otherwise
*/
protected void initLoadBalancer(boolean isHttps) {
String baseServiceURLTemplate = new String();
if (isHttps) {
baseServiceURLTemplate = "https://%1$s:4443";
} else {
baseServiceURLTemplate = "http://%1$s:8080";
}
String hostName = System.getenv("APP_HOST_NAMES");
String hostNames[] = hostName.split(",");
baseUrls = new LinkedList<String>();
for (String h : hostNames) {
String disp = String.format(baseServiceURLTemplate, h);
baseUrls.add(disp);
}
}
/**
* Update tenant attributes for the root tenant
*/
protected void updateRootTenantAttrs() {
TenantResponse tenantResp = rSys.path("/tenant").get(TenantResponse.class);
rootTenantId = tenantResp.getTenant();
/*
* PUT the ou=sanity attribute mapping into the root tenant attributes
*/
TenantUpdateParam tenantUpdate = new TenantUpdateParam();
tenantUpdate.setUserMappingChanges(new UserMappingChanges());
tenantUpdate.getUserMappingChanges().setAdd(new ArrayList<UserMappingParam>());
UserMappingParam rootMapping = new UserMappingParam();
rootMapping.setDomain("SANITY.local");
UserMappingAttributeParam rootAttr = new UserMappingAttributeParam();
rootAttr.setKey("ou");
rootAttr.setValues(Collections.singletonList(ROOTTENANT_ATTR));
rootMapping.setAttributes(Collections.singletonList(rootAttr));
tenantUpdate.getUserMappingChanges().getAdd().add(rootMapping);
tenantUpdate.setLabel(ROOTTENANT_NAME); // TODO: FIX: not sure why name is required for update
ClientResponse resp = rSys.path("/tenants/" + rootTenantId.toString()).put(ClientResponse.class, tenantUpdate);
Assert.assertEquals(200, resp.getStatus());
}
/**
* Add in the main AD configuration that will be used for the entire test suite
*/
protected URI _goodADConfig = null;
protected void updateADConfig() {
if (rSys == null) { // rSys may get nulled out between
// Tests depending on what Junit feels like doing that day
try {
rSys = createHttpsClient(SYSADMIN, SYSADMIN_PASS_WORD, baseUrls);
rSys.path("/tenant").get(String.class);
} catch (Exception e) {
Assert.fail();
}
}
AuthnCreateParam param = new AuthnCreateParam();
param.setLabel("ad apitest config good");
param.setDescription("ad configuration created by ApiTest.java");
param.setDisable(false);
// Put spaces in the doman to verify it does not cause a problem
param.getDomains().add(" SANITY.LOCAL ");
param.setGroupAttribute("CN");
param.getGroupWhitelistValues().add("*Admins*");
param.getGroupWhitelistValues().add("*Test*");
param.getGroupWhitelistValues().add("*Users*");
param.setManagerDn("CN=Administrator,CN=Users,DC=sanity,DC=local");
param.setManagerPassword("P@ssw0rd");
param.setSearchBase("DC=sanity,DC=local");
param.setSearchFilter("userPrincipalName=%u");
param.getServerUrls().add("ldap://" + AD_SERVER1_IP);
param.setMode("ad");
param.setSearchScope("SUBTREE");
try {
AuthnProviderRestRep authnResp = rSys.path("/vdc/admin/authnproviders").post(AuthnProviderRestRep.class, param);
Assert.assertNotNull(authnResp);
_goodADConfig = authnResp.getId();
} catch (UniformInterfaceException e) {
if (e.getResponse().getStatus() != 400) {
Assert.fail();
}
} catch (Exception e) {
Assert.fail();
}
}
protected boolean isControllerLicensed() {
License license = rSys.path("/license").get(License.class);
List<LicenseFeature> features = license.getLicenseFeatures();
if (features == null) {
return false;
}
for (LicenseFeature feature : features) {
if (feature.getModelId().startsWith("ViPR_Controller") && feature.isLicensed()) {
return true;
}
}
return false;
}
protected void addControllerLicense() {
License license = new License();
license.setLicenseText(LICENSE_FILE);
ClientResponse resp = rSys.path("/license").post(ClientResponse.class, license);
Assert.assertEquals(200, resp.getStatus());
Assert.assertTrue(isControllerLicensed());
}
BalancedWebResource getHttpsClient(String userName, String password) throws NoSuchAlgorithmException {
return createHttpsClient(userName, password, baseUrls);
}
/**
* initialize http resources
*/
protected void setupHttpResources() {
initLoadBalancer(false);
rSys = createHttpClient(SYSADMIN, "LOCAL_STORAGEOS_USER=true", "", baseUrls);
rProxyUser = createHttpClient(PROXY_USER, "LOCAL_STORAGEOS_USER=true", "", baseUrls);
rMon = createHttpClient(SYSMONITOR, "LOCAL_STORAGEOS_USER=true", "", baseUrls);
updateADConfig();
updateRootTenantAttrs();
rZAdmin = createHttpClient(ZONEADMIN, "ou=" + ROOTTENANT_ATTR, "", baseUrls);
rZAdminGr = createHttpClient(SUPERUSER, "ou=" + ROOTTENANT_ATTR, ZONEADMINS_GROUP, baseUrls);
rTAdmin = createHttpClient(ROOTTENANTADMIN, "ou=" + ROOTTENANT_ATTR, "", baseUrls);
rTAdminGr = createHttpClient(TENANTADMIN, "ou=" + ROOTTENANT_ATTR, TENANT_ADMINS_GROUP, baseUrls);
rSTAdmin1 = createHttpClient(SUBTENANT1_ADMIN, "department=" + SUBTENANT1_ATTR, "", baseUrls);
rSTAdminGr1 = createHttpClient(SUBTENANT1_ADMIN2, "department=" + SUBTENANT1_ATTR, SUBTENANT1_ADMINS_GROUP, baseUrls);
rSTAdmin2 = createHttpClient(SUBTENANT2_ADMIN, "company=" + SUBTENANT2_ATTR, "", baseUrls);
rSTAdminGr2 = createHttpClient(SUBTENANT2_ADMIN2, "company=" + SUBTENANT2_ATTR, SUBTENANT2_ADMINS_GROUP, baseUrls);
rProjRead = createHttpClient(SUBTENANT1_READER, "company=" + SUBTENANT1_ATTR, "", baseUrls);
rProjUserGr = createHttpClient(SUBTENANT1_USER, "company=" + SUBTENANT1_ATTR, SUBTENANT1_USERS_GROUP + ",Dummy", baseUrls);
rUnAuth = createHttpClient(ROOTUSER, "ou=" + ROOTTENANT_ATTR, "", baseUrls);
rRootUser2 = createHttpClient(ROOTUSER2, "ou=" + ROOTTENANT_ATTR, "", baseUrls);
rSTAdmin3 = createHttpClient(SUBTENANT3_ADMIN, "group=" + SUBTENANT3_ATTR, "", baseUrls);
rLdaps = createHttpClient(LDAPS_USER, "postalCode=01748", "", baseUrls);
rST13User = createHttpClient(SUBTENANT13_USER, "company=" + SUBTENANT1_ATTR, "group=" + SUBTENANT3_ATTR, baseUrls);
rSTCross = createHttpClient(CROSS_TENANT_USER, "company=crosstenant", "", baseUrls);
}
/*
* initialize https resources
*/
@SuppressWarnings("unchecked")
protected void setupHttpsResources() throws NoSuchAlgorithmException {
initLoadBalancer(true);
setupLicenseAndInitialPasswords();
rProxyUser = createHttpsClient(PROXY_USER, PROXY_USER_PWD, baseUrls);
rProxyUser.path("/tenant").get(String.class);
rMon = createHttpsClient(SYSMONITOR, SYSMONITOR_PASS_WORD, baseUrls);
updateADConfig();
updateRootTenantAttrs();
rZAdmin = createHttpsClient(ZONEADMIN, AD_PASS_WORD, baseUrls);
ClientResponse r = rZAdmin.path("/tenant").get(ClientResponse.class);
rZAdminGr = createHttpsClient(SUPERUSER, AD_PASS_WORD, baseUrls);
rZAdminGr.path("/tenant").get(String.class);
rTAdmin = createHttpsClient(ROOTTENANTADMIN, AD_PASS_WORD, baseUrls);
rTAdmin.path("/tenant").get(String.class);
rTAdminGr = createHttpsClient(TENANTADMIN, AD_PASS_WORD, baseUrls);
rTAdminGr.path("/tenant").get(String.class);
rSTAdmin1 = createHttpsClient(SUBTENANT1_ADMIN, AD_PASS_WORD, baseUrls);
rSTAdminGr1 = createHttpsClient(SUBTENANT1_ADMIN2, AD_PASS_WORD, baseUrls);
rSTAdmin2 = createHttpsClient(SUBTENANT2_ADMIN, AD_PASS_WORD, baseUrls);
rSTAdminGr2 = createHttpsClient(SUBTENANT2_ADMIN2, AD_PASS_WORD, baseUrls);
rST2User = createHttpsClient(SUBTENANT2_USER, AD_PASS_WORD, baseUrls);
rProjRead = createHttpsClient(SUBTENANT1_READER, AD_PASS_WORD, baseUrls);
rProjUserGr = createHttpsClient(SUBTENANT1_USER, AD_PASS_WORD, baseUrls);
rUnAuth = createHttpsClient(ROOTUSER, AD_PASS_WORD, baseUrls);
rRootUser2 = createHttpsClient(ROOTUSER2, AD_PASS_WORD, baseUrls);
rSTAdmin3 = createHttpsClient(SUBTENANT3_ADMIN, AD_PASS_WORD, baseUrls);
rLdaps = createHttpsClient(LDAPS_USER, LDAPS_PASS_WORD, baseUrls);
rST13User = createHttpsClient(SUBTENANT13_USER, AD_PASS_WORD, baseUrls);
rSTCross = createHttpsClient(CROSS_TENANT_USER, AD_PASS_WORD, baseUrls);
}
public void logoutUser(BalancedWebResource resource) {
resource.path("/logout")
.queryParam("force", "true")
.queryParam("proxytokens", "true")
.get(ClientResponse.class);
}
protected void tearDownHttpsResources() {
logoutUser(rProxyUser);
logoutUser(rMon);
logoutUser(rZAdmin);
logoutUser(rZAdminGr);
logoutUser(rTAdmin);
logoutUser(rTAdminGr);
logoutUser(rSTAdmin1);
logoutUser(rSTAdminGr1);
logoutUser(rSTAdmin2);
logoutUser(rSTAdminGr2);
logoutUser(rST2User);
logoutUser(rProjRead);
logoutUser(rProjUserGr);
logoutUser(rUnAuth);
logoutUser(rRootUser2);
logoutUser(rSTAdmin3);
logoutUser(rLdaps);
logoutUser(rST13User);
logoutUser(rSTCross);
logoutUser(rSys);
}
protected void setupLicenseAndInitialPasswords() throws NoSuchAlgorithmException {
rSys = createHttpsClient(SYSADMIN, SYSADMIN_PASS_WORD, baseUrls);
rSys.path("/tenant").get(String.class);
// Initialize proxyuser password to ChangeMe
String usernames[] = { "sysmonitor", "proxyuser" };
String pass_word = "ChangeMe1!";
ClientResponse resp = null;
for (String username : usernames) {
PasswordResetParam params = new PasswordResetParam();
params.setUsername(username);
params.setPassword(pass_word);
resp = rSys.path("/password/reset").put(ClientResponse.class, params);
Assert.assertThat(resp.getStatus(), anyOf(is(200), is(400)));
waitForClusterToBeStable();
}
if (!isControllerLicensed()) {
addControllerLicense();
}
}
/**
* waits until the cluster is stable
*/
protected void waitForClusterToBeStable() {
ClientResponse resp;
String info = "";
Boolean notStable = true;
while (notStable) {
try {
Thread.sleep(2000);
System.out.println("Waiting for stable cluster state.");
} catch (InterruptedException e) {
_log.error(e.getMessage(), e);
}
try {
resp = rSys.path("/upgrade/cluster-state").get(ClientResponse.class);
} catch (ClientHandlerException e) {
_log.warn(
"Caught ClientHandlerException while waiting for cluster to be stable. Continuing...",
e);
continue;
}
info = resp.getEntity(String.class);
if (info.contains("<cluster_state>STABLE</cluster_state>")) {
notStable = false;
System.out.println("Cluster state is stable.");
}
}
boolean apiSvcUp = false;
while (!apiSvcUp) {
resp = rSys.path("/tenant").get(ClientResponse.class);
if (resp.getStatus() != 503) {
apiSvcUp = true;
} else {
try {
Thread.sleep(2000);
System.out.println("Waiting apisvc to be up");
} catch (InterruptedException e) {
_log.error(e.getMessage(), e);
}
}
}
}
/**
* create the httpclient, returns a BalancedWebResource that can be used the same
* way a WebResource is.
*/
protected BalancedWebResource createHttpClient(final String username, final String attribute, final String groups,
List<String> hostNames) {
BalancedWebResource lbw = new BalancedWebResource();
for (String h : hostNames) {
final ClientConfig config = new DefaultClientConfig();
final Client c = Client.create(config);
c.addFilter(new ClientFilter() {
@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
ArrayList<Object> headerValue = new ArrayList<Object>();
String userAndAttribute = username;
if (!attribute.isEmpty()) {
userAndAttribute += "," + attribute;
}
headerValue.add(userAndAttribute + ";" + groups);
request.getHeaders().put(NoAuthHeaderUserFilter.USER_INFO_HEADER_TAG, headerValue);
return getNext().handle(request);
}
});
lbw.addWebResource(c.resource(h));
}
return lbw;
}
public static String AUTH_TOKEN_HEADER = "X-SDS-AUTH-TOKEN";
public static String AUTH_PROXY_TOKEN_HEADER = "X-SDS-AUTH-PROXY-TOKEN";
protected Map<String, Object> _savedTokens = new HashMap<String, Object>();
protected Map<String, Object> _savedProxyTokens = new HashMap<String, Object>();
/**
* create the httpsclient, returns a BalancedWebResource that can be used the same
* way a WebResource is.
*/
protected BalancedWebResource createHttpsClient(final String username, final String password, List<String> hosts)
throws NoSuchAlgorithmException {
return createHttpsClient(username, password, hosts, true);
}
/**
* Use this when you need to toggle authfilters on and off, to test more specific behavior with tokens and
* no credentials
*/
protected String _lastUsedAuthTokenCookie = null;
protected BalancedWebResource createHttpsClient(final String username, final String password, List<String> hosts,
boolean addAuthFilters) throws NoSuchAlgorithmException {
String verb = System.getenv("API_TEST_VERBOSE");
boolean verbose = false;
if (verb != null && verb.equalsIgnoreCase("true")) {
verbose = true;
}
// Disable server certificate validation as we are using
// self-signed certificate
disableCertificateValidation();
BalancedWebResource lbw = new BalancedWebResource();
for (String h : hosts) {
final ClientConfig config = new DefaultClientConfig();
final Client c = Client.create(config);
if (verbose) {
c.addFilter(new LoggingFilter());
}
if (addAuthFilters) {
c.setFollowRedirects(false);
c.addFilter(new HTTPBasicAuthFilter(username, password));
c.addFilter(new ClientFilter() {
@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
if (_savedTokens.containsKey(username)) {
ArrayList<Object> token = new ArrayList<Object>();
token.add(_savedTokens.get(username));
request.getHeaders().put(AUTH_TOKEN_HEADER, token);
}
ClientResponse response = getNext().handle(request);
// save cookies for post request processing. Not being used in request itself.
// this only used to inspect cookies after the fact.
if (null == _lastUsedAuthTokenCookie) {
System.out.println("Cookie was null");
List<NewCookie> allCookies = response.getCookies();
System.out.println("Cookie list size:" + allCookies.size());
for (NewCookie ck : allCookies) {
System.out.print("Cookie name " + ck.getName());
if (ck.getName().equals(AUTH_TOKEN_HEADER)) {
_lastUsedAuthTokenCookie = ck.getValue();
break;
}
}
}
if (response.getHeaders() != null && response.getHeaders().get(AUTH_TOKEN_HEADER) != null) {
_savedTokens.put(username, response.getHeaders().getFirst(AUTH_TOKEN_HEADER));
}
if (response.getHeaders() != null && response.getHeaders().get(AUTH_PROXY_TOKEN_HEADER) != null) {
_savedProxyTokens.put(username, response.getHeaders().getFirst(AUTH_PROXY_TOKEN_HEADER));
}
if (response.getStatus() == 302) {
WebResource wb = c.resource(response.getLocation());
response = wb.header(AUTH_TOKEN_HEADER, _savedTokens.get(username)).get(ClientResponse.class);
}
return response;
}
});
} else {
c.setFollowRedirects(true);
}
lbw.addWebResource(c.resource(h));
}
return lbw;
}
/**
* Use this client if you want to use cookies instead of the http headers for holding the
* auth token
*/
protected Client createCookieHttpsClient(final String username, final String password)
throws NoSuchAlgorithmException {
// Disable server certificate validation as we are using
// self-signed certificate
disableCertificateValidation();
final ClientConfig config = new DefaultClientConfig();
final Client c = Client.create(config);
c.addFilter(new LoggingFilter());
c.setFollowRedirects(false);
c.addFilter(new HTTPBasicAuthFilter(username, password));
c.addFilter(new ClientFilter() {
private ArrayList<Object> cookies;
private ArrayList<Object> getCookiesToSet() {
if (cookies != null && !cookies.isEmpty()) {
ArrayList<Object> cookiesToSet = new ArrayList<Object>();
StringBuilder cookieToAdd = new StringBuilder();
for (Object cookieRaw : cookies) {
NewCookie cookie = (NewCookie) cookieRaw;
cookieToAdd.append(cookie.getName());
cookieToAdd.append("=");
cookieToAdd.append(cookie.getValue());
cookieToAdd.append("; ");
}
cookiesToSet.add(cookieToAdd);
return cookiesToSet;
}
return null;
}
@Override
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
ArrayList<Object> cookiesToSet = getCookiesToSet();
if (cookiesToSet != null) {
request.getHeaders().put("Cookie", cookiesToSet);
}
ClientResponse response = getNext().handle(request);
if (response.getCookies() != null) {
if (cookies == null) {
cookies = new ArrayList<Object>();
}
// simple addAll just for illustration (should probably check for duplicates and expired cookies)
cookies.addAll(response.getCookies());
}
if (response.getStatus() == 302) {
WebResource wb = c.resource(response.getLocation());
cookiesToSet = getCookiesToSet();
if (cookiesToSet != null) {
response = wb.header("Cookie", cookiesToSet).get(ClientResponse.class);
} else {
response = wb.get(ClientResponse.class);
}
}
return response;
}
});
return c;
}
public static void disableCertificateValidation() {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(final X509Certificate[] certs, final String authType) {
}
@Override
public void checkServerTrusted(final X509Certificate[] certs, final String authType) {
}
}
};
// Ignore differences between given hostname and certificate hostname
final HostnameVerifier hv = new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession session) {
return true;
}
};
// Install the all-trusting trust manager
try {
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
} catch (final Exception e) {
_log.error(e.getMessage(), e);
}
}
/**
* Some utilities structures
*
*
*
*/
protected static class ListElement {
@XmlElement
public URI id;
@XmlElement
public String name;
}
@XmlRootElement(name = "subtenants")
protected static class TenantList {
public TenantList() {
_subtenants = new ArrayList<ListElement>();
}
@XmlElement(name = "tenant")
public List<ListElement> _subtenants;
}
@XmlRootElement(name = "projects")
public static class ProjectList {
@XmlElement(name = "project")
public List<ProjectEntry> _projects = new ArrayList<ProjectEntry>();
}
@XmlRootElement(name = "tenant_project")
public static class ProjectEntry implements Comparable {
@XmlElement
public URI id;
@XmlElement
public String name;
public ProjectEntry() {
}
public ProjectEntry(URI i, String n) {
id = i;
name = n;
}
public ProjectEntry(ProjectEntry el) {
id = el.id;
name = el.name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ProjectEntry that = (ProjectEntry) o;
if (id != null ? !id.equals(that.id) : that.id != null) {
return false;
}
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
@Override
public int compareTo(Object o) {
if (!(o instanceof ProjectEntry)) {
throw new ClassCastException();
}
ProjectEntry e = (ProjectEntry) o;
return name.compareTo(e.name);
}
}
/**
* Utilities conversion methods
*
*
*
*/
protected StringSetMap convertRolesToMap(List<RoleAssignmentEntry> entries) {
StringSetMap assignments = new StringSetMap();
if (entries != null && !entries.isEmpty()) {
for (RoleAssignmentEntry roleAssignment : entries) {
PermissionsKey key;
if (roleAssignment.getGroup() != null) {
key = new PermissionsKey(PermissionsKey.Type.GROUP, roleAssignment.getGroup());
} else if (roleAssignment.getSubjectId() != null) {
key = new PermissionsKey(PermissionsKey.Type.SID, roleAssignment.getSubjectId());
} else {
continue;
}
for (String role : roleAssignment.getRoles()) {
assignments.put(key.toString(), role);
}
}
}
return assignments;
}
protected StringSetMap convertAclsToMap(List<ACLEntry> entries) {
StringSetMap assignments = new StringSetMap();
if (entries != null && !entries.isEmpty()) {
for (ACLEntry acl : entries) {
PermissionsKey key;
if (acl.getGroup() != null) {
key = new PermissionsKey(PermissionsKey.Type.GROUP, acl.getGroup());
} else if (acl.getSubjectId() != null) {
key = new PermissionsKey(PermissionsKey.Type.SID, acl.getSubjectId());
} else if (acl.getTenant() != null) {
key = new PermissionsKey(PermissionsKey.Type.TENANT, acl.getTenant());
} else {
continue;
}
for (String role : acl.getAces()) {
assignments.put(key.toString(), role.toUpperCase());
}
}
}
return assignments;
}
protected boolean checkEqualsRoles(List<RoleAssignmentEntry> expected,
List<RoleAssignmentEntry> got) {
if (expected != null && got != null) {
if (expected.size() != got.size()) {
return false;
}
if (!convertRolesToMap(expected).equals(convertRolesToMap(got))) {
return false;
}
return true;
}
return false;
}
protected boolean checkEqualsAcls(List<ACLEntry> expected,
List<ACLEntry> got) {
if (expected != null && got != null) {
if (expected.size() != got.size()) {
return false;
}
if (!convertAclsToMap(expected).equals(convertAclsToMap(got))) {
return false;
}
return true;
}
return false;
}
protected boolean checkEqualsList(List<ProjectEntry> gotElements, List<ProjectEntry> expected) {
if (expected != null && gotElements != null) {
if (expected.size() != gotElements.size()) {
return false;
}
Collections.sort(gotElements);
Collections.sort(expected);
if (!gotElements.equals(expected)) {
return false;
}
return true;
}
return false;
}
protected void assertExpectedError(final ClientResponse actualResponse,
final int expectedStatusCode, final ServiceCode expectedServiceCode,
final String expectedMessage) {
Assert.assertEquals(expectedStatusCode, actualResponse.getStatus());
try {
final ServiceErrorRestRep error = actualResponse.getEntity(ServiceErrorRestRep.class);
assertServiceError(expectedServiceCode.getCode(),
expectedServiceCode.getSummary(), expectedMessage, error);
} catch (final ClientHandlerException e) {
Assert.fail("Expected a ServiceError object");
}
}
private void assertServiceError(final int expectedServiceCode,
final String expectedDescription, final String expectedMessage,
final ServiceErrorRestRep actualError) {
Assert.assertEquals(expectedServiceCode, actualError.getCode());
Assert.assertEquals(expectedDescription, actualError.getCodeDescription());
Assert.assertEquals(expectedMessage, actualError.getDetailedMessage());
}
}