001/* 002 * Copyright 2011-2022 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2022 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-2022 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 return sendBindRequest(connection, bindDN, credentials, getControls(), 166 getResponseTimeoutMillis(connection)); 167 } 168 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override() 175 @NotNull() 176 public GenericSASLBindRequest duplicate() 177 { 178 return duplicate(getControls()); 179 } 180 181 182 183 /** 184 * {@inheritDoc} 185 */ 186 @Override() 187 @NotNull() 188 public GenericSASLBindRequest duplicate(@Nullable final Control[] controls) 189 { 190 return new GenericSASLBindRequest(bindDN, mechanism, credentials, 191 controls); 192 } 193 194 195 196 /** 197 * {@inheritDoc} 198 */ 199 @Override() 200 public void toString(@NotNull final StringBuilder buffer) 201 { 202 buffer.append("GenericSASLBindRequest(mechanism='"); 203 buffer.append(mechanism); 204 buffer.append('\''); 205 206 if (bindDN != null) 207 { 208 buffer.append(", bindDN='"); 209 buffer.append(bindDN); 210 buffer.append('\''); 211 } 212 213 if (credentials != null) 214 { 215 buffer.append(", credentials=byte["); 216 buffer.append(credentials.getValueLength()); 217 buffer.append(']'); 218 } 219 220 final Control[] controls = getControls(); 221 if (controls.length > 0) 222 { 223 buffer.append(", controls={"); 224 for (int i=0; i < controls.length; i++) 225 { 226 if (i > 0) 227 { 228 buffer.append(", "); 229 } 230 231 buffer.append(controls[i]); 232 } 233 buffer.append('}'); 234 } 235 236 buffer.append(')'); 237 } 238 239 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override() 245 public void toCode(@NotNull final List<String> lineList, 246 @NotNull final String requestID, 247 final int indentSpaces, final boolean includeProcessing) 248 { 249 // Create the request variable. 250 final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(4); 251 constructorArgs.add(ToCodeArgHelper.createString(bindDN, "Bind DN")); 252 constructorArgs.add(ToCodeArgHelper.createString(mechanism, 253 "SASL Mechanism Name")); 254 constructorArgs.add(ToCodeArgHelper.createByteArray( 255 "---redacted-SASL-credentials".getBytes(StandardCharsets.UTF_8), true, 256 "SASL Credentials")); 257 258 final Control[] controls = getControls(); 259 if (controls.length > 0) 260 { 261 constructorArgs.add(ToCodeArgHelper.createControlArray(controls, 262 "Bind Controls")); 263 } 264 265 ToCodeHelper.generateMethodCall(lineList, indentSpaces, 266 "GenericSASLBindRequest", requestID + "Request", 267 "new GenericSASLBindRequest", constructorArgs); 268 269 270 // Add lines for processing the request and obtaining the result. 271 if (includeProcessing) 272 { 273 // Generate a string with the appropriate indent. 274 final StringBuilder buffer = new StringBuilder(); 275 for (int i=0; i < indentSpaces; i++) 276 { 277 buffer.append(' '); 278 } 279 final String indent = buffer.toString(); 280 281 lineList.add(""); 282 lineList.add(indent + '{'); 283 lineList.add(indent + " BindResult " + requestID + 284 "Result = connection.bind(" + requestID + "Request);"); 285 lineList.add(indent + " // The bind was processed successfully."); 286 lineList.add(indent + '}'); 287 lineList.add(indent + "catch (SASLBindInProgressException e)"); 288 lineList.add(indent + '{'); 289 lineList.add(indent + " // The SASL bind requires multiple stages. " + 290 "Continue it here."); 291 lineList.add(indent + " // Do not attempt to use the connection for " + 292 "any other purpose until bind processing has completed."); 293 lineList.add(indent + '}'); 294 lineList.add(indent + "catch (LDAPException e)"); 295 lineList.add(indent + '{'); 296 lineList.add(indent + " // The bind failed. Maybe the following will " + 297 "help explain why."); 298 lineList.add(indent + " // Note that the connection is now likely in " + 299 "an unauthenticated state."); 300 lineList.add(indent + " ResultCode resultCode = e.getResultCode();"); 301 lineList.add(indent + " String message = e.getMessage();"); 302 lineList.add(indent + " String matchedDN = e.getMatchedDN();"); 303 lineList.add(indent + " String[] referralURLs = e.getReferralURLs();"); 304 lineList.add(indent + " Control[] responseControls = " + 305 "e.getResponseControls();"); 306 lineList.add(indent + '}'); 307 } 308 } 309}