/*
* DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2014 ForgeRock AS. All rights reserved.
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (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/CDDL-1.0
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://opensource.org/licenses/CDDL-1.0
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*/
#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
#if ($ALL_OPERATIONS == 'Y' || $ALL_OPERATIONS == 'y')
#set( $all_operations_safe = true)
#end
#if ( $poolableConnector == 'Y' || $poolableConnector == 'y' )
#set( $poolable_connector_safe = true)
#end
#if ( $attributeNormalizer == 'Y' || $attributeNormalizer == 'y')
#set( $attribute_normalizer_safe = true)
#end
#if ( $all_operations_safe || $OP_AUTHENTICATE == 'Y' || $OP_AUTHENTICATE == 'y' )
#set( $op_authenticate_safe = true)
#end
#if ( $all_operations_safe || $OP_CREATE == 'Y' || $OP_CREATE == 'y')
#set( $op_create_safe = true)
#end
#if ( $all_operations_safe || $OP_DELETE == 'Y' || $OP_DELETE == 'y' )
#set( $op_delete_safe = true)
#end
#if ( $all_operations_safe || $OP_RESOLVEUSERNAME == 'Y' || $OP_RESOLVEUSERNAME == 'y')
#set( $op_resolveusername_safe = true)
#end
#if ( $all_operations_safe || $OP_SCHEMA == 'Y' || $OP_SCHEMA == 'y' )
#set( $op_schema_safe = true)
#end
#if ( $all_operations_safe || $OP_SCRIPTONCONNECTOR == 'Y' || $OP_SCRIPTONCONNECTOR == 'y')
#set( $op_scriptonconnector_safe = true)
#end
#if ( $all_operations_safe || $OP_SCRIPTONRESOURCE == 'Y' || $OP_SCRIPTONRESOURCE == 'y' )
#set( $op_scriptonresource_safe = true)
#end
#if ( $all_operations_safe || $OP_SEARCH == 'Y' || $OP_SEARCH == 'y')
#set( $op_search_safe = true)
#end
#if ( $all_operations_safe || $OP_SYNC == 'Y' || $OP_SYNC == 'y' )
#set( $op_sync_safe = true)
#end
#if ( $all_operations_safe || $OP_TEST == 'Y' || $OP_TEST == 'y')
#set( $op_test_safe = true)
#end
#if ( $all_operations_safe || $OP_UPDATEATTRIBUTEVALUES == 'Y' || $OP_UPDATEATTRIBUTEVALUES == 'y' )
#set( $op_updateattributevalues_safe = true)
#end
#if ( $all_operations_safe || $OP_UPDATE == 'Y' || $OP_UPDATE == 'y')
#set( $op_update_safe = true)
#end
package ${package};
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.Set;
import org.identityconnectors.common.Assertions;
import org.identityconnectors.common.CollectionUtil;
import org.identityconnectors.common.StringUtil;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.script.ScriptExecutor;
import org.identityconnectors.common.script.ScriptExecutorFactory;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.common.security.SecurityUtil;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeInfoBuilder;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.AttributesAccessor;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.ConnectorObjectBuilder;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder;
import org.identityconnectors.framework.common.objects.OperationOptionInfoBuilder;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.OperationalAttributeInfos;
import org.identityconnectors.framework.common.objects.PredefinedAttributeInfos;
import org.identityconnectors.framework.common.objects.ResultsHandler;
import org.identityconnectors.framework.common.objects.Schema;
import org.identityconnectors.framework.common.objects.SchemaBuilder;
import org.identityconnectors.framework.common.objects.ScriptContext;
import org.identityconnectors.framework.common.objects.SearchResult;
import org.identityconnectors.framework.common.objects.SyncDelta;
import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.identityconnectors.framework.common.objects.SyncResultsHandler;
import org.identityconnectors.framework.common.objects.SyncToken;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.spi.AttributeNormalizer;
import org.identityconnectors.framework.spi.Configuration;
import org.identityconnectors.framework.spi.ConnectorClass;
#if ( $poolable_connector_safe )
import org.identityconnectors.framework.spi.PoolableConnector;
#else
import org.identityconnectors.framework.spi.Connector;
#end
import org.identityconnectors.framework.spi.SearchResultsHandler;
import org.identityconnectors.framework.spi.SyncTokenResultsHandler;
import org.identityconnectors.framework.spi.operations.AuthenticateOp;
import org.identityconnectors.framework.spi.operations.CreateOp;
import org.identityconnectors.framework.spi.operations.DeleteOp;
import org.identityconnectors.framework.spi.operations.ResolveUsernameOp;
import org.identityconnectors.framework.spi.operations.SchemaOp;
import org.identityconnectors.framework.spi.operations.ScriptOnConnectorOp;
import org.identityconnectors.framework.spi.operations.ScriptOnResourceOp;
import org.identityconnectors.framework.spi.operations.SearchOp;
import org.identityconnectors.framework.spi.operations.SyncOp;
import org.identityconnectors.framework.spi.operations.TestOp;
import org.identityconnectors.framework.spi.operations.UpdateAttributeValuesOp;
import org.identityconnectors.framework.spi.operations.UpdateOp;
/**
* Main implementation of the ${connectorName} Connector.
*
*/
#set( $connectorName = $connector_name.toLowerCase())
@ConnectorClass(
displayNameKey = "${connectorName}.connector.display",
configurationClass = ${connectorName}Configuration.class)
public class ${connectorName}Connector implements #if($poolable_connector_safe)PoolableConnector#{else}Connector#end#if ( $attribute_normalizer_safe ), AttributeNormalizer#end#if ( $op_authenticate_safe ), AuthenticateOp#end#if ( $op_create_safe ), CreateOp#end#if ( $op_delete_safe ), DeleteOp#end#if ( $op_resolveusername_safe ), ResolveUsernameOp#end#if ( $op_schema_safe ), SchemaOp#end#if ( $op_scriptonconnector_safe ), ScriptOnConnectorOp#end#if ( $op_scriptonresource_safe ), ScriptOnResourceOp#end#if ( $op_search_safe ), SearchOp<String>#end#if ( $op_sync_safe ), SyncOp#end#if ( $op_test_safe ), TestOp#end#if ( $op_updateattributevalues_safe ), UpdateAttributeValuesOp#elseif ( $op_update_safe ), UpdateOp#end {
/**
* Setup logging for the {@link ${connectorName}Connector}.
*/
private static final Log logger = Log.getLog(${connectorName}Connector.class);
/**
* Place holder for the {@link Configuration} passed into the init() method
* {@link ${connectorName}Connector${symbol_pound}init(org.identityconnectors.framework.spi.Configuration)}.
*/
private ${connectorName}Configuration configuration;
private Schema schema = null;
/**
* Gets the Configuration context for this connector.
*
* @return The current {@link Configuration}
*/
public Configuration getConfiguration() {
return this.configuration;
}
/**
* Callback method to receive the {@link Configuration}.
*
* @param configuration the new {@link Configuration}
* @see org.identityconnectors.framework.spi.Connector${symbol_pound}init(org.identityconnectors.framework.spi.Configuration)
*/
public void init(final Configuration configuration) {
this.configuration = (${connectorName}Configuration) configuration;
}
/**
* Disposes of the {@link ${connectorName}Connector}'s resources.
*
* @see org.identityconnectors.framework.spi.Connector${symbol_pound}dispose()
*/
public void dispose() {
configuration = null;
}
#if ( $poolable_connector_safe )
/**
* {@inheritDoc}
*/
public void checkAlive() {
// Do some cheap operartion to verify it's a healty Connector instance from the pool.
}
#end
#if ( $attribute_normalizer_safe )
/**
* {@inheritDoc}
*/
public Attribute normalizeAttribute(ObjectClass oclass, Attribute attribute) {
if (AttributeUtil.namesEqual(attribute.getName(), Uid.NAME)) {
return new Uid(AttributeUtil.getStringValue(attribute).toLowerCase(Locale.US));
}
return attribute;
}
#end
/******************
* SPI Operations
*
* Implement the following operations using the contract and
* description found in the Javadoc for these methods.
******************/
#if ( $op_authenticate_safe )
/**
* {@inheritDoc}
*/
public Uid authenticate(final ObjectClass objectClass, final String userName,
final GuardedString password, final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objectClass)) {
return new Uid(userName);
} else {
logger.warn("Authenticate of type {0} is not supported", configuration
.getConnectorMessages().format(objectClass.getDisplayNameKey(),
objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Authenticate of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
}
#end
#if ( $op_resolveusername_safe )
/**
* {@inheritDoc}
*/
public Uid resolveUsername(final ObjectClass objectClass, final String userName,
final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objectClass)) {
return new Uid(userName);
} else {
logger.warn("ResolveUsername of type {0} is not supported", configuration
.getConnectorMessages().format(objectClass.getDisplayNameKey(),
objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("ResolveUsername of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
}
#end
#if ( $op_create_safe )
/**
* {@inheritDoc}
*/
public Uid create(final ObjectClass objectClass, final Set<Attribute> createAttributes,
final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objectClass) || ObjectClass.GROUP.equals(objectClass)) {
Name name = AttributeUtil.getNameFromAttributes(createAttributes);
if (name != null) {
// do real create here
return new Uid(AttributeUtil.getStringValue(name).toLowerCase(Locale.US));
} else {
throw new InvalidAttributeValueException("Name attribute is required");
}
} else {
logger.warn("Create of type {0} is not supported", configuration.getConnectorMessages()
.format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Create of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
}
#end
#if ( $op_delete_safe )
/**
* {@inheritDoc}
*/
public void delete(final ObjectClass objectClass, final Uid uid, final OperationOptions options) {
if (ObjectClass.ACCOUNT.equals(objectClass) || ObjectClass.GROUP.equals(objectClass)) {
// do real delete here
} else {
logger.warn("Delete of type {0} is not supported", configuration.getConnectorMessages()
.format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Delete of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
}
#end
#if ( $op_schema_safe )
/**
* {@inheritDoc}
*/
public Schema schema() {
if (null == schema) {
final SchemaBuilder builder = new SchemaBuilder(${connectorName}Connector.class);
// Account
ObjectClassInfoBuilder accountInfoBuilder = new ObjectClassInfoBuilder();
accountInfoBuilder.addAttributeInfo(Name.INFO);
accountInfoBuilder.addAttributeInfo(OperationalAttributeInfos.PASSWORD);
accountInfoBuilder.addAttributeInfo(PredefinedAttributeInfos.GROUPS);
accountInfoBuilder.addAttributeInfo(AttributeInfoBuilder.build("firstName"));
accountInfoBuilder.addAttributeInfo(AttributeInfoBuilder.define("lastName")
.setRequired(true).build());
builder.defineObjectClass(accountInfoBuilder.build());
// Group
ObjectClassInfoBuilder groupInfoBuilder = new ObjectClassInfoBuilder();
groupInfoBuilder.setType(ObjectClass.GROUP_NAME);
groupInfoBuilder.addAttributeInfo(Name.INFO);
groupInfoBuilder.addAttributeInfo(PredefinedAttributeInfos.DESCRIPTION);
groupInfoBuilder.addAttributeInfo(AttributeInfoBuilder.define("members").setCreateable(
false).setUpdateable(false).setMultiValued(true).build());
// Only the CRUD operations
builder.defineObjectClass(groupInfoBuilder.build(), CreateOp.class, SearchOp.class,
UpdateOp.class, DeleteOp.class);
// Operation Options
builder.defineOperationOption(OperationOptionInfoBuilder.buildAttributesToGet(),
SearchOp.class);
// Support paged Search
builder.defineOperationOption(OperationOptionInfoBuilder.buildPageSize(),
SearchOp.class);
builder.defineOperationOption(OperationOptionInfoBuilder.buildPagedResultsCookie(),
SearchOp.class);
// Support to execute operation with provided credentials
builder.defineOperationOption(OperationOptionInfoBuilder.buildRunWithUser());
builder.defineOperationOption(OperationOptionInfoBuilder.buildRunWithPassword());
schema = builder.build();
}
return schema;
}
#end
#if ( $op_scriptonconnector_safe )
/**
* {@inheritDoc}
*/
public Object runScriptOnConnector(ScriptContext request, OperationOptions options) {
final ScriptExecutorFactory factory =
ScriptExecutorFactory.newInstance(request.getScriptLanguage());
final ScriptExecutor executor =
factory.newScriptExecutor(getClass().getClassLoader(), request.getScriptText(),
true);
if (StringUtil.isNotBlank(options.getRunAsUser())) {
String password = SecurityUtil.decrypt(options.getRunWithPassword());
// Use these to execute the script with these credentials
Assertions.blankCheck(password, "password");
}
try {
return executor.execute(request.getScriptArguments());
} catch (Throwable e) {
logger.warn(e, "Failed to execute Script");
throw ConnectorException.wrap(e);
}
}
#end
#if ( $op_scriptonresource_safe )
/**
* {@inheritDoc}
*/
public Object runScriptOnResource(ScriptContext request, OperationOptions options) {
try {
// Execute the script on remote resource
if (StringUtil.isNotBlank(options.getRunAsUser())) {
String password = SecurityUtil.decrypt(options.getRunWithPassword());
// Use these to execute the script with these credentials
Assertions.blankCheck(password, "password");
return options.getRunAsUser();
}
throw new UnknownHostException("Failed to connect to remote SSH");
} catch (Throwable e) {
logger.warn(e, "Failed to execute Script");
throw ConnectorException.wrap(e);
}
}
#end
#if ( $op_search_safe )
/**
* {@inheritDoc}
*/
public FilterTranslator<String> createFilterTranslator(ObjectClass objectClass,
OperationOptions options) {
return new ${connectorName}FilterTranslator();
}
/**
* {@inheritDoc}
*/
public void executeQuery(ObjectClass objectClass, String query, ResultsHandler handler,
OperationOptions options) {
final ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
builder.setUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
builder.setName("Foo");
builder.addAttribute(AttributeBuilder.buildEnabled(true));
for (ConnectorObject connectorObject : CollectionUtil.newSet(builder.build())) {
if (!handler.handle(connectorObject)) {
// Stop iterating because the handler stopped processing
break;
}
}
if (options.getPageSize() != null && 0 < options.getPageSize()) {
logger.info("Paged Search was requested");
((SearchResultsHandler) handler).handleResult(new SearchResult("0", 0));
}
}
#end
#if ( $op_sync_safe )
/**
* {@inheritDoc}
*/
public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler handler,
final OperationOptions options) {
if (ObjectClass.ALL.equals(objectClass)) {
//
} else if (ObjectClass.ACCOUNT.equals(objectClass)) {
final ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
builder.setUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
builder.setName("Foo");
builder.addAttribute(AttributeBuilder.buildEnabled(true));
final SyncDeltaBuilder deltaBuilder = new SyncDeltaBuilder();
deltaBuilder.setObject(builder.build());
deltaBuilder.setDeltaType(SyncDeltaType.CREATE);
deltaBuilder.setToken(new SyncToken(10));
for (SyncDelta connectorObject : CollectionUtil.newSet(deltaBuilder.build())) {
if (!handler.handle(connectorObject)) {
// Stop iterating because the handler stopped processing
break;
}
}
} else {
logger.warn("Sync of type {0} is not supported", configuration.getConnectorMessages()
.format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Sync of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
((SyncTokenResultsHandler) handler).handleResult(new SyncToken(10));
}
/**
* {@inheritDoc}
*/
public SyncToken getLatestSyncToken(ObjectClass objectClass) {
if (ObjectClass.ACCOUNT.equals(objectClass)) {
return new SyncToken(10);
} else {
logger.warn("Sync of type {0} is not supported", configuration.getConnectorMessages()
.format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Sync of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
}
#end
#if ( $op_test_safe )
/**
* {@inheritDoc}
*/
public void test() {
logger.ok("Test works well");
}
#end
#if ( $op_update_safe )
/**
* {@inheritDoc}
*/
public Uid update(ObjectClass objectClass, Uid uid, Set<Attribute> replaceAttributes,
OperationOptions options) {
AttributesAccessor attributesAccessor = new AttributesAccessor(replaceAttributes);
Name newName = attributesAccessor.getName();
Uid uidAfterUpdate = uid;
if (newName != null) {
logger.info("Rename the object {0}:{1} to {2}", objectClass.getObjectClassValue(), uid
.getUidValue(), newName.getNameValue());
uidAfterUpdate = new Uid(newName.getNameValue().toLowerCase(Locale.US));
}
if (ObjectClass.ACCOUNT.equals(objectClass)) {
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
if (attributesAccessor.hasAttribute("members")) {
throw new InvalidAttributeValueException(
"Requested to update a read only attribute");
}
} else {
logger.warn("Update of type {0} is not supported", configuration.getConnectorMessages()
.format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
throw new UnsupportedOperationException("Update of type"
+ objectClass.getObjectClassValue() + " is not supported");
}
return uidAfterUpdate;
}
#end
#if ( $op_updateattributevalues_safe )
/**
* {@inheritDoc}
*/
public Uid addAttributeValues(ObjectClass objectClass, Uid uid, Set<Attribute> valuesToAdd,
OperationOptions options) {
return uid;
}
/**
* {@inheritDoc}
*/
public Uid removeAttributeValues(ObjectClass objectClass, Uid uid,
Set<Attribute> valuesToRemove, OperationOptions options) {
return uid;
}
#end
}