001/*
002 * Copyright 2020-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2020-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2020-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk;
037
038
039
040import java.io.Serializable;
041import java.util.Collections;
042import java.util.Iterator;
043import java.util.LinkedHashMap;
044import java.util.Map;
045
046import com.unboundid.util.Mutable;
047import com.unboundid.util.NotNull;
048import com.unboundid.util.Nullable;
049import com.unboundid.util.ThreadSafety;
050import com.unboundid.util.ThreadSafetyLevel;
051import com.unboundid.util.Validator;
052
053
054
055/**
056 * This class provides a data structure that may be used to hold a number of
057 * properties used during processing for a OAUTHBEARER SASL bind operation.
058 *
059 * @see OAUTHBEARERBindRequest
060 */
061@Mutable()
062@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
063public final class OAUTHBEARERBindRequestProperties
064       implements Serializable
065{
066  /**
067   * The serial version UID for this serializable class.
068   */
069  private static final long serialVersionUID = -7664683436256231975L;
070
071
072
073  // The port of the server to which the request will be sent.
074  @Nullable private Integer serverPort;
075
076  // A set of additional key-value pairs that should be included in the bind
077  // request.
078  @NotNull private final Map<String,String> additionalKeyValuePairs;
079
080  // The access token to include in the bind request.
081  @NotNull private String accessToken;
082
083  // The authorization identity to include in the GS2 header for the bind
084  // request.
085  @Nullable private String authorizationID;
086
087  // The method to use for HTTP-based requests.
088  @Nullable private String requestMethod;
089
090  // The path to use for HTTP-based requests.
091  @Nullable private String requestPath;
092
093  // The post data for HTTP-based requests.
094  @Nullable private String requestPostData;
095
096  // The query string for HTTP-based requests.
097  @Nullable private String requestQueryString;
098
099  // The address of the server to which the request will be sent.
100  @Nullable private String serverAddress;
101
102
103
104  /**
105   * Creates a new set of OAUTHBEARER bind request properties with the provided
106   * access token.
107   *
108   * @param  accessToken  The access token to include in the bind request.  It
109   *                      must not be {@code null} or empty.
110   */
111  public OAUTHBEARERBindRequestProperties(@NotNull final String accessToken)
112  {
113    Validator.ensureNotNullOrEmpty(accessToken,
114         "OAUTHBEARERBindRequestProperties.accessToken must not be null or " +
115              "empty.");
116
117    this.accessToken = accessToken;
118
119    authorizationID = null;
120    serverAddress = null;
121    serverPort = null;
122    requestMethod = null;
123    requestPath = null;
124    requestPostData = null;
125    requestQueryString = null;
126
127    additionalKeyValuePairs = new LinkedHashMap<>();
128  }
129
130
131
132  /**
133   * Creates a new set of OAUTHBEARER bind request properties that is a copy of
134   * the provided set of properties.
135   *
136   * @param  properties  The set of properties to duplicate.  It must not be
137   *                     {@code null}.
138   */
139  public OAUTHBEARERBindRequestProperties(
140              @NotNull final OAUTHBEARERBindRequestProperties properties)
141  {
142    Validator.ensureNotNullWithMessage(properties,
143         "OAUTHBEARERBindRequestProperties.properties must not be null.");
144
145    accessToken = properties.accessToken;
146    authorizationID = properties.authorizationID;
147    serverAddress = properties.serverAddress;
148    serverPort = properties.serverPort;
149    requestMethod = properties.requestMethod;
150    requestPath = properties.requestPath;
151    requestPostData = properties.requestPostData;
152    requestQueryString = properties.requestQueryString;
153    additionalKeyValuePairs =
154         new LinkedHashMap<>(properties.additionalKeyValuePairs);
155  }
156
157
158
159  /**
160   * Creates a new set of OAUTHBEARER bind request properties that is a copy of
161   * the properties used for the provided bind request.
162   *
163   * @param  bindRequest  The OAUTHBEARER bind request to use to create this set
164   *                      of properties.  It must not be {@code null}.
165   */
166  public OAUTHBEARERBindRequestProperties(
167              @NotNull final OAUTHBEARERBindRequest bindRequest)
168  {
169    Validator.ensureNotNullWithMessage(bindRequest,
170         "OAUTHBEARERBindRequestProperties.bindRequest must not be null.");
171
172    accessToken = bindRequest.getAccessToken();
173    authorizationID = bindRequest.getAuthorizationID();
174    serverAddress = bindRequest.getServerAddress();
175    serverPort = bindRequest.getServerPort();
176    requestMethod = bindRequest.getRequestMethod();
177    requestPath = bindRequest.getRequestPath();
178    requestPostData = bindRequest.getRequestPostData();
179    requestQueryString = bindRequest.getRequestQueryString();
180    additionalKeyValuePairs =
181         new LinkedHashMap<>(bindRequest.getAdditionalKeyValuePairs());
182  }
183
184
185
186  /**
187   * Retrieves the access token to include in the bind request.
188   *
189   * @return  The access token to include in the bind request.
190   */
191  @NotNull()
192  public String getAccessToken()
193  {
194    return accessToken;
195  }
196
197
198
199  /**
200   * Specifies the access token to include in the bind request.
201   *
202   * @param  accessToken  The access token to include in the bind request.  It
203   *                      must not be {@code null} or empty.
204   */
205  public void setAccessToken(@NotNull final String accessToken)
206  {
207    Validator.ensureNotNullOrEmpty(accessToken,
208         "OAUTHBEARERBindRequestProperties.accessToken must not be null or " +
209              "empty.");
210
211    this.accessToken = accessToken;
212  }
213
214
215
216  /**
217   * Retrieves the authorization ID to include in the GS2 header for the bind
218   * request, if any.
219   *
220   * @return  The authorization ID to include in the GS2 header for the bind
221   *          request, or {@code null} if no authorization ID should be
222   *          included.
223   */
224  @Nullable()
225  public String getAuthorizationID()
226  {
227    return authorizationID;
228  }
229
230
231
232  /**
233   * Specifies the authorization ID to include in the GS2 header for the bind
234   * request, if any.
235   *
236   * @param  authorizationID  The authorization ID to include in the bind
237   *                          request.  It may be {@code null} if no
238   *                          authorization ID should be provided.
239   */
240  public void setAuthorizationID(@Nullable final String authorizationID)
241  {
242    this.authorizationID = authorizationID;
243  }
244
245
246
247  /**
248   * Retrieves the server address to include in the bind request, if any.
249   *
250   * @return  The server address to include in the bind request, or {@code null}
251   *          if it should be omitted.
252   */
253  @Nullable()
254  public String getServerAddress()
255  {
256    return serverAddress;
257  }
258
259
260
261  /**
262   * Specifies the server address to include in the bind request, if any.
263   *
264   * @param  serverAddress  The server address to include in the bind request.
265   *                        It may be {@code null} if the server address should
266   *                        be omitted.
267   */
268  public void setServerAddress(@Nullable final String serverAddress)
269  {
270    this.serverAddress = serverAddress;
271  }
272
273
274
275  /**
276   * Retrieves the server port to include in the bind request, if any.
277   *
278   * @return  The server port to include in the bind request, or {@code null}
279   *          if it should be omitted.
280   */
281  @Nullable()
282  public Integer getServerPort()
283  {
284    return serverPort;
285  }
286
287
288
289  /**
290   * Specifies the server port to include in the bind request, if any.
291   *
292   * @param   serverPort  The server port to include in the bind request.  It
293   *                      may be {@code null} if the server port should be
294   *                      omitted.  If it is non-{@code null}, then the value
295   *                      must be between 1 and 65535, inclusive.
296   */
297  public void setServerPort(@Nullable final Integer serverPort)
298  {
299    if (serverPort != null)
300    {
301      Validator.ensureTrue(((serverPort >= 1) && (serverPort <= 65535)),
302           "If provided, OAUTHBEARERBindRequestProperties.serverPort must be " +
303                "between 1 and 65535, inclusive.");
304    }
305
306    this.serverPort = serverPort;
307  }
308
309
310
311  /**
312   * Retrieves the method to use for HTTP-based requests, if any.
313   *
314   * @return  The method to use for HTTP-based requests, or {@code null} if it
315   *          should be omitted from the bind request.
316   */
317  @Nullable()
318  public String getRequestMethod()
319  {
320    return requestMethod;
321  }
322
323
324
325  /**
326   * Specifies the method to use for HTTP-based requests, if it should be
327   * included in the bind request.
328   *
329   * @param   requestMethod  The method to use for HTTP-based requests.  It may
330   *                         be {@code null} if the request method should be
331   *                         omitted.
332   */
333  public void setRequestMethod(@Nullable final String requestMethod)
334  {
335    this.requestMethod = requestMethod;
336  }
337
338
339
340  /**
341   * Retrieves the path to use for HTTP-based requests, if any.
342   *
343   * @return  The path to use for HTTP-based requests, or {@code null} if it
344   *          should be omitted from the bind request.
345   */
346  @Nullable()
347  public String getRequestPath()
348  {
349    return requestPath;
350  }
351
352
353
354  /**
355   * Specifies the path to use for HTTP-based requests, if it should be included
356   * in the bind request.
357   *
358   * @param  requestPath  The path to use for HTTP-based requests.  It may be
359   *                      {@code null} if the request path should be omitted.
360   */
361  public void setRequestPath(@Nullable final String requestPath)
362  {
363    this.requestPath = requestPath;
364  }
365
366
367
368  /**
369   * Retrieves the data to submit when posting an HTTP-based request, if any.
370   *
371   * @return  The post data for HTTP-based requests, or {@code null} if it
372   *          should be omitted from the bind request.
373   */
374  @Nullable()
375  public String getRequestPostData()
376  {
377    return requestPostData;
378  }
379
380
381
382  /**
383   * Specifies the data to submit when posting an HTTP-based request, if it
384   * should be included in the bind request.
385   *
386   * @param  requestPostData  The post data for HTTP-based requests.  It may be
387   *                          {@code null} if the post data should be omitted.
388   */
389  public void setRequestPostData(@Nullable final String requestPostData)
390  {
391    this.requestPostData = requestPostData;
392  }
393
394
395
396  /**
397   * Retrieves the query string to use for HTTP-based requests, if any.
398   *
399   * @return  The query string to use for HTTP-based requests, or {@code null}
400   *          if it should be omitted from the bind request.
401   */
402  @Nullable()
403  public String getRequestQueryString()
404  {
405    return requestQueryString;
406  }
407
408
409
410  /**
411   * Specifies the query string to use for HTTP-based requests, if it should be
412   * included in the bind request.
413   *
414   * @param  requestQueryString  The query string to use for HTTP-based
415   *                             requests.  It may be {@code null} if it should
416   *                             be omitted from the bind request.
417   */
418  public void setRequestQueryString(@Nullable final String requestQueryString)
419  {
420    this.requestQueryString = requestQueryString;
421  }
422
423
424
425  /**
426   * Retrieves an unmodifiable map of additional key-value pairs that should be
427   * included in the bind request.
428   *
429   * @return  An unmodifiable map of additional key-value pairs that should be
430   *          included in the bind request.
431   */
432  @NotNull()
433  public Map<String,String> getAdditionalKeyValuePairs()
434  {
435    return Collections.unmodifiableMap(additionalKeyValuePairs);
436  }
437
438
439
440  /**
441   * Adds an item to the set of additional key-value pairs that should be
442   * included in the bind request.  If an item is already defined with the
443   * provided key, then its value will be replaced.
444   *
445   * @param  key    The key to use.  It must not be {@code null} or empty, and
446   *                it must contain only alphabetic characters.
447   * @param  value  The value to use for the key.  It must not be {@code null},
448   *                and it must not contain the 0x00 or 0x01 characters.
449   */
450  public void addKeyValuePair(@NotNull final String key,
451                              @NotNull final String value)
452  {
453    Validator.ensureNotNullOrEmpty(key,
454         "OAUTHBEARERBindRequestProperties.addKeyValuePair.key must not be " +
455              "null or empty.");
456    for (final char c : key.toCharArray())
457    {
458      Validator.ensureTrue(
459           (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))),
460           "OAUTHBEARERBindRequestProperties.addKeyValuePair.key must " +
461                "contain only alphabetic characters.");
462    }
463
464    Validator.ensureNotNull(value,
465         "OAUTHBEARERBindRequestProperties.addKeyValuePair.value must not be " +
466              "null.");
467    for (final char c : value.toCharArray())
468    {
469      Validator.ensureFalse(
470           ((c == '\u0000') || (c == '\u0001')),
471           "OAUTHBEARERBindRequestProperties.addKeyValuePair.value must not " +
472                "contain the characters \\u0000 or \\u0001.");
473    }
474
475    additionalKeyValuePairs.put(key, value);
476  }
477
478
479
480  /**
481   * Removes the specified additional key-value pair so it will not be included
482   * in the bind request.
483   *
484   * @param  key  The key to remove.
485   *
486   * @return  The value that was associated with the key.  It may be
487   *          {@code null} if the specified key was not set.
488   */
489  @Nullable()
490  public String removeKeyValuePair(@NotNull final String key)
491  {
492    return additionalKeyValuePairs.remove(key);
493  }
494
495
496
497  /**
498   * Clears the set of additional key-value pairs.
499   */
500  public void clearAdditionalKeyValuePairs()
501  {
502    additionalKeyValuePairs.clear();
503  }
504
505
506
507  /**
508   * Retrieves a string representation of the OAUTHBEARER bind request
509   * properties.
510   *
511   * @return  A string representation of the OAUTHBEARER bind request
512   *          properties.
513   */
514  @Override()
515  @NotNull()
516  public String toString()
517  {
518    final StringBuilder buffer = new StringBuilder();
519    toString(buffer);
520    return buffer.toString();
521  }
522
523
524
525  /**
526   * Appends a string representation of the OAUTHBEARER bind request properties
527   * to the provided buffer.
528   *
529   * @param  buffer  The buffer to which the information should be appended.  It
530   *                 must not be {@code null}.
531   */
532  public void toString(@NotNull final StringBuilder buffer)
533  {
534    buffer.append("OAUTHBEARERBindRequestProperties(accessToken='{redacted}'");
535
536    if (authorizationID != null)
537    {
538      buffer.append(", authorizationID='");
539      buffer.append(authorizationID);
540      buffer.append('\'');
541    }
542
543    if (serverAddress != null)
544    {
545      buffer.append(", serverAddress='");
546      buffer.append(serverAddress);
547      buffer.append('\'');
548    }
549
550    if (serverPort != null)
551    {
552      buffer.append(", serverPort=");
553      buffer.append(serverPort);
554    }
555
556    if (requestMethod != null)
557    {
558      buffer.append(", requestMethod='");
559      buffer.append(requestMethod);
560      buffer.append('\'');
561    }
562
563    if (requestPath != null)
564    {
565      buffer.append(", requestPath='");
566      buffer.append(requestPath);
567      buffer.append('\'');
568    }
569
570    if (requestPostData != null)
571    {
572      buffer.append(", requestPostData='{redacted}'");
573    }
574
575    if (requestQueryString != null)
576    {
577      buffer.append(", requestQueryString='");
578      buffer.append(requestQueryString);
579      buffer.append('\'');
580    }
581
582    if (! additionalKeyValuePairs.isEmpty())
583    {
584      buffer.append(", additionalKeyValuePairs=[");
585
586      final Iterator<Map.Entry<String,String>> iterator =
587           additionalKeyValuePairs.entrySet().iterator();
588      while (iterator.hasNext())
589      {
590        final Map.Entry<String,String> e = iterator.next();
591        buffer.append(" \"");
592        buffer.append(e.getKey());
593        buffer.append("\"=\"");
594        buffer.append(e.getValue());
595        buffer.append('"');
596
597        if (iterator.hasNext())
598        {
599          buffer.append(',');
600        }
601      }
602
603      buffer.append(" ]");
604    }
605
606    buffer.append(')');
607  }
608}