jp.openstandia.connector.atlassian.AtlassianGuardConnector Maven / Gradle / Ivy
The newest version!
/*
* Copyright Nomura Research Institute, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.openstandia.connector.atlassian;
import jp.openstandia.connector.util.ObjectHandler;
import jp.openstandia.connector.util.SchemaDefinition;
import jp.openstandia.connector.util.Utils;
import okhttp3.*;
import org.identityconnectors.common.StringUtil;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.exceptions.*;
import org.identityconnectors.framework.common.objects.*;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.spi.*;
import org.identityconnectors.framework.spi.operations.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@ConnectorClass(configurationClass = AtlassianGuardConfiguration.class, displayNameKey = "Atlassian Guard Connector")
public class AtlassianGuardConnector implements PoolableConnector, CreateOp, UpdateDeltaOp, DeleteOp, SchemaOp, TestOp, SearchOp, InstanceNameAware {
private static final Log LOG = Log.getLog(AtlassianGuardConnector.class);
protected AtlassianGuardConfiguration configuration;
protected AtlassianGuardRESTClient client;
private AtlassianGuardSchema cachedSchema;
private String instanceName;
@Override
public Configuration getConfiguration() {
return configuration;
}
@Override
public void init(Configuration configuration) {
this.configuration = (AtlassianGuardConfiguration) configuration;
try {
authenticateResource();
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
LOG.ok("Connector {0} successfully initialized", getClass().getName());
}
protected void authenticateResource() {
OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
okHttpBuilder.connectTimeout(configuration.getConnectionTimeoutInMilliseconds(), TimeUnit.MILLISECONDS);
okHttpBuilder.readTimeout(configuration.getReadTimeoutInMilliseconds(), TimeUnit.MILLISECONDS);
okHttpBuilder.writeTimeout(configuration.getWriteTimeoutInMilliseconds(), TimeUnit.MILLISECONDS);
okHttpBuilder.addInterceptor(getInterceptor(configuration.getToken()));
// Setup http proxy aware httpClient
if (StringUtil.isNotEmpty(configuration.getHttpProxyHost())) {
okHttpBuilder.proxy(new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(configuration.getHttpProxyHost(), configuration.getHttpProxyPort())));
if (StringUtil.isNotEmpty(configuration.getHttpProxyUser()) && configuration.getHttpProxyPassword() != null) {
configuration.getHttpProxyPassword().access(c -> {
okHttpBuilder.proxyAuthenticator((Route route, Response response) -> {
String credential = Credentials.basic(configuration.getHttpProxyUser(), String.valueOf(c));
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
});
});
}
}
OkHttpClient httpClient = okHttpBuilder.build();
client = new AtlassianGuardRESTClient();
client.init(instanceName, configuration, httpClient);
// Verify we can access the Atlassian Guard API
client.test();
}
private Interceptor getInterceptor(GuardedString accessToken) {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder()
.addHeader("Accept", "application/json");
accessToken.access(c -> {
builder.addHeader("Authorization", "Bearer " + String.valueOf(c));
});
return chain.proceed(builder.build());
}
};
}
@Override
public Schema schema() {
try {
cachedSchema = new AtlassianGuardSchema(configuration, client);
return cachedSchema.schema;
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
}
private ObjectHandler getSchemaHandler(ObjectClass objectClass) {
if (objectClass == null) {
throw new InvalidAttributeValueException("ObjectClass value not provided");
}
// Load schema map if it's not loaded yet
if (cachedSchema == null) {
schema();
}
ObjectHandler handler = cachedSchema.getSchemaHandler(objectClass);
if (handler == null) {
throw new InvalidAttributeValueException("Unsupported object class " + objectClass);
}
return handler;
}
@Override
public Uid create(ObjectClass objectClass, Set createAttributes, OperationOptions options) {
if (createAttributes == null || createAttributes.isEmpty()) {
throw new InvalidAttributeValueException("Attributes not provided or empty");
}
try {
return getSchemaHandler(objectClass).create(createAttributes);
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
}
@Override
public Set updateDelta(ObjectClass objectClass, Uid uid, Set modifications, OperationOptions options) {
if (uid == null) {
throw new InvalidAttributeValueException("uid not provided");
}
try {
return getSchemaHandler(objectClass).updateDelta(uid, modifications, options);
} catch (UnknownUidException e) {
LOG.warn("Not found object when updating. instanceName; {0}, objectClass: {1}, uid: {2}", instanceName, objectClass, uid);
throw processRuntimeException(e);
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
}
@Override
public void delete(ObjectClass objectClass, Uid uid, OperationOptions options) {
if (uid == null) {
throw new InvalidAttributeValueException("uid not provided");
}
try {
getSchemaHandler(objectClass).delete(uid, options);
} catch (UnknownUidException e) {
LOG.warn("Not found object when deleting. instanceName={0}, objectClass={1}, uid={2}", instanceName, objectClass, uid);
throw processRuntimeException(e);
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
}
@Override
public FilterTranslator createFilterTranslator(ObjectClass objectClass, OperationOptions options) {
return new AtlassianGuardFilterTranslator(objectClass, options);
}
@Override
public void executeQuery(ObjectClass objectClass, AtlassianGuardFilter filter, ResultsHandler resultsHandler, OperationOptions options) {
ObjectHandler schemaHandler = getSchemaHandler(objectClass);
SchemaDefinition schema = schemaHandler.getSchema();
int pageSize = Utils.resolvePageSize(options, configuration.getDefaultQueryPageSize());
int pageOffset = Utils.resolvePageOffset(options);
// Create full attributesToGet by RETURN_DEFAULT_ATTRIBUTES + ATTRIBUTES_TO_GET
Map attributesToGet = Utils.createFullAttributesToGet(schema, options);
Set returnAttributesSet = attributesToGet.keySet();
// Collect actual resource fields for fetching (We can them for filtering attributes if the resource supports it)
Set fetchFieldSet = new HashSet<>(attributesToGet.values());
boolean allowPartialAttributeValues = Utils.shouldAllowPartialAttributeValues(options);
int total = 0;
AtomicInteger fetchedCount = new AtomicInteger();
ResultsHandler countableResultHandler = (connectorObject) -> {
fetchedCount.getAndIncrement();
return resultsHandler.handle(connectorObject);
};
if (filter != null) {
if (filter.isByUid()) {
total = schemaHandler.getByUid((Uid) filter.attributeValue, countableResultHandler, options,
returnAttributesSet, fetchFieldSet,
allowPartialAttributeValues, pageSize, pageOffset);
} else if (filter.isByName()) {
total = schemaHandler.getByName((Name) filter.attributeValue, countableResultHandler, options,
returnAttributesSet, fetchFieldSet,
allowPartialAttributeValues, pageSize, pageOffset);
} else if (filter.isByMembers()) {
total = schemaHandler.getByMembers(filter.attributeValue, countableResultHandler, options,
returnAttributesSet, fetchFieldSet,
allowPartialAttributeValues, pageSize, pageOffset);
}
// No result
} else {
total = schemaHandler.getAll(countableResultHandler, options,
returnAttributesSet, fetchFieldSet,
allowPartialAttributeValues, pageSize, pageOffset);
}
if (resultsHandler instanceof SearchResultsHandler &&
pageOffset > 0) {
int remaining = total - (pageOffset - 1) - fetchedCount.get();
SearchResultsHandler searchResultsHandler = (SearchResultsHandler) resultsHandler;
SearchResult searchResult = new SearchResult(null, remaining);
searchResultsHandler.handleResult(searchResult);
}
}
@Override
public void test() {
try {
dispose();
authenticateResource();
} catch (RuntimeException e) {
throw processRuntimeException(e);
}
}
@Override
public void dispose() {
client.close();
this.client = null;
this.cachedSchema = null;
}
@Override
public void checkAlive() {
// Do nothing
}
@Override
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}
protected ConnectorException processRuntimeException(RuntimeException e) {
if (e instanceof ConnectorException) {
// Write error log because IDM might not write full stack trace
// It's hard to debug the error
if (e instanceof AlreadyExistsException) {
LOG.warn(e, "Detected the object already exists. instanceName={0}, message={1}", instanceName, e.getMessage());
} else {
LOG.error(e, "Detected Atlassian Guard connector error. instanceName={0}, message={1}", instanceName, e.getMessage());
}
return (ConnectorException) e;
}
LOG.error(e, "Detected Atlassian Guard connector unexpected error. instanceName={0}, message={1}", instanceName, e.getMessage());
return new ConnectorIOException(e);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy