/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.db2;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.api.APIConfiguration;
import org.identityconnectors.framework.api.ConnectorFacade;
import org.identityconnectors.framework.api.ConnectorFacadeFactory;
import org.identityconnectors.framework.common.exceptions.AlreadyExistsException;
import org.identityconnectors.framework.common.exceptions.UnknownUidException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeInfo;
import org.identityconnectors.framework.common.objects.AttributeInfoUtil;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.ObjectClassInfo;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
import org.identityconnectors.framework.common.objects.ResultsHandler;
import org.identityconnectors.framework.common.objects.Schema;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.ContainsAllValuesFilter;
import org.identityconnectors.framework.common.objects.filter.EndsWithFilter;
import org.identityconnectors.framework.common.objects.filter.EqualsFilter;
import org.identityconnectors.framework.common.objects.filter.StartsWithFilter;
import org.identityconnectors.test.common.PropertyBag;
import org.identityconnectors.test.common.TestHelpers;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Test for {@link DB2Connector}
*
* @author kitko
*
*/
@Test(groups = { "integration" })
public class DB2ConnectorTest {
private static PropertyBag testProps;
private static DB2Configuration testConf;
private static ConnectorFacade facade;
/**
* Setup for all tests
*/
@BeforeClass
public static void setupClass() {
testConf = DB2ConfigurationTest.createTestConfiguration();
facade = createFacade(testConf);
testProps = TestHelpers.getProperties(DB2Connector.class);
}
private static ConnectorFacade createFacade(DB2Configuration conf) {
ConnectorFacadeFactory factory = ConnectorFacadeFactory.getInstance();
APIConfiguration apiCfg = TestHelpers.createTestConfiguration(DB2Connector.class, conf);
return factory.newInstance(apiCfg);
}
/**
* Just call test
*/
@Test
public void testTest() {
facade.test();
}
/**
* Test schema api
*/
@Test
public void testSchemaApi() {
Schema schema = facade.schema();
// Schema should not be null
assertNotNull(schema);
Set<ObjectClassInfo> objectInfos = schema.getObjectClassInfo();
assertNotNull(objectInfos);
assertEquals(1, objectInfos.size());
ObjectClassInfo objectInfo = (ObjectClassInfo) objectInfos.toArray()[0];
assertNotNull(objectInfo);
// the object class has to ACCOUNT_NAME
assertTrue(objectInfo.is(ObjectClass.ACCOUNT_NAME));
// iterate through AttributeInfo Set
Set<AttributeInfo> attInfos = objectInfo.getAttributeInfo();
assertNotNull(AttributeInfoUtil.find(Name.NAME, attInfos));
}
/**
* test successful Authenticate
*/
@Test
public void testAuthenticateSuc() {
String username = getTestRequiredProperty("testUser");
String password = getTestRequiredProperty("testPassword");
Map<String, Object> emptyMap = Collections.emptyMap();
facade.authenticate(ObjectClass.ACCOUNT, username,
new GuardedString(password.toCharArray()), new OperationOptions(emptyMap));
}
/**
* Test fail of Authenticate
*/
@Test(expectedExceptions = RuntimeException.class)
public void testAuthenticateFail() {
String username = "undefined";
String password = "testPassword";
Map<String, Object> emptyMap = Collections.emptyMap();
facade.authenticate(ObjectClass.ACCOUNT, username,
new GuardedString(password.toCharArray()), new OperationOptions(emptyMap));
}
static Connection createTestConnection() throws Exception {
DB2Configuration conf = DB2ConfigurationTest.createTestConfiguration();
return conf.createAdminConnection();
}
static String getTestRequiredProperty(String name) {
String value = testProps.getStringProperty(name);
return value;
}
/**
* test create
*/
@Test
public void testCreate() {
String username = getTestRequiredProperty("testUser");
Map<String, Object> emptyMap = Collections.emptyMap();
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(new Name(username));
// attributes.add(AttributeBuilder.buildPassword(new
// char[]{'a','b','c'}));
attributes
.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "CONNECT ON DATABASE"));
Uid uid = null;
try {
uid = facade.create(ObjectClass.ACCOUNT, attributes, new OperationOptions(emptyMap));
assertNotNull(uid);
} catch (AlreadyExistsException e) {
facade.delete(ObjectClass.ACCOUNT, new Uid(username), new OperationOptions(emptyMap));
uid = facade.create(ObjectClass.ACCOUNT, attributes, new OperationOptions(emptyMap));
assertNotNull(uid);
}
// find user
uid = findUser(username);
assertNotNull("Cannot find new created user", uid);
}
private Uid createTestUser() {
String userName = getTestRequiredProperty("testUser");
return createTestUser(userName);
}
private Uid createTestUser(String userName) {
Map<String, Object> emptyMap = Collections.emptyMap();
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(new Name(userName));
// attributes.add(AttributeBuilder.buildPassword(new
// char[]{'a','b','c'}));
attributes
.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "CONNECT ON DATABASE"));
Uid uid = null;
try {
uid = facade.create(ObjectClass.ACCOUNT, attributes, new OperationOptions(emptyMap));
assertNotNull(uid);
return uid;
} catch (AlreadyExistsException e) {
return new Uid(userName);
}
}
/**
* Test delete of user
*/
@Test
public void testDelete() {
String username = testProps.getProperty("testUser", String.class, "TEST");
Map<String, Object> emptyMap = Collections.emptyMap();
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(new Name(username));
attributes.add(AttributeBuilder.buildPassword(new char[] { 'a', 'b', 'c' }));
Uid uid = findUser(username);
if (uid == null) {
uid = facade.create(ObjectClass.ACCOUNT, attributes, new OperationOptions(emptyMap));
assertNotNull(uid);
}
facade.delete(ObjectClass.ACCOUNT, new Uid(username), new OperationOptions(emptyMap));
uid = findUser(username);
assertNull("User not deleted", uid);
}
private Uid findUser(String name) {
final Uid expected = new Uid(name);
FindUidObjectHandler handler = new FindUidObjectHandler(expected);
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(expected), handler, null);
final Uid actual = handler.getFoundUID();
return actual;
}
/**
* test find by uid
*/
@Test
public void testFindUserByUid() {
String username = testProps.getProperty("testUser", String.class, "TEST");
createTestUser();
final Uid expected = new Uid(username);
FindUidObjectHandler handler = new FindUidObjectHandler(expected);
// attempt to find the newly created object..
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(expected), handler, null);
assertTrue("The testuser was not found", handler.found);
final Uid actual = handler.getFoundUID();
assertNotNull(actual);
assertTrue(actual.is(expected.getName()));
}
/**
* Test searching by grants attribute
*/
@Test
public void testFindByGrants() {
AllResultsHandler handler = new AllResultsHandler();
facade.search(ObjectClass.ACCOUNT, null, handler, null);
for (ConnectorObject object : handler.getResults()) {
final String uidValue = object.getUid().getUidValue().toUpperCase();
if (!uidValue.startsWith("db2inst".toUpperCase())
&& !uidValue.startsWith("db2admin".toUpperCase())) {
facade.delete(ObjectClass.ACCOUNT, object.getUid(), null);
}
}
Attribute grants1 =
AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "LOAD ON DATABASE",
"SELECT ON SYSCAT.TABLES");
Set<Attribute> attributes1 = new HashSet<Attribute>();
attributes1.add(grants1);
attributes1.add(new Name("TEST1"));
Uid testUid1 = facade.create(ObjectClass.ACCOUNT, attributes1, null);
assertNotNull(testUid1);
Attribute grants2 =
AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "LOAD ON DATABASE",
"SELECT ON SYSCAT.TABLES");
Set<Attribute> attributes2 = new HashSet<Attribute>();
attributes2.add(grants2);
attributes2.add(new Name("TEST2"));
Uid testUid2 = facade.create(ObjectClass.ACCOUNT, attributes2, null);
assertNotNull(testUid2);
Attribute grants3 =
AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "LOAD ON DATABASE");
Set<Attribute> attributes3 = new HashSet<Attribute>();
attributes3.add(grants3);
attributes3.add(new Name("TEST3"));
Uid testUid3 = facade.create(ObjectClass.ACCOUNT, attributes3, null);
assertNotNull(testUid3);
handler.clear();
facade.search(ObjectClass.ACCOUNT, new ContainsAllValuesFilter(grants1), handler,
new OperationOptionsBuilder().setAttributesToGet(
Arrays.asList(DB2Connector.USER_AUTH_GRANTS)).build());
assertTrue(!handler.getResults().isEmpty());
assertTrue(handler.getResultUids().contains(new Uid("TEST1")));
assertTrue(handler.getResultUids().contains(new Uid("TEST2")));
assertFalse(handler.getResultUids().contains(new Uid("TEST3")));
}
/**
* Test find by end with operator
*/
@Test
public void testFindUserByEndWith() {
String username = testProps.getProperty("testUser", String.class, "TEST");
createTestUser();
final Attribute expected = AttributeBuilder.build(Name.NAME, username);
FindUidObjectHandler handler = new FindUidObjectHandler(new Uid(username));
// attempt to find the newly created object..
facade.search(ObjectClass.ACCOUNT, new EndsWithFilter(expected), handler, null);
assertTrue("The user was not found", handler.found);
final ConnectorObject actual = handler.getFoundObject();
assertNotNull(actual);
assertEquals("Expected user is not same", username.toUpperCase(), AttributeUtil
.getAsStringValue(actual.getName()).toUpperCase());
}
/**
* test find by start with operator
*/
@Test
public void testFindUserByStartWith() {
String username = testProps.getProperty("testUser", String.class, "TEST");
createTestUser();
final Attribute expected = AttributeBuilder.build(Name.NAME, username);
FindUidObjectHandler handler = new FindUidObjectHandler(new Uid(username));
// attempt to find the newly created object..
facade.search(ObjectClass.ACCOUNT, new StartsWithFilter(expected), handler, null);
assertTrue("The user was not found", handler.found);
final ConnectorObject actual = handler.getFoundObject();
assertNotNull(actual);
assertEquals("Expected user is not same", username.toUpperCase(), AttributeUtil
.getAsStringValue(actual.getName()).toUpperCase());
}
/**
* Test find by uid and check grants attribute
*/
@Test
public void testFindCheckAttributes() {
String username = testProps.getProperty("testUser", String.class, "TEST");
final Uid expected = new Uid(username);
createTestUser();
FindUidObjectHandler handler = new FindUidObjectHandler(new Uid(username));
OperationOptionsBuilder builder = new OperationOptionsBuilder();
builder.setAttributesToGet(Arrays.asList(Name.NAME, DB2Connector.USER_AUTH_GRANTS));
OperationOptions options = builder.build();
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(expected), handler, options);
assertTrue("The user was not found", handler.found);
final ConnectorObject actual = handler.getFoundObject();
assertNotNull(actual);
final Attribute grants = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS);
assertNotNull(grants);
assertNotNull(grants.getValue());
}
/**
* Testing update
*/
@Test
public void testUpdate() {
String username = getTestRequiredProperty("testUser");
final Uid uid = new Uid(username);
createTestUser();
FindUidObjectHandler handler = new FindUidObjectHandler(new Uid(username));
OperationOptionsBuilder builder = new OperationOptionsBuilder();
builder.setAttributesToGet(Arrays.asList(Name.NAME, DB2Connector.USER_AUTH_GRANTS));
OperationOptions options = builder.build();
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
ConnectorObject actual = handler.getFoundObject();
assertNotNull(actual);
Attribute grants1 = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS);
Attribute oldGrants = grants1;
grants1 =
AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "LOAD ON DATABASE",
"SELECT ON SYSCAT.TABLES");
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(grants1);
Map<String, Object> emptyMap = Collections.emptyMap();
// Test add
facade.addAttributeValues(ObjectClass.ACCOUNT, uid, attributes, new OperationOptions(
emptyMap));
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
actual = handler.getFoundObject();
List<Object> newGrantsValue =
actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS).getValue();
assertTrue(newGrantsValue.contains("LOAD ON DATABASE"));
assertTrue(newGrantsValue.contains("CONNECT ON DATABASE"));
assertTrue(newGrantsValue.contains("SELECT ON SYSCAT.TABLES"));
// Test replace
handler.clear();
attributes.clear();
attributes.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS,
"SELECT ON SYSCAT.TABLES"));
facade.update(ObjectClass.ACCOUNT, uid, attributes, new OperationOptions(emptyMap));
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
actual = handler.getFoundObject();
newGrantsValue = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS).getValue();
assertFalse(newGrantsValue.contains("LOAD ON DATABASE"));
assertTrue(newGrantsValue.contains("CONNECT ON DATABASE"));
assertTrue(newGrantsValue.contains("SELECT ON SYSCAT.TABLES"));
// Test delete
handler.clear();
facade.removeAttributeValues(ObjectClass.ACCOUNT, uid, AttributeUtil.filterUid(attributes),
new OperationOptions(emptyMap));
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
actual = handler.getFoundObject();
newGrantsValue = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS).getValue();
assertFalse(newGrantsValue.contains("LOAD ON DATABASE"));
assertTrue(newGrantsValue.contains("CONNECT ON DATABASE"));
assertFalse(newGrantsValue.contains("SELECT ON SYSCAT.TABLES"));
// test replace/add using DB2Configuration.isReplaceAllGrantsOnUpdate
// switch
// Test replace
final DB2Configuration testConfiguration = DB2ConfigurationTest.createTestConfiguration();
testConfiguration.setReplaceAllGrantsOnUpdate(true);
ConnectorFacade testFacade = createFacade(testConfiguration);
attributes.clear();
attributes.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS,
"SELECT ON SYSCAT.TABLES"));
testFacade.update(ObjectClass.ACCOUNT, uid, attributes, new OperationOptions(emptyMap));
testFacade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
actual = handler.getFoundObject();
newGrantsValue = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS).getValue();
assertFalse(newGrantsValue.contains("LOAD ON DATABASE"));
assertTrue(newGrantsValue.contains("CONNECT ON DATABASE"));
assertTrue(newGrantsValue.contains("SELECT ON SYSCAT.TABLES"));
// Test add
testConfiguration.setReplaceAllGrantsOnUpdate(false);
testFacade = createFacade(testConfiguration);
attributes.clear();
attributes.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "LOAD ON DATABASE"));
testFacade.update(ObjectClass.ACCOUNT, uid, attributes, new OperationOptions(emptyMap));
testFacade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, options);
actual = handler.getFoundObject();
newGrantsValue = actual.getAttributeByName(DB2Connector.USER_AUTH_GRANTS).getValue();
assertTrue(newGrantsValue.contains("LOAD ON DATABASE"));
assertTrue(newGrantsValue.contains("CONNECT ON DATABASE"));
assertTrue(newGrantsValue.contains("SELECT ON SYSCAT.TABLES"));
// Reset to old value
attributes.clear();
attributes.add(oldGrants);
facade.update(ObjectClass.ACCOUNT, uid, attributes, new OperationOptions(emptyMap));
}
private static class FindUidObjectHandler implements ResultsHandler {
private ConnectorObject connectorObject = null;
private boolean found = false;
private final Uid uid;
/**
* @param uid
*/
public FindUidObjectHandler(Uid uid) {
this.uid = uid;
}
ConnectorObject getFoundObject() {
return connectorObject;
}
Uid getFoundUID() {
return connectorObject != null ? connectorObject.getUid() : null;
}
void clear() {
found = false;
connectorObject = null;
}
public boolean handle(ConnectorObject obj) {
System.out.println("Object: " + obj);
if (obj.getUid().getUidValue().equalsIgnoreCase(uid.getUidValue())) {
found = true;
connectorObject = obj;
return false;
}
return true;
}
}
private static class AllResultsHandler implements ResultsHandler {
private List<ConnectorObject> results = new ArrayList<ConnectorObject>();
public boolean handle(ConnectorObject obj) {
results.add(obj);
return true;
}
List<ConnectorObject> getResults() {
return Collections.unmodifiableList(results);
}
void clear() {
results.clear();
}
List<Uid> getResultUids() {
List<Uid> uids = new ArrayList<Uid>(results.size());
for (ConnectorObject co : results) {
uids.add(co.getUid());
}
return uids;
}
}
/**
* Tests deleting user that does not exist
*/
@Test(expectedExceptions = UnknownUidException.class)
public void testDeleteUnexisting() {
assertNotNull(facade);
String userName = "delUser";
Uid uid = createTestUser(userName);
uid = findUser(userName);
assertNotNull(uid);
facade.delete(ObjectClass.ACCOUNT, uid, null);
uid = findUser(userName);
assertNull(uid);
facade.delete(ObjectClass.ACCOUNT, new Uid("UNKNOWN"), null);
Assert.fail("Delete of not existing user should fail");
}
/**
* Tests more creates
*/
@Test
public void testMultiCreate() {
for (int i = 0; i < 10; i++) {
String userName = "testUser" + i;
Uid uid = new Uid(userName);
try {
facade.delete(ObjectClass.ACCOUNT, uid, null);
} catch (UnknownUidException e) {
}
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(new Name(userName));
// attributes.add(AttributeBuilder.buildPassword(new
// char[]{'a','b','c'}));
attributes.add(AttributeBuilder.build("grants", "CONNECT ON DATABASE"));
facade.create(ObjectClass.ACCOUNT, attributes, null);
FindUidObjectHandler handler = new FindUidObjectHandler(uid);
// attempt to find the newly created object..
try {
facade.search(ObjectClass.ACCOUNT, new EqualsFilter(uid), handler, null);
assertTrue("The testuser was not found", handler.found);
} finally {
facade.delete(ObjectClass.ACCOUNT, uid, null);
}
}
}
/**
* Test validity of names for create
*/
@Test
public void testValidNamesOnCreate() {
// too long name
char[] goodName = new char[DB2Specifics.MAX_NAME_SIZE];
char[] tooLongName = new char[DB2Specifics.MAX_NAME_SIZE + 1];
for (int i = 0; i < tooLongName.length; i++) {
tooLongName[i] = ('a');
}
System.arraycopy(tooLongName, 0, goodName, 0, goodName.length);
String invalid1 = "%";
String invalid2 = "SQL";
String invalid3 = "DATABASE";
Set<Attribute> attributes = new HashSet<Attribute>();
attributes.add(new Name(new String(tooLongName)));
// attributes.add(AttributeBuilder.buildPassword(new
// char[]{'a','b','c'}));
attributes
.add(AttributeBuilder.build(DB2Connector.USER_AUTH_GRANTS, "CONNECT ON DATABASE"));
try {
facade.create(ObjectClass.ACCOUNT, attributes, null);
Assert.fail("Validate should fail : too long user name");
} catch (IllegalArgumentException e) {
}
attributes.remove(new Name(new String(tooLongName)));
attributes.add(new Name(new String(goodName)));
Uid uid = facade.create(ObjectClass.ACCOUNT, attributes, null);
facade.delete(ObjectClass.ACCOUNT, uid, null);
attributes.remove(new Name(new String(goodName)));
attributes.add(new Name(new String(invalid1)));
try {
facade.create(ObjectClass.ACCOUNT, attributes, null);
Assert.fail("Validate should fail : Invalid character name");
} catch (IllegalArgumentException e) {
}
attributes.remove(new Name(invalid1));
attributes.add(new Name(new String(invalid2)));
try {
facade.create(ObjectClass.ACCOUNT, attributes, null);
Assert.fail("Validate should fail : Invalid prefix");
} catch (IllegalArgumentException e) {
}
attributes.remove(new Name(invalid2));
attributes.add(new Name(new String(invalid3)));
try {
facade.create(ObjectClass.ACCOUNT, attributes, null);
Assert.fail("Validate should fail : Reserved keyword");
} catch (IllegalArgumentException e) {
}
}
/** Test valid names */
@Test
public void testDB2Validity() {
DB2Connector connector = new DB2Connector();
connector.init(testConf);
connector.checkDB2Validity("TEST1");
connector.checkDB2Validity("#TEST1");
testFailForValidity(connector, "ABCDEFGHIJKLMNOPRSTABCDEFGHIJKLMNO",
"Must fail for too long name");
testFailForValidity(connector, "US%US", "Must fail for invalid char");
}
@Test(enabled = false)
private void testFailForValidity(DB2Connector connector, String name, String msg) {
try {
connector.checkDB2Validity(name);
Assert.fail(msg);
} catch (RuntimeException e) {
}
}
}