/*
* ====================
* 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.solaris.operation;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.Set;
import org.identityconnectors.common.CollectionUtil;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
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.OperationOptionsBuilder;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
import org.identityconnectors.solaris.attr.AccountAttribute;
import org.identityconnectors.solaris.attr.ConnectorAttribute;
import org.identityconnectors.solaris.attr.NativeAttribute;
import org.identityconnectors.solaris.test.SolarisTestBase;
import org.identityconnectors.test.common.ToListResultsHandler;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;
/**
* Set of password attribute related tests.
*
* These attributes are: {@link NativeAttribute#MAX_DAYS_BETWEEN_CHNG},
* {@link NativeAttribute#MAX_DAYS_BETWEEN_CHNG}, {@link NativeAttribute#LOCK},
* {@link NativeAttribute#DAYS_BEFORE_TO_WARN}.
*
* Prerequisite of this test is to have password aging enabled in
* /etc/default/passwd: MAXWEEKS=2 MINWEEKS=1 HISTORY=10 {@link https
* ://blogs.oracle.com/gbrunett/entry/solaris_10_password_history}
*
* @author David Adam
* @see <a
* href=https://blogs.oracle.com/gbrunett/entry/solaris_10_password_history
* >Solaris 10 password history</a>
*/
public class PasswdCommandTest extends SolarisTestBase {
private static Log log = Log.getLog(PasswdCommandTest.class);
/**
* order of setting the password aging attributes should be respected: max,
* min, warn.
*/
@Test
public void testPasswordAgingAttributesWithUpdate() {
if (getConnection().isNis()) {
log.info("skipping test 'testPasswordAgingAttributesWithUpdate' for NIS configuration, as it is not supported there.");
return;
}
String username = getUsername();
Set<Attribute> passwordAgingAttrs =
CollectionUtil.newSet(AttributeBuilder.build(AccountAttribute.MIN.getName(), 2),
AttributeBuilder.build(AccountAttribute.MAX.getName(), 5), AttributeBuilder
.build(AccountAttribute.WARN.getName(), 4));
getFacade().update(ObjectClass.ACCOUNT, new Uid(username), passwordAgingAttrs, null);
ToListResultsHandler handler = new ToListResultsHandler();
getFacade().search(
ObjectClass.ACCOUNT,
FilterBuilder.equalTo(AttributeBuilder.build(Name.NAME, username)),
handler,
new OperationOptionsBuilder().setAttributesToGet(
CollectionUtil.newSet(AccountAttribute.MAX.getName(), AccountAttribute.MIN
.getName(), AccountAttribute.WARN.getName())).build());
assertTrue(handler.getObjects().size() >= 1);
ConnectorObject result = handler.getObjects().get(0);
assertTrue(controlAttributeValue(2, AccountAttribute.MIN, result));
assertTrue(controlAttributeValue(5, AccountAttribute.MAX, result));
assertTrue(controlAttributeValue(4, AccountAttribute.WARN, result));
}
@Test
public void testPasswordAgingAttributesWithCreate() {
if (getConnection().isNis()) {
log.info("skipping test 'testPasswordAgingAttributesWithCreate' for NIS configuration, as it is not supported there.");
return;
}
String username = "batman";
ToListResultsHandler handler = new ToListResultsHandler();
getFacade().search(ObjectClass.ACCOUNT,
FilterBuilder.equalTo(AttributeBuilder.build(Name.NAME, username)), handler, null);
assertTrue(handler.getObjects().size() <= 0, "user '" + username + "' should be cleaned up");
try {
Set<Attribute> attrs =
CollectionUtil.newSet(AttributeBuilder.build(Name.NAME, username),
AttributeBuilder.build(AccountAttribute.MIN.getName(), 1),
AttributeBuilder.build(AccountAttribute.MAX.getName(), 4),
AttributeBuilder.build(AccountAttribute.WARN.getName(), 2));
getFacade().create(ObjectClass.ACCOUNT, attrs, null);
getFacade().search(
ObjectClass.ACCOUNT,
FilterBuilder.equalTo(AttributeBuilder.build(Name.NAME, username)),
handler,
new OperationOptionsBuilder().setAttributesToGet(
CollectionUtil
.newSet(AccountAttribute.MAX.getName(), AccountAttribute.MIN
.getName(), AccountAttribute.WARN.getName())).build());
assertTrue(handler.getObjects().size() >= 1);
ConnectorObject result = handler.getObjects().get(0);
assertTrue(controlAttributeValue(1, AccountAttribute.MIN, result));
assertTrue(controlAttributeValue(4, AccountAttribute.MAX, result));
assertTrue(controlAttributeValue(2, AccountAttribute.WARN, result));
} finally {
try {
getFacade().delete(ObjectClass.ACCOUNT, new Uid(username), null);
} catch (Exception ex) {
// OK
}
}
}
private boolean controlAttributeValue(int i, ConnectorAttribute attr, ConnectorObject co) {
Attribute attrFound = co.getAttributeByName(attr.getName());
Object valueFound = AttributeUtil.getSingleValue(attrFound);
return valueFound.equals(i);
}
/**
* Test for {@link NativeAttribute#LOCK}.
*
* If an account is locked, authentication should fail.
*/
@Test
public void testLock() {
if (getConnection().isNis()) {
// TODO Workaround on Solaris NIS: there doesn't seem to be a way
// how to handle user locks on NIS.
log.info("skipping test 'testLock', as LOCK attribute is not supported by the connector on NIS.");
return;
}
String username = getUsername();
enableTrustedLogin(username);
GuardedString password = new GuardedString(SAMPLE_PASSWD.toCharArray());
// authentication involves login, so try to authenticate
try {
getFacade().authenticate(ObjectClass.ACCOUNT, username, password, null);
} catch (Exception ex) {
fail("failed to authenticate freshly created user: " + username);
}
// lock the account, then authenticate should fail
getFacade().update(
ObjectClass.ACCOUNT,
new Uid(username),
CollectionUtil.newSet(AttributeBuilder.build(AccountAttribute.LOCK.getName(),
Boolean.TRUE)), null);
try {
getFacade().authenticate(ObjectClass.ACCOUNT, username, password, null);
fail("Locked account should not able to login.");
} catch (Exception ex) {
// OK
}
}
/**
* Test for {@link NativeAttribute#LOCK}
*
* If an account is unlocked authentication should succeed. {@see
* PasswdCommandTest#testLock()}
*/
@Test
public void testUnLock() {
if (getConnection().isNis()) {
// TODO Workaround on Solaris NIS: there doesn't seem to be a way
// how to handle user locks on NIS.
log.info("skipping test 'testLock', as LOCK attribute is not supported by the connector on NIS.");
return;
}
String username = "connuser";
GuardedString passwd = new GuardedString("foo123".toCharArray());
// create a locked account, login should fail
try {
getFacade().create(
ObjectClass.ACCOUNT,
CollectionUtil.newSet(AttributeBuilder.build(Name.NAME, username),
AttributeBuilder.buildPassword(passwd), AttributeBuilder.build(
AccountAttribute.LOCK.getName(), Boolean.TRUE)), null);
enableTrustedLogin(username);
try {
getFacade().authenticate(ObjectClass.ACCOUNT, username, passwd, null);
AssertJUnit
.fail("expecting to fail when we attempt to authenticate a locked account.");
} catch (Exception ex) {
// OK
}
// unlock the account, authenticate should succeed.
getFacade().update(
ObjectClass.ACCOUNT,
new Uid(username),
CollectionUtil.newSet(AttributeBuilder.build(AccountAttribute.LOCK.getName(),
Boolean.FALSE)), null);
try {
getFacade().authenticate(ObjectClass.ACCOUNT, username, passwd, null);
} catch (Exception ex) {
AssertJUnit
.fail("authentication of an unlocked account should pass, but received a failure.");
}
} finally {
getFacade().delete(ObjectClass.ACCOUNT, new Uid(username), null);
}
}
/**
* null is unacceptable value for LOCK attribute.
*/
@Test
public void testFailLock() {
if (getConnection().isNis()) {
// TODO Workaround on Solaris NIS: there doesn't seem to be a way
// how to handle user locks on NIS.
log.info("skipping test 'testLock', as LOCK attribute is not supported by the connector on NIS.");
return;
}
try {
getFacade().update(ObjectClass.ACCOUNT, new Uid(getUsername()),
CollectionUtil.newSet(AttributeBuilder.build(AccountAttribute.LOCK.getName())),
null);
AssertJUnit
.fail("passing null option to Lock should cause failure. It must have a boolean value.");
} catch (Exception ex) {
// OK
}
try {
getFacade().create(
ObjectClass.ACCOUNT,
CollectionUtil.newSet(AttributeBuilder.build(Name.NAME, "fooconn"),
AttributeBuilder.buildPassword("foo134".toCharArray()),
AttributeBuilder.build(AccountAttribute.LOCK.getName())), null);
AssertJUnit
.fail("passing null option to Lock should cause failure. It must have a boolean value.");
} catch (Exception ex) {
// OK
} finally {
try {
getFacade().delete(ObjectClass.ACCOUNT, new Uid("foo134"), null);
} catch (Exception ex) {
// OK
}
}
}
@Override
public boolean createGroup() {
return false;
}
@Override
public int getCreateUsersNumber() {
return 1;
}
private String getUsername() {
return getUsername(0);
}
}