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 }