/* * 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://forgerock.org/license/CDDLv1.0.html * 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://forgerock.org/license/CDDLv1.0.html * 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]" */ package org.forgerock.openicf.connectors.box; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Set; import com.box.boxjavalibv2.requests.requestobjects.BoxUserDeleteRequestObject; import org.identityconnectors.common.Assertions; 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.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException; import org.identityconnectors.framework.common.objects.*; import org.identityconnectors.framework.common.objects.AttributeInfo.Flags; import org.identityconnectors.framework.common.objects.filter.FilterTranslator; import org.identityconnectors.framework.spi.Configuration; import org.identityconnectors.framework.spi.Connector; import org.identityconnectors.framework.spi.ConnectorClass; import org.identityconnectors.framework.spi.operations.CreateOp; import org.identityconnectors.framework.spi.operations.DeleteOp; import org.identityconnectors.framework.spi.operations.SchemaOp; import org.identityconnectors.framework.spi.operations.ScriptOnConnectorOp; import org.identityconnectors.framework.spi.operations.SearchOp; import org.identityconnectors.framework.spi.operations.TestOp; import org.identityconnectors.framework.spi.operations.UpdateOp; import com.box.boxjavalibv2.dao.BoxGroup; import com.box.boxjavalibv2.dao.BoxUser; import com.box.boxjavalibv2.exceptions.AuthFatalFailureException; import com.box.boxjavalibv2.exceptions.BoxServerException; import com.box.boxjavalibv2.requests.requestobjects.BoxUserRequestObject; import com.box.boxjavalibv2.resourcemanagers.IBoxGroupsManager; import com.box.boxjavalibv2.resourcemanagers.IBoxUsersManager; import com.box.restclientv2.exceptions.BoxRestException; /** * Main implementation of the Box Connector. * */ @ConnectorClass(displayNameKey = "box.connector.display", configurationClass = BoxConfiguration.class) public class BoxConnector implements Connector, CreateOp, DeleteOp, SearchOp<String>, TestOp, UpdateOp, SchemaOp, ScriptOnConnectorOp { /** * Setup logging for the {@link BoxConnector}. */ private static final Log logger = Log.getLog(BoxConnector.class); protected static final String GROOVY = "Groovy"; protected static final String CONNECTOR_ARG = "connector"; protected static final String BOX_CLIENT_ARG = "boxClient"; protected static final String FORCE = "force"; protected static final String NOTIFY = "notify"; /** * Place holder for the {@link Configuration} passed into the init() method * {@link BoxConnector#init(org.identityconnectors.framework.spi.Configuration)} * . */ private BoxConfiguration configuration; /** * 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#init(org.identityconnectors.framework.spi.Configuration) */ public void init(final Configuration configuration) { this.configuration = (BoxConfiguration) configuration; } /** * Disposes of the {@link BoxConnector}'s resources. * * @see org.identityconnectors.framework.spi.Connector#dispose() */ public void dispose() { configuration = null; } /****************** * SPI Operations * * Implement the following operations using the contract and description * found in the Javadoc for these methods. ******************/ /** * {@inheritDoc} */ public Uid create(final ObjectClass objectClass, final Set<Attribute> createAttributes, final OperationOptions options) { if (ObjectClass.ACCOUNT.equals(objectClass)) { AttributesAccessor attributeAccessor = new AttributesAccessor(createAttributes); // TODO need to figure out how to create user. Read the javadoc. // TODO examples how to get an attribute and throw error message in // case something is wrong Name name = attributeAccessor.getName(); Attribute login = attributeAccessor.find("login"); String loginString = AttributeUtil.getStringValue(login); if (StringUtil.isBlank(loginString)) { throw new InvalidAttributeValueException(configuration.getConnectorMessages() .format("ErrorAttributeRequired", "Email attribute is required.", "email")); } final IBoxUsersManager manager = configuration.getBoxClient().getUsersManager(); BoxUserRequestObject request = BoxUserRequestObject.createEnterpriseUserRequestObject(loginString, name .getNameValue()); try { return new Uid(manager.createEnterpriseUser(request).getId()); } catch (BoxRestException e) { e.printStackTrace(); } catch (BoxServerException e) { e.printStackTrace(); } catch (AuthFatalFailureException e) { e.printStackTrace(); } } else if (ObjectClass.GROUP.equals(objectClass)) { for (Attribute attribute : createAttributes) { if (attribute.is(Name.NAME)) { final IBoxGroupsManager manager = configuration.getBoxClient().getGroupsManager(); try { return new Uid(manager.createGroup(AttributeUtil.getStringValue(attribute)) .getId()); } catch (final BoxRestException e) { throw ConnectorException.wrap(e); } catch (final AuthFatalFailureException e) { throw ConnectorException.wrap(e); } catch (final BoxServerException e) { throw ConnectorException.wrap(e); } } } throw new InvalidAttributeValueException("Required attribute __NAME__ is missing"); } else { throw new UnsupportedOperationException(); } return null; } private <T> T getValueAs(Object source, Class<T> type, T defaultValue) { if (null == source || type.isAssignableFrom(source.getClass()) == false) { return defaultValue; } else { return (T) source; } } /** * {@inheritDoc} */ public void delete(final ObjectClass objectClass, final Uid uid, final OperationOptions options) { if (ObjectClass.ACCOUNT.equals(objectClass)) { final IBoxUsersManager manager = configuration.getBoxClient().getUsersManager(); boolean force = getValueAs(options.getOptions().get(FORCE), Boolean.TYPE, false); boolean notify = getValueAs(options.getOptions().get(NOTIFY), Boolean.TYPE, false); try { manager.deleteEnterpriseUser(uid.getUidValue(), BoxUserDeleteRequestObject .deleteEnterpriseUserRequestObject(notify, force)); } catch (BoxRestException e) { throw ConnectorException.wrap(e); } catch (BoxServerException e) { throw ConnectorException.wrap(e); } catch (AuthFatalFailureException e) { throw ConnectorException.wrap(e); } } else if (ObjectClass.GROUP.equals(objectClass)) { final IBoxGroupsManager manager = configuration.getBoxClient().getGroupsManager(); try { manager.deleteGroup(uid.getUidValue(), null); } catch (final BoxRestException e) { throw ConnectorException.wrap(e); } catch (final AuthFatalFailureException e) { throw ConnectorException.wrap(e); } catch (final BoxServerException e) { throw ConnectorException.wrap(e); } } else { throw new UnsupportedOperationException(); } } /** * {@inheritDoc} */ public FilterTranslator<String> createFilterTranslator(final ObjectClass objectClass, OperationOptions options) { return new BoxFilterTranslator(objectClass); } /** * {@inheritDoc} */ public void executeQuery(ObjectClass objectClass, String query, ResultsHandler handler, OperationOptions options) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ public void test() { // this tests the connection is OK. if (!Assertions.nullChecked(configuration.getBoxClient(), "BoxClient").isAuthenticated()) { throw new IllegalStateException("BoxClient is not authenticated"); } } /** * {@inheritDoc} */ public Uid update(ObjectClass objectClass, Uid uid, Set<Attribute> replaceAttributes, OperationOptions options) { throw new UnsupportedOperationException(); } @Override public Schema schema() { SchemaBuilder builder = new SchemaBuilder(BoxConnector.class); // User ObjectClassInfoBuilder userInfo = new ObjectClassInfoBuilder(); // - name: The name of this user. userInfo.addAttributeInfo(Name.INFO); // - login: The email address this user uses to login. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_LOGIN, String.class, EnumSet.of(Flags.REQUIRED))); // - created_at: The time this user was created. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_CREATED_AT, String.class, EnumSet.of(Flags.NOT_CREATABLE, Flags.NOT_UPDATEABLE))); // - modified_at: The time this user was last modified. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_MODIFIED_AT, String.class, EnumSet.of(Flags.NOT_CREATABLE, Flags.NOT_UPDATEABLE))); // - role: This user’s enterprise role. Can be admin, coadmin, or user. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_ROLE, String.class, EnumSet.of(Flags.NOT_RETURNED_BY_DEFAULT))); // - language: The language of this user. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_LANGUAGE)); // - space_amount: The user’s total available space amount in bytes. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_SPACE_AMOUNT, int.class)); // - space_used: The amount of space in use by the user. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_SPACE_USED, int.class)); // - max_upload_size: The maximum individual file size in bytes this // user can have. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_MAX_UPLOAD_SIZE, int.class)); // - tracking_codes: An array of key/value pairs set by the user’s // admin. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_TRACKING_CODES, String.class, EnumSet.of(Flags.MULTIVALUED, Flags.NOT_RETURNED_BY_DEFAULT))); // - can_see_managed_users: Whether this user can see other enterprise // users in its contact list. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_CAN_SEE_MANAGED_USERS, Boolean.class, EnumSet.of(Flags.NOT_RETURNED_BY_DEFAULT))); // - is_sync_enabled: Whether or not this user can use Box Sync. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_IS_SYNC_ENABLED, Boolean.class, EnumSet.of(Flags.NOT_RETURNED_BY_DEFAULT))); // - status: Can be active or inactive. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_STATUS)); // - job_title: The user’s job title. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_JOB_TITLE)); // - phone: The user’s phone number. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_PHONE)); // - address: The user’s address. The user’s address. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_ADDRESS)); // - avatar_url: URL of this user’s avatar image. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_AVATAR_URL)); // - is_exempt_from_device_limits: Whether to exempt this user from // Enterprise device limits. userInfo.addAttributeInfo(AttributeInfoBuilder.build( BoxUser.FIELD_IS_EXEMPT_FROM_DEVICE_LIMITS, Boolean.class, EnumSet .of(Flags.NOT_RETURNED_BY_DEFAULT))); // - is_exempt_from_login_verification: Whether or not this user must // use two-factor authentication. userInfo.addAttributeInfo(AttributeInfoBuilder.build( BoxUser.FIELD_IS_EXEMPT_FROM_LOGIN_VERIFICATION, Boolean.class, EnumSet .of(Flags.NOT_RETURNED_BY_DEFAULT))); // - enterprise: Mini representation of this user’s enterprise, // including the ID of its enterprise. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_ENTERPRISE, Map.class, EnumSet.of(Flags.NOT_RETURNED_BY_DEFAULT))); // - my_tags: Tags for all files and folders owned by this user. userInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxUser.FIELD_MY_TAGS, String.class, EnumSet.of(Flags.MULTIVALUED, Flags.NOT_RETURNED_BY_DEFAULT))); ObjectClassInfo user = userInfo.build(); builder.defineObjectClass(user); builder.removeSupportedObjectClass(DeleteOp.class, user); // Group ObjectClassInfoBuilder groupInfo = new ObjectClassInfoBuilder(); groupInfo.setType(ObjectClass.GROUP_NAME); // - name: The name of this group groupInfo.addAttributeInfo(Name.INFO); // - created_at: When this groups was created on Box’s servers groupInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxGroup.FIELD_CREATED_AT, String.class, EnumSet.of(Flags.NOT_CREATABLE, Flags.NOT_UPDATEABLE))); // - modified_at: When this group was last updated on the Box servers groupInfo.addAttributeInfo(AttributeInfoBuilder.build(BoxGroup.FIELD_MODIFIED_AT, String.class, EnumSet.of(Flags.NOT_CREATABLE, Flags.NOT_UPDATEABLE))); builder.defineObjectClass(groupInfo.build()); // Define Operation Options //builder.defineOperationOption(OperationOptionInfoBuilder.build(NOTIFY, Boolean.TYPE), // CreateOp.class, UpdateOp.class, DeleteOp.class); //builder.defineOperationOption(OperationOptionInfoBuilder.build(FORCE, Boolean.TYPE), // DeleteOp.class); return builder.build(); } @Override public Object runScriptOnConnector(ScriptContext scriptContext, OperationOptions operationOptions) { final String language = scriptContext.getScriptLanguage(); if (GROOVY.equalsIgnoreCase(language)) { final ScriptExecutor executor = ScriptExecutorFactory.newInstance(language).newScriptExecutor( getClass().getClassLoader(), scriptContext.getScriptText(), false); Map<String, Object> scriptArgs = new HashMap<String, Object>(); scriptArgs.putAll(scriptContext.getScriptArguments()); scriptArgs.put(CONNECTOR_ARG, this); scriptArgs.put(BOX_CLIENT_ARG, configuration.getBoxClient()); try { return executor.execute(scriptArgs); } catch (Exception e) { throw ConnectorException.wrap(e); } } else { throw new InvalidAttributeValueException(String.format("Language not supported: %s", language)); } } }