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