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 }