001/* 002 * Copyright 2011-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-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) 2011-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.nio.charset.StandardCharsets; 041import java.util.ArrayList; 042import java.util.List; 043 044import com.unboundid.asn1.ASN1OctetString; 045import com.unboundid.util.NotMutable; 046import com.unboundid.util.NotNull; 047import com.unboundid.util.Nullable; 048import com.unboundid.util.ThreadSafety; 049import com.unboundid.util.ThreadSafetyLevel; 050import com.unboundid.util.Validator; 051 052 053 054/** 055 * This class provides a mechanism for performing SASL authentication in a 056 * generic manner. The caller is responsible for properly encoding the 057 * credentials (if any) and interpreting the result. Further, if the requested 058 * SASL mechanism is one that requires multiple stages, then the caller is 059 * responsible for all processing in each stage. 060 */ 061@NotMutable() 062@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 063public final class GenericSASLBindRequest 064 extends SASLBindRequest 065{ 066 /** 067 * The serial version UID for this serializable class. 068 */ 069 private static final long serialVersionUID = 7740968332104559230L; 070 071 072 073 // The SASL credentials that should be used for the bind request. 074 @Nullable private final ASN1OctetString credentials; 075 076 // The bind DN to use for the bind request. 077 @Nullable private final String bindDN; 078 079 // The name of the SASL mechanism that should be used for the bind request. 080 @NotNull private final String mechanism; 081 082 083 084 /** 085 * Creates a new generic SASL bind request with the provided information. 086 * 087 * @param bindDN The bind DN that should be used for the request. It 088 * may be {@code null} if the target identity should be 089 * derived from the credentials or some other source. 090 * @param mechanism The name of the mechanism that should be used for the 091 * SASL bind. It must not be {@code null}. 092 * @param credentials The credentials that should be used for the SASL bind. 093 * It may be {@code null} if no credentials should be 094 * used. 095 * @param controls The set of controls to include in the SASL bind 096 * request. It may be {@code null} or empty if no 097 * request controls are needed. 098 */ 099 public GenericSASLBindRequest(@Nullable final String bindDN, 100 @NotNull final String mechanism, 101 @Nullable final ASN1OctetString credentials, 102 @Nullable final Control... controls) 103 { 104 super(controls); 105 106 Validator.ensureNotNull(mechanism); 107 108 this.bindDN = bindDN; 109 this.mechanism = mechanism; 110 this.credentials = credentials; 111 } 112 113 114 115 /** 116 * Retrieves the bind DN for this SASL bind request, if any. 117 * 118 * @return The bind DN for this SASL bind request, or {@code null} if the 119 * target identity should be determined from the credentials or some 120 * other mechanism. 121 */ 122 @Nullable() 123 public String getBindDN() 124 { 125 return bindDN; 126 } 127 128 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override() 134 @NotNull() 135 public String getSASLMechanismName() 136 { 137 return mechanism; 138 } 139 140 141 142 /** 143 * Retrieves the credentials for the SASL bind request, if any. 144 * 145 * @return The credentials for the SASL bind request, or {@code null} if 146 * there are none. 147 */ 148 @Nullable() 149 public ASN1OctetString getCredentials() 150 { 151 return credentials; 152 } 153 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override() 160 @NotNull() 161 protected BindResult process(@NotNull final LDAPConnection connection, 162 final int depth) 163 throws LDAPException 164 { 165 setReferralDepth(depth); 166 167 return sendBindRequest(connection, bindDN, credentials, getControls(), 168 getResponseTimeoutMillis(connection)); 169 } 170 171 172 173 /** 174 * {@inheritDoc} 175 */ 176 @Override() 177 @NotNull() 178 public GenericSASLBindRequest duplicate() 179 { 180 return duplicate(getControls()); 181 } 182 183 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override() 189 @NotNull() 190 public GenericSASLBindRequest duplicate(@Nullable final Control[] controls) 191 { 192 final GenericSASLBindRequest bindRequest = 193 new GenericSASLBindRequest(bindDN, mechanism, credentials, controls); 194 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 195 bindRequest.setIntermediateResponseListener( 196 getIntermediateResponseListener()); 197 bindRequest.setReferralDepth(getReferralDepth()); 198 bindRequest.setReferralConnector(getReferralConnectorInternal()); 199 return bindRequest; 200 } 201 202 203 204 /** 205 * {@inheritDoc} 206 */ 207 @Override() 208 public void toString(@NotNull final StringBuilder buffer) 209 { 210 buffer.append("GenericSASLBindRequest(mechanism='"); 211 buffer.append(mechanism); 212 buffer.append('\''); 213 214 if (bindDN != null) 215 { 216 buffer.append(", bindDN='"); 217 buffer.append(bindDN); 218 buffer.append('\''); 219 } 220 221 if (credentials != null) 222 { 223 buffer.append(", credentials=byte["); 224 buffer.append(credentials.getValueLength()); 225 buffer.append(']'); 226 } 227 228 final Control[] controls = getControls(); 229 if (controls.length > 0) 230 { 231 buffer.append(", controls={"); 232 for (int i=0; i < controls.length; i++) 233 { 234 if (i > 0) 235 { 236 buffer.append(", "); 237 } 238 239 buffer.append(controls[i]); 240 } 241 buffer.append('}'); 242 } 243 244 buffer.append(')'); 245 } 246 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override() 253 public void toCode(@NotNull final List<String> lineList, 254 @NotNull final String requestID, 255 final int indentSpaces, final boolean includeProcessing) 256 { 257 // Create the request variable. 258 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(4); 259 constructorArgs.add(ToCodeArgHelper.createString(bindDN, "Bind DN")); 260 constructorArgs.add(ToCodeArgHelper.createString(mechanism, 261 "SASL Mechanism Name")); 262 constructorArgs.add(ToCodeArgHelper.createByteArray( 263 "---redacted-SASL-credentials".getBytes(StandardCharsets.UTF_8), true, 264 "SASL Credentials")); 265 266 final Control[] controls = getControls(); 267 if (controls.length > 0) 268 { 269 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 270 "Bind Controls")); 271 } 272 273 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 274 "GenericSASLBindRequest", requestID + "Request", 275 "new GenericSASLBindRequest", constructorArgs); 276 277 278 // Add lines for processing the request and obtaining the result. 279 if (includeProcessing) 280 { 281 // Generate a string with the appropriate indent. 282 final StringBuilder buffer = new StringBuilder(); 283 for (int i=0; i < indentSpaces; i++) 284 { 285 buffer.append(' '); 286 } 287 final String indent = buffer.toString(); 288 289 lineList.add(""); 290 lineList.add(indent + '{'); 291 lineList.add(indent + " BindResult " + requestID + 292 "Result = connection.bind(" + requestID + "Request);"); 293 lineList.add(indent + " // The bind was processed successfully."); 294 lineList.add(indent + '}'); 295 lineList.add(indent + "catch (SASLBindInProgressException e)"); 296 lineList.add(indent + '{'); 297 lineList.add(indent + " // The SASL bind requires multiple stages. " + 298 "Continue it here."); 299 lineList.add(indent + " // Do not attempt to use the connection for " + 300 "any other purpose until bind processing has completed."); 301 lineList.add(indent + '}'); 302 lineList.add(indent + "catch (LDAPException e)"); 303 lineList.add(indent + '{'); 304 lineList.add(indent + " // The bind failed. Maybe the following will " + 305 "help explain why."); 306 lineList.add(indent + " // Note that the connection is now likely in " + 307 "an unauthenticated state."); 308 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 309 lineList.add(indent + " String message = e.getMessage();"); 310 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 311 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 312 lineList.add(indent + " Control[] responseControls = " + 313 "e.getResponseControls();"); 314 lineList.add(indent + '}'); 315 } 316 } 317}