001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/ds/resource/legal-notices/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/ds/resource/legal-notices/cddl.txt. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2013 UnboundID Corp.
026 */
027 package com.unboundid.directory.sdk.broker.api;
028
029 import com.unboundid.directory.sdk.broker.config.StoreAdapterConfig;
030 import com.unboundid.directory.sdk.broker.internal.IdentityBrokerExtension;
031 import com.unboundid.directory.sdk.http.types.AuthenticationException;
032 import com.unboundid.directory.sdk.http.types.AuthenticationRequest;
033 import com.unboundid.directory.sdk.broker.types.IdentityBrokerContext;
034 import com.unboundid.directory.sdk.broker.types.MetaDataMods;
035 import com.unboundid.directory.sdk.broker.types.StoreCreateRequest;
036 import com.unboundid.directory.sdk.broker.types.StoreDeleteRequest;
037 import com.unboundid.directory.sdk.broker.types.StoreSearchRequest;
038 import com.unboundid.directory.sdk.broker.types.StoreUpdateRequest;
039 import com.unboundid.directory.sdk.common.internal.Configurable;
040 import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
041 import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
042 import com.unboundid.scim.data.BaseResource;
043 import com.unboundid.scim.schema.ResourceDescriptor;
044 import com.unboundid.scim.sdk.Resources;
045 import com.unboundid.scim.sdk.SCIMException;
046 import com.unboundid.util.ByteString;
047 import com.unboundid.util.Extensible;
048 import com.unboundid.util.ThreadSafety;
049 import com.unboundid.util.ThreadSafetyLevel;
050 import com.unboundid.util.args.ArgumentException;
051 import com.unboundid.util.args.ArgumentParser;
052
053 import java.util.Collection;
054 import java.util.Collections;
055 import java.util.List;
056 import java.util.Map;
057
058
059 /**
060 * This class defines an API that must be implemented by extensions that need
061 * to store user data in some non-LDAP data store. This adapter API is generic
062 * and can support a wide range of repositories. When using multiple Identity
063 * Broker instances in a deployment, the data store should be accessible from
064 * all instances.
065 * <p>
066 * A Store Adapter can optionally support authentication by implementing the
067 * {@code supportsAuthentication()} and
068 * {@code authenticate(StoreAuthenticationRequest)} methods.
069 * <p>
070 * A Store Adapter can also opt to store the Identity Broker user metadata
071 * attributes, which contain the consents, OAuth tokens, and consent history,
072 * among other things. This metadata is separated into two categories: small
073 * and large. Both types are multi-valued and store raw binary values. The
074 * main difference is that the "small" metadata will typically contain small
075 * binary values and be accessed more frequently, whereas the "large" metadata
076 * will contain more sizable values (or a larger number of values) and be
077 * accessed less frequently. Implementers should take this into consideration
078 * when deciding where to store these metadata attributes.
079 * <p>
080 * After the StoreAdapter is initialized (via the initializeStoreAdapter()
081 * method), all methods will be guarded by a call to {@link #isAvailable()} to
082 * make sure that the adapter is currently connected and ready to service
083 * requests. If this returns {@code false}, the DataView will return an
084 * appropriate 503 response code to clients until the adapter becomes available
085 * again.
086 * <H2>Configuring Store Adapters</H2>
087 * In order to configure a store adapter created using this API, use
088 * a command like:
089 * <PRE>
090 * dsconfig create-store-adapter \
091 * ---adapter-name "<I>{name}</I>" \
092 * --type third-party \
093 * --set "extension-class:<I>{class-name}</I>" \
094 * --set "extension-argument:<I>{name=value}</I>"
095 * </PRE>
096 * where "<I>{name}</I>" is the name to use for the token store
097 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
098 * that extends
099 * {@code com.unboundid.directory.sdk.broker.api.StoreAdapter},
100 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
101 * provide to the store adapter. If multiple arguments should be
102 * provided to extension, then the
103 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
104 * provided multiple times.
105 */
106 @Extensible()
107 @IdentityBrokerExtension
108 @ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
109 public abstract class StoreAdapter implements UnboundIDExtension,
110 Configurable, ExampleUsageProvider
111 {
112 /**
113 * Creates a new instance of this store adapter. All
114 * implementations must include a default constructor, but any
115 * initialization should generally be done in the
116 * {@link #initializeStoreAdapter} method.
117 */
118 public StoreAdapter()
119 {
120 // No implementation is required.
121 }
122
123 /**
124 * {@inheritDoc}
125 */
126 @Override
127 public abstract String getExtensionName();
128
129 /**
130 * {@inheritDoc}
131 */
132 @Override
133 public abstract String[] getExtensionDescription();
134
135 /**
136 * {@inheritDoc}
137 */
138 @Override
139 public Map<List<String>,String> getExamplesArgumentSets()
140 {
141 return Collections.emptyMap();
142 }
143
144 /**
145 * {@inheritDoc}
146 */
147 @Override
148 public void defineConfigArguments(final ArgumentParser parser)
149 throws ArgumentException
150 {
151 // No arguments will be allowed by default.
152 }
153
154 /**
155 * Initializes this store adapter. Any initialization should be performed
156 * here. This method should generally store the
157 * {@link com.unboundid.directory.sdk.broker.types.IdentityBrokerContext} in
158 * a class member so that it can be used elsewhere in the implementation.
159 * <p>
160 * The default implementation is empty.
161 *
162 * @param serverContext A handle to the server context for the server in
163 * which this extension is running. Extensions should
164 * typically store this in a class member.
165 * @param config The general configuration for this object.
166 * @param parser The argument parser which has been initialized from
167 * the configuration for this store adapter.
168 * @throws Exception If a problem occurs while initializing this store
169 * adapter.
170 */
171 public void initializeStoreAdapter(final IdentityBrokerContext serverContext,
172 final StoreAdapterConfig config,
173 final ArgumentParser parser)
174 throws Exception
175 {
176 // No initialization will be performed by default.
177 }
178
179 /**
180 * This hook is called when the DataView is disabled or the Identity Broker
181 * shuts down. Any clean-up of this store adapter should be performed here.
182 * <p>
183 * The default implementation is empty.
184 */
185 public void finalizeStoreAdapter()
186 {
187 // No implementation is performed by default.
188 }
189
190 /**
191 * Determines whether this StoreAdapter can handle the provided
192 * authentication request. The default implementation returns {@code false},
193 * but subclasses may override this if they do support authentication.
194 *
195 * @param request the class of the authentication request.
196 * @return true if the StoreAdapter supports the provided authentication
197 * request, false otherwise.
198 */
199 public boolean supportsAuthentication(
200 final Class<? extends AuthenticationRequest> request)
201 {
202 return false;
203 }
204
205 /**
206 * Determines whether this StoreAdapter supports reading and writing the user
207 * metadata attributes. The default implementation returns {@code false}, but
208 * subclasses may override this if they do support storing the metadata
209 * attributes.
210 *
211 * @return true if the StoreAdapter supports the Broker metadata, false
212 * otherwise.
213 */
214 public boolean supportsUserMetaData()
215 {
216 return false;
217 }
218
219 /**
220 * Authenticate the specified user against the backend data store. The default
221 * implementation throws UnsupportedOperationException; subclasses that
222 * support authentication should override this.
223 *
224 * @param scimId the id of the user to authenticate.
225 * @param request the authentication request.
226 * @return <code>true</code> if authentication succeeds or <code>false</code>
227 * if this StoreAdaptor is unable to support the authentication
228 * request. In this case, other StoreAdaptors that supports the
229 * authentication request will be tried.
230 * @throws SCIMException if there is a problem authenticating the user
231 * @throws AuthenticationException if authentication fails
232 */
233 public boolean authenticate(final String scimId,
234 final AuthenticationRequest request)
235 throws SCIMException, AuthenticationException
236 {
237 throw new com.unboundid.scim.sdk.UnsupportedOperationException(
238 "This StoreAdapter (" + getExtensionName() + ") is not " +
239 "configured to support authentication.");
240 }
241
242 /**
243 * Determines whether this StoreAdapter is currently available and
244 * in-service. This may return {@code false} in the case that all
245 * backend servers are down, for example; during this time the DataView
246 * will return an appropriate 503 response code to clients.
247 *
248 * @return {@code true} if the StoreAdapter initialized and connected;
249 * {@code false} otherwise.
250 */
251 public abstract boolean isAvailable();
252
253 /**
254 * Gets a ResourceDescriptor that describes the schema for the objects that
255 * will be returned by this StoreAdapter. The StoreAdapter will always be
256 * initialized before this method is called, and the {@link #isAvailable()}
257 * method will be checked as well.
258 *
259 * @return a SCIM ResourceDescriptor object. This may not be {@code null}.
260 */
261 public abstract ResourceDescriptor getNativeSchema();
262
263 /**
264 * Fetches the entries that match the specified criteria.
265 *
266 * @param request the search request
267 * @return a collection of SCIM resources that are in the native schema. This
268 * may be empty, but it may not be {@code null}.
269 * @throws SCIMException if there is a problem fulfilling the search request
270 */
271 public abstract Resources<? extends BaseResource> search(
272 final StoreSearchRequest request) throws SCIMException;
273
274 /**
275 * Create the specified entry in the native data store.
276 *
277 * @param request the create request
278 * @return the resource that was just created, scoped according to the
279 * SCIMQueryAttributes contained in the request
280 * @throws SCIMException if there is a problem creating the entry
281 */
282 public abstract BaseResource create(final StoreCreateRequest request)
283 throws SCIMException;
284
285 /**
286 * Update the specified entry in the native data store.
287 *
288 * @param request the update request
289 * @return the updated resource, scoped according to the SCIMQueryAttributes
290 * contained in the request
291 * @throws SCIMException if there is a problem modifying the entry
292 */
293 public abstract BaseResource update(final StoreUpdateRequest request)
294 throws SCIMException;
295
296 /**
297 * Delete the specified entry from the native data store.
298 *
299 * @param request the delete request
300 * @throws SCIMException if there is a problem deleting the entry
301 */
302 public abstract void delete(final StoreDeleteRequest request)
303 throws SCIMException;
304
305 /**
306 * Update the user metadata for the specified user with the specified
307 * modifications. The default implementation throws
308 * UnsupportedOperationException; subclasses should override this if they
309 * support the user metadata attributes.
310 *
311 * @param scimId the id of the user to who's metadata to update
312 * @param metaDataMods the set of modifications
313 * @throws SCIMException if there is a problem updating the metadata
314 */
315 public void updateUserMetaData(final String scimId,
316 final MetaDataMods metaDataMods)
317 throws SCIMException
318 {
319 throw new com.unboundid.scim.sdk.UnsupportedOperationException(
320 "This StoreAdapter (" + getExtensionName() + ") is not " +
321 "configured to store the user metadata attributes.");
322 }
323
324 /**
325 * Update the user large metadata for the specified user with the specified
326 * modifications. The default implementation throws
327 * UnsupportedOperationException; subclasses should override this if they
328 * support the user metadata attributes.
329 *
330 * @param scimId the id of the user to who's metadata to update
331 * @param metaDataMods the set of modifications
332 * @throws SCIMException if there is a problem updating the metadata
333 */
334 public void updateUserLargeMetaData(final String scimId,
335 final MetaDataMods metaDataMods)
336 throws SCIMException
337 {
338 throw new com.unboundid.scim.sdk.UnsupportedOperationException(
339 "This StoreAdapter (" + getExtensionName() + ") is not " +
340 "configured to store the user metadata attributes.");
341 }
342
343 /**
344 * Retrieve the user metadata for the specified user. The default
345 * implementation throws UnsupportedOperationException; subclasses should
346 * override this if they support the user metadata attributes.
347 *
348 * @param scimId the id of the user
349 * @return the set of values for the metadata attribute
350 * @throws SCIMException if there is a problem retrieving the metadata
351 */
352 public Collection<ByteString> getUserMetaData(final String scimId)
353 throws SCIMException
354 {
355 throw new com.unboundid.scim.sdk.UnsupportedOperationException(
356 "This StoreAdapter (" + getExtensionName() + ") is not " +
357 "configured to store the user metadata attributes.");
358 }
359
360 /**
361 * Retrieve the user large metadata for the specified user. The default
362 * implementation throws UnsupportedOperationException; subclasses should
363 * override this if they support the user metadata attributes.
364 *
365 * @param scimId the id of the user
366 * @return the set of values for the large metadata attribute
367 * @throws SCIMException if there is a problem retrieving the large metadata
368 */
369 public Collection<ByteString> getUserLargeMetaData(final String scimId)
370 throws SCIMException
371 {
372 throw new com.unboundid.scim.sdk.UnsupportedOperationException(
373 "This StoreAdapter (" + getExtensionName() + ") is not " +
374 "configured to store the user metadata attributes.");
375 }
376 }