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 * docs/licenses/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 * docs/licenses/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 2016-2018 Ping Identity Corporation
026 */
027
028package com.unboundid.directory.sdk.broker.types;
029
030import com.unboundid.util.NotExtensible;
031
032
033
034/**
035 * The result of a single step through the authentication flow of an Identity
036 * Authenticator. Use AuthenticationResult.Builder to create instances of
037 * this class.
038 */
039@NotExtensible()
040public final class AuthenticationResult
041{
042  /**
043   * Whether the authentication event is successful.
044   */
045  private final boolean successful;
046
047  /**
048   * The error code if an error occurred while processing the authentication
049   * request.
050   */
051  private final String error;
052
053  /**
054   * The message describing the error that occurred while processing the
055   * authentication request.
056   */
057  private final String errorDetail;
058
059  /**
060   * The authenticated user, or {@code null} if additional steps are required.
061   */
062  private final ScimResourcePrincipal principal;
063
064  /**
065   * Parameters to return that may be used to continue the authentication
066   * process. May be {@code null}.
067   */
068  private final String responseParams;
069
070  /**
071   * State parameters to be preserved and resubmitted to the authenticator
072   * to continue a multi-step authentication flow. May be {@code null}.
073   */
074  private final String flowStateParams;
075
076  /**
077   * The message that will be only be included in the trace log for diagnostic
078   * purposes.
079   */
080  private final String diagnosticMessage;
081
082
083
084  /**
085   * Builder class to build an instance of AuthenticationResult.
086   */
087  public static class Builder
088  {
089    private boolean successful;
090    private String error;
091    private String errorDetail;
092    private ScimResourcePrincipal principal;
093    private String responseParams;
094    private String flowStateParams;
095    private String diagnosticMessage;
096
097
098
099    /**
100     * Specifies the JSON object specifying the parameters to return that may be
101     * used to continue the authentication process.
102     * <p>
103     * Since this response is visible to the client in a potentially
104     * unauthenticated context, the authenticator should not expose any
105     * sensitive user or server information in the response.
106     * @param responseParams  The parameters to return.
107     * @return  this builder.
108     */
109    public Builder setResponseParams(final String responseParams)
110    {
111      this.responseParams = responseParams;
112      return this;
113    }
114
115
116
117    /**
118     * Specifies the JSON object specifying the state parameters to be preserved
119     * and resubmitted to the authenticator to continue a multi-step
120     * authentication flow. If no state parameters are set for this result,
121     * any existing state parameters will be resubmitted to the authenticator.
122     * @param flowStateParams  The state parameters to be preserved.
123     * @return  this builder.
124     */
125    public Builder setFlowStateParams(final String flowStateParams)
126    {
127      this.flowStateParams = flowStateParams;
128      return this;
129    }
130
131
132
133    /**
134     * Specifies the message that will be only be included in the trace log
135     * for diagnostic purposes.
136     * @param diagnosticMessage  The diagnostic message
137     * @return  this builder.
138     */
139    public Builder setDiagnosticMessage(final String diagnosticMessage)
140    {
141      this.diagnosticMessage = diagnosticMessage;
142      return this;
143    }
144
145
146
147    /**
148     * Builds a new AuthenticationResult.
149     *
150     * @return  A new AuthenticationResult.
151     */
152    public AuthenticationResult build()
153    {
154      return new AuthenticationResult(
155          successful,
156          error,
157          errorDetail,
158          principal,
159          responseParams,
160          flowStateParams,
161          diagnosticMessage);
162    }
163  }
164
165  /**
166   * Create a new builder for a successful response. An authenticator
167   * should only return success if the client provided the correct
168   * credentials.
169   *
170   * @param principal The authenticated user.
171   *
172   * @return  A new builder for a successful response.
173   */
174  public static Builder success(final ScimResourcePrincipal principal)
175  {
176    final Builder b = new Builder();
177    b.successful = true;
178    b.principal = principal;
179    return b;
180  }
181
182
183
184  /**
185   * Create a new builder for an unsuccessful response. An authenticator
186   * should return an unsuccessful response if additional info is needed.
187   *
188   * @return  A new builder for an unsuccessful response.
189   */
190  public static Builder failure()
191  {
192    final Builder b = new Builder();
193    b.successful = false;
194    return b;
195  }
196
197
198
199  /**
200   * Create a new builder for an unsuccessful error response. An authenticator
201   * should return an error response if the provided credentials are incorrect
202   * or an error occurred while processing the authentication request.
203   * <p>
204   * Since this response is visible to the client in a potentially
205   * unauthenticated context, the authenticator should not expose any sensitive
206   * user or server information in the error response.
207   *
208   * @param error The error code.
209   * @param errorDetail The details about the error.
210   * @return  A new builder for an unsuccessful response.
211   */
212  public static Builder failure(final String error, final String errorDetail)
213  {
214    final Builder b = new Builder();
215    b.successful = false;
216    b.error = error;
217    b.errorDetail = errorDetail;
218    return b;
219  }
220
221
222
223  /**
224   * Create a new AuthenticationResult from the provided information.
225   * @param successful      Whether the authentication event is successful.
226   * @param error           The error code.
227   * @param errorDetail     The error detail.
228   * @param principal       The authenticated user.
229   * @param responseParams  The response parameters.
230   * @param flowStateParams The flow state parameters.
231   * @param diagnosticMessage  The diagnostic message.
232   */
233  private AuthenticationResult(
234      final boolean successful,
235      final String error,
236      final String errorDetail,
237      final ScimResourcePrincipal principal,
238      final String responseParams,
239      final String flowStateParams,
240      final String diagnosticMessage)
241  {
242    this.successful = successful;
243    this.error = error;
244    this.errorDetail = errorDetail;
245    this.principal = principal;
246    this.responseParams = responseParams;
247    this.flowStateParams = flowStateParams;
248    this.diagnosticMessage = diagnosticMessage;
249  }
250
251
252
253  /**
254   * Indicates whether the authentication event is successful.
255   *
256   * @return {@code true} if the authentication event is successful, or
257   *         {@code false} otherwise.
258   */
259  public boolean isSuccessful()
260  {
261    return successful;
262  }
263
264
265
266  /**
267   * Retrieve the error code to return if an error occurred while processing the
268   * authentication request or {@code null} if an error did not occur.
269   *
270   * @return The error code.
271   */
272  public String getError()
273  {
274    return error;
275  }
276
277
278
279  /**
280   * Retrieve the message to return if an error occurred while processing
281   * the authentication request describing the details of the error
282   * or {@code null} if an error did not occur.
283   *
284   * @return The error details.
285   */
286  public String getErrorDetail()
287  {
288    return errorDetail;
289  }
290
291
292
293  /**
294   * Retrieve the authenticated user, or {@code null} if additional steps
295   * are required. An authenticator should set the principal in the result
296   * if it can identify a user with the provided credentials. Otherwise,
297   * it should return the principal that was provided in the authentication
298   * request.
299   *
300   * @return  The authenticated user, or {@code null} if additional steps
301   *          are required.
302   */
303  public ScimResourcePrincipal getPrincipal()
304  {
305    return principal;
306  }
307
308
309
310  /**
311   * Retrieve the JSON object specifying the parameters to return that may be
312   * used to continue the authentication process. This string can be parsed
313   * using any JSON library. For example, Jackson's ObjectMapper.readTree() or
314   * the UnboundID LDAP SDK's JSONObject constructor.
315   * @return  The parameters to return, may be {@code null}.
316   */
317  public String getResponseParams()
318  {
319    return responseParams;
320  }
321
322
323
324  /**
325   * Retrieve the state parameters to be preserved and resubmitted to the
326   * authenticator to continue a multi-step authentication flow.
327   * @return  The state parameters to be preserved, may be {@code null}.
328   */
329  public String getFlowStateParams()
330  {
331    return flowStateParams;
332  }
333
334  /**
335   * Gets the message that will be only be included in the trace log
336   * for diagnostic purposes.
337   *
338   * @return The message that will be only be included in the trace log
339   */
340  public String getDiagnosticMessage()
341  {
342    return diagnosticMessage;
343  }
344
345
346
347  /**
348   * {@inheritDoc}
349   */
350  @Override
351  public boolean equals(final Object o)
352  {
353    if (this == o)
354    {
355      return true;
356    }
357    if (o == null || getClass() != o.getClass())
358    {
359      return false;
360    }
361
362    final AuthenticationResult that = (AuthenticationResult) o;
363
364    if (successful != that.successful)
365    {
366      return false;
367    }
368    if (!error.equals(that.error))
369    {
370      return false;
371    }
372    if (!errorDetail.equals(that.errorDetail))
373    {
374      return false;
375    }
376    if (principal != null ?
377        !principal.equals(that.principal) : that.principal != null)
378    {
379      return false;
380    }
381    if (responseParams != null ?
382        !responseParams.equals(that.responseParams) :
383        that.responseParams != null)
384    {
385      return false;
386    }
387    return flowStateParams != null ?
388           flowStateParams.equals(that.flowStateParams) :
389           that.flowStateParams == null;
390  }
391
392
393
394  /**
395   * {@inheritDoc}
396   */
397  @Override
398  public int hashCode()
399  {
400    int result = (successful ? 1 : 0);
401    result = 31 * result +
402             (error != null ? error.hashCode() : 0);
403    result = 31 * result +
404             (errorDetail != null ? errorDetail.hashCode() : 0);
405    result = 31 * result +
406             (principal != null ? principal.hashCode() : 0);
407    result = 31 * result +
408             (responseParams != null ? responseParams.hashCode() : 0);
409    result = 31 * result +
410             (flowStateParams != null ? flowStateParams.hashCode() : 0);
411    return result;
412  }
413
414
415
416  /**
417   * {@inheritDoc}
418   */
419  @Override
420  public String toString()
421  {
422    final StringBuilder sb = new StringBuilder("AuthenticationResult{");
423    sb.append("successful=").append(successful);
424    sb.append(", error='").append(error).append('\'');
425    sb.append(", errorDetail='").append(errorDetail).append('\'');
426    sb.append(", principal='").append(principal).append('\'');
427    sb.append(", responseParams='").append(responseParams).append('\'');
428    sb.append(", flowStateParams='").append(flowStateParams).append('\'');
429    sb.append('}');
430    return sb.toString();
431  }
432}