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 2010-2013 UnboundID Corp.
026     */
027    package com.unboundid.directory.sdk.broker.api;
028    
029    import com.unboundid.directory.sdk.broker.types.AccessToken;
030    import com.unboundid.directory.sdk.broker.config.TokenStoreConfig;
031    import com.unboundid.directory.sdk.broker.internal.IdentityBrokerExtension;
032    import com.unboundid.directory.sdk.broker.types.AuthorizationCode;
033    import com.unboundid.directory.sdk.broker.types.IdentityBrokerContext;
034    import com.unboundid.directory.sdk.broker.types.OAuthException;
035    import com.unboundid.directory.sdk.common.internal.Configurable;
036    import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
037    import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
038    import com.unboundid.ldap.sdk.LDAPException;
039    import com.unboundid.util.Extensible;
040    import com.unboundid.util.ThreadSafety;
041    import com.unboundid.util.ThreadSafetyLevel;
042    import com.unboundid.util.args.ArgumentException;
043    import com.unboundid.util.args.ArgumentParser;
044    
045    import java.util.Collection;
046    import java.util.Collections;
047    import java.util.List;
048    import java.util.Map;
049    
050    /**
051     * This class defines an API that must be implemented by extensions that
052     * wish to store and retrieve authorization codes and access tokens instances
053     * for the OAuth 2 service. This type of token store is generic and can support
054     * a wide range of repositories. When using multiple Identity Broker instances
055     * in a deployment, the repository should be accessible from all instances.
056     * In addition, this type of token store has the ability to generate the values
057     * of the codes and tokens that are returned to the client application. These
058     * values are also used to retrieve the authorization code and access token
059     * instances from the token store.
060     *
061     * <H2>Configuring Token Stores</H2>
062     * In order to configure a token store created using this API, use
063     * a command like:
064     * <PRE>
065     *      dsconfig create-token-store \
066     *           ---store-name "<I>{name}</I>" \
067     *           --type third-party \
068     *           --set "extension-class:<I>{class-name}</I>" \
069     *           --set "extension-argument:<I>{name=value}</I>"
070     * </PRE>
071     * where "<I>{name}</I>" is the name to use for the token store
072     * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
073     * that extends
074     * {@code com.unboundid.directory.sdk.broker.api.TokenStore},
075     * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
076     * provide to the token store. If multiple arguments should be
077     * provided to extension, then the
078     * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
079     * provided multiple times.
080     */
081    @Extensible()
082    @IdentityBrokerExtension
083    @ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
084    public abstract class TokenStore
085        implements UnboundIDExtension, Configurable, ExampleUsageProvider
086    {
087      /**
088       * Creates a new instance of this token store.  All
089       * implementations must include a default constructor, but any
090       * initialization should generally be done in the
091       * {@link #initializeTokenStore} method.
092       */
093      public TokenStore()
094      {
095        // No implementation is required.
096      }
097    
098    
099    
100      /**
101       * {@inheritDoc}
102       */
103      public abstract String getExtensionName();
104    
105    
106    
107      /**
108       * {@inheritDoc}
109       */
110      public abstract String[] getExtensionDescription();
111    
112    
113    
114      /**
115       * {@inheritDoc}
116       */
117      public Map<List<String>,String> getExamplesArgumentSets()
118      {
119        return Collections.emptyMap();
120      }
121    
122    
123    
124      /**
125       * {@inheritDoc}
126       */
127      public void defineConfigArguments(final ArgumentParser parser)
128             throws ArgumentException
129      {
130        // No arguments will be allowed by default.
131      }
132    
133    
134    
135      /**
136       * Initializes this token store. This hook is called when the Identity Broker
137       * first starts up. Any initialization should be performed here. This method
138       * should generally store the
139       * {@link com.unboundid.directory.sdk.broker.types.IdentityBrokerContext} in
140       * a class member so that it can be used elsewhere in the implementation.
141       * <p>
142       * The default implementation is empty.
143       *
144       * @param  serverContext  A handle to the server context for the server in
145       *                        which this extension is running. Extensions should
146       *                        typically store this in a class member.
147       * @param  config         The general configuration for this object.
148       * @param  parser         The argument parser which has been initialized from
149       *                        the configuration for this token store.
150       * @throws LDAPException  If a problem occurs while initializing this token
151       *                        store.
152       */
153      public void initializeTokenStore(final IdentityBrokerContext serverContext,
154                                       final TokenStoreConfig config,
155                                       final ArgumentParser parser)
156          throws LDAPException
157      {
158        // No initialization will be performed by default.
159      }
160    
161    
162    
163      /**
164       * This hook is called when the Identity Broker shuts down. Any clean-up of
165       * this token store should be performed here.
166       * <p>
167       * The default implementation is empty.
168       */
169      public void finalizeTokenStore()
170      {
171        // No implementation is performed by default.
172      }
173    
174      /**
175        * Retrieves the authorization code associated with the specified code value.
176        * If successfully retrieved, the authorization code is no longer considered
177        * valid and may not be retrieved again.
178        *
179        * @param codeValue The value of the authorization code.
180        * @return The authorization code associated with the specified code value or
181        *         {@code null} if the code value is not found.
182        * @throws OAuthException if an error occurred while retrieving the
183       *                         authorization code.
184        */
185       public abstract AuthorizationCode consumeAuthorizationCode(
186           final String codeValue) throws OAuthException;
187    
188    
189       /**
190        * Store a new authorization code and overwrite any existing codes for the
191        * same application by the same owner. Implementations must set the
192        * authorization code value that may be used to retrieve this
193        * {@link AuthorizationCode} instance from the token store by calling the
194        * following on the passed-in authorization code:
195        *
196        * {@code AuthorizationCode.setValue()}
197        *
198        * @param authorizationCode The authorization code to store.
199        * @throws OAuthException if an error occurred while creating the
200        *                        authorization code.
201        */
202       public abstract void storeAuthorizationCode(
203           final AuthorizationCode authorizationCode) throws OAuthException;
204    
205       /**
206        * Store a new access token with an optional refresh token and overwrite any
207        * existing tokens for the same application by the same owner. If the owner
208        * is not available, any existing tokens for the same application without an
209        * owner should also be overwritten. Implementations must set the access and,
210        * if available, refresh token values that may be used to retrieve this
211        * {@link AccessToken} instance from the token store by calling the following
212        * on the passed-in access token:
213        *
214        * {@code AccessToken.setValue()}
215        * and
216        * {@code AccessToken.getRefreshToken().setValue()}
217        *
218        * If the provided token's value is not {@code null}, the implementation
219        * should try to use those values to reference the stored token without
220        * generating a new value.
221        *
222        * @param accessToken the access token to store.
223        * @throws OAuthException if an error occurred while creating the access
224        *                        token.
225        */
226       public abstract void storeAccessToken(final AccessToken accessToken)
227           throws OAuthException;
228    
229       /**
230        * Retrieves the access token associated with the specified token value.
231        * The AccessToken instance returned by implementations must have its refresh
232        * token (if available) set by calling {@code AccessToken.setRefreshToken()}
233        * and the token value set by calling {@code AccessToken.setValue()}.
234        *
235        * @param tokenValue The value of the access token.
236        * @return The access token associated with the specified token value or
237        *         {@code null} if not found.
238        * @throws OAuthException if an error occurred while reading the access token
239        */
240       public abstract AccessToken getAccessToken(final String tokenValue)
241           throws OAuthException;
242    
243       /**
244        * Retrieves the access token associated with the refresh token value.
245        * The AccessToken instance returned by implementations must have its refresh
246        * token set by calling {@code AccessToken.setRefreshToken()} and the token
247        * value set by calling {@code AccessToken.setValue()}.
248        *
249        * @param tokenValue The value of the refresh token.
250        * @return The access token associated with the specified refresh token value
251        *         or {@code null} if not found.
252        * @throws OAuthException If an error occurred while retrieving the access
253        *                        token.
254        */
255       public abstract AccessToken getAccessTokenFromRefreshToken(
256           final String tokenValue) throws OAuthException;
257    
258       /**
259        * Retrieves all the access tokens associated with the provided username.
260        * All AccessToken instances returned by implementations must have their
261        * refresh token (if available) set by calling
262        * {@code AccessToken.setRefreshToken()} and the token value set by calling
263        * {@code AccessToken.setValue()}.
264        *
265        * @param username The username to use to identify the token user.
266        * @return The access tokens associated with the provided username or
267        *        {@code null} if not found.
268        * @throws OAuthException If an error occurred while revoking the access
269        *                        token.
270        */
271       public abstract Collection<AccessToken> getAccessTokensByUser(
272           final String username) throws OAuthException;
273    
274       /**
275        * Revoke the access token along with the associated refresh token if it
276        * exists so they will no longer be considered valid.
277        *
278        * @param tokenValue The value of the access or refresh token to revoke.
279        * @return The revoked access token or {@code null} if the token value was
280        *         not found.
281        * @throws OAuthException If an error occurred while revoking the access
282        *                        token.
283        */
284       public abstract AccessToken revokeToken(final String tokenValue)
285           throws OAuthException;
286    
287      /**
288       * Retrieves a string representation of this token store.
289       *
290       * @return  A string representation of this token store.
291       */
292      @Override()
293      public final String toString()
294      {
295        final StringBuilder buffer = new StringBuilder();
296        toString(buffer);
297        return buffer.toString();
298      }
299    
300    
301    
302      /**
303       * Appends a string representation of this token store to the
304       * provided buffer.
305       *
306       * @param  buffer  The buffer to which the string representation should be
307       *                 appended.
308       */
309      public abstract void toString(final StringBuilder buffer);
310    }