All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.OAUTHBEARERBindResult Maven / Gradle / Ivy

/*
 * Copyright 2020 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2020 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2020 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk;



import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.StringTokenizer;

import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.json.JSONObject;



/**
 * This class provides a bind result that can provide access to the details of
 * a failed OAUTHBEARER SASL bind attempt.
 *
 * @see  OAUTHBEARERBindRequest
 */
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class OAUTHBEARERBindResult
       extends BindResult
{
  /**
   * The name of the failure details field that holds the authorization error
   * code.
   */
  @NotNull private static final String FAILURE_DETAILS_FIELD_AUTHZ_ERROR_CODE =
       "status";



  /**
   * The name of the failure details field that holds the OpenID configuration
   * URL.
   */
  @NotNull private static final String FAILURE_DETAILS_FIELD_OPENID_CONFIG_URL =
       "openid-configuration";



  /**
   * The name of the failure details field that holds the space-delimited set of
   * scopes.
   */
  @NotNull private static final String FAILURE_DETAILS_FIELD_SCOPE = "scope";



  /**
   * The serial version UID for this serializable class.
   */
  private static final long serialVersionUID = 6513765034667496311L;



  // The final bind result received during bind processing.
  @Nullable private final BindResult finalBindResult;

  // The initial bind result received during bind processing.
  @NotNull private final BindResult initialBindResult;

  // A JSON object with additional details about a failed authentication
  // attempt.
  @Nullable private final JSONObject failureDetailsObject;

  // The set of scopes included in the failure details object.
  @NotNull private final Set scopes;

  // The authorization error code included in the failure details object.
  @Nullable private final String authorizationErrorCode;

  // The OpenID configuration URL included in the failure details object.
  @Nullable private final String openIDConfigurationURL;



  /**
   * Creates a new OAUTHBEARER bind result from the provided single bind
   * result.  The provided result is not expected to contain server SASL
   * credentials, but it will attempt to decode any credentials included in the
   * provided result.
   *
   * @param  bindResult  The bind result to use to create this OAUTHBEARER bind
   *                     result.  It must not be {@code null}.
   */
  public OAUTHBEARERBindResult(@NotNull final BindResult bindResult)
  {
    this(bindResult, null);
  }



  /**
   * Creates a new OAUTHBEARER bind result from the provided pair of results,
   * which correspond to the initial and final (if any) phases of bind
   * processing.
   *
   * @param  initialBindResult  The result obtained in response to the initial
   *                            OAUTHBEARER bind request.  It must not be
   *                            {@code null}.
   * @param  finalBindResult    The result obtained in response to the final
   *                            OAUTHBEARER bind request, if any.  It may be
   *                            {@code null} if the bind consisted of only a
   *                            single request.
   */
  public OAUTHBEARERBindResult(@NotNull final BindResult initialBindResult,
                               @Nullable final BindResult finalBindResult)
  {
    super(mergeBindResults(initialBindResult, finalBindResult));

    this.initialBindResult = initialBindResult;
    this.finalBindResult = finalBindResult;

    final ASN1OctetString serverSASLCredentials =
         initialBindResult.getServerSASLCredentials();
    if (serverSASLCredentials == null)
    {
      failureDetailsObject = null;
      authorizationErrorCode = null;
      scopes = Collections.emptySet();
      openIDConfigurationURL = null;
      return;
    }

    final JSONObject credentialsObject;
    try
    {
      credentialsObject = new JSONObject(serverSASLCredentials.stringValue());
    }
    catch (final Exception e)
    {
      Debug.debugException(e);
      failureDetailsObject = null;
      authorizationErrorCode = null;
      scopes = Collections.emptySet();
      openIDConfigurationURL = null;
      return;
    }

    failureDetailsObject = credentialsObject;
    authorizationErrorCode = credentialsObject.getFieldAsString(
         FAILURE_DETAILS_FIELD_AUTHZ_ERROR_CODE);
    openIDConfigurationURL = credentialsObject.getFieldAsString(
         FAILURE_DETAILS_FIELD_OPENID_CONFIG_URL);

    final String scopeStr =
         credentialsObject.getFieldAsString(FAILURE_DETAILS_FIELD_SCOPE);
    if (scopeStr == null)
    {
      scopes = Collections.emptySet();
      return;
    }

    final Set scopeSet = new LinkedHashSet<>();
    final StringTokenizer tokenizer = new StringTokenizer(scopeStr, " ");
    while (tokenizer.hasMoreTokens())
    {
      scopeSet.add(tokenizer.nextToken());
    }
    scopes = Collections.unmodifiableSet(scopeSet);
  }



  /**
   * Creates a bind result that is merged from the provided results.  If the
   * provided final result is {@code null}, then this will simply return the
   * initial result.  If both are non-{@code null}, then it will use all details
   * from the final result except the server SASL credentials, which will come
   * from the initial result.
   *
   * @param  initialBindResult  The result obtained in response to the initial
   *                            OAUTHBEARER bind request.  It must not be
   *                            {@code null}.
   * @param  finalBindResult    The result obtained in response to the final
   *                            OAUTHBEARER bind request, if any.  It may be
   *                            {@code null} if the bind consisted of only a
   *                            single request.
   *
   * @return  The merged bind results.
   */
  @NotNull()
  private static BindResult mergeBindResults(
               @NotNull final BindResult initialBindResult,
               @Nullable final BindResult finalBindResult)
  {
    if (finalBindResult == null)
    {
      return initialBindResult;
    }

    return new BindResult(finalBindResult.getMessageID(),
         finalBindResult.getResultCode(),
         finalBindResult.getDiagnosticMessage(),
         finalBindResult.getMatchedDN(),
         finalBindResult.getReferralURLs(),
         finalBindResult.getResponseControls(),
         initialBindResult.getServerSASLCredentials());
  }



  /**
   * Retrieves the result obtained from the initial bind attempt in the
   * OAUTHBEARER authentication process.  For a successful authentication, there
   * should only be a single bind.  For a failed authentication attempt, there
   * may be either one or two binds, based on whether credentials were included
   * in the initial bind result.
   *
   * @return  The result obtained from the initial bind attempt in the
   *          OAUTHBEARER authentication process.
   */
  @NotNull()
  public BindResult getInitialBindResult()
  {
    return initialBindResult;
  }



  /**
   * Retrieves the result obtained from the final bind attempt in the
   * OAUTHBEARER authentication process, if any.  This should always be
   * {@code null} for a successful bind, and it may or may not be {@code null}
   * for a failed attempt, based on whether credentials were included in the
   * initial bind result.
   *
   * @return  The result obtained for the final bind attempt in the
   *          OAUTHBEARER authentication process, or {@code null} if the
   *          authentication process only included a single bind.
   */
  @Nullable()
  public BindResult getFinalBindResult()
  {
    return finalBindResult;
  }



  /**
   * Retrieves a JSON object with additional information about a failed
   * authentication attempt, if any.
   *
   * @return  A JSON object with additional information about a failed
   *          authentication attempt, or {@code null} this is not available.
   */
  @Nullable()
  public JSONObject getFailureDetailsObject()
  {
    return failureDetailsObject;
  }



  /**
   * Retrieves the authorization error code obtained from the failure details
   * object, if available.
   *
   * @return  The authorization error code obtained from the failure details
   *          object, or {@code null} if no failure details object was provided
   *          or if it did not include an authorization error code.
   */
  @Nullable()
  public String getAuthorizationErrorCode()
  {
    return authorizationErrorCode;
  }



  /**
   * Retrieves the set of scopes included in the failure details object, if
   * available.
   *
   * @return  The set of scopes included in teh failure details object, or an
   *          empty set if no failure details object was provided or if it did
   *          not include any scopes.
   */
  @NotNull()
  public Set getScopes()
  {
    return scopes;
  }



  /**
   * Retrieves the OpenID configuration URL obtained from the failure details
   * object, if available.
   *
   * @return  The OpenID configuration URL obtained from the failure details
   *          object, or {@code null} if no failure details object was provided
   *          or if it did not include an OpenID configuration URL.
   */
  @Nullable()
  public String getOpenIDConfigurationURL()
  {
    return openIDConfigurationURL;
  }



  /**
   * {@inheritDoc}
   */
  @Override()
  public void toString(@NotNull final StringBuilder buffer)
  {
    buffer.append("OAUTHBEARERBindResult(resultCode=");
    buffer.append(getResultCode());

    final int messageID = getMessageID();
    if (messageID >= 0)
    {
      buffer.append(", messageID=");
      buffer.append(messageID);
    }

    final String diagnosticMessage = getDiagnosticMessage();
    if (diagnosticMessage != null)
    {
      buffer.append(", diagnosticMessage='");
      buffer.append(diagnosticMessage);
      buffer.append('\'');
    }

    final String matchedDN = getMatchedDN();
    if (matchedDN != null)
    {
      buffer.append(", matchedDN='");
      buffer.append(matchedDN);
      buffer.append('\'');
    }

    final String[] referralURLs = getReferralURLs();
    if (referralURLs.length > 0)
    {
      buffer.append(", referralURLs={");
      for (int i=0; i < referralURLs.length; i++)
      {
        if (i > 0)
        {
          buffer.append(", ");
        }

        buffer.append('\'');
        buffer.append(referralURLs[i]);
        buffer.append('\'');
      }
      buffer.append('}');
    }

    buffer.append(", hasServerSASLCredentials=");
    buffer.append(getServerSASLCredentials() != null);

    if (finalBindResult != null)
    {
      buffer.append(", initialBindResult=");
      initialBindResult.toString(buffer);

      buffer.append(", finalBindResult=");
      finalBindResult.toString(buffer);
    }

    if (failureDetailsObject != null)
    {
      buffer.append(", failureDetailsObject=");
      failureDetailsObject.toSingleLineString(buffer);
    }

    if (authorizationErrorCode != null)
    {
      buffer.append(", authorizationErrorCode='");
      buffer.append(authorizationErrorCode);
      buffer.append('\'');
    }

    if (! scopes.isEmpty())
    {
      buffer.append(", scopes={");

      final Iterator iterator = scopes.iterator();
      while (iterator.hasNext())
      {
        buffer.append(' ');
        buffer.append(iterator.next());

        if (iterator.hasNext())
        {
          buffer.append(',');
        }
      }

      buffer.append(" }");
    }

    if (openIDConfigurationURL != null)
    {
      buffer.append(", openIDConfigURL='");
      buffer.append(openIDConfigurationURL);
      buffer.append('\'');
    }

    final Control[] responseControls = getResponseControls();
    if (responseControls.length > 0)
    {
      buffer.append(", responseControls={");
      for (int i=0; i < responseControls.length; i++)
      {
        if (i > 0)
        {
          buffer.append(", ");
        }

        buffer.append(responseControls[i]);
      }
      buffer.append('}');
    }

    buffer.append(')');
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy