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}